Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with:

Creating An Image Zoom And Clip Effect With jQuery And ColdFusion

By Ben Nadel on

This is just a quick follow-up post to my previous image zoom experiment. In my previous post, I demonstrated the ability to zoom into selected portions of an image using jQuery. Today, I built on top of that idea, including a server-side, ColdFusion-powered aspect that would load the zoomed-in, hi-resolution subsections of the image on demand. There are two ColdFusion components to this process: one to get the initial low-resolution image to display; and one to get the incrementally higher-resolution image to serve up dynamically.

 
 
 
 
 
 
 
 
 
 

The HTML and Javascript are basically the same as they were yesterday. All I did was add another overlay image that would hold the hi-resolution photo. Then, I had to add some control code to set the hi-resolution SRC as necessary (based on the zoom) as well as hide and show the overlay when zooming and not zooming, respectively.

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>Image Zoom With jQuery</title>
  • <style type="text/css">
  •  
  • #view {
  • border: 1px solid #333333 ;
  • overflow: hidden ;
  • position: relative ;
  • width: 500px ;
  • }
  •  
  • #image {
  • display: block ;
  • left: 0px ;
  • top: 0px ;
  • }
  •  
  • #hi-res-image {
  • display: none ;
  • left: 0px ;
  • position: absolute ;
  • top: 0px ;
  • z-index: 500 ;
  • }
  •  
  • #zoom {
  • background-image: url( "./white_fade.png" ) ;
  • border: 1px solid #000000 ;
  • cursor: pointer ;
  • display: none ;
  • position: absolute ;
  • z-index: 1000 ;
  • }
  •  
  • </style>
  • <script type="text/javascript" src="../jquery-1.4.js"></script>
  • <script type="text/javascript">
  •  
  • // When the WINDOW is ready, initialize. We are going with
  • // the window load rather than the document so that we
  • // know our image will be ready as well (complete with
  • // gettable dimentions).
  • $( window ).load(function(){
  •  
  • // First, let's get refernces to the elements we will
  • // be using.
  • var view = $( "#view" );
  • var image = $( "#image" );
  • var hiResImage = $( "#hi-res-image" );
  •  
  • // Create the ZOOM element - this will be added with
  • // Javascript since it's more of an "effect".
  • var zoom = $( "<a id='zoom'><span><br /></span></a>" );
  •  
  • // Before we start messing with the scripts, let's
  • // update the display to allow for the absolute
  • // positioning of the image and zoomer.
  •  
  • // Set an exlicit dimension on the image (to make sure
  • // that some of the later calcualtions don't get
  • // messed up - I saw some irradic caculated-height
  • // behavior).
  • image.width( image.width() );
  • image.height( image.height() );
  •  
  • // Now that the view has an explicit width and height,
  • // we can change the displays for positioning.
  • image.css( "position", "absolute" );
  •  
  • // Set an explict height on the hi-res image so that
  • // it will display properly. The hi-res image will
  • // always have the same dimensions as the base image.
  • hiResImage.width( image.width() );
  • hiResImage.height( image.height() );
  •  
  • // Set an explicit height / width on the view based
  • // on the initial size of the image.
  • view.width( image.width() );
  • view.height( image.height() );
  •  
  • // Before we add the zoom square, we need it to match
  • // the aspect ratio of the image.
  • zoom.width( Math.floor( image.width() / 2 ) );
  • zoom.height( Math.floor( image.height() / 2 ) );
  •  
  • // Now, add the zoom square to the view.
  • view.append( zoom );
  •  
  • // ---------------------------------------------- //
  • // ---------------------------------------------- //
  •  
  •  
  • // Now that we have our UI set up physically, we need
  • // to bind the event handlers.
  •  
  • // We want to show and hide the zoom only when the
  • // user hovers over the view.
  • view.hover(
  • function( event ){
  • // Show the soom.
  • zoom.show();
  • },
  • function( event ){
  • // Hide the zoom.
  • zoom.hide();
  • }
  • );
  •  
  •  
  • // As the user mouses over the view, we can get the
  • // mouse coordinates in terms of the page; we need
  • // to be able to translate those into VIEW-based
  • // X and Y cooridates. As such, let's get the offset
  • // of the view as our base 0x0 coordinate.
  • //
  • // NOTE: We are doing this here so that we do it once,
  • // rather than every time the mouse moves.
  • viewOffset = view.offset();
  •  
  • // Get the jQuery-ed version of the window as we will
  • // need to access it's scroll offsets every time the
  • // mouse moves over the div.
  • //
  • // NOTE: This will change the change the refernce to
  • // "window" for all of the code in this closure.
  • var window = $( window );
  •  
  •  
  • // As the user moves across the view, we want to move
  • // the zoom square with them.
  • view.mousemove(
  • function( event ){
  • // Get the window scroll top; the mouse
  • // position is relative to the window, NOT
  • // the document.
  • var windowScrollTop = window.scrollTop();
  • var windowScrollLeft = window.scrollLeft();
  •  
  • // Translate the mouse X / Y into view-local
  • // coordinates that can be used to position
  • // the zoom box.
  • setZoomPosition(
  • Math.floor(
  • event.clientX - viewOffset.left + windowScrollLeft
  • ),
  • Math.floor(
  • event.clientY - viewOffset.top + windowScrollTop
  • )
  • );
  • }
  • );
  •  
  •  
  • // I position the zoom box within the view based on
  • // the given view-local mouse coordinates.
  • var setZoomPosition = function( mouseLeft, mouseTop ){
  • // Ideally, we want to keep the zoom box centered
  • // on the mouse. As such, we want the given mouse
  • // left and mouse top coordiantes to be in the
  • // middle of the zoom box.
  • var zoomLeft = (mouseLeft - (zoom.width() / 2));
  • var zoomTop = (mouseTop - (zoom.height() / 2))
  •  
  • // As we move the zoom box around, however, we
  • // never want it to go out of bounds of the view.
  •  
  • // Protect the top-left bounds.
  • zoomLeft = Math.max( zoomLeft, 0 );
  • zoomTop = Math.max( zoomTop, 0 );
  •  
  • // Protect the bottom-right bounds. Because the
  • // bottom and right need to take the dimensions
  • // of the zoom box into account, be sure to use
  • // the outer width to include the border.
  • zoomLeft = Math.min(
  • zoomLeft,
  • (view.width() - zoom.outerWidth())
  • );
  • zoomTop = Math.min(
  • zoomTop,
  • (view.height() - zoom.outerHeight())
  • );
  •  
  • // Position the zoom box in the bounds of the
  • // image view box.
  • zoom.css({
  • left: (zoomLeft + "px"),
  • top: (zoomTop + "px")
  • });
  • };
  •  
  •  
  • // Now that we have the mouse movements being tracked
  • // properly, we need to track the click on the zoom to
  • // zoom in the image on demand. To do that, however,
  • // we need to start storing some information with the
  • // image so we can manipulate it as needed.
  • image.data({
  • zoomFactor: (view.width() / zoom.width()),
  • zoom: 1,
  • top: 0,
  • left: 0,
  • width: image.width(),
  • height: image.height(),
  • originalWidth: image.width(),
  • originalHeight: image.height()
  • });
  •  
  •  
  • // Now, let's attach the click event handler to the
  • // zoom box.
  • zoom.click(
  • function( event ){
  • // First, prevent the default since this is
  • // not a navigational link.
  • event.preventDefault();
  •  
  • // There are a couple of situations in which
  • // we do not want the person to keep zooming.
  • // 1. The zoom is currently animating.
  • // 2. The zoom is too large (max 4).
  • // 3. The hi-resolution image at this zoom has
  • // not yet finished loading.
  • if (
  • image.is( ":animated" ) ||
  • (image.data( "zoom" ) == 4) ||
  • !hiResImage[ 0 ].complete
  • ){
  • return;
  • }
  •  
  • // If the current hi-res image has completed
  • // loading, then we can zoom. Let's pass the
  • // position of the zoom box off to the
  • // function that is responsible for zooming
  • // the image.
  • zoomImage(
  • zoom.position().left,
  • zoom.position().top
  • );
  • }
  • );
  •  
  •  
  • // I take the zoom box coordinates and translate them
  • // into an actual image zoom based on the existing
  • // zoom and offset of the image.
  • //
  • // NOTE: We don't care about the dimensions of the
  • // zoom box itself as those should have already been
  • // properly translated into the zoom *factor*.
  • var zoomImage = function( zoomLeft, zoomTop ){
  • // Get a reference to the image data object so we
  • // don't need to keep retreiving it.
  • var imageData = image.data();
  •  
  • // Scale the image up based on the zoom factor.
  • imageData.width = Math.floor(
  • image.width() * imageData.zoomFactor
  • );
  •  
  • imageData.height = Math.floor(
  • image.height() * imageData.zoomFactor
  • );
  •  
  • // Change the offset set data to re-position the
  • // 0,0 coordinate back up in the top left.
  • imageData.left = Math.floor(
  • (imageData.left - zoomLeft) * imageData.zoomFactor
  • );
  •  
  • imageData.top = Math.floor(
  • (imageData.top - zoomTop) * imageData.zoomFactor
  • );
  •  
  • // Increase the zoom.
  • imageData.zoom++;
  •  
  • // Hide the hi-resolution image if it is showing.
  • hiResImage.fadeOut( 50 );
  •  
  • // Animate the zoom.
  • image.animate(
  • {
  • width: imageData.width,
  • height: imageData.height,
  • left: imageData.left,
  • top: imageData.top
  • },
  • 500
  • );
  •  
  • // Load the hi-resolution image based on what the
  • // zoom is about to do.
  • loadHiResImage();
  • };
  •  
  •  
  • // I reset the image zoom.
  • var resetZoom = function(){
  • // Get a reference to the image data object so we
  • // don't need to keep retreiving it.
  • var imageData = image.data();
  •  
  • // Reset the image data.
  • imageData.zoom = 1;
  • imageData.top = 0;
  • imageData.left = 0;
  • imageData.width = imageData.originalWidth;
  • imageData.height = imageData.originalHeight;
  •  
  • // Hide the hi-resolution image if it is showing.
  • hiResImage.fadeOut( 50 );
  •  
  • // Animate the zoom.
  • image.animate(
  • {
  • width: imageData.width,
  • height: imageData.height,
  • left: imageData.left,
  • top: imageData.top
  • },
  • 300
  • );
  • };
  •  
  •  
  • // I load the hi-resolution zoom image based on the
  • // current image data.
  • var loadHiResImage = function( targetZoom ){
  • // Get a reference to the image data object so we
  • // don't need to keep retreiving it.
  • var imageData = image.data();
  •  
  • // Load the hi-res image source.
  • hiResImage.attr(
  • "src",
  • (
  • "get_hi_res.cfm" +
  • "?image=" + image.attr( "rel" ) +
  • "&width=" + imageData.width +
  • "&height=" + imageData.height +
  • "&top=" + Math.abs( imageData.top ) +
  • "&left=" + Math.abs( imageData.left ) +
  • "&zoomWidth=" + view.width() +
  • "&zoomHeight=" + view.height()
  • )
  • );
  • };
  •  
  •  
  • // Bind to the hi-res image load event so that we can
  • // show it when it's loaded.
  • hiResImage.load(
  • function( event ){
  • hiResImage.fadeIn( 100 );
  • }
  • );
  •  
  •  
  • // As a final step, to make sure that the image can
  • // be zoomed out, bind the mousedown to the document.
  • $( document ).mousedown(
  • function( event ){
  • // Check to see if the view is in the event
  • // bubble chain for the mouse down. If it is,
  • // then this click was in the view or its
  • // child elements.
  • var closestView = $( event.target ).closest( "#view" );
  •  
  • // Check to see if this mouse down was in the
  • // image view.
  • if (!closestView.size()){
  •  
  • // The view was not found in the chain.
  • // This was clicked outside of the view.
  • // Reset the image zoom.
  • resetZoom();
  •  
  • }
  • }
  • );
  •  
  • });
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • Image Zoom And Clip With jQuery
  • </h1>
  •  
  • <div id="view">
  • <!---
  • Hold the original image. We are using the REL
  • attribute here so that we can get access to the
  • image name for the hi-resolution image loads.
  • --->
  • <img
  • id="image"
  • rel="desert.jpg"
  • src="./get_low_res.cfm?image=desert.jpg"
  • />
  •  
  • <!--- Holds the hi-res image that will be loaded. --->
  • <img id="hi-res-image" />
  • </div>
  •  
  • </body>
  • </html>

As you can see, there's not much more going on. As the user zooms into the photo, I call the newly created loadHiResImage() method. This takes the zoom and offset information associated to the image and uses it to create the hi-resolution image source value; this image source is, in reality, a request to a ColdFusion page that will create the zoomed subsection of the original image on demand.

Image manipulation is a very expensive process, especially when it involves scaling. To control this cost (in a light, superficial way), I am caching the resized images on the server. This way, if the user makes a request for an image zoomed-in at the given dimensions, I'll still have to crop the image, but I won't have to resize it, which turns out to be the most expensive part of this process. Both the creation of the low-resolution and hi-resolution images use this approach.

To start with, let's take a look at the ColdFusion page that produces the low-resolution image:

get_low_res.cfm

  • <!--- Param the image name. --->
  • <cfparam name="url.image" type="string" />
  •  
  • <!--- Read the image into a ColdFusion image object. --->
  • <cfimage
  • name="image"
  • action="read"
  • source="./#url.image#"
  • />
  •  
  •  
  • <!---
  • Before we go through the both of resizing the image (which
  • is processing intensive), let's see if we have a cached
  • version of the image at this size.
  • --->
  • <cfset cachedImagePath = (
  • expandPath( "./" ) &
  • "cache/" &
  • ("low-res-src-" & url.image)
  • ) />
  •  
  • <!--- Check to see if the cached file exists. --->
  • <cfif fileExists( cachedImagePath )>
  •  
  • <!--- Read in the cached file size. --->
  • <cfimage
  • name="image"
  • action="read"
  • source="#cachedImagePath#"
  • />
  •  
  • <cfelse>
  •  
  • <!--- Resize the image to fit in a low-res box. --->
  • <cfset imageScaleToFit( image, 500, 500 ) />
  •  
  • <!---
  • Now that we have scaled the image to the appropriate
  • size, write it to the cache so that we won't have to
  • perform this resize again.
  • --->
  • <cfset imageWrite(
  • image,
  • cachedImagePath
  • ) />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • Write the image to the output buffer and parse it as XML.
  • This way, we can get access to the SRC attribute of the
  • server's temp PNG file.
  • --->
  • <cfxml variable="imageHtml">
  •  
  • <!--- Write IMG html tag as XML node. --->
  • <cfimage
  • action="writetobrowser"
  • source="#image#"
  • />
  •  
  • </cfxml>
  •  
  • <!--- Relocate user the temp PNG file. --->
  • <cflocation
  • url="#imageHtml.xmlRoot.xmlAttributes.src#"
  • addtoken="false"
  • />

