views:

5693

answers:

8

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?

+3  A: 

I think the problem is that you're doing a scan line-based resize, which is going to lead to jaggies no matter how hard you tweak it. Good image resize quality requires you to do some more work to figure out the average color of the pre-resized pixels that your resized pixel covers.

The guy who runs this website has a blog post that discusses a few image resizing algorithms. You probably want a bicubic image scaling algorithm.

Better Image Resizing

Jonathan
Heh, "the guy who runs this website" :)
Shawn Miller
+4  A: 

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

Dillie-O
+19  A: 
Markus Olsson
it only works with square like images and doesn't resize proportionally
eKek0
Here's a list of TODO items when resizing images: http://nathanaeljones.com/163/20-image-resizing-pitfalls/Also, I've implemented GIF quantization with transparency support if anyone needs it (Google "ASP.NET image resizing module")
Computer Linguist
A: 

Wow, Markus - that's very nice.

I put a sample online: http://www.thewallcompany.dk/test/

As far as I can see - there's absolutely no loss compared to the manually resized gif image.

Thanks a lot.

MartinHN
A: 

is it possible to get transparent resize without any white or black back color?

A: 

Is there any function how can we make an image transparent. I want to make an image transparent.

A: 

For anyone that may be trying to use Markus Olsson's solution to dynamically resize images and write them out to the Response Stream.

This will not work:

Response.ContentType = "image/png";
dst.Save( Response.OutputStream, ImageFormat.Png );

But this will:

Response.ContentType = "image/png";
using (MemoryStream stream = new MemoryStream())
{
 dst.Save( stream, ImageFormat.Png );

 stream.WriteTo( Response.OutputStream );
}
Bela
Why will the second work but not the first? (just curious)
Johann Gerell
This link explains things.http://www.west-wind.com/Weblog/posts/6008.aspx
Bela
A: 

Check this solution i wrote it may help: Trick to resize transparent images

Amr ElGarhy