Click here to Skip to main content
15,891,136 members
Articles / Programming Languages / C#
Tip/Trick

Resize PNG Image and Keep Transparent Background

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
10 Sep 2014CPOL2 min read 25.5K   6  
Taking a byte[] image from SQL DB, make it into an image, resize the image and save it with transparent background

Introduction

I found that during a recent project, I had to make sure images that were being rotated were not bigger than the space we were allocating on the web form. Resizing an image seemed simple enough, but after creating the code, the site ended up getting certain logos to come out only as a black background. In reviewing which logos were being turned into black boxes, we figured it was the PNG images that were created with a transparent background. Since a JPG cannot be saved with such a background, the resize code was not written to handle this specific file type.

Background

The problem came by allowing both PNG and JPG formats to be uploaded by sponsors to the site and the PNG having been created with a transparent background. The images were appearing as a black box. I searched the web for an answer and saw that many people had run into this issue. There were a few examples on the various sites, but they seemed to have a differing opinion.

Using the Code

The code is quite straight forward. The resize allows a byte[] to be passed to the method along with a height you would like the image and then a max width of the image as an optional parameter should resizing the image create an image that is wider than what you would like to display. The resize code does keep the Aspect Ratio by default, but you can change that in the method call to Resize.

The real trick was that we test the RawFormat of the original image and make sure that the image was saved back to that type. It may seem simple enough, and it is, but it was overlooked by our team and from searching the web for an answer, many more developers.

The code below assumes you know how to get an image type from whatever database you are using and converting it to a byte[] (LINQ data example = i.LeagueSponsorLogoImage.ToArray()), but a method call to the code below would look something like this:

C++
csharpClasses.ImageSize imgSize = new csharpClasses.ImageSize();

byte[] img = imgSize.ResizeImage(i.LeagueSponsorLogoImage.ToArray(), 400, 250);
//
// Main class method 
internal byte[] ResizeImage(byte[] p, int htOfImage, int maxOfWidth = 0)
        {
            System.Drawing.Image img = MakeImage(p);
            int width = Convert.ToInt32(Convert.ToDouble(img.Width) * 
            (Convert.ToDouble(htOfImage) / Convert.ToDouble(img.Height)));
            if (maxOfWidth != 0)
            {
                if (width > maxOfWidth)
                {
                    htOfImage = Convert.ToInt32(Convert.ToDouble(img.Height) * 
                    (Convert.ToDouble(maxOfWidth) / Convert.ToDouble(img.Width)));
                    width = maxOfWidth;
                }
            }
            System.Drawing.Size s = new System.Drawing.Size(width, htOfImage);
            System.Drawing.Image resizedImg = Resize(img, s, true);
            using (System.IO.MemoryStream memStream = new System.IO.MemoryStream())
            {
                if (System.Drawing.Imaging.ImageFormat.Png.Equals(img.RawFormat))
                {
                    resizedImg.Save(memStream, System.Drawing.Imaging.ImageFormat.Png);
                }
                else //of course you could check for bmp, jpg, etc depending on what you allowed
                {
                    resizedImg.Save(memStream, System.Drawing.Imaging.ImageFormat.Jpeg);
                }
                return memStream.ToArray();
            }
        }

private System.Drawing.Image MakeImage(byte[] byteArrayIn)
        {
            System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArrayIn);
            System.Drawing.Image returnImage = System.Drawing.Image.FromStream(ms);
            return returnImage;
        }  

private static System.Drawing.Image Resize(System.Drawing.Image image, 
    System.Drawing.Size size, bool preserveAspectRatio = true)
        {
            int newWidth;
            int newHeight;
            if (preserveAspectRatio)
            {
                int originalWidth = image.Width;
                int originalHeight = image.Height;
                float percentWidth = (float)size.Width / (float)originalWidth;
                float percentHeight = (float)size.Height / (float)originalHeight;
                float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
                newWidth = (int)(originalWidth * percent);
                newHeight = (int)(originalHeight * percent);
            }
            else
            {
                newWidth = size.Width;
                newHeight = size.Height;
            }
            System.Drawing.Image newImage = new System.Drawing.Bitmap(newWidth, newHeight);
            using (System.Drawing.Graphics graphicsHandle = System.Drawing.Graphics.FromImage(newImage))            {
                graphicsHandle.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                graphicsHandle.InterpolationMode = 
                           System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
            }
            return newImage;
        }

Points of Interest

Not any real PoI here other than I saw many answers from setting the pixel format to include the A, to some other pretty wild code that did funny things to the image

History

  • 9th September, 2014: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --