After getting most of Send Me a Pic completed, I needed to figure out a way to handle the image scaling widget. The reason for needed this widget was that displaying images on cell phones causes a couple problems:

• Screen sizes are really small, even the large screen sizes are still only 320 x 240. Most are around 128px on their longest side.

• Aspect Ratios for cell phones are different for each model. Aspect Ratio is the ratio of the width of the screen divided by the height. aspect-ratio = width / height.

Both of these problems means that with out a way to scale and offset the image the photos would not show up correctly on the users phones.

Before Transform:

photo_bad.jpg

Above is how the image would look if it wasn’t resized. Notice all the space at the top and bottom. This looks the same as the Widescreen DVD playing on a regular TV set. Letterboxing the image is the most reasonable way to display the image at first because all of the image is displayed

After Transform:

photo_good.jpg

This image has been custom fit to enhance just the area of the image I wanted and fills the entire screen.

The Goal:

Provide an image scaling widget and able to do it without using any Flash code. The UI needs to be as response as possible, can’t suffer usablity. The issue with Flash, is one, interacting between flash and ajax is cumbersome and I would need to pay for a Flash tool. The other issue is having done this in the past with Flash is that I need to manage the flash files and the output swf file and embeded it into the page, it is just not as elegant as pure Ajax.

Looking into the Ajax Image Manipulation tools I have seen on Ajaxian.com, these seemed like an even worse choice than flash. The apps would make round trips to the server for every command even resizing, causing really bad performance. After experimenting with numerous different ways, I found the KISS solution which makes it easy to handle image resize. The problem wasn’t the math or graphics code needed, I understand that, it was the HTML / Ajax piece.

Making an Ajax Image Manipulation Widget:

First you will need the following HTML:

<div id=”imageDiv” style=”overflow:hidden;position:relative”>
<img id=”largeImage” style=”cursor:move;”>
</div>
Wrap an image in a div that has overflow set to hidden. This will mean that anything that would normally show up outside of the div is “clipped” or not displayed. Once I figured out this piece the rest is simply hooking up the functionality. You will also want set the “img” style to have a move cursor. This will give users a visual hint that they can move the image around to change the center position.

Now load the image into the “img” tag. To do this you will need to use some JS, this is where we will actually do the image transformation. Below is the snippet of code to load the image.

function loadImage(){
var largeImg = document.getElementById(”largeImage”);
largeDiv = document.getElementById(”imageDiv”);
//set the “img” to have the standard Ajax loading symbol.
//Load an image may take a while.
largeImg.src=”images/big_rotation.gif”
//create a new Image Object. This object will be responsible for loading the image
//provide a callback for the onload event.

loadedImage = new Image();
loadedImage.onload = function(){

//when the image is loaded set the display to none so the screen
//won’t flicker.

largeDiv.style.display = “none”;
//This is where the image code is.
insideImage(largeImg);

centerDiv(largeDiv);

//set the actual image into the on screen “img” and turn it to visible.

largeImg.src = imageSrc;
largeDiv.style.display = “block”;
}
//This causes the loading of the image.
loadedImage.src = imageSrc;
}

Image Manipulation:
When the image is displayed on screen the first time, I want it to be displayed so that the entire image is visible and centered with-in surrounding div. The “insideImage” function performs the center and scaling of the so that it fits perfectly with-in the div. Before we go through the code, let’s look more at aspect ratios, this will make it clear what’s going on in “insideImage” function.
Aspect Ratio:

Below are two rectangles: The one on the left represents a fictional phone screen 200×100pixels. The rectangle on the right is a fictional image that is 100×200 pixels. Below each rectangle is the aspect ratio of the rectangles.


insideImage Function:

Function makes the image fit center inside the surrounding div or what is called letterboxing the image. To do this we need to first compare the aspect ratio of the two rectangles to determine how to fit the image of the cell phone screen. If the image’s aspect ratio is smaller than the cell phones, the letterboxing will occur on the left and right, otherwise the letterboxing occurs on the top and bottom similar to a DVD.

Once we determine where the letterboxing goes now we need to make it happen. Let’s start with the left and right scenario. Make the height equal to the height of the phone screen. The width becomes the height multiplied by the images aspect ratio. Now the image is sized correctly, now we need to center the image horizontally. Set the top of the image to be “0″, and the left location to be the width of the phone screen – the width of the image all of which is divided by 2.
That’s it five lines of code:

largeImg.style.height=window.phoneScreenHeight;
width = window.phoneScreenHeight*window.imageRatio;
largeImg.style.width=width;
largeImg.style.left = (window.phoneScreenWidth – width) / 2.0;
largeImg.style.top = 0;
To do the letterboxing on the top and bottom we need to make the width the same as the phone screen width and the height becomes the width divided by the aspect ratio. Now we need to center the image vertically to do this, set the left of the image to “0” and the top becomes the phone screen height minus the image height all of which is divided by 2.
Again to do this all that is need is 5 lines of JS:

largeImg.style.width=window.phoneScreenWidth;
height = window.phoneScreenWidth/window.imageRatio;
largeImg.style.height=height;
largeImg.style.top = (window.phoneScreenHeight – height) / 2.0;
largeImg.style.left = 0;

Complete insideImage function:

function insideImage(){
var largeImg = document.getElementById(”largeImage”);
if (window.imageRatio < window.phoneRatio){
largeImg.style.height=window.phoneScreenHeight;
width = window.phoneScreenHeight*window.imageRatio;
largeImg.style.width=width;
largeImg.style.left = (window.phoneScreenWidth – width) / 2.0;
largeImg.style.top = 0;
}else{
largeImg.style.width=window.phoneScreenWidth;
height = window.phoneScreenWidth/window.imageRatio;
largeImg.style.height=height;
largeImg.style.top = (window.phoneScreenHeight – height) / 2.0;
largeImg.style.left = 0;
}
}
Scaling the Image:
Two scale the image you need to change the width and height of the image by the same percentage of the aspect ratio will change the image will look destorted. I multiply both the width and height of the image by the precentage to change the size.
Note:Don’t use the style.width or style.height, these properties contain the “px” at the end of them will get an error.

function bigger(precentage){
var largeImg = document.getElementById(”largeImage”);
largeImg.style.width=largeImg.width*precentage;
largeImg.style.height=largeImg.height*precentage;
}

Moving the image inside of the div:

I am not sure why I spent so much time worrying about this widget it is actually quite simple. I used script.aculo.us for other areas of the site, in script.aculo.us they provide drag and drop functionality, so I need to hook this up to the image. Just one line of code: by default just move the image with-in the area of the surrounding div and because overflow is set to hidden it works perfectly.

//set the largeImage to be draggable.
new Draggable(’largeImage’);

Conculsion:

There you have it. This is all the pieces to make a stretching and draggable image widget for your Ajax application. No Flash, No Problem.