As you can see, this ColdFusion page reads in the image and then checks to see if it has been cached at the given size (lo-res). If it has, it reads in the cached version. If it has not been cached, it then scales the original image down to its low-resolution size and caches it. At the end, ColdFusion writes the image to the image servlet and redirects the user to the temporary PNG. This works well because an IMG tag will follow "302 Temporarily Moved" redirects when loading its binary source file.

As the user zooms into the image, the Javascript makes subsequent requests to the ColdFusion server to return a hi-resolution image defined by the current zoom and offset values. Just as with the other ColdFusion page, this one makes use of superficial, size-based caching to cut down on the amount of resizing. This ColdFusion page, however, takes an additional step and overlays a watermark on top of the hi-resolution image. In this way, we can give the user a preview of what the hi-resolution image will look like without actually give them access to the full, hi-resolution image.

get_hi_res.cfm

  • <!--- Param the url values. --->
  • <cfparam name="url.image" type="string" />
  • <cfparam name="url.width" type="numeric" />
  • <cfparam name="url.top" type="numeric" />
  • <cfparam name="url.left" type="numeric" />
  • <cfparam name="url.zoomWidth" type="numeric" />
  • <cfparam name="url.zoomHeight" type="numeric" />
  •  
  •  
  • <!---
  • This is mean to only show part of the image. As such,
  • make sure that the zoomWidth and zoomHeight do not exceed
  • the "allowed" hi-res size.
  • --->
  • <cfif (
  • (url.zoomWidth gt 500) ||
  • (url.zoomHeight gt 500)
  • )>
  •  
  • <!---
  • The user is trying to scam the system - throw an error;
  • there's no need to return something or even worry about
  • their user experience at this point.
  • --->
  • <cfthrow
  • type="IllegalDimensions"
  • message="The dimensions you have requested are invalid."
  • />
  •  
  • </cfif>
  •  
  •  
  • <!--- Read the image into a ColdFusion image object. --->
  • <cfimage
  • name="image"
  • action="read"
  • source="./#url.image#"
  • />
  •  
  • <!---
  • Get the image dimensions as we will need these a few times
  • throughout this process.
  • --->
  • <cfset imageWidth = imageGetWidth( image ) />
  • <cfset imageHeight = imageGetHeight( image ) />
  •  
  • <!---
  • From the image width / height ratio, let's calculate the
  • height of the image we are zooming to.
  • --->
  • <cfset url.height = ceiling(
  • (imageHeight / imageWidth) * url.width
  • ) />
  •  
  •  
  • <!---
  • Before we go through the both of resizing the image (which
  • is processing intensive), let's see if we have a cached
  • version of the image at this size.
  • --->
  • <cfset cachedImagePath = (
  • expandPath( "./" ) &
  • "cache/" &
  • ("w-" & url.width & "-") &
  • ("h-" & url.height & "-") &
  • ("src-" & url.image)
  • ) />
  •  
  • <!--- Check to see if the cached file exists. --->
  • <cfif fileExists( cachedImagePath )>
  •  
  • <!--- Read in the cached file size. --->
  • <cfimage
  • name="image"
  • action="read"
  • source="#cachedImagePath#"
  • />
  •  
  • <cfelse>
  •  
  • <!---
  • The cached file does not exist, which means we are
  • going to need to create it.
  • --->
  •  
  • <!---
  • Resize the image to fit the requested hi-resolution size
  • (this will then be cropped down). When re-sizing, we need
  • to see if the new size is smaller (which is hopefully is)
  • or larger than the requested size. If it is large, we will
  • have to scale up.
  • --->
  • <cfif (
  • (imageWidth lt url.width) ||
  • (imageHeight lt url.height)
  • )>
  •  
  • <!---
  • We need to scale up. When doing so, we need to
  • make sure the image will completely fill the given
  • dimensions.
  • --->
  • <cfset imageResize(
  • image,
  • url.width,
  • url.height
  • ) >
  •  
  • <cfelse>
  •  
  • <!---
  • We need to scale down. When scaling to fit in a box,
  • we are going to scale based on the WIDTH - the height
  • can just be set to an arbitrary MAX value.
  • --->
  • <cfset imageScaleToFit(
  • image,
  • url.width,
  • imageHeight
  • ) />
  •  
  • </cfif>
  •  
  • <!---
  • Now that we have scaled the image to the appropriate
  • size, write it to the cache so that we won't have to
  • perform this resize again.
  • --->
  • <cfset imageWrite(
  • image,
  • cachedImagePath
  • ) />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • Now that we have resized the image, crop it based on the
  • zoom and and offset.
  • --->
  • <cfset imageCrop(
  • image,
  • url.left,
  • url.top,
  • min( url.zoomWidth, (imageGetWidth( image ) - url.left) ),
  • min( url.zoomHeight, (imageGetHeight( image ) - url.top) )
  • ) />
  •  
  • <!---
  • Now that we have the zoomed and cropped image, let's
  • overlay the water mark (we don't want people stealing our
  • hi-resolution images). Read in the watermark image.
  • --->
  • <cfimage
  • name="watermark"
  • action="read"
  • source="./watermark.gif"
  • />
  •  
  • <!---
  • Overlay the watermark on the hi-res image. Notice that we
  • have to use the paste method here rather than the overlay
  • method because the two images will most likely not have
  • the same format and "bands".
  • --->
  • <cfset imagePaste( image, watermark, 0, 0 ) />
  •  
  • <!---
  • Write the image to the output buffer and parse it as XML.
  • This way, we can get access to the SRC attribute of the
  • server's temp PNG file.
  • --->
  • <cfxml variable="imageHtml">
  •  
  • <!--- Write IMG html tag as XML node. --->
  • <cfimage
  • action="writetobrowser"
  • source="#image#"
  • />
  •  
  • </cfxml>
  •  
  • <!--- Relocate user the temp PNG file. --->
  • <cflocation
  • url="#imageHtml.xmlRoot.xmlAttributes.src#"
  • addtoken="false"
  • />

