Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resize transparent images using C#

Does anyone have the secret formula to resizing transparent images (mainly GIFs) without ANY quality loss - what so ever?

I've tried a bunch of stuff, the closest I get is not good enough.

Take a look at my main image:

http://www.thewallcompany.dk/test/main.gif

And then the scaled image:

http://www.thewallcompany.dk/test/ScaledImage.gif

//Internal resize for indexed colored images void IndexedRezise(int xSize, int ySize) {   BitmapData sourceData;   BitmapData targetData;    AdjustSizes(ref xSize, ref ySize);    scaledBitmap = new Bitmap(xSize, ySize, bitmap.PixelFormat);   scaledBitmap.Palette = bitmap.Palette;   sourceData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),     ImageLockMode.ReadOnly, bitmap.PixelFormat);   try   {     targetData = scaledBitmap.LockBits(new Rectangle(0, 0, xSize, ySize),       ImageLockMode.WriteOnly, scaledBitmap.PixelFormat);     try     {       xFactor = (Double)bitmap.Width / (Double)scaledBitmap.Width;       yFactor = (Double)bitmap.Height / (Double)scaledBitmap.Height;       sourceStride = sourceData.Stride;       sourceScan0 = sourceData.Scan0;       int targetStride = targetData.Stride;       System.IntPtr targetScan0 = targetData.Scan0;       unsafe       {         byte* p = (byte*)(void*)targetScan0;         int nOffset = targetStride - scaledBitmap.Width;         int nWidth = scaledBitmap.Width;         for (int y = 0; y < scaledBitmap.Height; ++y)         {           for (int x = 0; x < nWidth; ++x)           {             p[0] = GetSourceByteAt(x, y);             ++p;           }           p += nOffset;         }       }     }     finally     {       scaledBitmap.UnlockBits(targetData);     }   }   finally   {     bitmap.UnlockBits(sourceData);   } } 

I'm using the above code, to do the indexed resizing.

Does anyone have improvement ideas?

like image 422
MartinHN Avatar asked Aug 27 '08 16:08

MartinHN


2 Answers

If there's no requirement on preserving file type after scaling I'd recommend the following approach.

using (Image src = Image.FromFile("main.gif")) using (Bitmap dst = new Bitmap(100, 129)) using (Graphics g = Graphics.FromImage(dst)) {    g.SmoothingMode = SmoothingMode.AntiAlias;    g.InterpolationMode = InterpolationMode.HighQualityBicubic;    g.DrawImage(src, 0, 0, dst.Width, dst.Height);    dst.Save("scale.png", ImageFormat.Png); } 

The result will have really nice anti aliased edges

  • removed image shack image that had been replaced by an advert

If you must export the image in gif you're in for a ride; GDI+ doesn't play well with gif. See this blog post about it for more information

Edit: I forgot to dispose of the bitmaps in the example; it's been corrected

like image 124
Markus Olsson Avatar answered Sep 18 '22 22:09

Markus Olsson


This is a basic resize function I've used for a few of my applications that leverages GDI+

/// <summary> ///    Resize image with GDI+ so that image is nice and clear with required size. /// </summary> /// <param name="SourceImage">Image to resize</param> /// <param name="NewHeight">New height to resize to.</param> /// <param name="NewWidth">New width to resize to.</param> /// <returns>Image object resized to new dimensions.</returns> /// <remarks></remarks> public static Image ImageResize(Image SourceImage, Int32 NewHeight, Int32 NewWidth) {    System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(NewWidth, NewHeight, SourceImage.PixelFormat);     if (bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format1bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format4bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format8bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Undefined | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.DontCare | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppArgb1555 | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppGrayScale)     {       throw new NotSupportedException("Pixel format of the image is not supported.");    }     System.Drawing.Graphics graphicsImage = System.Drawing.Graphics.FromImage(bitmap);     graphicsImage.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality;    graphicsImage.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;    graphicsImage.DrawImage(SourceImage, 0, 0, bitmap.Width, bitmap.Height);    graphicsImage.Dispose();    return bitmap;  } 

I don't remember off the top of my head if it will work with GIFs, but you can give it a try.

Note: I can't take full credit for this function. I pieced a few things together from some other samples online and made it work to my needs 8^D

like image 32
Dillie-O Avatar answered Sep 18 '22 22:09

Dillie-O