JavaScript Development
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me
Go Back   Dev Shed ForumsWeb DesignJavaScript Development

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
  #1  
Old February 12th, 2003, 04:02 PM
lmcccha lmcccha is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Feb 2003
Location: Montreal
Posts: 2 lmcccha User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Javascript image preload race condition

Hello all.

I'm trying to resolve a race condition I'm having with Netscape 4.7, Opera, and Mozilla (don't seem to have it with IE yet, but that doesn't mean it can't happen).

What I have to do is load an image, calculate it's height/width, and based on what I get back determine if I have to resize the image (and proportionally resize it as opposed to trying to slam it into a window and skew the image all around).

My problem is that the image.height and image.width only returns proper values once the image is preloaded.

So, here is the logic which I think I need to implement in a function for all of this to work:
1) preload the image based on URL
2) wait for the image to complete (have some trigger tell me that it's complete)
3) extract the original height/width of the image and return the value to the caller.

What I get however is problems. I was able to dig up one trigger image.onload which can fire once the image is loaded. I also have the image.complete flag which I can test to see if the image is finished loading into cache. However, it's my while loop which is causing me problems. It seems that if I stick myself in a while loop and check to see when the image is finished preloading, the thread of execution is never given back to the browser to finish loading up the image (likely in the background). So, as long as I'm in the while loop, the image does not seem to load. However, until the image is loaded, I have to remain in the loop. Catch-22.

The other possibility (using the image.onload trigger) can't work either, as I cannot seem to guarentee when it will go off (not serializable -- I cannot seem to direct the thread of execution back to the function which called the image to be loaded). Fubar.

Here is the code which demonstrates the problem. To set it up, simply have two images (image1.jpg and image2.jpg)in the same directory as this html file and it'll go:

[code]
<html>
<head>
<title>javascript image test</title>
</head>
<body>
<script language="JavaScript1.2">
<!--
var TRUE = 1;
var FALSE = 0;

var image01 = new Image();
image01.src='image1.jpg';

function getImgHeight(path) {
if (document.images) {
var tmpImage = new Image();
tmpImage.src=path;

if (tmpImage.complete) {
return tmpImage.height;
} else {

while (!tmpImage.complete) {
continue;
};

return tmpImage.height;
}
}
}

function getImgWidth(path) {
if (document.images) {
var tmpImage = new Image();
tmpImage.src=path;

if (tmpImage.complete) {
return tmpImage.width;
} else {

while (!tmpImage.complete) {
continue;
};

return tmpImage.width;
}
}
}

document.write("<table border=1>");
document.write("<tr><td></td><td></td><td>IMAGE 1</td><td></td><td>IMAGE 2</td></tr>");

document.write("<tr><td>Height</td>");
document.write("<td></td><td>" + image01.height+ "</td>");
document.write("<td></td><td>" + getImgHeight('image2.jpg') + "</td></tr>");

document.write("<tr><td>Width</td>");
document.write("<td></td><td>" + image01.width + "</td>");

document.write("<td></td><td>" + getImgWidth('image2.jpg') + "</td></tr>");

document.write("</table>");

// -->
</script>
<p>
<table border=1>
<tr>
<td>Image1: </td>
<td><img src=image1.jpg></td>
<td>Image2: </td>
<td><img src=image2.jpg></td>
</tr>
</table>
</body>
</html>