Right now, I am using ColdFusion's "WriteToBrowser" image functionality to serve up the temporary PNG files. This seemed to be the easiest approach, but the PNG files that it creates are rather large (the ones in the video are all over 100K). If I were to write them explicitly to a web-accessible folder, I'd have more control over the quality of the images produced; but for a proof of concept, using ColdFusion's image servlet just made things really easy.

Once you start dealing with producing images on demand, you have a whole host of other efficiency constraints to deal with. I tried to solve some of them with a very superficial, size-based caching strategy; but, I am sure there is much more that can be done to make this user experience feel snappier. Ultimately, though, this was just a super fun experiment and another example of how well jQuery and ColdFusion can play together.




Reader Comments

I'm sorry. I was distracted by your zooming in and out of that image. One the best saucy ones yet.

Let me replay the video and _only_ listen to it so I can pay attention to the technical parts. :)

- Gabriel

Thanks for posting this, it is very descriptive and very informative.

Your posts and code are so easy to follow and gives me a thorough understanding of everything you do.

Can i use this code and attempt to add an extra feature? Was looking at adding a 'viewfinder' like you get on Photoshop to show where you are on the image?

Hi, I could reproduce the nice effect: Creating An Image Zoom And Clip Effect With jQuery, Posted January 21, 2010 at 1:52 PM

