【问题标题】:Need to clone a bitmap image without locking the original image需要克隆位图图像而不锁定原始图像
【发布时间】:2013-10-13 23:29:00
【问题描述】:

我使用下面的代码来克隆位图图像而不锁定原始文件。但我面临克隆图像(.Gif)与原始图像不同的问题。特别是克隆图像的颜色不合适。

我做错了吗?有没有更好的方法让内存中的图像和硬盘中的原始文件删除?

代码:

private Bitmap CloneImage(Bitmap src)
    {
        if (src == null)
            return src;
        Bitmap bitmap = new Bitmap(src.Size.Width, src.Size.Height, src.PixelFormat);
        System.Drawing.Rectangle bounds = new System.Drawing.Rectangle(0, 0, src.Width, src.Height);
        System.Drawing.Imaging.BitmapData bmpData = src.LockBits(bounds, System.Drawing.Imaging.ImageLockMode.ReadWrite, src.PixelFormat);
        System.Drawing.Imaging.BitmapData newBmpData = bitmap.LockBits(bounds, System.Drawing.Imaging.ImageLockMode.ReadWrite, src.PixelFormat);
        IntPtr bPtr = bmpData.Scan0;
        IntPtr nbPtr = newBmpData.Scan0;
        int bytes = Math.Abs(bmpData.Stride) * src.Height;
        byte[] rgbValues = new byte[bytes];

        System.Runtime.InteropServices.Marshal.Copy(bPtr, rgbValues, 0, bytes);
        System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, nbPtr, bytes);
        bitmap.UnlockBits(newBmpData);
        src.UnlockBits(bmpData);
        return bitmap;
    }

原图:

克隆图像:

【问题讨论】:

  • 运行时的src.PixelFormat 是什么?步幅值是多少?这看起来像一个托盘问题。各个像素位于正确的位置,因此 memcpy 代码可能是正确的。
  • 我猜 PixelFormat 是 Format8bppIndexed 并且生成的图像具有正确的像素信息,只是一个错误/错误的颜色表。
  • 你试过Bitmap result = new Bitmap(source);吗?
  • 感谢您的 cmets。 src.pixelformat 是 Format8bppIndexed stride = 240.. 如果颜色表或调色板有误,请建议我解决这个问题?
  • @Rotem :是的,我已经尝试过了。但我不能使用该构造函数,因为我需要删除原始文件。如果我使用它,那么在删除原始图像时会导致锁定问题。

标签: c# .net


【解决方案1】:

根据这个SO answer,你在这里做的应该和,

private Bitmap CloneImage(Bitmap src)
{
  return new Bitmap(src);
}

【讨论】:

    【解决方案2】:

    通过将图像保存到 MemoryStream 来克隆图像更容易(代码更少)。然后您可以从 MemoryStream 加载它,您将拥有克隆的位图,并且您不必弄乱像素格式。

    【讨论】:

    • 感谢您的回答。但是使用内存流会导致一个问题,即我的应用程序是一个图像处理应用程序,它可以处理一些高质量的大量图像,这会导致应用程序的内存增加。
    • @learner 你可以compress流。
    • 现有代码已经使用了额外的内存,位图也不是免费的。流已经被编码器压缩了。
    【解决方案3】:

    这看起来像是调色板问题。各个像素位于正确的位置,因此 memcpy 代码可能是正确的。

    要么复制调色板,要么使用 24 位或 32 位像素格式并使用Graphics.FromImage 将源图像blit 到目标位图上。然后你可以保存为 PNG,它可能会是一个更小的文件。

    【讨论】:

    • 感谢您的回答...复制原始文件的调色板就像一个魅力...
    猜你喜欢
    • 2020-01-10
    • 1970-01-01
    • 2021-10-06
    • 2014-07-28
    • 2012-02-10
    • 1970-01-01
    • 2022-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多