3

I used the below code to clone a bitmap image without locking the original file. But i am facing an issue that cloned image (.Gif) is not the same as the original image. Especially, the color of the cloned image is not proper.

Am I doing anything wrong? Is any better way to have Image in memory and original file deleted from hard disk?

Code:

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;
    }

Original Image:

Original Image

Cloned image:

Cloned Image

bland
  • 1,968
  • 1
  • 15
  • 22
Amsath
  • 81
  • 1
  • 7
  • What's the `src.PixelFormat` at runtime? What is the stride value? This looks like a pallette issue. The individual pixels are at the right location, so the memcpy code is probably right. – usr Oct 07 '13 at 11:51
  • 2
    I am guessing PixelFormat is Format8bppIndexed and that the produced image has the correct pixel information, just a faulty/wrong color table. – sisve Oct 07 '13 at 11:52
  • Have you tried `Bitmap result = new Bitmap(source);`? – Rotem Oct 07 '13 at 11:54
  • Thanks for ur comments. src.pixelformat is Format8bppIndexed stride = 240.. If the colortable or palette is wrong, then please advice me to overcome this? – Amsath Oct 07 '13 at 11:57
  • @Rotem : yes, i already tried that. But i cant use that constructor because, i need to delete the original file. If i used that then it will leads to locking issue while deleting the original image. – Amsath Oct 07 '13 at 12:01

3 Answers3

3

This looks like a palette issue. The individual pixels are at the right location, so the memcpy code is probably right.

Either also copy the palette, or use a 24 or 32 bit pixel format and use Graphics.FromImage to blit the source image onto the target bitmap. Then you can save as PNG which is probably going to be a smaller file anyway.

usr
  • 168,620
  • 35
  • 240
  • 369
1

It is easier (less code) to clone the image by saving it to a MemoryStream. Then you can load it from the MemoryStream and you will have your cloned Bitmap and you won't have to mess with pixel formats.

mortb
  • 9,361
  • 3
  • 26
  • 44
  • Thanks for your answer. But using the memory stream will leads to an issue that my app is an image processing app which handles some large number images also with high quality which in leads to increasing memory of the app. – Amsath Oct 07 '13 at 12:06
  • @learner You could [compress](http://msdn.microsoft.com/en-us/library/system.io.compression.gzipstream.aspx) the stream. – Sam Oct 07 '13 at 12:16
  • 1
    The existing code already uses extra memory, the Bitmap doesn't come for free either. The stream is already compressed by the encoder. – Hans Passant Oct 07 '13 at 12:38
0

According to this SO answer, what you are doing here should be as hard as,

private Bitmap CloneImage(Bitmap src)
{
  return new Bitmap(src);
}
Community
  • 1
  • 1
Sumsuddin Shojib
  • 3,583
  • 3
  • 26
  • 45
  • This does not preserve the PixelFormat! When passing a `Format8bppIndexed` bitmap, the constructed bitmap's format was `Format32bppArgb`. – trigger_segfault Aug 23 '23 at 18:55