But this one.. something is not working with the images path I think... (new to this) if I do this:

<img id="image" rel="Dibujo_uno_big.jpg" src="get_low_res.cfm?image=Dibujo_uno_small.jpg"/>

<!--- Holds the hi-res image that will be loaded. --->
<img id="hi-res-image" />

I see nothing...
But if src="Dibujo_uno_small.jpg" then same effect than before...

I've Dibujo_uno_small.jpg, Dibujo_uno_big.jpg, get_hi_res.cfm, get_low_res.cfm and Maincode.cfm in the same folder, then jquery-1.4.js as "../js/jquery-1.4.js" in another folder...

Dibujo_uno_small.jpg is 474px × 570px 72dpi
Dibujo_uno_big.jpg is 1947px × 2337px 72dpi

It's something I'm missing, but what? :)
Could you explain a little please?

@Khristofe,

Are you getting a Javascript error? Do you have FireBug in your browser (for FireFox) - it's the info-panel I have at the bottom of my video? If so, you can look at the network activity to see how the files / images are being loaded. If you open it up, then run the page, you can see if you're getting a Javascript error, or a ColdFusion error (which will show up as a 500 error on your network activity).

Let's narrow it down to see where the problem is originating.

As far as the SRC attribute of the original file being set to "Dibujo_uno_small.jpg", you should be fine with that. The only reason I use a CFM file to load my "lo-res" image is because I didn't have one already created. Really, the most important part is the ColdFusion page that creates the hi-res image.

