In the Here My Am! app of my book, one problem I didn’t get around to solving was scaling of captured images to fit the display area. Typically this isn’t a problem when you capture an image large enough for that area, but when you have a low-res camera (or a high-res camera set to a low res output), or when you change view states, the image can become distorted.

As I’m working through the book now for a  second edition, I fixed this particular problem in Chapter 2’s version of the app, and fortunately the solution turns out to be pretty simple. The trick is to first wrap the img element in a div where that div contains a 1×1 CSS grid. The img element, as a child, is then centered within that cell. So in default.html I replaced the <img> element line with these:

<divid=”photo”class=”graphic”>
<imgid=”photoImg”src=”#”alt=”Tap to capture image from camera”role=”img”/>
</div>

And added these bits to default.css:

#photo {
    display: -ms-grid;
    -ms-grid-columns: 1fr;
    -ms-grid-rows: 1fr;
}

#photoImg {
    -ms-grid-column-align: center;
    -ms-grid-row-align: center;
}

Within photoImg, then, we can style that element to be 100% width or 100% height depending on whether the picture’s aspect ration is greater than or smaller than the parent div, photo. The original image size can be easily obtained from StorageFile.properties.getImagePropertiesAsync. So in this added function, imgElement is photoImg, parentDiv is photo, and file is the captured StorageFile object:

function scaleImageToFit(imgElement, parentDiv, file) {
    file.properties.getImagePropertiesAsync().done(function (props) {
        var scaleToWidth = (props.width / props.height > parentDiv.clientWidth / parentDiv.clientHeight);
        imgElement.style.width = scaleToWidth ? “100%” : “”;
        imgElement.style.height = scaleToWidth ? “” : “100%”;
}, function (e) {
        console.log(“getImageProperties error: “ + e.message);
    });
}

I then call this function from within the completed handler of captureUI.captureFileAsync, after setting the img.src URI. I also have a window.onresize handler to call this again with the most recently captured file, which handles scaling the image again for new view states.

With this approach, specifically centering the image in the parent div’s one grid cell, we get automatic letterboxing around the image.

I believe it would also be possible to solve this with a WinJS FlexBox control, which effectively does the same thing. I don’t think it would mean any less code, however. The solution here, of course, depends on the WinRT APIs and having a StorageFile object. For use with pure HTML/CSS, you can create a new Image and assign its src, and once loaded that object’s width and height properties will be available. When you have those values, you can then use the same calculation as above to scale the image without changing the aspect ratio.

 

 


2 Comments

  1. Posted April 4, 2013 at 11:59 am | Permalink

    How to do same in C#/XAML ?

    • Posted April 4, 2013 at 4:01 pm | Permalink

      Couldn’t say, unfortunately. I don’t work much in XAML.