PDA

View Full Version : Wildcard for loading filenames into Array



jimbowvu80s
12-02-2009, 10:43 PM
I've been using this script for several years (not sure where it came from). I have a directory with several images in it. I then change the file name of the images to 1.jpg, 2.jpg..etc. Is there a way I can change this script to use wildcards to read the files in a specific directory into the array? It's already reading the image name into the array (filename = (file_number + ".jpg")), but is there the possibility that I don't have to change the image names in the folder all the time?

Also, I change the variable - NUMBER_OF_IMAGES to reflect how many images are in the directory. I know all this can be done in PHP, but I would like to see if it can be done with what I have so far.

Thanks for your help.

<script language="JavaScript"><!--
which_image_loaded = 0;
NUMBER_OF_IMAGES = 8;

ImageNames = new Array;
ImageNames.length = NUMBER_OF_IMAGES - 1;

for (counter = 0; counter < NUMBER_OF_IMAGES; counter++){
file_number = counter + 1;
filename = (file_number + ".jpg");
ImageNames[counter] = filename;
}

function changeImage(direction) {
which_image_loaded += direction;
if (which_image_loaded < 0)
which_image_loaded = NUMBER_OF_IMAGES - 1;
var jim = which_image_loaded;
if (which_image_loaded == NUMBER_OF_IMAGES)
which_image_loaded = 0;
document.jobimage.src = ImageNames[which_image_loaded];
}
//--></script>

<td><form>
<div align="center">
<input type="button" value="&nbsp;&nbsp;&nbsp;Next&nbsp;&nbsp;&nbsp;" SIZE=30 onClick='changeImage(1);'>
<input type="button" value="Previous" onClick='changeImage(-1);'>
</div>

jscheuer1
12-03-2009, 06:23 AM
To read images from a directory with only javascript requires some naming convention including numbers be employed for the images. this means that all og the images must be of the same name except for differences in number. However, the script can be constructed to start at a given number and go until there are no more sequentially numbered images. So the number of images need not be specified and one can start at any number:


<script type="text/javascript">

/* ImageFindLoad Script 2009 John Davenport Scheuer
as first seen in http://www.dynamicdrive.com/forums/
username: jscheuer1 - This Notice Must Remain for Legal Use
*/

var ims = [];
(function(){
//Configure folder and naming convention of images
var imFold = 'http://www.whatever.com/images/',
imPrefix = '',
imSuffix = '_slide.jpg',
numberingStart = 10,
numberPaddingLength = 0,
numberPaddingChar = '0',
//End configuration
imNum = --numberingStart, oops = null, im;
function numPad(n){
n += '';
while(n.length < numberPaddingLength){
n = numberPaddingChar + n;
}
return n;
}
function loadem(){
im = imFold + imPrefix + numPad(++imNum) + imSuffix;
(function(im){
var pIm = new Image();
pIm.onerror = function(){
oops = true;
alert(ims.join('\n') + '\n' + oops);
}
pIm.onload = function(){
ims.push(this.src);
setTimeout(loadem, 0);
}
pIm.src = im;
})(im);
}
loadem();
})();
</script>

As configured the above will look in:

http://www.whatever.com/images/

It will find images starting with:

10_slide.jpg

and continuing until there are no more images in sequence from that number. the images will be placed in sequence into a globally available array called ims. A side effect of this process is that all of the images found will be preloaded.

The highlighted parts are just so you can see what the result is, and may be removed. But you may use:


pIm.onerror = function(){
doWhatever();
}

to spawn other code that will do something with the images.

Other possibilities exist. With minor alteration, each time an image is found and loaded it could be displayed and a timeout interval set before looking for the next one.

jimbowvu80s
12-03-2009, 10:05 PM
John - Thank you for the information. Sorry for not completely understanding your script, but do the jpg's need to be in number sequence or can they have any name? Most of the pictures I receive are from different camera types and have different file names (DSC0001, 000_8981, IMG_0990,...).

Currently, I place the file popup.html in each picture folder (the code I posted) and reference that file through another html file that has a listing of dates of when the pictures were sent in. See the attached image. You helped me with some of other javascript with this project.

Also, how do I call the function to display the pictures. I let the user click throught the pictures. Is it the loadem funtion?

<table border="0" cellpadding="1" width="100%">
<tr>
<td width="75%"><img src="1.jpg" width="500" height="400" name="jobimage"></td>
<td width="25%">
<form>
<input type="button" value="&nbsp;&nbsp;&nbsp;Next&nbsp;&nbsp;&nbsp;" SIZE=30 onClick='changeImage(1);'>
<input type="button" value="Previous" onClick='changeImage(-1);'>
</form>
</td>
</table>