@Ben Nadel,

Hi, thanks for answering that fast, i did a little debug...

Image data:

-----------

Dibujo_uno_small.jpg : 474px × 570px 72dpi

Dibujo_uno_big.jpg : 1947px × 2337px 72dpi

Code source:

-------------

<img id="image" rel="Dibujo_uno_big.jpg" src="Dibujo_uno_small.jpg" />

FireBug message:

----------------

"

NetworkError:

500 The dimensions you have requested are invalid.

http://toastedfrench.com/JqueryCFZoom/get_hi_res.cfm

?image=Dibujo_uno_big.jpg

&width=948

&height=1140

&top=91

&left=263

&zoomWidth=474

&zoomHeight=570

"

New test:

---------

Code source:

-------------

<img id="image" rel="Dibujo_uno_small.jpg" src="Dibujo_uno_small.jpg" />

FireBug message:

----------------

"

NetworkError: 500 The dimensions you have requested are invalid.

http://toastedfrench.com/JqueryCFZoom/get_hi_res.cfm

?image=Dibujo_uno_small.jpg

&width=948

&height=1140

&top=239

&left=185

&zoomWidth=474

&zoomHeight=570

"

Here have noticed that the ratio is x4,

and this conditional for the error throw:

(url.zoomWidth gt 500) || (url.zoomHeight gt 500)

So I created a new image, smaller (500/4) ...

new image: 125x125.jpg 125px × 125px 72dpi

code:

-----

<img id="image" rel="img125x125.jpg" src="img125x125.jpg" />

FireBug message:

----------------

"

NetworkError: 500 An exception occure...ing to write the image.

http://toastedfrench.com/JqueryCFZoom/get_hi_res.cfm

?image=img125x125.jpg

&width=252

&height=252

&top=65

&left=89

&zoomWidth=125

&zoomHeight=125

"

Any idea? :)

@Khristofe,

In subsequent comments, would not you mind not double-spacing your text? It just takes up more room.

That said, you can remove the 500x500 constraint on the resize if you want to. I put it in to make sure people couldn't ask for the "entire image" by messing with the URL parameters.

Also, keep in my that my 500x500 is based on the fact that I was scaling my low-res image to fit within a 500x500 box. If your low-res image is larger than 500x500, you will have to adjust to whatever is appropriate.

As far as the exception when writing the image, you have to look at your log files for that - it could be cause by any number of things.