4

Possible Duplicate:
How can I get better results when shrinking an image

I am trying to generate a thumbnail of size 200 x 200px using the code below. It works fine for certain images but does not for others. When it does not work, the thumbnail is generated with that size but only partial image is seen and the other part is gray (like you have used a gray brush and smeared on top of the thumbnail). I haven't been able to see a trend when it fails. For example, it fails for a JPEG image with 400px x 400px size. If I try to generate the thumbnail with size 150px x 150px, there is no image loss. If this helps here is one image that causes problems - http://s11.postimage.org/sse5zhpqr/Drawing_8.jpg

Appreciate your time.

    public Bitmap GenerateThumbnail(Bitmap sourceBitmap, int thumbnailWidth, int thumbnailHeight)
    {
        Bitmap thumbnailBitmap = null;

        decimal ratio;
        int newWidth = 0;
        int newHeight = 0;

        // If the image is smaller than the requested thumbnail size just return it
        if (sourceBitmap.Width < thumbnailWidth &&
            sourceBitmap.Height < thumbnailHeight)
        {
            newWidth = sourceBitmap.Width;
            newHeight = sourceBitmap.Height; 
        }
        else if (sourceBitmap.Width > sourceBitmap.Height)
        {
            ratio = (decimal)thumbnailWidth / sourceBitmap.Width;
            newWidth = thumbnailWidth;
            decimal tempDecimalHeight = sourceBitmap.Height * ratio;
            newHeight = (int)tempDecimalHeight;
        }
        else
        {
            ratio = (decimal)thumbnailHeight / sourceBitmap.Height;
            newHeight = thumbnailHeight;
            decimal tempDecimalHeight = sourceBitmap.Width * ratio;
            newWidth = (int)tempDecimalHeight;
        }

        thumbnailBitmap = new Bitmap(newWidth, newHeight);

        Graphics g = Graphics.FromImage(thumbnailBitmap);
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
        g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;

        g.FillRectangle(Brushes.White, 0, 0, newWidth, newHeight);
        g.DrawImage(sourceBitmap, 0, 0, newWidth, newHeight);
        g.Dispose();


        return thumbnailBitmap;
    }

Update:

I did some more analysis and it seems that the issue is while saving the thumbnail to the SQL Server database in a varbinary column. I am using a MemoryStream to do that as below. If I save it to the disk it appears just fine. Here is my thumbnail from the database - http://s12.postimage.org/a7j50vr8d/Generated_Thumbnail.jpg

 using (MemoryStream thumbnailStream = new MemoryStream())
{             
          thumbnailBitmap.Save(thumbnailStream, System.Drawing.Imaging.ImageFormat.Jpeg);               
          return thumbnailStream.ToArray();

}

Update - This problem is resolved. The issue was NHibernate mapping that I was using for the varbinary column. I had to specify the type as "BinaryBlob" to make sure there is no silent truncation of data > 8KB.

Community
  • 1
  • 1
nipps
  • 111
  • 3
  • 1
    I suggest taking a look at http://stackoverflow.com/questions/6170912/how-can-i-get-better-results-when-shrinking-an-image/6171145#6171145 – Chris Baxter Oct 25 '12 at 16:10
  • Thanks for the response. I tried the code with the same results. Here is the image I am trying to process - http://s11.postimage.org/sse5zhpqr/Drawing_8.jpg – nipps Oct 25 '12 at 16:31
  • http://stackoverflow.com/questions/1890605/ghost-borders-ringing-when-resizing-in-gdi will solve the issue of your unexpected border. – Chris Baxter Oct 25 '12 at 19:30

1 Answers1

2

I appreciate, this should probably be a comment and not an answer, but for the extra formatting I'm posting as an answer.

Here's the code I've used to shrink an image and I've never had this issue:

private byte[] ResizeImage(System.Drawing.Image image, double scaleFactor)
        {
            //a holder for the result
            int newWidth = (int)(image.Width * scaleFactor);
            int newHeight = (int)(image.Height * scaleFactor);

            Bitmap result = new Bitmap(newWidth, newHeight);

            //use a graphics object to draw the resized image into the bitmap
            using (Graphics graphics = Graphics.FromImage(result))
            {
                //set the resize quality modes to high quality
                graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                //draw the image into the target bitmap
                graphics.DrawImage(image, 0, 0, result.Width, result.Height);
            }

            //return the resulting bitmap
            ImageConverter converter = new ImageConverter();
            return (byte[])converter.ConvertTo(result, typeof(byte[]));            
        }

Granted, I return a byte[] and not a Bitmap, as I then save it to a database.

The only differences I can really see is that instantiate my result Bitmap with a height and width, I have no call to the FillRectangle method, and I do not set the PixelOffsetMode. I also start off with an Image instead of a Bitmap

Hope this helps you somehow though.

bgs264
  • 4,572
  • 6
  • 38
  • 72