Thanks again for all your help.

jscheuer1
12-04-2009, 01:09 AM
As I said:


To read images from a directory with only javascript requires some naming convention

This means that all images must have the same name except for a number of some sort somewhere in the name that differentiates them from each other.

That is unless you use some sort of server side code. This can be done in conjunction with javascript to make things go more smoothly for the user, but may also be done solely with server side code and, if well thought out, provide a fairly smooth experience for the user. My current thinking is a combination of both, with a completely server side fall back for non-javascript enabled users.

The script I provided is just a suggestion of what javascript alone, pushed to its limits, can do in this regard, though it will always as far as I know still have to follow some naming conventions as I've been talking about. For the flexibility in naming files that you want, at lest some server side code is required.

jimbowvu80s
12-08-2009, 10:16 PM
Hi John. I have been reviewing the code I posted and brushing up on arrays and I realize now that arrays don't have the capability of retrieving a directory listing. I did take a look around at PHP and saw that there are several commands related to directory listing, creation...etc.

Not to beat a dead horse...but I found this code and I can get it to display a directory listing of files. Is it possible to store the information in an array to manipulate the data instead of displaying the information?

Thanks for all your help.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0043)http://tech.irt.org/articles/js014/main.htm -->
<HTML lang=en><HEAD>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type><LINK
href="main_files/main.css" rel=STYLESHEET type=text/css>
<META content="Microsoft FrontPage 4.0" name=GENERATOR></HEAD>

<html>
<body>
<h1>Contents of directory</h1>

<script language="JavaScript"><!--
var links_length = parent.directory.window.document.links.length;
var link = "";
for (var i = 0; i < links_length ; i++) {
link = parent.directory.window.document.links[i].href;
document.write(
'<a href="'+link+'">'+link+'</a><br>'
);
}
//-->
</script>

<p><a href="index.htm" target="_parent">Return</a>
</body>
</html>

jscheuer1
12-09-2009, 12:56 AM
If that works, I imagine that there is a page (call it pageD) in another frame of the parent page of the one (cal it pageG) with that code on it, and that pageD has a directory listing (in link form, each file in the listing is represented as a link to itself) on it (presumably generated by the server, but any method that produces this would be fine). I also imagine that the code shown in your post would not work properly if pageD hasn't fully loaded yet. But assuming that's all worked out somehow, this code placed on pageG will make an array called thelinks comprised of the paths and filenames of the files in pageD's listing:


<script type="text/javascript">
var links_length = parent.directory.window.document.links.length;
var thelinks = [];
for (var i = 0; i < links_length ; i++) {
thelinks[i] = parent.directory.window.document.links[i].href;
}
</script>

However, if using PHP, you should also consider code more like so:


<?php
Header("content-type: application/x-javascript");

function returnimages() {
$dirname = "./" . $_GET['dir'] . "/";
$thedir = "http://" . $SERVER_NAME . "/" . $_GET['dir'] . "/";
$pattern="\.(jpg|jpeg|png|gif|bmp)$";
$files = array();
$curimage=0;
if($handle = opendir($dirname)) {
while(false !== ($file = readdir($handle))){
if(eregi($pattern, $file)){
echo 'galleryarray[' . $curimage .']=[galleryarray.baseurl + "' . $file . '"];' . "\n";
$curimage++;
}
}

closedir($handle);
}
return($files);
}
echo "var galleryarray=new Array();" . "\n";
echo "galleryarray.baseurl = 'http://" . $SERVER_NAME . "/" . $_GET['dir'] . "/';\n";
returnimages();
?>

This file may be saved as getimages.php and be placed in the root of your domain. Then, from any page on your domain, you may place a script tag that looks like so:


<script type="text/javascript" src="/getimages.php?dir=images"></script>

It will produce an array called galleryarray of all images (if any) in the images folder (if any) off of the root of the domain. The dir=images part may be changed to point to any path from the root of the domain. However, this will only work if opendir and readdir are enabled. And, once anyone finds out that you are doing this, they will be able to get the same array of image addresses from any folder on your domain as well. Though unless you are paranoid, this isn't as bad as it might seem.

With that last bit in mind though, it is possible to hard code into getimages.php the folder it will look at. That way it can only return the addresses of images from that folder.

