【问题标题】:Bitmap Image Repetition with Memory Stream带内存流的位图图像重复
【发布时间】:2021-09-05 00:42:13
【问题描述】:

位图图像乘法 我找到了这个内存流选项来合并具有给定重复次数的文件。 所有的东西都是工作文件,但最后,生成的 BMP 文件不是按输入重复的。 需要帮忙。 代码中的注释行是我尝试过的另一种方式。 在此处输入代码 公共部分类Form1:表格 { FileStream 位图文件加载; 位图 bmp; int NoOfRepeats; 公共表格1() { 初始化组件(); }

    private void btnOpenFile_Click(object sender, EventArgs e)
    {
        DoubleBuffered = true;
        OpenFileDialog openFileDialog1 = new OpenFileDialog
        {
            InitialDirectory = @"D:\",
            Title = "Browse Design Files",
            CheckFileExists = true,
            CheckPathExists = true,
            DefaultExt = "tif",
            Filter = "Images (*.BMP;*.TIF)|*.BMP;*.TIF|" + "All files (*.*)|*.*",
            FilterIndex = 1,
            RestoreDirectory = true,
            Multiselect = false,
            ReadOnlyChecked = false,
            ShowReadOnly = true
        };

        if (openFileDialog1.ShowDialog() == DialogResult.OK)
        {
            byte[] ba = null;
            foreach (String file in openFileDialog1.FileNames)
            {
                Image temp = new Bitmap(file);
                LblSourceWidth.Text = Convert.ToString(temp.Width);
                LblSourHeight.Text = Convert.ToString(temp.Height);
                temp.Dispose();
                bitmapfileload = new FileStream(file,FileMode.Open,FileAccess.Read,FileShare.ReadWrite);
                ba = streamToByteArray(bitmapfileload);
            }
            NoOfRepeats = int.Parse(ltbRepeat.Text); // Text box will give no of repeat for writing proceedure
            // List <byte[]> ListBa = new List<byte[]>();
            MemoryStream MergeFile = new MemoryStream();
            using (MemoryStream allFrameStream = new MemoryStream())
            {
                for (int i = 0; i < NoOfRepeats; i++)
                {
                    allFrameStream.Write(ba, 0, ba.Length);
                    allFrameStream.Position = ba.Length * i;
                    //ListBa.Add(allFrameStream.ToArray());
                    //ListBa.Add(ba);
                }
                MergeFile = allFrameStream;
                bmp = new Bitmap(MergeFile);
            }
            //byte[] finaleba = Combine(ListBa.ToArray());
            //byte[] finaleba = ListBa.Cast<byte[]>().SelectMany(a => a).ToArray();
            //LblListCount.Text = Convert.ToString(finaleba.Length); // List Count = no of repeats for FOR-LOOP
            //Stream Finalfile = new MemoryStream(MergeFile);
            //richTextBox1.Text = Convert.ToString(Finalfile);
          
           
            LblDestiWidth.Text = Convert.ToString(bmp.Width); // no change here
            LblDestiHeight.Text = Convert.ToString(bmp.Height); // no change here
            pictureBox1.Image = bmp;
            pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
        }
    }
    private static byte[] Combine(byte[][] arrays)
    {
        byte[] bytes = new byte[arrays.Sum(a => a.Length)];
        int offset = 0;

        foreach (byte[] array in arrays)
        {
            Buffer.BlockCopy(array, 0, bytes, offset, array.Length);
            offset += array.Length;
        }

        return bytes;
    }
    public static byte[] streamToByteArray(Stream input)
    {
        MemoryStream ms = new MemoryStream();
        input.CopyTo(ms);
        return ms.ToArray();
    }

【问题讨论】:

  • 图片大小不同。因此,当您将图像添加到内存流时,您需要在前面加上字节数。然后在删除每个图像时读取字节数,然后根据字节大小获取图像。
  • 感谢@jdweng 的及时回复。我使用重复次数不重复的 For 循环多次重复相同的图像。我还检查了数组长度,发现数组长度根据重复次数增加,但显示的图像大小与原始大小相同。
  • 这很有意义。如果将多个图像添加到数组中,则每个图像的大小不会改变。但是整个数组的大小变大了。
  • 如何将所有图像按长度写入流???这实际上是我正在做的。因此,如果流长度增加,那么图像长度也应该增加,但它没有。你能建议对代码进行任何更正吗???
  • 请在此处解释您想要的实际最终目标,您似乎希望简单地将所有字节从保存这些文件到一个大字节数组中以某种方式导致 1 个具有所有这些像素的图像?这不是图像文件格式的工作原理。

标签: c#


【解决方案1】:

这个例子不是很明显。我假设最终目标是生成更大的图像,源图像的多个副本彼此堆叠。

您似乎正在尝试通过连接图像的流来做到这一点。这不起作用,因为图像有标题。这将导致仅对第一张图像进行解码。

正确的方法是创建一个新的、更大的位图,并将所有像素值复制到该位图中。例如:

    public static unsafe Bitmap Repeat(Bitmap source, int count)
    {
        var targetHeight = source.Height * count;
        var target = new Bitmap(source.Width, targetHeight, source.PixelFormat);
        var sourceData = source.LockBits(new Rectangle(0,0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat);
        var targetData = target.LockBits(new Rectangle(0, 0, target.Width, target.Height), ImageLockMode.ReadOnly,
            target.PixelFormat);
        try
        {
            var frameLength = sourceData.Stride * sourceData.Height;
            for (int i = 0; i < count; i++)
            {
                var targetPtr = targetData.Scan0 + i * frameLength;
                Buffer.MemoryCopy(sourceData.Scan0.ToPointer(), targetPtr.ToPointer(), frameLength * count, frameLength);
            }
        }
        finally
        {
            source.UnlockBits(sourceData);
            target.UnlockBits(targetData);
        }
        return target;
    }

这可以用来合并不同大小的图像,但它需要逐行复制图像,以及关于高度、索引等的更多数学运算。请注意,此代码未经测试,使用风险自负。

另一种方法是将Graphics api 与FromImage 和DrawImageUnscaled 一起使用。如果您有多个图像,这可能会更容易。

【讨论】:

  • 不幸的是,他的图像是 18k x 60k,您甚至无法为其创建第一个 Bitmap 对象,他可能需要从头开始为他的图像编写图像处理。
  • '试图读取或写入受保护的内存。这通常表明其他内存已损坏。它仅适用于 2 次重复,在第 3 次重复后我得到了上述错误。重复是我改变的水平方向。根据我的目标大小,我需要至少 40 次重复才能被接受。实际上我尝试了同样的过程,但在每次试验的最后一次都出现了大小错误,所以我决定使用一些内存流>
  • 您不能为此使用 .NET Image/Bitmap 类,它们将无法处理这些海量图像。您需要从头开始为此编写图像处理程序,或者找到可以处理大量图像的第三方库。
  • 我尝试了magickimage,LibTiff.net,但对我有用,但他们花费的时间是 15 秒,这对我的过程来说太慢了。我想我需要用 C++ 开发整个项目
  • @jaydeep6720 水平方向的图像需要逐行复制。在计算索引以获取每一行的开头时,您需要小心。同样根据this,GDI 位图的最大大小为 2Gb,因此您需要一个外部库来处理更大的图像。不过,可能也可以使用相同的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-13
  • 2018-03-26
  • 2011-10-04
  • 1970-01-01
  • 2013-12-20
  • 1970-01-01
相关资源
最近更新 更多