Asked by:
Quality of image downscaling to thumbnail size

Question
-
This post is related to an earlier thread posted by me which for some reason seems to have been deleted.
In the image below I'm displaying an image from the article content (to the right) for each article summary item on the left. As you might notice, the quality of the downscaled thumbnail is extremely poor. Is there really nothing that can be down about this?
http://img27.imageshack.us/img27/4082/ie10metroimagedownscali.png
Friday, July 27, 2012 11:08 AM
All replies
-
Hi Oliver,
What graphics related functions have you tried to create a downscaled image so far? Why don't you simply set the size of the image element to a smaller size and let the HTML engine render it for you (since you already have the image loaded)?
-Jeff
Jeff Sanders (MSFT)
- Proposed as answer by Jeff SandersMicrosoft employee, Moderator Friday, July 27, 2012 12:27 PM
Friday, July 27, 2012 12:27 PMModerator -
Hi Oliver,
What graphics related functions have you tried to create a downscaled image so far? Why don't you simply set the size of the image element to a smaller size and let the HTML engine render it for you (since you already have the image loaded)?
-Jeff
Jeff Sanders (MSFT)
Hey Jeff
That is exactly what I am doing. The thumbnail points to the same image src URI. Like I said in my earlier thread, browser like Google Chrome and even Firefox seems to emply bicubic filtering for downscaling images, something which could be forced using -ms-interpolation-mode: bicubic; until IE8 but since this style is no longer supported since IE9 I have no idea how to fix it.
- Oliver
Friday, July 27, 2012 12:30 PM -
Got it! Can you provide a real simple example of the source image and how far down you are scaling it so I can see this?
Jeff Sanders (MSFT)
Friday, July 27, 2012 12:32 PMModerator -
Got it! Can you provide a real simple example of the source image and how far down you are scaling it so I can see this?
Jeff Sanders (MSFT)
Huh, isn't that obvious in the image I've linked in my initial post? :)
The Samsung Logo to the left is the downscaled version of the image displayed to the right.
- Edited by Oliver Weichhold Friday, July 27, 2012 12:36 PM
Friday, July 27, 2012 12:35 PM -
Post a repro please, thanks!
Jeff Sanders (MSFT)
Friday, July 27, 2012 12:47 PMModerator -
Post a repro please, thanks!
You mean a code snippet or a working example project?
Jeff Sanders (MSFT)
Friday, July 27, 2012 12:48 PM -
As simple as:
<img src="urlhere" style ->> size info here>
Jeff Sanders (MSFT)
Friday, July 27, 2012 12:50 PMModerator -
.postthumbnail { margin-top: 5px; margin-left: 10px; margin-bottom: 5px; max-width: 100px; max-height: 70px; float: right; image-rendering: optimizeQuality !important; }
Here you go. This is the style applied to the thumbnails in the image above. The 'image-rendering" style seems to get ignored though.
- Edited by Oliver Weichhold Friday, July 27, 2012 12:58 PM
Friday, July 27, 2012 12:54 PM -
Thanks Oliver,
That looks terrible. Let me do some digging on this and see if we have some good alternatives!
-Jeff
Jeff Sanders (MSFT)
Friday, July 27, 2012 2:29 PMModerator -
I did not forget you Oliver. I could not find a simple solution but I am investigating other alternatives. We could potentially do something with WinRT since we have the power to use those APIs as well.
-Jeff
Jeff Sanders (MSFT)
Friday, July 27, 2012 8:21 PMModerator -
I did not forget you Oliver. I could not find a simple solution but I am investigating other alternatives. We could potentially do something with WinRT since we have the power to use those APIs as well.
-Jeff
Jeff Sanders (MSFT)
Friday, July 27, 2012 8:37 PM -
Thanks +1
I have the similar issue :-(
woodhead is as woodhead does
Monday, July 30, 2012 3:20 AM -
You can get a much nicer image by using a bitmapTransform and the fant interpolation like this:
var transform = new Windows.Graphics.Imaging.BitmapTransform(); // Dimensions are rounded down by BitmapEncoder to the nearest integer. transform.scaledHeight = decoder.orientedPixelHeight * ScaleFactor; transform.scaledWidth = decoder.orientedPixelWidth * ScaleFactor; transform.interpolationMode = Windows.Graphics.Imaging.BitmapInterpolationMode.fant;
I don't believe you can do it all in memory however, you may have to write this to your temp folder and set it to the img.src attribute. Depending on how you get the image you can get the blob from an XHR object, or read the image src attribute and convert it. Here is a real rough sample, it has some TODOs in it for you.var theTempFile; function getTempFile(theExt) { return Windows.Storage.ApplicationData.current.temporaryFolder.createFileAsync("dataFile." + theExt, Windows.Storage.CreationCollisionOption.replaceExisting) .then(function (sampleFile) { theTempFile = sampleFile.name; return sampleFile; }); } function resizeImage(event){ // Keep data in-scope across multiple asynchronous methods. var inputStream; var outputStream; var encoderId; var pixels; var pixelFormat; var alphaMode; var dpiX; var dpiY; var outputFilename; var DisplayWidthNonScaled = 0; var DisplayHeightNonScaled = 0; var ScaleFactor = .25; //TODO amount to scale by //get a stream from the source image var imageSource = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(new Windows.Foundation.Uri(theThumbnail.src)); imageSource.openReadAsync().then(function (stream) { inputStream = stream; return Windows.Graphics.Imaging.BitmapDecoder.createAsync(inputStream); }).then(function (decoder) { var transform = new Windows.Graphics.Imaging.BitmapTransform(); // Note that we are requesting the oriented pixel dimensions, and not applying // EXIF orientation in the BitmapTransform. We will request oriented pixel data // later in the BitmapDecoder.GetPixelDataAsync() call. // Dimensions are rounded down by BitmapEncoder to the nearest integer. transform.scaledHeight = decoder.orientedPixelHeight * ScaleFactor; transform.scaledWidth = decoder.orientedPixelWidth * ScaleFactor; // not rotating -->> transform.rotation = Helpers.convertToBitmapRotation(UserRotation); transform.interpolationMode = Windows.Graphics.Imaging.BitmapInterpolationMode.fant; // The BitmapDecoder indicates what pixel format and alpha mode best match the // natively stored image data. This can provide a performance and/or quality gain. pixelFormat = decoder.bitmapPixelFormat; alphaMode = decoder.bitmapAlphaMode; dpiX = decoder.dpiX; dpiY = decoder.dpiY; DisplayWidthNonScaled = decoder.orientedPixelWidth; DisplayHeightNonScaled = decoder.orientedPixelHeight; // Get pixel data from the decoder. We apply the user-requested transforms on the // decoded pixels to take advantage of potential optimizations in the decoder. return decoder.getPixelDataAsync( pixelFormat, alphaMode, transform, Windows.Graphics.Imaging.ExifOrientationMode.respectExifOrientation, Windows.Graphics.Imaging.ColorManagementMode.colorManageToSRgb ); }).then(function (pixelProvider) { pixels = pixelProvider.detachPixelData(); // Now that we have the pixel data, get the destination file // todo get the type of image from image.src return getTempFile("png"); }).then(function (file) { outputFilename = file.name; switch (file.fileType) { case ".jpg": encoderId = Windows.Graphics.Imaging.BitmapEncoder.jpegEncoderId; break; case ".bmp": encoderId = Windows.Graphics.Imaging.BitmapEncoder.bmpEncoderId; break; case ".png": default: encoderId = Windows.Graphics.Imaging.BitmapEncoder.pngEncoderId; break; } return file.openAsync(Windows.Storage.FileAccessMode.readWrite); }).then(function (stream) { outputStream = stream; // BitmapEncoder expects an empty output stream; the user may have selected a // pre-existing file. outputStream.size = 0; return Windows.Graphics.Imaging.BitmapEncoder.createAsync(encoderId, outputStream); }).then(function (encoder) { // Write the pixel data onto the encoder. Note that we can't simply use the // BitmapTransform.ScaledWidth and ScaledHeight members as the user may have // requested a rotation (which is applied after scaling). encoder.setPixelData( pixelFormat, alphaMode, DisplayWidthNonScaled * ScaleFactor, DisplayHeightNonScaled * ScaleFactor, dpiX, dpiY, pixels ); return encoder.flushAsync(); }).then(function () { ///WinJS.log("Successfully saved a copy: " + outputFilename, "sample", "status"); }, function (error) { //WinJS.log("Failed to update file: " + error.message, "sample", "error"); resetSessionState(); resetPersistedState(); }).done(function () { // Finally, close each stream to release any locks. inputStream && inputStream.close(); outputStream && outputStream.close(); theThumbnail.src = "ms-appdata:///temp/" + theTempFile; }); }
-Jeff
Jeff Sanders (MSFT)
- Proposed as answer by Jeff SandersMicrosoft employee, Moderator Monday, July 30, 2012 6:31 PM
Monday, July 30, 2012 6:31 PMModerator -
Thanks a lot for the sample Jeff. Really appreciated. That's quite a lot of code for something that used to work out of the box (ok using a simple CSS style) in IE8. Any idea why this has been dropped from IE9+?Monday, July 30, 2012 8:07 PM
-
No idea! I asked the same question and so far... crickets. I could guess, but that would do no good :-)
Jeff Sanders (MSFT)
Monday, July 30, 2012 8:21 PMModerator -
No idea! I asked the same question and so far... crickets. I could guess, but that would do no good :-)
Jeff Sanders (MSFT)
Saturday, August 18, 2012 4:16 PM