Annotation of scaleomat/scaleomat.pl, revision 1.10
1.1 casties 1: #!/usr/bin/perl
2:
1.9 casties 3: # Copyright (C) 2003-2005 Robert Casties, IT-Group MPIWG
1.3 casties 4: #
5: # This program is free software; you can redistribute it and/or modify it
6: # under the terms of the GNU General Public License as published by the Free
7: # Software Foundation; either version 2 of the License, or (at your option)
8: # any later version.
9: #
10: # Please read license.txt for the full details. A copy of the GPL may be found
11: # at http://www.gnu.org/copyleft/lgpl.html
12: #
13: # You should have received a copy of the GNU General Public License along with
14: # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15: # Place, Suite 330, Boston, MA 02111-1307 USA
16:
1.2 casties 17: use strict;
1.4 casties 18: use sigtrap qw(die normal-signals);
1.2 casties 19:
20: # MPIWG libraries
21: use lib '/usr/local/mpiwg/scripts';
22: use MPIWGlib;
23:
24:
1.1 casties 25: $| = 1; # unblock IO
26:
1.10 ! casties 27: my $version = "V0.9.7 (ROC 27.4.2005)";
1.1 casties 28:
29: $debug = 0;
30:
1.2 casties 31: my $simulate = 0;
32:
33: my $do_descend = 1;
1.1 casties 34:
1.2 casties 35: my $dir_perm = 0775;
36: my $file_perm = 0664;
1.1 casties 37:
38: umask 000; # to make shure we can actually use these perms
39:
1.2 casties 40: my $overwrite = 0; # overwrite already converted files
1.9 casties 41: my $synchronise = 0; # delete unmatched destination files
1.1 casties 42:
1.2 casties 43: # image file extensions and formats
44: my %img_type_ext = ("tif" => "TIFF", "tiff" => "TIFF", "gif" => "GIF",
1.6 casties 45: "jpg" => "JPEG", "png" => "PNG", "dcr" => "RAW");
1.2 casties 46: # destination image file extensions
47: my %target_ext_type = ("TIFF" => "jpg", "JPEG" => "jpg");
48:
49: # default scale settings
1.7 casties 50: my $scale_w = 2048; # width in pixel
51: my $scale_h = 2048; # height in pixel
1.2 casties 52: my $scale_relative = 0; # scale by relative factor instead of destination size
53: my $jpeg_quality = 75; # default JPEG compression quality
1.9 casties 54: my $use_encoder = 0; # false: autodetect encoder
1.2 casties 55:
56: # programs to use
57: my $identifier;
58: my $tiffinfo;
59: my $jpegloader;
60: my $tiffloader;
61: my $quantizer;
62: my $scaler;
63: my $jpegwriter;
64: my $pngwriter;
65: my $converter;
1.1 casties 66:
67: ##########################################################################
68: # subroutines
69: #
70:
71: #
72: # checksoft()
73: #
74: # returns if all necessary external programs are installed
75: #
76: sub checksoft {
77:
78: my @softdirs = ("/usr/X11R6/bin", "/usr/bin", "/usr/local/bin");
79:
80: $identifier = findfile(\@softdirs, "identify")
81: or die("ABORT: neccessary external program not found: identify");
1.2 casties 82: $tiffinfo = findfile(\@softdirs, "tiffinfo")
83: or die("ABORT: neccessary external program not found: tiffinfo");
1.1 casties 84: $jpegloader = findfile(\@softdirs, "jpegtopnm")
85: or die("ABORT: neccessary external program not found: jpegtopnm");
86: $tiffloader = findfile(\@softdirs, "tifftopnm")
87: or die("ABORT: neccessary external program not found: tifftopnm");
88: $quantizer = findfile(\@softdirs, "pbmtopgm")
89: or die("ABORT: neccessary external program not found: pbmtopgm");
90: $scaler = findfile(\@softdirs, "pnmscale")
91: or die("ABORT: neccessary external program not found: pnmscale");
92: $jpegwriter = findfile(\@softdirs, "ppmtojpeg")
93: or die("ABORT: neccessary external program not found: ppmtojpeg");
94: $pngwriter = findfile(\@softdirs, "pnmtopng")
95: or die("ABORT: neccessary external program not found: pnmtopng");
96: $converter = findfile(\@softdirs, "convert")
97: or die("ABORT: neccessary external program not found: convert");
98:
99: }
100:
101:
102:
103: #
104: # findir(\@basedirs, $subdir)
105: #
106: # check directories in @basedirs+$subdir and return the first existing basedir
107: #
108: sub findir {
109: my($dirlist, $subdir) = @_;
110:
111: foreach my $dir (@$dirlist) {
112: if (-d "$dir/$subdir") {
113: return "$dir";
114: }
115: }
116: return;
117: }
118:
119: #
120: # findfile(\@basedirs, $filename)
121: #
122: # check @basedirs+$filename and return the first existing file
123: #
124: sub findfile {
125: my($dirlist, $fn) = @_;
126:
127: foreach my $dir (@$dirlist) {
128: if (-f "$dir/$fn") {
129: return "$dir/$fn";
130: }
131: }
132: return;
133: }
134:
1.5 casties 135: #
136: # $p = cleanpath($path, $startslash).
137: #
138: # returns a pathname with trailing and starting slash removed (if
139: # $startslash is true the starting slash is not removed)
140: #
1.4 casties 141: sub cleanpath {
142: my ($path, $startslash) = @_;
143:
144: if ($path =~ /^(\/)*(.*?)\/*$/) {
145: if ($startslash) {
146: return $1 . $2;
147: } else {
148: return $2;
149: }
150: }
151: return $path;
152: }
153:
1.1 casties 154: #
1.2 casties 155: # ($basename, $extension) = splitfn($filename)
156: #
157: # split filename into base and (lowercase) extension
158: #
159: sub splitfn {
160: my ($filepath) = @_;
161: if ($filepath =~ /^(.*)\.(\w+)$/) {
162: return ($1, lc($2));
163: }
164: return;
165: }
166:
167:
168: #
1.1 casties 169: # mmkdir($dirname)
170: #
171: # create directory recursively and check permissions
172: #
173: sub mmkdir {
174: my($dirname) = @_;
175: my $newdir;
176:
177: # does the directory already exist?
1.2 casties 178: if (-d $dirname) {
179: chmod $dir_perm, $dirname or do {
1.4 casties 180: logger('WARNING', "unable to change permission on $dirname!");
1.1 casties 181: };
182: return 1;
183: }
184: # split directory name by levels
185: my @dirlist = split /\//, $dirname;
186: my @newlist = ();
187: my $dir = join("/", @dirlist);
188: # test backwards which directories exist
189: while (not -d $dir) {
1.2 casties 190: last unless ($dir);
1.1 casties 191: # move missing elements from the end of @dirlist to @newlist
192: unshift @newlist, pop @dirlist;
193: $dir = join("/", @dirlist);
194: }
195: # create missing directories level by level
196: foreach $newdir (@newlist) {
197: push @dirlist, $newdir;
198: $dir = join("/", @dirlist);
199: mkdir "$dir", $dir_perm or do {
1.2 casties 200: logger('ERROR', "unable to create $dir!");
1.1 casties 201: return 0;
202: }
203: }
204: return 1;
205: }
206:
207: #
1.2 casties 208: # ($type, $width, $height) = identify($filepath)
209: #
1.9 casties 210: # returns type, width and height of the image using ImageMagick's identify
211: #
1.2 casties 212: sub identify {
213: my ($filepath) = @_;
1.4 casties 214: my $pictype = "";
215: my $picwidth = 0;
216: my $picheight = 0;
1.2 casties 217: my $bitdepth = 0;
218: # use quickident first
219: $pictype = quickident($filepath);
1.7 casties 220: # optimized tiff identification
1.2 casties 221: if (($pictype)&&($pictype eq 'TIFF')) {
222: logger('DEBUG', "running tiffinfo $tiffinfo");
223: if (open(IDENT, "nice -10 $tiffinfo '$filepath' 2>/dev/null |")) {
224: while (<IDENT>) {
225: chomp;
1.7 casties 226: # we take the biggest values, because embedded thumbnails
227: # may also show up
1.2 casties 228: if (/Image Width:\s*(\d+)\s*Image Length:\s*(\d+)/) {
1.4 casties 229: $picwidth = $1 if ($1 > $picwidth);
230: $picheight = $2 if ($2 > $picheight);
1.2 casties 231: next;
232: }
233: if (/Bits\/Sample:\s*(\d+)/) {
1.4 casties 234: $bitdepth = $1 if ($1 > $bitdepth);
1.2 casties 235: next;
236: }
237: }
238: if ($picwidth) {
1.4 casties 239: logger('DEBUG', "TIFF $picwidth x $picheight");
1.2 casties 240: return ($pictype, $picwidth, $picheight, $bitdepth);
241: }
242: }
243: }
244: # run ident to get image type and dimensions
245: logger('DEBUG', "running identifier $identifier");
246: if (open(IDENT, "nice -10 $identifier -ping -format '%w %h %m\n' '$filepath' 2>/dev/null |")) {
247: my @id = <IDENT>;
248: my $picinfo = $id[0];
249: close IDENT;
250: chomp $picinfo;
251: logger('DEBUG', "PIC is '$picinfo'");
252: if ($picinfo =~ /^(\d+) (\d+) (\w+)$/) {
253: $picwidth = $1;
254: $picheight = $2;
255: $pictype = $3;
256: }
257: } else {
258: logger('DEBUG', "unable to identify $filepath!");
259: }
260: return ($pictype, $picwidth, $picheight, $bitdepth);
261: }
262:
263: #
264: # $type = quickident($filepath);
265: #
1.9 casties 266: # returns image type based on file extension only
267: #
1.2 casties 268: sub quickident {
269: my ($filepath) = @_;
270: logger('DEBUG', "running quickident");
271: # look at file extension
272: my ($filebase, $fileext) = splitfn($filepath);
273: if ($fileext) {
274: return $img_type_ext{$fileext};
275: }
276: return;
277: }
278:
279:
280: #
1.7 casties 281: # $fact = scalefactor(\$args)
1.1 casties 282: #
1.9 casties 283: # returns the necessary scaling factor
284: #
1.7 casties 285: sub scalefactor {
1.2 casties 286: my ($args) = @_;
287:
288: my $srcdir = $$args{'srcdir'};
289: my $filename = $$args{'filename'};
1.7 casties 290: my $scale_w = $$args{'scale_w'};
291: my $scale_h = $$args{'scale_h'};
1.2 casties 292: my $scale_rel = $$args{'scale_rel'};
1.7 casties 293: my $scale = 0;
1.2 casties 294:
295: if ($scale_rel) {
296: # scale relative -- no size needed, only scaling factor
1.7 casties 297: $scale = $scale_w;
1.2 casties 298: } else {
299: # scale to size -- size needed
300: my $pictype = $$args{'pictype'};
301: my $picwidth = $$args{'picwidth'};
302: my $picheight = $$args{'picheight'};
303: if (! $picwidth) {
1.7 casties 304: # no size yet - identify
1.2 casties 305: ($pictype, $picwidth, $picheight) = identify("$srcdir/$filename");
306: if ((! $pictype)||($picwidth == 0)||($picheight == 0)) {
307: logger('ERROR', "unable to identify $srcdir/$filename!");
1.7 casties 308: return 0;
1.2 casties 309: }
1.7 casties 310: # save values
311: $$args{'pictype'} = $pictype;
312: $$args{'picwidth'} = $picwidth;
313: $$args{'picheight'} = $picheight;
314: }
315: # calculate x and y scaling factors
316: my $scale_x = $scale_w / $picwidth;
317: my $scale_y = $scale_h / $picheight;
318: # take the smallest
319: if ($scale_x < $scale_y) {
320: $scale = $scale_x;
321: logger('DEBUG', "PIC scale to width");
1.2 casties 322: } else {
1.7 casties 323: $scale = $scale_y;
324: logger('DEBUG', "PIC scale to height");
1.2 casties 325: }
1.7 casties 326: if ($scale >= 1) {
327: $scale = 1;
1.2 casties 328: logger('DEBUG', "PIC is already smaller");
1.7 casties 329: # continue since we may have to convert
1.2 casties 330: }
331: }
1.7 casties 332: return $scale;
333: }
334:
335:
336: #
337: # $error = scale_jpeg(\$args);
338: #
339: # scale JPEG images to JPEG using netpbm tools
340: #
341: # args needed: $srcdir, $filename, $destdir,
342: # $scale_w, $scale_h, $scale_rel, $picwidth, $picheight
343: #
344: sub scale_jpeg {
345: my ($args) = @_;
346:
347: my $srcdir = $$args{'srcdir'};
348: my $filename = $$args{'filename'};
349: my $destdir = $$args{'destdir'};
350: my $scale_w = $$args{'scale_w'};
351: my $scale_h = $$args{'scale_h'};
352: my $scale_rel = $$args{'scale_rel'};
353: my $scaleopt;
354:
355: # convert jpg -> jpg
356: my ($basename, $fileext) = splitfn($filename);
357: my $newfn = $basename . ".jpg";
358: logger('INFO', "Convert(jpg): $filename -> $newfn");
359: return 1 if ($simulate);
360:
361: $scaleopt = scalefactor($args);
1.1 casties 362:
1.2 casties 363: if (!$scaleopt) {
364: logger('ERROR', "unable to calculate scaling options!");
365: return 1;
1.1 casties 366: }
1.2 casties 367:
1.8 casties 368: if ($scaleopt == 1) {
1.7 casties 369: # is already smaller
1.8 casties 370: logger('DEBUG', "PIC is smaller and JPEG - ignoring");
1.7 casties 371: return 0;
372: }
373:
1.2 casties 374: # convert
375: logger('DEBUG', "nice -10 $jpegloader '$srcdir/$filename' 2>/dev/null | nice -10 $scaler $scaleopt 2>/dev/null | nice -10 $jpegwriter > '$destdir/$newfn' 2>/dev/null");
376: return 0 if ($simulate);
377: if (system("nice -10 $jpegloader '$srcdir/$filename' 2>/dev/null | nice -10 $scaler $scaleopt 2>/dev/null | nice -10 $jpegwriter > '$destdir/$newfn' 2>/dev/null") != 0) {
378: logger('ERROR', "error converting '$srcdir/$filename'!");
1.7 casties 379: if (! -s "$destdir/$newfn") {
380: # file broken (size 0)
381: logger('ERROR', "created file '$destdir/$newfn' broken -- will be removed!");
382: unlink "$destdir/$newfn";
383: }
1.2 casties 384: return 1;
1.1 casties 385: }
1.2 casties 386:
387: # change permissions
388: chmod $file_perm, "$destdir/$newfn" or
389: logger('WARNING', "unable to set permission on '$destdir/$newfn'");
390:
391: if (! -s "$destdir/$newfn") {
392: # file broken (size 0)
393: logger('ERROR', "created file '$destdir/$newfn' broken -- will be removed!");
394: unlink "$destdir/$newfn";
395: return 1;
1.1 casties 396: }
1.2 casties 397: return 0;
1.1 casties 398: }
399:
400:
401: #
1.2 casties 402: # $error = scale_tiff_jpeg2(\$args);
403: #
404: # scale TIFF images to JPEG using ImageMagick convert
1.1 casties 405: #
1.2 casties 406: # args needed: $srcdir, $filename, $destdir,
1.7 casties 407: # $scale_w, $scale_h, $scale_rel, $picwidth, $picheight
1.1 casties 408: #
1.2 casties 409: sub scale_tiff_jpeg2 {
410: my ($args) = @_;
411:
412: my $srcdir = $$args{'srcdir'};
413: my $filename = $$args{'filename'};
414: my $destdir = $$args{'destdir'};
1.7 casties 415: my $scale_w = $$args{'scale_w'};
416: my $scale_h = $$args{'scale_h'};
1.2 casties 417: my $scale_rel = $$args{'scale_rel'};
418: my $scaleopt;
419:
420: my ($basename, $fileext) = splitfn($filename);
421: my $newfn = $basename . ".jpg";
422: logger('INFO', "Convert(tiff2): $filename -> $newfn");
423:
424: if ($scale_rel) {
1.7 casties 425: my $per_scale = 100 * $scale_w;
1.2 casties 426: logger('DEBUG', "nice -10 $converter -quality $jpeg_quality -scale $per_scale\% '$srcdir/$filename' '$destdir/$newfn' 2>/dev/null");
427: return 0 if ($simulate);
428: if (system("nice -10 $converter -quality $jpeg_quality -scale $per_scale\% '$srcdir/$filename' '$destdir/$newfn' 2>/dev/null\n") != 0) {
429: logger('ERROR', "error converting '$srcdir/$filename'!");
430: return 1;
431: }
432: } else {
1.7 casties 433: logger('DEBUG', "nice -10 $converter -quality $jpeg_quality -scale ${scale_w}x${scale_h} '$srcdir/$filename' '$destdir/$newfn' 2>/dev/null");
1.2 casties 434: return 0 if ($simulate);
1.7 casties 435: if (system("nice -10 $converter -quality $jpeg_quality -scale ${scale_w}x${scale_h} '$srcdir/$filename' '$destdir/$newfn' 2>/dev/null\n") != 0) {
1.2 casties 436: logger('ERROR', "error converting '$srcdir/$filename'!");
1.7 casties 437: if (! -s "$destdir/$newfn") {
438: # file broken (size 0)
439: logger('ERROR', "created file '$destdir/$newfn' broken -- will be removed!");
440: unlink "$destdir/$newfn";
441: }
1.2 casties 442: return 1;
1.1 casties 443: }
444: }
1.2 casties 445:
446: # change permissions
447: chmod $file_perm, "$destdir/$newfn" or
448: logger('WARNING', "unable to set permission on '$destdir/$newfn'");
449:
450: return 0;
451: }
452:
453:
454: #
455: # $error = scale_tiff_jpeg(\$args);
456: #
457: # scale TIFF images to JPEG using netpbm tools
458: #
459: # args needed: $srcdir, $filename, $destdir,
1.7 casties 460: # $scale_w, $scale_h, $scale_rel, $picwidth, $picheight
1.2 casties 461: #
462: sub scale_tiff_jpeg {
463: my ($args) = @_;
464:
465: my $srcdir = $$args{'srcdir'};
466: my $filename = $$args{'filename'};
467: my $destdir = $$args{'destdir'};
1.7 casties 468: my $bitdepth = $$args{'bitdepth'};
469: my $scale_w = $$args{'scale_w'};
470: my $scale_h = $$args{'scale_h'};
1.2 casties 471: my $scale_rel = $$args{'scale_rel'};
472: my $scaleopt;
473:
474: # convert jpg -> jpg
475: my ($basename, $fileext) = splitfn($filename);
476: my $newfn = $basename . ".jpg";
477: logger('INFO', "Convert(tiff1): $filename -> $newfn");
478: return 1 if ($simulate);
479:
1.7 casties 480: $scaleopt = scalefactor($args);
1.2 casties 481:
482: if (!$scaleopt) {
483: logger('ERROR', "unable to calculate scaling options!");
1.1 casties 484: return 1;
485: }
486:
1.2 casties 487: # convert
1.7 casties 488: my $cmd = "nice -10 $tiffloader \'$srcdir/$filename\' 2>/dev/null ";
489: if ($bitdepth == 1) {
490: # antialiasing bilevel images
491: $cmd .= "| nice -10 $quantizer 2 2 2>/dev/null ";
492: }
493: $cmd .= "| nice -10 $scaler $scaleopt 2>/dev/null | nice -10 $jpegwriter --quality $jpeg_quality > '$destdir/$newfn' 2>/dev/null";
494: logger('DEBUG', "$cmd");
1.2 casties 495: return 0 if ($simulate);
1.7 casties 496: if (system($cmd) != 0) {
1.2 casties 497: logger('ERROR', "error converting '$srcdir/$filename'!");
1.7 casties 498: if (! -s "$destdir/$newfn") {
499: # file broken (size 0)
500: logger('ERROR', "created file '$destdir/$newfn' broken -- will be removed!");
501: unlink "$destdir/$newfn";
502: }
1.2 casties 503: return 1;
504: }
505:
506: # change permissions
507: chmod $file_perm, "$destdir/$newfn" or
508: logger('WARNING', "unable to set permission on '$destdir/$newfn'");
509:
510: return 0;
511: }
512:
513:
514:
515: #
516: # $error = scale_tiff_png(\$args);
517: #
518: # scale TIFF images to PNG using netpbm tools
519: #
520: # args needed: $srcdir, $filename, $destdir,
1.7 casties 521: # $scale_w, $scale_h, $scale_rel, $picwidth, $picheight
1.2 casties 522: #
523: sub scale_tiff_png {
524: my ($args) = @_;
525:
526: my $srcdir = $$args{'srcdir'};
527: my $filename = $$args{'filename'};
528: my $destdir = $$args{'destdir'};
529: my $bitdepth = $$args{'bitdepth'};
1.7 casties 530: my $scale_w = $$args{'scale_w'};
531: my $scale_h = $$args{'scale_h'};
1.2 casties 532: my $scale_rel = $$args{'scale_rel'};
533: my $scaleopt;
534:
1.7 casties 535: # convert tif -> png
1.2 casties 536: my ($basename, $fileext) = splitfn($filename);
537: my $newfn = $basename . ".png";
538: logger('INFO', "Convert(tiff3): $filename -> $newfn");
539:
1.7 casties 540: $scaleopt = scalefactor($args);
1.2 casties 541:
542: if (!$scaleopt) {
543: logger('ERROR', "unable to calculate scaling options!");
1.1 casties 544: return 1;
545: }
546:
1.2 casties 547: # convert
548: my $cmd = "nice -10 $tiffloader \'$srcdir/$filename\' 2>/dev/null ";
549: if ($bitdepth == 1) {
550: # antialiasing bilevel images
551: $cmd .= "| nice -10 $quantizer 2 2 2>/dev/null ";
552: }
553: $cmd .= "| nice -10 $scaler $scaleopt 2>/dev/null | nice -10 $pngwriter > '$destdir/$newfn' 2>/dev/null";
554: logger('DEBUG', "$cmd");
555: return 0 if ($simulate);
556: if (system($cmd) != 0) {
557: logger('ERROR', "error converting '$srcdir/$filename'!");
1.7 casties 558: if (! -s "$destdir/$newfn") {
559: # file broken (size 0)
560: logger('ERROR', "created file '$destdir/$newfn' broken -- will be removed!");
561: unlink "$destdir/$newfn";
562: }
1.2 casties 563: return 1;
564: }
565:
566: # change permissions
567: chmod $file_perm, "$destdir/$newfn" or
568: logger('WARNING', "unable to set permission on '$destdir/$newfn'");
569:
570: return 0;
571: }
572:
573:
574: #
575: # $error = convert_file($srcdir, $filename, $destdir);
576: #
577: # convert file
578: #
579: sub convert_file {
1.9 casties 580: my($srcdir, $filename, $destdir, $filelist) = @_;
1.2 casties 581: my $filebase;
582: my $fileext;
583: my $newfn;
584: my $pictype;
585: my $picwidth;
586: my $picheight;
587: my $bitdepth;
588: my $error = 0;
589:
590: logger('DEBUG', "convert_file ($srcdir, $filename, $destdir)");
591:
592: if (not (( -f "$srcdir/$filename") && (-r _))) {
593: logger('ERROR', "unable to read file '$srcdir/$filename'");
594: return 1;
595: }
596:
597: # get base name and extension
1.9 casties 598: ($filebase, $fileext) = splitfn($filename);
1.2 casties 599:
1.1 casties 600: #
1.2 casties 601: # quick check if target image exists
1.1 casties 602: #
1.2 casties 603: $pictype = quickident("$srcdir/$filename");
604: if ($pictype) {
1.6 casties 605: if ($pictype eq "RAW") {
606: logger('DEBUG', "skipping raw file '$srcdir/$filename'");
607: return 0;
608: }
1.2 casties 609: my $newext = $target_ext_type{$pictype};
610: if ($newext) {
611: $newfn = $filebase . ".$newext";
1.9 casties 612: logger('DEBUG', "adding $destdir/$newfn'");
613: $$filelist{"$destdir/$newfn"} = $filename;
1.2 casties 614: # check if file exists
615: if (-f "$destdir/$newfn") {
616: logger('DEBUG', "CONV file exists: $newfn");
617: if (! $overwrite) {
1.7 casties 618: # compare age with source file
619: if (-M "$destdir/$newfn" > -M "$srcdir/$filename") {
620: logger('DEBUG', "CONV file is older: $newfn");
621: } else {
622: logger('INFO', "File already converted: $newfn");
623: return 0;
624: }
1.2 casties 625: }
1.1 casties 626: }
1.2 casties 627: } else {
628: logger('DEBUG', "target extension for $pictype unknown!");
1.1 casties 629: }
1.2 casties 630: } else {
631: # quick ident failed -- do it slowly
632: ($pictype, $picwidth, $picheight, $bitdepth) = identify("$srcdir/$filename");
633: if ((! $pictype)||($picwidth == 0)||($picheight == 0)) {
634: logger('WARNING', "unknown file type '$srcdir/$filename'");
1.1 casties 635: return 0;
636: }
637: }
638:
1.2 casties 639: # collect arguments for the conversion
640: my %args;
641: $args{'srcdir'} = $srcdir;
642: $args{'destdir'} = $destdir;
643: $args{'filename'} = $filename;
644: $args{'pictype'} = $pictype;
645: $args{'picwidth'} = $picwidth;
646: $args{'picheight'} = $picheight;
647: $args{'bitdepth'} = $bitdepth;
648: $args{'srcdir'} = $srcdir;
1.7 casties 649: $args{'scale_w'} = $scale_w;
650: $args{'scale_h'} = $scale_h;
1.2 casties 651: $args{'scale_rel'} = $scale_relative;
652:
653: # decide conversion based on image type and encoding preferences
654: if ($pictype eq 'JPEG') {
655: $args{'jpeg_qual'} = $jpeg_quality;
656: #default encoder
657: $error = scale_jpeg(\%args);
658: } elsif ($pictype eq 'TIFF') {
659: if ($use_encoder) {
660: # use specific encoder
661: if ($use_encoder eq 'tiff_jpeg') {
662: $error = scale_tiff_jpeg(\%args);
663: } elsif ($use_encoder eq 'tiff_jpeg2') {
664: $error = scale_tiff_jpeg2(\%args);
665: } elsif ($use_encoder eq 'tiff_png') {
666: $error = scale_tiff_png(\%args);
667: }
668: } else {
669: # default
670: $error = scale_tiff_jpeg(\%args);
671: }
672: } else {
673: logger('WARNING', "unknown file type: $pictype ($srcdir/$filename)");
674: }
675: return $error;
676: }
1.1 casties 677:
678:
679: #
680: # walk_convert_dir($dirname)
681: #
682: # Descend recursively through $dirname and work on all files
683: #
684: sub walk_convert_dir {
1.9 casties 685: my($srcdir, $workdir, $destdir, $filelist) = @_;
1.1 casties 686: my $errcnt = 0;
687: my $newfn;
688:
1.2 casties 689: opendir WORKDIR, "$srcdir/$workdir" or do {
690: logger('ERROR', "Unable to open directory $srcdir/$workdir!");
1.1 casties 691: return 0;
692: };
693:
694: my @dirlist = readdir(WORKDIR);
695:
696: closedir WORKDIR;
697:
1.9 casties 698: # check all directories first
1.1 casties 699: if ($do_descend) {
700: foreach (sort @dirlist) {
1.9 casties 701: # skip dot-directories
1.10 ! casties 702: next if (/^\..*$/);
1.9 casties 703: # skip junk directories
1.2 casties 704: next if ($junk_files{$_});
1.9 casties 705: # recurse through the rest
1.2 casties 706: if (-d "$srcdir/$workdir/$_") {
1.9 casties 707: walk_convert_dir($srcdir, "$workdir/$_", $destdir, $filelist);
1.1 casties 708: }
709: }
710: }
711:
1.2 casties 712: logger('INFO', "Working on $workdir");
713: logger('INFO', "Reading from $srcdir/$workdir.");
714: logger('INFO', "Writing to $destdir/$workdir");
1.1 casties 715:
1.2 casties 716: # create destination directory
1.1 casties 717: if (not ($simulate)) {
1.2 casties 718: mmkdir("$destdir/$workdir") or do {
719: logger("ERROR", "unable to create directory '$destdir/$workdir'");
1.1 casties 720: $errcnt++;
721: return 0;
722: };
723: }
1.2 casties 724:
1.9 casties 725: # check all files in this directory
1.1 casties 726: foreach (sort @dirlist) {
1.9 casties 727: # skip dot-files
728: next if (/^[.]+.*$/);
729: # try to convert the rest
1.2 casties 730: if (-f "$srcdir/$workdir/$_") {
1.9 casties 731: $errcnt += convert_file("$srcdir/$workdir", "$_", "$destdir/$workdir", $filelist);
1.1 casties 732: }
733: }
734:
735: if ($errcnt) {
1.2 casties 736: logger('INFO', "There were $errcnt errors converting '$workdir'!");
1.1 casties 737: } else {
1.2 casties 738: logger('INFO', "Finished converting $workdir!");
1.1 casties 739: }
740:
741: return 1;
742: }
743:
744:
745: #
746: # convert_dir($from_dir)
747: #
748: # Convert directory "from_dir" and its subdirectories
749: #
750: sub convert_dir {
1.2 casties 751: my ($srcdir, $workdir, $destdir) = @_;
1.9 casties 752: my %files = ();
1.1 casties 753:
1.2 casties 754: logger('INFO', "** Converting Scans **");
1.7 casties 755:
756: if (-d "$srcdir/$workdir") {
757: # it's a dirrectory
758: logger('INFO', "Starting in directory '$srcdir/$workdir'");
1.9 casties 759: walk_convert_dir($srcdir, $workdir, $destdir, \%files);
760: if ($synchronise) {
761: logger('INFO', "Removing unmatched files in '$destdir/$workdir'");
762: remove_unmatched_files("$destdir/$workdir", \%files);
763: }
1.7 casties 764: # touch source directory so digilib rescans the thumbnails
765: #logger('DEBUG', "/usr/bin/touch $source_base_dirs[0]/$workdir");
766: system("/usr/bin/touch '$srcdir/$workdir'");
767: } elsif (-f _) {
768: # it's a file
769: logger('INFO', "Converting file '$srcdir/$workdir'");
770: convert_file($srcdir, $workdir, $destdir);
771: # touch source parent directory so digilib rescans the thumbnails
772: my $pdir = "$srcdir/$workdir";
773: # chop off after the last slash
774: $pdir =~ s/\/[^\/]+$/\//;
775: system("/usr/bin/touch '$pdir'");
776: }
1.1 casties 777:
1.2 casties 778: logger('DONE', "** Finished converting scans **");
1.1 casties 779: return 1;
780: }
781:
782:
783:
1.9 casties 784: #
785: # remove_unmatched_files($basedir, \%files)
786: #
787: # removes all files from $basedir and its subdirectories that are not
788: # in %files
789: #
790: sub remove_unmatched_files {
791: my ($basedir, $files) = @_;
792: my $cnt = 0;
793:
794: if (! opendir DIR, $basedir) {
795: logger('ERROR', "directory $basedir doesn't exist (in remove_unmatched_files)");
796: return 0;
797: }
798: my @dirfiles = readdir DIR;
799: foreach my $fn (@dirfiles) {
800: # ignore names starting with a dot
801: next if ($fn =~ /^\./);
802: # ignore other silly files
803: next if ($junk_files{$fn});
804:
805: $cnt++;
806: my $f = "$basedir/$fn";
807: #print "fs_file: \"$f\"\n";
808: if (-f $f) {
809: #print " is file\n";
810: logger('DEBUG', "checking '$f'");
811: if (not exists($$files{$f})) {
812: logger('DEBUG', "removing orphaned file $f");
813: unlink $f;
814: }
815: } elsif (-d _) {
816: # recurse into directory
817: $cnt += remove_unmatched_files($f, $files);
818: # delete if its empty
819: rmdir $f;
820: }
821: }
822: return $cnt;
823: }
1.1 casties 824:
825:
826:
827: ###############################################################
828: ## Main
829:
1.2 casties 830: if ($#ARGV < 3) {
1.1 casties 831: print "Scale-O-Mat $version\n";
1.2 casties 832: print " use: scaleomat.pl -src=src-base -dest=dest-base -dir=workdir [...]\n";
833: print " reads from scr-base/workdir and writes to dest-base/workdir\n";
1.7 casties 834: print " -scaleto=destination size (S or WxH)\n";
1.2 casties 835: print " -scaleby=magnification factor.\n";
836: print " -jpegqual=JPEG quality (0-100)\n";
1.9 casties 837: print " -replace=yes replaces existing files (default=update).\n";
838: print " -sync=yes delete unmatched file in destination (default=ignore).\n";
1.2 casties 839: print " -encoder=tiff_png|tiff_jpeg|tiff_jpeg2\n";
1.1 casties 840: exit 1;
841: }
842:
843: # test software installation
1.2 casties 844: checksoft();
845:
846: # read command line parameters
847: my $args = parseargs();
848:
849: # source dir
1.4 casties 850: my $srcdir = cleanpath($$args{'src'}, 1);
1.1 casties 851:
1.2 casties 852: # destination dir
1.4 casties 853: my $destdir = cleanpath($$args{'dest'}, 1);
1.2 casties 854:
855: # working dir
1.4 casties 856: my $workdir = cleanpath($$args{'dir'});
1.2 casties 857:
858: # destination size
859: if ($$args{'scaleby'}) {
860: $scale_relative = 1;
1.7 casties 861: $scale_w = $$args{'scaleby'};
862: logger('INFO', "Scaling relative by factor $scale_w");
1.2 casties 863: }
864: if ($$args{'scaleto'}) {
865: $scale_relative = 0;
1.7 casties 866: if ($$args{'scaleto'} =~ /(\d+)x(\d+)/) {
867: $scale_w = $1;
868: $scale_h = $2;
869: } else {
870: $scale_w = $$args{'scaleto'};
871: $scale_h = $$args{'scaleto'};
872: }
873: logger('INFO', "Scaling absolute to size $scale_w x $scale_h");
1.2 casties 874: }
875:
876: # JPEG quality
877: if ($$args{'jpegqual'}) {
878: logger('INFO', "JPEG quality set to '$$args{'jpegqual'}'!");
879: $jpeg_quality = $$args{'jpegqual'};
880: }
881:
882: # force encoder
883: if ($$args{'encoder'}) {
884: logger('INFO', "Using encoder '$$args{'encoder'}'!");
885: $use_encoder = $$args{'encoder'};
1.1 casties 886: }
887:
1.2 casties 888: # Overwrite
889: if ($$args{'replace'}) {
890: logger('INFO', "Set to overwrite existing files!");
891: $overwrite = 1;
1.9 casties 892: }
893:
894: # Synchronise
895: if ($$args{'sync'}) {
896: logger('INFO', "Set to delete unmatched files!");
897: $synchronise = 1;
1.1 casties 898: }
899:
1.2 casties 900: # debug
901: if ($$args{'debug'}) {
902: logger('INFO', "Set debug level to $$args{'debug'}!");
903: $debug = $$args{'debug'};
1.1 casties 904: }
905:
1.2 casties 906: # simulate
907: if ($$args{'simulate'}) {
908: logger('INFO', "Set to simulate operation only ($$args{'simulate'})!");
909: $simulate = $$args{'simulate'};
1.1 casties 910: }
1.2 casties 911:
912: convert_dir($srcdir, $workdir, $destdir);
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>