Just a quick post about something I've gotten working over at 2D Forever.

With the recent realign of 2D Forever, something I focused on was making the website scale to whatever resolution you're viewing it at. I wanted to do this to allow the images to be an appropriate size for your screen, so that you're not:

  • a) Trying to view a large image on a small screen (lots of scrolling!)
  • b) Having to view a small image on a large screen (lots of squinting!)

To achieve this, the images are simply scaled up to a percentage of the screen size. Thanks to Safari's image smoothing this looks fantastic, however on other browsers you're left with a distorted looking pixelated image.

To fix the distorted images, I've developed a method working on the principles of progressive enhancement; if you have the required specs, the images are smoothed automatically with a combination of JavaScript and Flash.

The technicalities are thus:

  1. A Flash object is placed over the original image, inheriting it's size and position;
  2. The original image URL is passed to the Flash, which then renders the image with smoothing;
  3. The original image is duplicated; the duplicate is made invisible and placed over the Flash, again inheriting the original size and position.

Point 3 is an important one. I didn't want to stop people being able to right click and save the image - or even to disable any of their expected right click options.

I'll expand on this at a later date, and maybe even release a version for public use with some documentation. For now you can view it in operation at 2D Forever.

Update (20th October '09)

As browsers have matured the problem primarily remains for IE, a discussion on a solution without Flash can be found here: Fluid Images.

Read the comments or see my most recent example of this technique.

Update (24th October '07)

The duplicate image isn't created anymore as the original is now used to cover the Flash. This gives a better view when you have css styling turned off, and there will be no repeated content if you're using a screen reader.

Code

Here's the code for the Flash. As I wanted to use Flash's inbuilt scaling, getting the width and height to display correctly was tricky - I ended up having to hard code the width and height set on the stage (either through the compiler or the IDE):

package {
	
[SWF(width='300',height='600')] 
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.external.*;	
	import com.nomensa.util.PageXML;
	
	public class SmoothScale extends flash.display.Sprite {
		
		/* Width and Height of original stage as defined in build properties */
		public var originalStageWidth:uint = 300;
		public var originalStageHeight:uint = 300;
		
		public var image:Bitmap;
		public var contentXML:PageXML = new PageXML();
		
		
		public function SmoothScale():void {
			// Get page data
			contentXML.addEventListener("complete", pageLoaded);
			contentXML.load(this.root.loaderInfo.parameters);
			
			if (ExternalInterface.available) {
				ExternalInterface.addCallback("loadImage", loadImage);
			}			
			
			function pageLoaded(evtObj:Event):void {
				var returnResult:* = (contentXML.javascriptFunction("init"));
				loadImage(new String(returnResult))
			}		
		}
		
		public function loadImage(src:String):void {
			// Load the image
			var imageURL:URLRequest = new URLRequest(src);
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener("complete", imageLoaded);			
			loader.load(imageURL);
		}
		
		public function imageLoaded(evtObj:Event):void {
			// Place image and stretch to fit the stage
			image = evtObj.target.content as Bitmap;
			image.smoothing = true;			
			image.pixelSnapping = "never";
			
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.EXACT_FIT;			
			
			image.x = 0;
			image.y = 0;

			image.width = originalStageWidth;
			image.height = originalStageHeight;

			addChild(image);
			contentXML.javascriptFunction("render")
		}		
	}
}

Comments

HimSelf says

29 September 2007 - 11:47am

This is a great idea, and your solution works quite well (even in Firefox). :-)
However, the image duplication thingy... It would be nice, if one could get around with out it, as it is kind of distracting, when viewing the page in a browser with CSS disabled.

I know, I know - disabling CSS takes the point out of the whole concept. Users should have the opportunity to browse meaningful pages of pure content though, in my oppinion. Don't you think?

tdhooper says

29 September 2007 - 5:31pm

Good point, although there's always the 'Disable Scripts' link that turns it off.

I had intended to fix the problem for another reason, having two images in the source is just messy. I should be able to get the original image to display above the Flash without having to duplicate it.

Brandon says

26 December 2007 - 8:12pm

You mentioned releasing a public version... could I get the source to this or a usable version to use on a site I'm developing? I could recreate it, but it looks like yours is working like a charm. Thanks.

tdhooper says

27 December 2007 - 1:47am

The release was hinging on the much bigger release of the Flash embedding method, however this isn't likely to go anywhere soon; so I may make a streamlined version.
Can you give me an idea of how it would be used? There were a number of different use cases that I wanted to cover.

Brandon says

28 December 2007 - 5:59pm

I'm essentially wanting to use it like you did on 2dforever... to maintain visual integrity and quality of images.

Anon says

30 January 2008 - 12:32am

Is it possible to view smooth-scale.swf?

tdhooper says

31 January 2008 - 10:44pm

I've posted the source for you

ESCBlueWire.com says

18 February 2008 - 6:08pm

I am hardly trying to scale my baner to fit the screen wide regarding the size of it but keeping the geometry of the orginal image!
It is annoing to see huge differences of photo sizes on diffrent screen resolutions (800x600, 1024x768 and so on).
A clear example of what i try is to have the banner size like 80-90% of the screen size regarding the monitor size!
How can i acomplish such thing?
The code from here shoud be saved as a .CSS ? and how i can apply it to one photo?
Thank you!
Cherwally

tdhooper says

18 February 2008 - 9:30pm

The code above is ActionScript. If you want to get the effect achieved on 2D Forever, keep checking back because I hope to release something in a few weeks.

Otherwise, you might find these useful:

RBakker says

31 July 2008 - 10:01am

I love the way this works, its flawless, however I try to implement it on my own site, no luck, still looks terrible in IE.

do you have a very basic example available for download ? in stead of me trying to mimic your site ?

Brian says

28 January 2009 - 5:22pm

Thanks for sharing that nifty trick. I checked out 2dforever, and I have one suggestion: it looks like you're basing the image size on the browser window _width_, but for portrait-oriented images (like the Siberian Girl), the window's _height_ is more of a concern. Easy fix in the javascript to see whether the image is longer vertically or width-wise. Maybe the shape of the browser window should be taken into account too? Anyway, cool trick!