Search code examples
c#.netimageresizeimage-scaling

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?


Solution

  • 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