XManBG
08-04-2011, 10:27 PM
Hello John... Sorry to bother you with that question 2 years later, but I'm stuck on that function and looking for a solution. Again, I'm trying to load unknown number of images from a known location, where the image names are ordered numbers.

Taking a look at your JS code in the first answer, I could extract the function, which does the "searching" job and re-use it like this:



function imgload(){
var oops = false;
var n = 1;
while(!oops){
var img = new Image();
img.onerror = function(){alert("Error");oops = true;};
img.onload = function(){alert("OK");};
img.src = "img/exterior/slider1/" + n + "_B.png";
++n;
};
return (n-1);
};


What a surprise to me, when the function didn't react at all: neither "onload" nor "onerror" shoot alert, and the "while" loops to infinity. Any ideas?!

Thanks in advance.

Cheers, Hristo

jscheuer1
08-05-2011, 07:25 AM
The while loop takes precedence over the load and error functions. The latter two take place in the global scope, while the loop is in the local scope. It's unclear if the oops variable is communicated or not, and if so in which direction(s). But the facts that the loop remains unbroken and these events don't fire show that the loop needs to finish first. Here, until it does, oops will always be false, and it will never end. This often happens with other operations. Like if you have an alert. It delays what follows until after you click OK (until after it's finished), while at the same time allowing other processes already underway (if any) to catch up and complete.

Also, even if the loop weren't taking precedence, the value of the var img keeps getting replaced possibly/probably before either load or error can fire. I'm not sure what this does, if anything. It may be moot considering the first points.

This 'works':


function imgload(){
var n = 1;
(function(im){
var f = arguments.callee;
var img = new Image();
img.onerror = function(){alert("Error");};
img.onload = function(){alert("OK"); f("img/exterior/slider1/" + (++n) + "_B.png");};
img.src = im;
})("img/exterior/slider1/" + n + "_B.png");
return (n-1);
}

But it always returns 0 because the imgload function returns before the error or load functions do. If you placed n in the global scope or made it globally accessible, or did something with it in the onerror function (like assigning its value minus 1 to an input's value, or to an element's innerHTML), once all this had run its course it would be available as the count:


img.onerror = function(){alert("Error"); document.getElementById('count').innerHTML = 'count: ' + (--n);};

Here's a simplified version as a working demo page:


<!DOCTYPE html>
<html>
<head>
<title>Image Load - Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div id="count"></div>
<script type="text/javascript">
function imgload(){
var n = 1;
function f(){
var img = new Image();
img.onerror = function(){document.getElementById('count').innerHTML = 'count: ' + (--n);};
img.onload = function(){++n; f();};
img.src = 'img/exterior/slider1/' + n + '_B.png';
}
f();
}
imgload();
</script>
</body>
</html>

XManBG
08-05-2011, 12:50 PM
Thank you very much for the detailed answer. I had already the feeling, that "while" overshoots all other functions.

Just to understand the syntax of your function, I'd like to ask, where can I read more about such a function structure, marked bold below:




function imgload(){
var n = 1;
(function(im){
var f = arguments.callee;
var img = new Image();
img.onerror = function(){alert("Error");};
img.onload = function(){alert("OK"); f("img/exterior/slider1/" + (++n) + "_B.png");};
img.src = im;
})("img/exterior/slider1/" + n + "_B.png");
return (n-1);
}

jscheuer1
08-05-2011, 01:36 PM
It's a self executing anonymous function. Some explanations are here:

http://stackoverflow.com/questions/592396/what-is-the-purpose-of-a-self-executing-function-in-javascript

You can Google:

self executing anonymous javascript function

and sift through that for more info.

The way I'm using it, it gets called over and over as long as the image loads.

It creates a new img variable for each image in its own scope, so that their load and error functions remain separate.

If you look back at my previous post (I added to it in stages), at the bottom is the same basic thing without a self executing function.

The function f takes its place. Since it's defined within the imgload function, it inherits n from it. It gets repeated until there's an error (presumably a missing image in the sequence). Each time it runs var img is new and unique to that run. The same thing for the self executing version.

A self executing anonymous function goes like:


(function(){
//do stuff here
})();

And it runs right away.

A named function that you want to run right away goes:


function someName(){
//do stuff here
}
someName();

XManBG
08-07-2011, 02:23 PM
Hi,

I've noticed, that the "search" function doesn't work completely correct. I've tried it with IE and Chrome and Opera. Each time I press the button, the folders shall be searched for the images, and the number of founded images shall come on the top of each column. Just try to push the buttons more times, and reload the page and push again...

I can't get it...

http://www.x-mediapro.de/jass.performance/testreadimg3.html

Cheers

jscheuer1
08-07-2011, 04:16 PM
Here's a simplified example, with a twist. It not only counts the images but lists out the array contents and also displays the images:

http://home.comcast.net/~jscheuer1/side/images/buts_load.htm

Use your browser's 'view source' to see the code, or look here:


<!DOCTYPE html>
<html>
<head>
<title>Image Load - Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div id="count"></div>
<div id="images"></div>
<script type="text/javascript">
function imgload(){
var n = 1, ims = [];
function f(){
var img = new Image();
img.onerror = function(){
document.getElementById('count').innerHTML = 'count: ' + ims.length + '<br>' + ims.join('<br>');
document.getElementById('images').innerHTML = '<img src="' + ims.join('" alt=""> <img src="') + '" alt="">';
};
img.onload = function(){ims.push(this.src); ++n; f();};
img.src = n + '.gif';
}
f();
}
imgload();
</script>
</body>
</html>

All the 'real fun' starts when we run out of images that fit the criteria - the onerror function.

Added Later:

Looking at your code:


function imgcounter(whereareimg,whatext,wheretocount,whichnote){
var n = 1;
var filenames = document.getElementById(whichnote).innerHTML;
function checkfiles(){
var img = new Image();
filenames += whereareimg + n + whatext;
img.src = whereareimg + String(n) + whatext;
img.onerror = function(){filenames += " Error<br /><br />";document.getElementById(whichnote).innerHTML = filenames;document.getElementById(wheretocount).innerHTML = (--n);return;};
img.onload = function(){filenames += " OK<br />";(++n);checkfiles();};
};
checkfiles();

};

You shouldn't set the src until the onerror and onload functions are set:


function imgcounter(whereareimg,whatext,wheretocount,whichnote){
var n = 1;
var filenames = document.getElementById(whichnote).innerHTML;
function checkfiles(){
var img = new Image();
filenames += whereareimg + n + whatext;
img.onerror = function(){filenames += " Error<br /><br />";document.getElementById(whichnote).innerHTML = filenames;document.getElementById(wheretocount).innerHTML = (--n);return;};
img.onload = function(){filenames += " OK<br />";(++n);checkfiles();};
img.src = whereareimg + String(n) + whatext;
};
checkfiles();

};

XManBG
08-07-2011, 06:34 PM
Hi John,

thanks for thinking with me. You're right, the function works correct on IE, when I moved the src to the end. What is the sense to set-up the src of the image after the onerror and onload?! Do the parameters in a function load bottom-up or backwards?! I've thought, that I have to set the src parameter first, so that later onload or onerror could react to that src. Was my thought wrong?!

Cheers




Added Later:

Looking at your code:


function imgcounter(whereareimg,whatext,wheretocount,whichnote){
var n = 1;
var filenames = document.getElementById(whichnote).innerHTML;
function checkfiles(){
var img = new Image();
filenames += whereareimg + n + whatext;
img.src = whereareimg + String(n) + whatext;
img.onerror = function(){filenames += " Error<br /><br />";document.getElementById(whichnote).innerHTML = filenames;document.getElementById(wheretocount).innerHTML = (--n);return;};
img.onload = function(){filenames += " OK<br />";(++n);checkfiles();};
};
checkfiles();

};

You shouldn't set the src until the onerror and onload functions are set:


function imgcounter(whereareimg,whatext,wheretocount,whichnote){
var n = 1;
var filenames = document.getElementById(whichnote).innerHTML;
function checkfiles(){
var img = new Image();
filenames += whereareimg + n + whatext;
img.onerror = function(){filenames += " Error<br /><br />";document.getElementById(whichnote).innerHTML = filenames;document.getElementById(wheretocount).innerHTML = (--n);return;};
img.onload = function(){filenames += " OK<br />";(++n);checkfiles();};
img.src = whereareimg + String(n) + whatext;
};
checkfiles();

};

jscheuer1
08-07-2011, 10:47 PM
Your thinking is right, but the conclusion isn't.

If you set the src property when there are no onload or onerror properties set, there's always a chance that the new Image() object will have already loaded or errored or already be in the process of loading or erroring before you do. The browser cannot be expected to at that point go back and add the onerror and onload properties. Some will though, at least under certain circumstances. IE generally will not. And any browser can be expected to and will follow the code if presented in the proper order (the order shown in my examples and in my suggestion for your code).