Note that there are some explanatory texts on larger screens.

plurals
  1. POImage Manipulation - auto resize / crop for thumbnails
    text
    copied!<p>I have hit a brick wall with this... I know my flaw is in the logic somehow but I'll explain where I'm at.</p> <p>I'm (trying) to write code to dynamically create a square (75x75) pixel thumbnail for a navigation bar along the bottom of my Silverlight app. When I debug my code below I keep getting an "Array index out of bounds" error during the scaling nested loops (I've only debugged with srcWidth > srcHeight, one step at a time)</p> <p>The source image I'm testing with is 307x162 (49734 pixels) The dest size (per current logic) for this is 150x75 (11250 pixels) Of course after this then I intend to crop the result down to 75x75</p> <p>It's only getting about half through the source image before hitting 11251 as the index of the destination. I know it's my logic, I just don't know if I went wrong in the sizes I used to construct the destination, or in the approximations used from casting the floats to ints, or maybe it's neither</p> <p>I don't know, which is why I'm posting here... anyhow, here's my source:</p> <pre><code> private void ResizeNavBarImage(Image src) { const int SizeOfRGB = 4; WriteableBitmap bmpSource = new WriteableBitmap((BitmapSource)src.Source); int[] iSourcePixels = bmpSource.Pixels; int srcWidth = bmpSource.PixelWidth; int srcHeight = bmpSource.PixelHeight; int destWidth = 75; int destHeight = 75; float xFactor = srcWidth / destWidth; float yFactor = srcHeight / destHeight; float xSource, ySource; int iApprox; int iIndex = 0; if (srcWidth &gt; srcHeight) { WriteableBitmap bmpDest = new WriteableBitmap((int)(destWidth * yFactor), destHeight); int[] iDestPixels = bmpDest.Pixels; // Resize srcHeight to destHeight, srcWidth to same ratio for (int i = 0; i &lt; srcHeight; i++) { for (int j = 0; j &lt; srcWidth; j++) { xSource = j * yFactor; ySource = i * yFactor; iApprox = (int)(ySource * srcWidth + xSource); iDestPixels[iIndex++] = iSourcePixels[iApprox]; } } // Crop half of difference from each side of the width srcWidth = bmpDest.PixelWidth; srcHeight = bmpDest.PixelHeight; int xLeftOffset = (srcWidth - srcHeight) / 2; WriteableBitmap bmpFinalDest = new WriteableBitmap(destWidth, destHeight); for (int iPixelRow = 0; iPixelRow &lt; destHeight; iPixelRow++) { int srcOffset = (iPixelRow * srcWidth + xLeftOffset) * SizeOfRGB; int destOffset = iPixelRow * destWidth * SizeOfRGB; Buffer.BlockCopy(bmpDest.Pixels, srcOffset, bmpFinalDest.Pixels, destOffset, destWidth * SizeOfRGB); } src.Source = (ImageSource)bmpFinalDest; } else if (srcWidth &lt; srcHeight) { WriteableBitmap bmpDest = new WriteableBitmap(destWidth, (int)(destHeight * xFactor)); int[] iDestPixels = bmpDest.Pixels; // Resize srcWidth to destWidth, srcHeight to same ratio for (int i = 0; i &lt; srcHeight; i++) { for (int j = 0; j &lt; srcWidth; j++) { xSource = j * xFactor; ySource = i * xFactor; iApprox = (int)(ySource * srcWidth + xSource); iDestPixels[iIndex++] = iSourcePixels[iApprox]; } } // Crop half of difference from each side of the height srcWidth = bmpDest.PixelWidth; srcHeight = bmpDest.PixelHeight; int yTopOffset = (srcHeight - srcWidth) / 2; WriteableBitmap bmpFinalDest = new WriteableBitmap(destWidth, destHeight); for (int iPixelRow = yTopOffset; iPixelRow &lt; (destHeight - (yTopOffset * 2)); iPixelRow++) { int srcOffset = iPixelRow * srcWidth * SizeOfRGB; int destOffset = iPixelRow * destWidth * SizeOfRGB; Buffer.BlockCopy(bmpDest.Pixels, srcOffset, bmpFinalDest.Pixels, destOffset, destWidth * SizeOfRGB); } src.Source = (ImageSource)bmpFinalDest; } else // (srcWidth == srcHeight) { WriteableBitmap bmpDest = new WriteableBitmap(destWidth, destHeight); int[] iDestPixels = bmpDest.Pixels; // Resize and set source for (var i = 0; i &lt; srcHeight; i++) { for (var j = 0; j &lt; srcWidth; j++) { xSource = j * xFactor; ySource = i * yFactor; iApprox = (int)(ySource * srcWidth + xSource); iDestPixels[iIndex++] = iSourcePixels[iApprox]; } } src.Source = (ImageSource)bmpDest; } } </code></pre> <p>===============================================================================</p> <p>Here's my working code (with WriteableBitmapEx) for posterity:</p> <pre><code> private void ResizeNavBarImage(Image src) { WriteableBitmap bmpSource = new WriteableBitmap((BitmapSource)src.Source); int srcWidth = bmpSource.PixelWidth; int srcHeight = bmpSource.PixelHeight; int finalDestWidth = 75; int finalDestHeight = 75; // Resize float xFactor = ((float)finalDestWidth / (float)srcWidth); float yFactor = ((float)finalDestHeight / (float)srcHeight); float Factor = 0; if (xFactor &lt; yFactor) Factor = yFactor; else Factor = xFactor; int destWidth = (int)(srcWidth * Factor); int destHeight = (int)(srcHeight * Factor); if (destWidth &lt; destHeight &amp;&amp; destWidth != finalDestWidth) destWidth = finalDestWidth; else if (destWidth &gt; destHeight &amp;&amp; destHeight != finalDestHeight) destHeight = finalDestHeight; WriteableBitmap bmpDest = bmpSource.Resize(destWidth, destHeight, WriteableBitmapExtensions.Interpolation.Bilinear); // Crop int Offset; WriteableBitmap bmpFinalDest = new WriteableBitmap(finalDestWidth, finalDestHeight); if (destWidth &gt; destHeight) { Offset = (bmpDest.PixelWidth - bmpDest.PixelHeight) / 2; if (finalDestWidth % 2 != 0 &amp;&amp; Offset % 2 == 0) Offset -= 1; bmpFinalDest = bmpDest.Crop(Offset, 0, finalDestWidth, finalDestHeight); } else if (destWidth &lt; destHeight) { Offset = (bmpDest.PixelHeight - bmpDest.PixelWidth) / 2; if (finalDestHeight % 2 != 0 &amp;&amp; Offset % 2 == 0) Offset -= 1; bmpFinalDest = bmpDest.Crop(0, Offset, finalDestWidth, finalDestHeight); } else bmpFinalDest = bmpDest; src.Source = (ImageSource)bmpFinalDest; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload