/[dtapublic]/projs/dtats/trunk/projs/20161008_web_page_thumbnail_make/pics_thumbnails_make.php
ViewVC logotype

Annotation of /projs/dtats/trunk/projs/20161008_web_page_thumbnail_make/pics_thumbnails_make.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 117 - (hide annotations) (download)
Sun Jan 1 04:06:02 2017 UTC (7 years, 2 months ago) by dashley
File size: 25318 byte(s)
Correct minor typo.
1 dashley 107 <?php
2     //-------------------------------------------------------------------------------------------------
3 dashley 110 //$Header$
4 dashley 107 //-------------------------------------------------------------------------------------------------
5 dashley 110 //This source code and any program in which it is compiled/used is provided under the MIT
6     //LICENSE (full license text below).
7 dashley 107 //-------------------------------------------------------------------------------------------------
8 dashley 116 //pics_thumbnails_make.php, Copyright (c) 2016 David T. Ashley
9 dashley 107 //
10 dashley 110 //Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
11     //associated documentation files (the "Software"), to deal in the Software without restriction,
12     //including without limitation the rights to use, copy, modify, merge, publish, distribute,
13     //sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
14     //furnished to do so, subject to the following conditions:
15 dashley 107 //
16 dashley 110 //The above copyright notice and this permission notice shall be included in all copies or
17     //substantial portions of the Software.
18 dashley 107 //
19 dashley 110 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
20     //NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21     //NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22     //DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23     //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 dashley 107 //-------------------------------------------------------------------------------------------------
25 dashley 116 //This program, a PHP script, creates thumbnails from recognized image types. This program is part
26     //of a 3-program suite designed to collectively create a web page directly from digital camera
27     //files (and of course the web page can be customized by hand-editing after it is automatically
28     //generated).
29     //
30     //The 3 programs in the 3-program suite are:
31     //
32     // pics_filenames_canonize.php:
33     // Converts all names of files in a directory to lower-case, and makes substitutions for any
34     // unusual characters.
35     //
36     // pics_thumbnails_make.php (this script):
37     // Creates thumbnails from recognized image types. The thumbnails are named relative to the
38     // original image file with the suffix "_small". To support shared hosting environments where
39     // CPU utilization of a script may be capped, there is a configuration constant in the script
40     // that will perform only a fixed number of conversions per invocation. If this configuration
41     // option is used, the script should be run repeatedly until it indicates that it has no more
42     // thumbnails to create.
43     //
44     // If any full-sized photos are modified, any corresponding thumbnails should be deleted and
45     // pics_thumbnails_make.php and pics_indexfile_make.php should be run again.
46     //
47 dashley 117 // pics_indexfile_make.php:
48 dashley 116 // Scans a directory and makes an index file ("index2.php") displaying all the thumbnail
49     // images, each of which link to the corresponding full-sized image. The index file is
50     // tailored to Dave Ashley's needs, but the created file can be edited and most of the
51     // content pasted into an HTML file. To avoid the accidental loss of information, any
52     // existing "index2.php" file is renamed out of the way.
53     //
54     //This script is designed to be run manually (rather than automatically invoked as a result of a
55     //web page request). It was written in PHP for convenience simply because DreamHost (the web
56     //hosting company Dave Ashley used at the time these scripts were written) has as part of its
57     //hosting environment PHP with the ImageMagick library compiled in.
58     //
59     //Usually, this script is invoked using "php <path>/pics_thumbnails_make.php", but the method of
60     //invocation may vary based on computing platform details.
61     //
62     //Using Fedora Linux, I had trouble getting PHP to use ImageMagick (the error was something like
63     //"Class Imagick not found"). Finally, I figured out that the missing package was
64     //php-pecl-imagemagick and "dnf install php-pecl-imagick" too care of it.
65     //
66     //After all conversions are complete, this script terminates with a segmentation fault under
67     //Linux. The segmentation fault is definitely tied to ImageMagick. The reason is not known, but
68     //the problem appears here and there on the Internet. All of the photo conversions occur
69     //correctly, and the problem seems to occur during the termination phase of the PHP script.
70     //-------------------------------------------------------------------------------------------------
71 dashley 107 //C O N F I G U R A T I O N
72 dashley 116 //-------------------------------------------------------------------------------------------------
73 dashley 107 //Configuration switch combinations were not tested. E-mail me any program
74     //corrections (dashley@gmail.com).
75 dashley 116 define ("CFG_PROGNAME", "pics_thumbnails_make.php");
76     //Program name.
77 dashley 107 define ("CFG_CONSOLE_STD_LINE_LEN", 78);
78     //Number of characters per line preferred for console output.
79     define ("CFG_THUMBNAIL_DIMENSION_MAX", 125);
80     //The maximum dimension of the created thumbnails. Thumbnails are sized so
81     //that the longest dimension is this many pixels.
82     define ("CFG_THUMBNAIL_BEVELED_BORDER_WIDTH", 4);
83     //The number of pixels that the thumbnail beveled borders should be.
84     define ("CFG_THUMBNAIL_FILENAME_SUFFIX", "_small");
85     //String added just before the filename extension to choose thumbnail names
86     //based on name of full-sized image.
87     define ("CFG_LANCZOS_FILTER_APPLY", FALSE);
88     //TRUE if should apply the Lanczos filter when making the thumbnail, FALSE
89     //otherwise. I have no idea if using a Lanczos filter improves the quality
90     //of the thumbnails, but the filter was applied in the PHP example I found
91     //online. Applying the Lanczos filter typically adds a few seconds to the
92     //time required to create each thumbnail.
93 dashley 116 define ("CFG_MAX_THUMBNAILS_PER_INVOCATION", 0);
94 dashley 107 //The maximum number of thumbnails that should be created per invocation.
95     //This is to prevent the program from being involuntarily terminated
96 dashley 116 //for consuming too much CPU time (mostly for use in shared hosting
97     //environments that cap CPU usage). Setting this to 0 means no limit is
98     //applied (unlimited number of photos processed per invocation).
99 dashley 107 //--------------------------------------------------------------------------------
100     //Calculates important integer indices related to creating a thumbnail, in order
101     //to minimize distortion in the thumbnail.
102     //
103     //When creating a thumbnail, the longer side may be relatively short (perhaps
104     //100 pixels), and the shorter side may be even shorter (perhaps even as short
105     //as 10 pixels). If the dimensions of the original image were not changed,
106     //converting the image to a thumbnail may result in distortion of up to about
107     //one percent. As an example, suppose that a 1600 x 900 image is converted to a
108     //thumbnail with the longer side of 125 pixels. The ideal dimension for the
109     //shorter side would be (900/1600) * 125 = 70.3125 pixels. The aspect ratio of
110     //the thumbnail can't be made to match the aspect ratio of the original image.
111     //
112     //To avoid any aspect ratio distortion that might be noticeable, this program
113     //chooses the shorter dimension for the thumbnail that is the ceiling of the actual
114     //quotient, then crops the longer dimension of the original image before the
115     //conversion to try and match the aspect ratios as closely as possible.
116     //
117     //In the example a paragraph or two above, the shorter side of the thumbnail
118     //would be chosen to be 71 pixels.
119     //
120     //Once this choice is made, we want to trim the original image before conversion
121     //so that n/900 is as close as possible to 125/71. n = (900 * 125) / 71 =
122     //1584.5070 pixels, so we choose 1585. This keeps the aspect ratio of the
123     //original image and the thumbnail as close as possible.
124     //
125     //Although the longer side of the original image may be reduced prior to the
126     //conversion to a thumbnail, this information is not written to disk, and
127     //the original image is not modified. The adjustment of the longer side is
128     //just a conversion trick to hopefully get better thumbnails.
129     function calc_thumbnail_conversion_pars
130     (
131     $in_orig_longer,
132     //Longer dimension of original image.
133     $in_orig_shorter,
134     //Shorter dimension of original image.
135     $in_thumbnail_longer,
136     //Longer dimension of desired thumbnail.
137     & $out_thumbnail_longer,
138     //Longer dimension of thumbnail that should be created.
139     & $out_thumbnail_shorter,
140     //Shorter dimension of thumbnail that should be created.
141     & $out_orig_crop_dim_longer,
142     //The size to crop to on the longer axis of the original.
143     & $out_orig_crop_dim_shorter,
144     //The size to crop to on the shorter axis of the original.
145     & $out_orig_crop_start_longer,
146     //For use with the Imagick:cropImage() method, the start
147     //position of the crop on the longer axis.
148     & $out_orig_crop_start_shorter
149     //For use with the Imagick:cropImage() method, the start
150     //position of the crop on the shorter axis.
151     )
152     {
153     //Set the thumbnail shorter dimension to the floor. This means would need to trim
154     //longest dimension of original to match aspect ratio as closely as possible.
155     $out_thumbnail_longer = $in_thumbnail_longer;
156     $out_thumbnail_shorter = ceil(((float)$in_thumbnail_longer *
157     (float)$in_orig_shorter) / (float)$in_orig_longer);
158     settype($out_thumbnail_shorter, "integer");
159    
160     //The aspect ratio of the thumbnail is now set. Try to match the aspect ratio of the larger
161     //image as closely as possible by selecting a smaller number for the long axis of the
162     //original image.
163     $out_orig_crop_dim_longer = round(((float)$in_thumbnail_longer *
164     (float)$in_orig_shorter) / (float)$out_thumbnail_shorter);
165     settype($out_orig_crop_dim_longer, "integer");
166    
167     //The original keeps its shorter dimension unchanged.
168     $out_orig_crop_dim_shorter = $in_orig_shorter;
169    
170     //Set the cropping of the longer side of the original to cover half the necessary
171     //reduction.
172     $out_orig_crop_start_longer = round(((float)$in_orig_longer -
173     (float)$out_orig_crop_dim_longer) / 2.0);
174     settype($out_orig_crop_start_longer, "integer");
175    
176     //No cropping of original shorter side.
177     $out_orig_crop_start_shorter = 0;
178     }
179     //--------------------------------------------------------------------------------
180     //Repeats a character to the console output a certain number of times.
181     function rep_char_con($c, $n)
182     {
183     while ($n--)
184     echo $c;
185     }
186     //--------------------------------------------------------------------------------
187     //Writes a standard thick horizontal line to the console.
188     function hor_line_thick()
189     {
190     rep_char_con("=", CFG_CONSOLE_STD_LINE_LEN);
191     echo "\n";
192     }
193     //--------------------------------------------------------------------------------
194     //Writes a standard thin horizontal line to the console.
195     function hor_line_thin()
196     {
197     rep_char_con("-", CFG_CONSOLE_STD_LINE_LEN);
198     echo "\n";
199     }
200     //--------------------------------------------------------------------------------
201     //Returns an array of all files in the working directory.
202     //If no files can be found, returns FALSE.
203     function get_file_names_in_dir()
204     {
205     //Get directory list.
206     $rv = scandir (".");
207    
208     //If the list is empty, something went wrong. Return FALSE.
209     if ($rv === FALSE)
210     return FALSE;
211    
212     return $rv;
213     }
214     //--------------------------------------------------------------------------------
215     //Returns TRUE if a file name appears to be a valid full-sized image name,
216     //or FALSE otherwise.
217     function is_full_sized_image_file_name($in_filename)
218     {
219     //Convert the string name to all lower case. This will do for
220     //comparisons and tests.
221 dashley 116 $in_filename = strtolower($in_filename);
222 dashley 107
223     //Attempt to split the name into a base and an extension. Any failure
224     //means it is an unsuitable name.
225     $extension_start = strrpos($in_filename, ".");
226     //Find position of last "." in string. This should precede the
227     //file extension.
228    
229     if ($extension_start === FALSE)
230     {
231     //Bad name. Unsuitable.
232     return FALSE;
233     }
234    
235     //Calculate the base and extension.
236     $filename_base = substr($in_filename, 0, $extension_start);
237     $filename_extension = substr($in_filename, $extension_start + 1);
238    
239 dashley 116 //If the extension is not "jpg", "jpeg", "gif", or "png"; it isn't anything we recognize.
240     if (
241     ($filename_extension != "jpg")
242     &&
243     ($filename_extension != "jpeg")
244     &&
245     ($filename_extension != "gif")
246     &&
247     ($filename_extension != "png")
248     )
249 dashley 107 return FALSE;
250    
251     //If the filename base is empty, the filename is unsuitable.
252     if (strlen($filename_base) == 0)
253     return FALSE;
254    
255     //If the last characters of the base are the CFG_THUMBNAIL_FILENAME_SUFFIX,
256     //the name is unsuitable.
257     if (strlen($filename_base) >= strlen(CFG_THUMBNAIL_FILENAME_SUFFIX))
258     {
259     if (substr($filename_base, strlen($filename_base) - strlen(CFG_THUMBNAIL_FILENAME_SUFFIX))
260     == CFG_THUMBNAIL_FILENAME_SUFFIX)
261     return FALSE;
262     }
263    
264     //Looks good.
265     return TRUE;
266     }
267     //--------------------------------------------------------------------------------
268     //As a function of the file name, creates the file name for the thumbnail.
269     function file_name_to_thumbnail_name($in_filename)
270     {
271     $extension_start = strrpos($in_filename, ".");
272     //Find position of last "." in string. This should precede the
273     //file extension.
274     if ($extension_start === FALSE)
275     {
276     //"." not found. Should not happen. Filenames were checked in advance.
277     echo "Fatal internal error at line " . __LINE__ . "\n";
278     exit(1);
279     }
280    
281     $filename_prefix = substr($in_filename, 0, $extension_start);
282     $filename_extension = substr($in_filename, $extension_start);
283    
284     $rv = $filename_prefix . CFG_THUMBNAIL_FILENAME_SUFFIX . $filename_extension;
285    
286     return $rv;
287     }
288     //--------------------------------------------------------------------------------
289     //Actually creates the thumbnail, and returns some information about what was
290     //done.
291     //
292     //The calls to the ImagMagick library take on the order of 5s per image if there
293     //is filtering.
294     function create_thumbnail( $in_filename,
295     $in_thumbnailname,
296     & $out_filename_filesize,
297     & $out_filename_xdim,
298     & $out_filename_ydim,
299     & $out_thumbnailname_filesize,
300     & $out_thumbnailname_xdim,
301     & $out_thumbnailname_ydim)
302     {
303     //Assign output parameters just in case something doesn't get assigned.
304     $out_filename_filesize = 0;
305     $out_filename_xdim = 0;
306     $out_filename_ydim = 0;
307     $out_thumbnailname_filesize = 0;
308     $out_thumbnailname_xdim = 0;
309     $out_thumbnailname_ydim = 0;
310    
311     //Establish target dimensions. Two cases, depending on which is the longer
312     //side.
313    
314     //Construct.
315     $imagick = new Imagick();
316    
317     //Load image.
318     $imagick->readImage($in_filename);
319    
320     //Get the dimensions of the image we just loaded.
321     $geo = $imagick->getImageGeometry();
322     $out_filename_xdim = $geo['width'];
323     $out_filename_ydim = $geo['height'];
324    
325     //Calculate target sizes. We rearrange parameters based on which is our
326     //longest side.
327     if ($out_filename_xdim >= $out_filename_ydim)
328     {
329     //Longer width (x-dimension), or square.
330     calc_thumbnail_conversion_pars
331     (
332     $out_filename_xdim,
333     $out_filename_ydim,
334     CFG_THUMBNAIL_DIMENSION_MAX,
335     $out_thumbnailname_xdim,
336     $out_thumbnailname_ydim,
337     $orig_crop_dim_x,
338     $orig_crop_dim_y,
339     $orig_crop_start_x,
340     $orig_crop_start_y
341     );
342     }
343     else
344     {
345     //Longer height (y-dimension).
346     calc_thumbnail_conversion_pars
347     (
348     $out_filename_ydim,
349     $out_filename_xdim,
350     CFG_THUMBNAIL_DIMENSION_MAX,
351     $out_thumbnailname_ydim,
352     $out_thumbnailname_xdim,
353     $orig_crop_dim_y,
354     $orig_crop_dim_x,
355     $orig_crop_start_y,
356     $orig_crop_start_x
357     );
358     }
359    
360     //For debugging only, might want to know intermediate calculation results.
361     //echo "xcropdim, ycropdim, xcropstart, ycropstart: "
362     // .
363     // $orig_crop_dim_x
364     // .
365     // " "
366     // .
367     // $orig_crop_dim_y
368     // .
369     // " "
370     // .
371     // $orig_crop_start_x
372     // .
373     // " "
374     // .
375     // $orig_crop_start_y
376     // .
377     // "\n";
378    
379     //Crop the original to try to preserve the aspect ratio of the thumbnail
380     //as precisely as possible.
381     $imagick->cropImage(
382     $orig_crop_dim_x,
383     $orig_crop_dim_y,
384     $orig_crop_start_x,
385     $orig_crop_start_y
386     );
387    
388     //For debugging only, might want to get a look at the cropped image, to
389     //be sure nothing unexpected happens on the canvas.
390     //$imagick->writeImage($in_filename . ".cropped.jpg");
391    
392     //Resize to thumbnail size.
393     if (CFG_LANCZOS_FILTER_APPLY)
394     {
395     $imagick->resizeImage($out_thumbnailname_xdim,
396     $out_thumbnailname_ydim,
397     Imagick::FILTER_LANCZOS,
398     1);
399     }
400     else
401     {
402     $imagick->resizeImage($out_thumbnailname_xdim,
403     $out_thumbnailname_ydim,
404     0,
405     1);
406     }
407    
408     //Create the border.
409     $imagick->raiseImage(CFG_THUMBNAIL_BEVELED_BORDER_WIDTH,
410     CFG_THUMBNAIL_BEVELED_BORDER_WIDTH,
411     0,
412     0,
413     1);
414    
415     //Set compression to get a smaller thumbnail written, and strip
416     //header information. stripImage() seems to have the largest effect
417     //on thumbnail file size, so leaving the thumbnail quality near 100%
418     //is feasible. The jump in file size between 90% and 95% seemed to be
419     //fairly large (40% to 50%), so I left it at 90%. My rationale is
420     //that with the proliferation of mobile devices and cellular data,
421     //getting the thumbnail as small as possible is more important than
422     //the thumbnail looking perfect. If the viewer wants a perfect image,
423     //they can view the full-sized image.
424     $imagick->setImageCompression(Imagick::COMPRESSION_JPEG);
425     $imagick->setImageCompressionQuality(90);
426     $imagick->stripImage();
427    
428     //Write the thumbnail.
429     $imagick->writeImage($in_thumbnailname);
430    
431 dashley 116 //Destroy to prevent possible memory leak.
432     $imagick->destroy();
433 dashley 107
434     //All of the writing is done. Try to obtain the file sizes.
435     $fsize = filesize($in_filename);
436     if ($fsize !== FALSE)
437     $out_filename_filesize = $fsize;
438     $fsize = filesize($in_thumbnailname);
439     if ($fsize !== FALSE)
440     $out_thumbnailname_filesize = $fsize;
441     }
442     //--------------------------------------------------------------------------------
443     //Write introductory message.
444     hor_line_thick();
445 dashley 116 echo CFG_PROGNAME . ", Copyright (c) 2016 David T. Ashley\n";
446     echo "This program comes with ABSOLUTELY NO WARRANTY; and is licensed under the\n";
447     echo "MIT License. A copy of this license is provided in the source code\n";
448     echo "of this program.\n";
449 dashley 107 hor_line_thin();
450     //-----------------------------------------------------------------------------
451     //Get and emit the names of everything in the directory.
452     $file_list = get_file_names_in_dir();
453     if ($file_list === FALSE)
454     {
455 dashley 116 echo "List of files from PHP function scandir() is empty (rv === FALSE).\n";
456 dashley 107 echo "Serious internal error, or nothing to do. Script cannot continue.\n";
457     hor_line_thick();
458     exit(1);
459     }
460     else
461     {
462     echo "Files in working directory (unsorted, unfiltered, "
463     .
464     count($file_list)
465     .
466     " files):\n";
467     for ($i = 0; $i < count($file_list); $i++)
468     echo " " . sprintf("[%5d]", $i) . " " . $file_list[$i] . "\n";
469     }
470     hor_line_thin();
471     //-----------------------------------------------------------------------------
472     //Remove the standard directory entries "." and ".." from the list, and
473     //remove any directories.
474     $temp_list = $file_list;
475     unset($file_list);
476     $n = 0;
477     for ($i = 0; $i < count($temp_list); $i++)
478     {
479     //echo "Checking " . $temp_list[$i] . "\n";
480    
481     if (strcmp($temp_list[$i], ".") == 0)
482     {
483     //. entry, not a file.
484     }
485     else if (strcmp($temp_list[$i], "..") == 0)
486     {
487     //.. entry, not a file.
488     }
489     else if (is_file($temp_list[$i]))
490     {
491     //This is a regular file.
492     $file_list[] = $temp_list[$i];
493     $n++;
494     }
495     }
496    
497     if ($n == 0)
498     $file_list = FALSE;
499    
500     unset($n);
501     unset($temp_list);
502     //-----------------------------------------------------------------------------
503     //If there is nothing to do, end the script.
504     if ($file_list === FALSE)
505     {
506     echo "No files to process.\n";
507     hor_line_thick();
508     exit(0);
509     }
510     //-----------------------------------------------------------------------------
511     //Sort the list. This is a non-event. The only rationale for sorting is that
512     //it ensures that the same set of files will be processed in the same order,
513     //regardless of the order provided by the underlying OS internals.
514     sort($file_list);
515     //-----------------------------------------------------------------------------
516     //Emit the names we now have.
517     echo "Files in working directory (directory entries removed, sorted, "
518     .
519     count($file_list)
520     .
521     " files):\n";
522     for ($i = 0; $i < count($file_list); $i++)
523     echo " " . sprintf("[%5d]", $i) . " " . $file_list[$i] . "\n";
524     hor_line_thin();
525    
526     //-----------------------------------------------------------------------------
527     //For each file that is appropriate and where the thumbnail does not already
528     //exist, up to the maximum we may do in one invocation, create the thumbnail.
529     $i = 0;
530     $completed = 0;
531 dashley 116 while (
532     (
533     (CFG_MAX_THUMBNAILS_PER_INVOCATION == 0)
534     ||
535     ($completed < CFG_MAX_THUMBNAILS_PER_INVOCATION)
536     )
537     &&
538     ($i < count($file_list))
539     )
540 dashley 107 {
541     if (is_full_sized_image_file_name($file_list[$i]))
542     {
543     $thumbnail_name = file_name_to_thumbnail_name($file_list[$i]);
544    
545     if (file_exists($thumbnail_name))
546     {
547     echo " " . sprintf("[%5d]", $i) . " " . $file_list[$i] . " : skipping because corresponding thumbnail exists.\n";
548     hor_line_thin();
549     }
550     else
551     {
552     echo " " . sprintf("[%5d]", $i) . " " . $file_list[$i] . " : creating thumbnail.\n";
553    
554     echo "Creating thumbnail \"" .
555     $thumbnail_name .
556     "\" from image \"" .
557     $file_list[$i] .
558     "\".\n";
559    
560     create_thumbnail($file_list[$i],
561     $thumbnail_name,
562     $filename_filesize,
563     $filename_xdim,
564     $filename_ydim,
565     $thumbnail_filesize,
566     $thumbnail_xdim,
567     $thumbnail_ydim);
568    
569     echo "Conversion complete.\n";
570     echo " Full-sized image file size/xdim/ydim = " .
571     $filename_filesize . "/" . $filename_xdim . "/" . $filename_ydim .
572     ",\n";
573     echo " Thumbnail image filesize/xdim/ydim = " .
574     $thumbnail_filesize . "/" . $thumbnail_xdim . "/" . $thumbnail_ydim .
575     ",\n";
576    
577     hor_line_thin();
578     $completed++;
579     }
580     }
581     else
582     {
583     //Unsuitable base name. Can't use it.
584     echo " " . sprintf("[%5d]", $i) . " " . $file_list[$i] . " : skipping due to unsuitable name.\n";
585     hor_line_thin();
586     }
587    
588     $i++;
589     }
590    
591     //Emit a message about whether the program should be run again. I am aware of
592     //the uncovered case--where the last thumbnail was made on the last iteration
593     //of this invocation--but I will leave it uncovered for now. All that happens
594     //is the user runs the program unnecessarily one more time.
595     if ($completed == 0)
596     {
597     echo "No thumbnails were created--this program is done creating thumbnails.\n";
598     echo "It is not necessary to run this program again.\n";
599     hor_line_thin();
600     }
601     else
602     {
603     echo $completed . " thumbnail(s) were created. Please run this program repeatedly again\n";
604     echo "until no more thumbnails are created.\n";
605     hor_line_thin();
606     }
607    
608     echo CFG_PROGNAME . " execution ends.\n";
609     hor_line_thick();
610     //--------------------------------------------------------------------------------
611     //End of File
612     //--------------------------------------------------------------------------------
613     ?>

Properties

Name Value
svn:eol-style native
svn:executable *
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25