Also notice that the image I preloaded (image01) seems to work (likely because the race condition doesn't seem to come up on my workstation). It's the image I preload in the functions which I can't ever get to work properly.

Any clue as to what I can do here? How can I get the image size reliably from a function call without having to wonder if that race condition is going to occure?

Thanks for any/all help,

Chris

Reply With Quote
  #2  
Old February 12th, 2003, 05:58 PM
M.Hirsch M.Hirsch is offline
Contributing User
Dev Shed God 1st Plane (5500 - 5999 posts)
 
Join Date: Oct 2000
Location: Back in the real world.
Posts: 5,969 M.Hirsch User rank is First Lieutenant (10000 - 20000 Reputation Level)M.Hirsch User rank is First Lieutenant (10000 - 20000 Reputation Level)M.Hirsch User rank is First Lieutenant (10000 - 20000 Reputation Level)M.Hirsch User rank is First Lieutenant (10000 - 20000 Reputation Level)M.Hirsch User rank is First Lieutenant (10000 - 20000 Reputation Level)M.Hirsch User rank is First Lieutenant (10000 - 20000 Reputation Level)M.Hirsch User rank is First Lieutenant (10000 - 20000 Reputation Level)M.Hirsch User rank is First Lieutenant (10000 - 20000 Reputation Level) 
Time spent in forums: 1 Month 1 Day 22 h 39 m 55 sec
Reputation Power: 184
you could poll for the image finishing loading in a window.setTimeout() function...
__________________
--
Manuel Hirsch - Linux, FreeBSD, programming, administration articles, tutorials and more.

Reply With Quote
  #3  
Old February 12th, 2003, 06:51 PM
adios adios is offline
Senior Citizen
Dev Shed Regular (2000 - 2499 posts)
 
Join Date: Jan 2001
Location: leftcoast
Posts: 2,019 adios User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 10
Thought you made up that phrase 'race condition' - so I looked it up - hah! Excellent...shows what I know.

A question: since the 'race condition' seems to be created by running two scripts - the preloader and the table writer - why don't you use a different methodology altogether? No sense pitting a scripting routine which hinges on network download speed (glacially slow compared to a client program) against a tiny JavaScript. This:

while (!tmpImage.complete) {
continue;
};

makes me wanna reboot...

If I'm seeing your purpose here, what you want is a prompt message - 'Please wait - images loading' - and, when the onload handlers of all the preload objects have run, output the rest of the page. As M. Hirsch suggested, you could poll for this; I prefer keeping it event-driven, setting up each onload handler to call a routine which checks a (persistent) counter which starts at images.length and is decremented by each load. Either way should be fine.

You should always set a preload object's onload handler, or set up to check its .complete property, before setting the .src property...running off a local drive, with cached images, load time is very fast.

btw, PHP eats this stuff for lunch...

Reply With Quote
  #4  
Old February 13th, 2003, 08:58 AM
lmcccha lmcccha is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Feb 2003
Location: Montreal
Posts: 2 lmcccha User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Yeah, don't let that "while - continue" loop get to you, it's just to prove a point.

In most languages, you can release the thread of execution to another function and wait to have it returned to you. However, I'm not sure Javascript allows anything similar to this, so I was trying to think of some way to loop until I get a positive responce that my image is loaded. From what I can tell, most browsers pass the image loading onto a background process (this is efficient, because it lets your browser become responsive while downloading images).

Harumph. Maybe I'm going about it the wrong way (I'm new at Javascript, and am trying to learn it's erratic behaviours).

Here's my scenario. Maybe someone can find a new approach which I can take.

I have a list of images which I have to fit inside a box (say 100x100 px). It a slide show of images found on a database (I don't control the image content, just the presentation). When these are passed to me (via JSP tag library), I want to resize the image if needed in an intelligent manner.

My first impression was to preload the image, calculate the height/width, and output the image onto the document by setting the <img height = y, width = x) tag accordingly (a little highschool math and my images don't get stretched). My problem is that for this function to work, I have to have the images completely preloaded before the image.height and .width to work.

Another thought that just occured to me is that I could set a trigger which automatically resizes all images after they have all registered being loaded. Can you resize the height/width of an image? I was given the impression that these were read-only values, and that once defined I'm bound by them.


Chris

Reply With Quote
  #5  
Old February 13th, 2003, 04:48 PM
adios adios is offline
Senior Citizen
Dev Shed Regular (2000 - 2499 posts)
 
Join Date: Jan 2001
Location: leftcoast
Posts: 2,019 adios User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 10
Hmm...how does one intelligently resize a rectangular image to fit a square frame? If all the images are square, this:

<img width="100" height="100" src="......

..will, believe it or no, do the trick. You don't even need to set both dimensions: whether in HTML or JS, resize an image on one side and the browser proportionately resizes it on the other. If the supplied images are rectangular, something like this might do:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>untitled</title>
<script type="text/javascript" language="javascript">

function smartResize(oImg, size) {
if (oImg.width>oImg.height) oImg.width = size;
else oImg.height = size;
if (typeof oImg.style != 'undefined')
setTimeout('document["'+oImg.name+'"].style.visibility = "visible"',1000);
}

</script>
</head>
<body>
<img name="resizer1" src="http://www.michellesgifts.com/figi/SWITCHPLATES/fruit_s.jpg"
onload="smartResize(this,100)" border="2" style="visibility:hidden;">
<img name="resizer2" src="http://www.michellesgifts.com/figi/SWITCHPLATES/fruit2_s.jpg"
onload="smartResize(this,100)" border="2" style="visibility:hidden;">
<img name="resizer3" src="http://www.trengovestudios.com/images/vegetables.jpg"
onload="smartResize(this,100)" border="2" style="visibility:hidden;">
</body>
</html>

If not, a description of the slide show workings would help (me!)...

cheers, adios

Reply With Quote
  #6  
Old February 13th, 2003, 08:21 PM
ngibsonau ngibsonau is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Feb 2003
Posts: 138 ngibsonau User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 6
Don't know if this helps because I'm not exactly sure what you are doing, but all of the things in the <head> of the
html page should be loaded and complete before anything in the <body> is displayed.

Why no try get initial size in the head and do your resizing in the body?
__________________
--

ngibsonau

Reply With Quote
Reply

Viewing: Dev Shed ForumsWeb DesignJavaScript Development > Javascript image preload race condition


Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump


Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 





© 2003-2008 by Developer Shed. All rights reserved. DS Cluster 3 hosted by Hostway