More Fun with Images (or System.Drawing Redux)


It’s high time I wrote another little piece on what I have been programming in my spare time.  I mentioned before that I have been playing with digital photos, extracting EXIF dates with Omar’s photo library (very handy) and posting them to the web for friends and family.  Well, Pavel Lebedinsky mentioned in the comments of that entry that GetImageThumbnail gave worse results than using DrawImage with InterpolationMode.HighQualityBicubic.  I took it to heart and started playing around with the classes in System.Drawing.  I also found this article on The Code Project which gave a nice example of how to do exactly what I wanted – just scale down my digital pictures to a more web appropriate size and make thumbnails too – using DrawImage.  I had been just creating a new Bitmap based off an instance that loads one of my jpegs and passing in the new width and height to the constructor.  The simplicity is what I really liked about my method, but anyhow… in looking at my scaled down bitmaps I could see that they were a little grainy.  I decided to run a comparison against the code in the Code Project example.


 


Sure enough, the DrawImage with InterpolationMode.HighQualityBicubic did produce a better quality image at 480 pixels across.  See CreateImage vs. CreateImage2 below.  CreateImage2 calls into The Code Project example.


 


Next I tried Pavel’s suggestion that GetThumbnailImage produces a worse image than one with DrawImage and HiQualityBicubic.  I set my thumbnail width at 96 pixels and gave it a shot.  It turns out that the thumbnail extracted from the original image via GetThumbnailImage is less grainy.  That’s not to say if you had an image without an embedded thumbnail it would be better than the DrawImage solution, but for my case, with our 3.2 megapixel Olympus, it is the best code path so far.


 


As a matter of fact, we are looking for a new camera that is more pocket-sized (Canon Elph sized) at something like 4 megapixel.  Anybody have a camera they like and recommend?


 


            /// <summary>


            /// The main entry point for the application.


            /// </summary>


            [STAThread]


            static void Main(string[] args)


            {


                  CreateImage(“145.jpg”, “145_1.jpg”, 480, ImageFormat.Jpeg);


                  CreateImage2(“145.jpg”, “145_2.jpg”, 480, ImageFormat.Jpeg);  // Better quality at 480 pixels wide


 


                  CreateImage2(“145.jpg”, “145_3.jpg”, 96, ImageFormat.Jpeg);


                  CreateThumbnailImage(“145.jpg”, “145_4.jpg”);   // Better quality at 96 pixels wide if image has an embedded thumbnail


            }


 


            internal static void CreateImage(string strOriginalImage, string strOutputImage, int intWidth, ImageFormat imgFmt)


            {


                  Bitmap bmp = new Bitmap(strOriginalImage);


                  double dblRatio = Convert.ToDouble(bmp.Height) / Convert.ToDouble(bmp.Width);


                  int intHeight = Convert.ToInt32(intWidth * dblRatio);


 


                  Image img = new Bitmap(bmp, intWidth, intHeight);


                  img.Save(strOutputImage, imgFmt);


 


                  bmp.Dispose();


                  img.Dispose();


            }


 


            internal static void CreateImage2(string strOriginalImage, string strOutputImage, int intWidth, ImageFormat imgFmt)


            {


                  Bitmap bmp = new Bitmap(strOriginalImage);


                  double dblRatio = Convert.ToDouble(bmp.Height) / Convert.ToDouble(bmp.Width);


                  int intHeight = Convert.ToInt32(intWidth * dblRatio);


 


                  Image img = FixedSize(bmp, intWidth, intHeight);


                  img.Save(strOutputImage, imgFmt);


 


                  bmp.Dispose();


                  img.Dispose();


            }


 


            internal static Image FixedSize(Image imgPhoto, int Width, int Height)


            {


                  int sourceWidth = imgPhoto.Width;


                  int sourceHeight = imgPhoto.Height;


                  int sourceX = 0;


                  int sourceY = 0;


                  int destX = 0;


                  int destY = 0;


 


                  float nPercent = 0;


                  float nPercentW = 0;


                  float nPercentH = 0;


 


                  nPercentW = ((float)Width/(float)sourceWidth);


                  nPercentH = ((float)Height/(float)sourceHeight);


                  if(nPercentH < nPercentW)


                  {


                        nPercent = nPercentH;


                        destX = System.Convert.ToInt16((Width –


                              (sourceWidth * nPercent))/2);


                  }


                  else


                  {


                        nPercent = nPercentW;


                        destY = System.Convert.ToInt16((Height –


                              (sourceHeight * nPercent))/2);


                  }


 


                  int destWidth  = (int)(sourceWidth * nPercent);


                  int destHeight = (int)(sourceHeight * nPercent);


 


                  Bitmap bmPhoto = new Bitmap(Width, Height,


                        PixelFormat.Format24bppRgb);


                  bmPhoto.SetResolution(imgPhoto.HorizontalResolution,


                        imgPhoto.VerticalResolution);


 


                  Graphics grPhoto = Graphics.FromImage(bmPhoto);


                  grPhoto.Clear(Color.Red);


                  grPhoto.InterpolationMode =


                        InterpolationMode.HighQualityBicubic;


 


                  grPhoto.DrawImage(imgPhoto,


                        new Rectangle(destX,destY,destWidth,destHeight),


                        new Rectangle(sourceX,sourceY,sourceWidth,sourceHeight),


                        GraphicsUnit.Pixel);


 


                  grPhoto.Dispose();


                  return bmPhoto;


            }


            internal static void CreateThumbnailImage(string strOriginalImage, string strThumbnailImage)


            {


                  Image.GetThumbnailImageAbort cbImg = new Image.GetThumbnailImageAbort(ThumbnailCallback);


 


                  Bitmap bmp = new Bitmap(strOriginalImage);


                  double dblRatio = Convert.ToDouble(bmp.Height) / Convert.ToDouble(bmp.Width);


                  int intHeight = Convert.ToInt32(96.0 * dblRatio);


 


                  Image img = bmp.GetThumbnailImage(96, intHeight, cbImg, IntPtr.Zero);


                  img.Save(strThumbnailImage);


 


                  bmp.Dispose();


                  img.Dispose();


            }


 


            internal static bool ThumbnailCallback()


            {


                  return false;


            }


 


 

Comments (4)

  1. theCoach says:

    The canon elph is fantastic. I would go with the 5 MP one at this point though. Another contender would be the little Sony T – something, also tiny and 5MP. I have not seen the results of the Sony, but have read they are good. The Canon Elph 4MP (I believe it is actually called the S400, and the 5MP on is the S500) takes great pictures for the form-factor. The sony appears to have a slightly better form-factor from my point of view.

    The quality will never really rival something like the Digital SLRs because the lenses are designed for size rather than picture quality, but they are great photos nonetheless, and you can take them anywhere (and the picture quality is a hell of a lot closer to SLR than to camera phones).

  2. Karan says:

    I’ll second theCoach on the Canon Sx00. Great camera.

    A friend recently purchased the Sony DSC-W1 and it has a great big LCD and takes great shots. It’s nice and small like the Canon Digital Elphs. The only thing that was a small detractor for me was that it doesn’t do the stitch images like the Canon’s.

    Finally, another co-worker purchae a small Olympus. Also a great size and form-factor. Didn’t get a chance to paly around with it, but I’ve seen some of his shots and the output was great.

    Good luck …

    PS. Check out dpreview.com for good reviews on the above digicams.

  3. Tosh Meston says:

    Thanks for the tips. Still making up my mind so if anybody else has a favorite tiny digital camera, I’d like to hear about it.