locked
Resizing GIFs and maintaining transparency RRS feed

  • Question

  • User1268429333 posted

    I've tried half a dozen different techniques to resize a gif and maintain it's transparency

    The current function looks like this 

     
    1    public static byte[] ResizeNoCrop(byte[] image, int width, int height)
    2    {
    3    	byte[] buffer2;
    4    	if (image == null)
    5    	{
    6    		return null;
    7    	}
    8    	if (width < 1)
    9    	{
    10   		throw new ArgumentException("The minimum permitted image width is one pixel.", "width");
    11   	}
    12   	if (height < 1)
    13   	{
    14   		throw new ArgumentException("The minimum permitted image height is one pixel.", "height");
    15   	}
    16   	using (MemoryStream stream = new MemoryStream())
    17   	{
    18   		stream.Write(image, 0, image.Length);
    19   		stream.Position = 0L;
    20   		using (Image image2 = Image.FromStream(stream, true, true))
    21   		{
    22   			decimal num = (decimal)width / image2.Width; 
    23   			decimal num2 = (decimal)height / image2.Height; 
    24   			decimal num3 = Math.Min(num, num2);
    25   			int num4 = (int)Math.Min(Math.Round((decimal)(image2.Width * num3)), 2147483647M);
    26   			int num5 = (int)Math.Min(Math.Round((decimal)(image2.Height * num3)), 2147483647M);
    27   			using (Bitmap bitmap = new Bitmap(num4, num5, image2.PixelFormat))
    28   			{
    29   				byte[] buffer;
    30   				bitmap.SetResolution(image2.HorizontalResolution, image2.VerticalResolution);
    31   				bitmap.MakeTransparent(Color.Black);
    32   				using (Graphics graphics = Graphics.FromImage(bitmap))
    33   				{
    34   					graphics.CompositingQuality = CompositingQuality.HighQuality;
    35   					graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
    36   					graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
    37   					graphics.SmoothingMode = SmoothingMode.HighQuality;
    38   					graphics.DrawImage(image2, 0, 0, num4, num5);
    39   				}
    40   				using (MemoryStream stream2 = new MemoryStream())
    41   				{
    42   					ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
    43   					EncoderParameters encoderParams = new EncoderParameters(1);
    44   					encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, 0x5fL);
    45   					bitmap.Save(stream2, imageEncoders[1], encoderParams);
    46   					stream2.Position = 0L;
    47   					int count = (int)Math.Min(stream2.Length, 0x7fffffffL);
    48   					buffer = new byte[count];
    49   					stream2.Read(buffer, 0, count);
    50   					stream2.Close();
    51   				}
    52   				buffer2 = buffer;
    53   			}
    54   		}
    55   	}
    56   	return buffer2;
    57   }
    
     
     

    But I keep getting an image with a black background...which is infuriating since the images I am resizing are drawn in black over a transparent background.

    I can NOT change to png.

    I also NEED to maintain the transparency

    Has anybody done this successfully? 

    Thanks for any help provided :)

    Friday, December 19, 2008 1:05 PM

Answers

  • User1268429333 posted

    Thanks, I had actually just come to fully undertand what was going on in the past few hours and had read those two links and written something that is fairly decent.  I am going to check out the first link though as I hadn't seen it, and see if I can improve upon my code.

    MS actually has a bit of usefull reading on the topic too, related to colour matching

    http://msdn.microsoft.com/en-us/library/aa479306.aspx

     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 22, 2008 3:46 PM

All replies

  • User1268429333 posted

    I've now got the following code, resizing and saving the incoming gif bytes to a png and a gif

    The png is perfect, the gif is just a black square.

    These gifs are two colours, one colour black, one colour transparent or so the source.Palette shows.  My guess is this is part of the problem?

    1    Image source = Image.FromStream(new MemoryStream(imageBytes));
    2    byte[] pngBytes = new byte[] { };
    3    decimal wR = (decimal)width / source.Width;
    4    decimal hR = (decimal)height / source.Height;
    5    decimal r = Math.Min(wR,hR);
    6    width = (int)Math.Min(Math.Round((decimal)(source.Width * r)), 2147483647M);
    7    height = (int)Math.Min(Math.Round((decimal)(source.Height * r)), 2147483647M);

    8   
    9    using (Bitmap oBmp = new Bitmap(width, height))
    10   {
    11   oBmp.Palette = source.Palette;
    12  
    13   using (Graphics g = Graphics.FromImage(oBmp))
    14   {
    15   g.CompositingQuality = CompositingQuality.HighQuality;
    16   g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    17   g.PixelOffsetMode = PixelOffsetMode.HighQuality;
    18   g.SmoothingMode = SmoothingMode.HighQuality;
    19  
    20   g.Clear(Color.Transparent);
    21   g.DrawImage(source, 0, 0, oBmp.Width, oBmp.Height);
    22   }
    23  
    24   // Save
    25   string resizedFileName = "image.png";
    26   try
    27   {
    28   oBmp.Save(Path.Combine(copyToPath, resizedFileName), ImageFormat.Png);
    29   oBmp.Save(Path.Combine(copyToPath, resizedFileName.Replace(".png", ".gif")), ImageFormat.Gif);
    30   }
    31   catch (Exception x)
    32   {
    33   // ReportError
    34   continue;
    35   }
    36   }
     
    Friday, December 19, 2008 4:45 PM
  • User1268429333 posted

    Nobody?

    Monday, December 22, 2008 9:58 AM
  • User878321963 posted

    The problem is that GDI+ doesn't have very good support for indexed images, such as GIF.  The main problems are that you can not use a Graphics object on a indexed image, and you have very limited control over the color palette.  In you example above, GDI+ is converting the indexed GIF into a 32-bit RGB image.  It is then performing the graphics manipulation and then converting the image back into an indexed GIF.  However, the transparent color is not retained in the conversion.  Because it is working with the image as a 32-bit RGB image, it ignores your attempt to set the color palette.

     Here are a couple of links that talk about the issue and give a work-around for it.  I personally like the first link best because it does not use unsafe code blocks.

     http://ewbi.blogs.com/develops/2005/08/sparklines_22.html

    http://www.bobpowell.net/giftransparency.htm

    http://support.microsoft.com/kb/319061

    Good Luck!

    Monday, December 22, 2008 11:53 AM
  • User1268429333 posted

    Thanks, I had actually just come to fully undertand what was going on in the past few hours and had read those two links and written something that is fairly decent.  I am going to check out the first link though as I hadn't seen it, and see if I can improve upon my code.

    MS actually has a bit of usefull reading on the topic too, related to colour matching

    http://msdn.microsoft.com/en-us/library/aa479306.aspx

     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 22, 2008 3:46 PM