locked
Quality of image downscaling to thumbnail size RRS feed

  • 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



    weichhold.com

    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)

    Friday, July 27, 2012 12:27 PM
    Moderator
  • 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


    weichhold.com

    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 PM
    Moderator
  • 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.


    weichhold.com


    Friday, July 27, 2012 12:35 PM
  • Post a repro please, thanks!

    Jeff Sanders (MSFT)

    Friday, July 27, 2012 12:47 PM
    Moderator
  • Post a repro please, thanks!

    Jeff Sanders (MSFT)

    You mean a code snippet or a working example project?

    weichhold.com

    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 PM
    Moderator
  • .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.


    weichhold.com





    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 PM
    Moderator
  • 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 PM
    Moderator
  • 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)

    Thanks for the update Jeff. Greatly appreciate your work!

    weichhold.com

    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)

    Monday, July 30, 2012 6:31 PM
    Moderator
  • 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+? 

    weichhold.com

    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 PM
    Moderator
  • No idea!  I asked the same question and so far... crickets.  I could guess, but that would do no good :-)


    Jeff Sanders (MSFT)

    Looks like this has been fixed for RTM.

    weichhold.com

    Saturday, August 18, 2012 4:16 PM