#!/usr/bin/perl $| = 1; # unblock IO $version = "V0.7 (ROC 23.12.2003)"; $debug = 0; $simulate = 0; $do_descend = 1; @source_base_dirs = ("/docuserver/images"); $dest_base_dir = "/docuserver/scaled/small"; $dir_perm = 0775; $file_perm = 0664; umask 000; # to make shure we can actually use these perms $dont_overwrite = 1; # don't overwrite already converted files @imgfile_ext = ("tif", "tiff", "gif", "jpg", "png"); $target_size = 2048; # pixel of longest side $scale_relative = 0; # scale by relative factor instead of destination size $jpeg_quality = 75; # default JPEG compression quality ########################################################################## # subroutines # # # checksoft() # # returns if all necessary external programs are installed # sub checksoft { my @softdirs = ("/usr/X11R6/bin", "/usr/bin", "/usr/local/bin"); $identifier = findfile(\@softdirs, "identify") or die("ABORT: neccessary external program not found: identify"); $jpegloader = findfile(\@softdirs, "jpegtopnm") or die("ABORT: neccessary external program not found: jpegtopnm"); $tiffloader = findfile(\@softdirs, "tifftopnm") or die("ABORT: neccessary external program not found: tifftopnm"); $quantizer = findfile(\@softdirs, "pbmtopgm") or die("ABORT: neccessary external program not found: pbmtopgm"); $scaler = findfile(\@softdirs, "pnmscale") or die("ABORT: neccessary external program not found: pnmscale"); $jpegwriter = findfile(\@softdirs, "ppmtojpeg") or die("ABORT: neccessary external program not found: ppmtojpeg"); $pngwriter = findfile(\@softdirs, "pnmtopng") or die("ABORT: neccessary external program not found: pnmtopng"); $converter = findfile(\@softdirs, "convert") or die("ABORT: neccessary external program not found: convert"); } # # dprint($message) # # print if $debug = 1 # sub dprint { my ($msg) = @_; if ($debug) { print "$msg"; } } # # findir(\@basedirs, $subdir) # # check directories in @basedirs+$subdir and return the first existing basedir # sub findir { my($dirlist, $subdir) = @_; foreach my $dir (@$dirlist) { if (-d "$dir/$subdir") { return "$dir"; } } return; } # # findfile(\@basedirs, $filename) # # check @basedirs+$filename and return the first existing file # sub findfile { my($dirlist, $fn) = @_; foreach my $dir (@$dirlist) { if (-f "$dir/$fn") { return "$dir/$fn"; } } return; } # # mmkdir($dirname) # # create directory recursively and check permissions # sub mmkdir { my($dirname) = @_; my $newdir; # does the directory already exist? if (-d $dir) { chmod $dir_perm, $dir or do { print "ERROR: unable to change permission on $dir!\n"; return 0; }; return 1; } # split directory name by levels my @dirlist = split /\//, $dirname; my @newlist = (); my $dir = join("/", @dirlist); # test backwards which directories exist while (not -d $dir) { # move missing elements from the end of @dirlist to @newlist unshift @newlist, pop @dirlist; $dir = join("/", @dirlist); } # create missing directories level by level foreach $newdir (@newlist) { push @dirlist, $newdir; $dir = join("/", @dirlist); mkdir "$dir", $dir_perm or do { print "ERROR: unable to create $dir!\n"; return 0; } } return 1; } # # dir_ok($dirname) # # check directory name against evil # sub dir_ok { my($dirname) = @_; if ($dirname eq "") { print "ERROR: DIR mustn't be empty!\n"; return 0; } if ($dirname =~ /\.\./) { print "ERROR: DIR mustn't backref!\n"; return 0; } if ($dirname =~ /[|<>]+/) { print "ERROR: DIR mustn't be special!\n"; return 0; } return 1; } # # convert_file($filename) # # convert file # sub convert_file { my($basedir, $filename) = @_; my $newfn; my $pictype; my $picwidth; my $picheight; my $scaleopt = 0.3; if (not (( -f "$basedir/$filename") && (-r _))) { print "ERROR: unable to read file '$basedir/$filename'\n;"; return 0; } # # run ident first to get image type and dimensions # calculate scaling factor based on destination size or factor # if (open(IDENT, "nice -10 $identifier -ping -format '%w %h %m\n' '$basedir/$filename' 2>/dev/null|")) { my @id = ; my $picinfo = $id[0]; close IDENT; chomp $picinfo; dprint "INFO: PIC is $picinfo\n"; if ($picinfo =~ /^(\d+) (\d+) (\w+)$/) { $picwidth = $1; $picheight = $2; $pictype = $3; if ($scale_relative) { $scaleopt = $target_size; } else { if ($picheight > $picwidth) { $scaleopt = $target_size / $picheight; dprint "INFO: PIC is portrait\n"; } else { $scaleopt = $target_size / $picwidth; dprint "INFO: PIC is landscape\n"; } if ($scaleopt >= 1) { $scaleopt = 1; dprint "INFO: PIC is already smaller\n"; } } } } # # scale JPEG images to JPEG using netpbm tools # if ($pictype eq 'JPEG') { # convert jpg -> jpg $newfn = $filename; $newfn =~ s/\.\w+$/.jpg/; if (-f "$dest_base_dir/$newfn") { dprint "INFO CONV file exists: $newfn\n"; if ($dont_overwrite) { print "INFO: File already converted: $newfn\n"; return 1; } } print "INFO: Convert(jpg): $filename -> $newfn\n"; return 1 if ($simulate); dprint("nice -10 $jpegloader '$basedir/$filename' 2>/dev/null | nice -10 $scaler $scaleopt 2>/dev/null | nice -10 $jpegwriter > '$dest_base_dir/$newfn' 2>/dev/null\n"); if (system("nice -10 $jpegloader '$basedir/$filename' 2>/dev/null | nice -10 $scaler $scaleopt 2>/dev/null | nice -10 $jpegwriter > '$dest_base_dir/$newfn' 2>/dev/null") != 0) { return 0; } chmod $file_perm, "$dest_base_dir/$newfn" or print "WARNING: unable to set permission on '$dest_base_dir/$newfn'\n"; return 1; } # # scale TIFF images to JPEG using convert # (slower but netpbm doesn't always work) # if ($pictype eq 'TIFF') { # convert tif -> jpg $newfn = $filename; $newfn =~ s/\.\w+$/.jpg/; if (-f "$dest_base_dir/$newfn") { dprint "INFO: CONV file exists: $newfn\n"; if ($dont_overwrite) { print "INFO: File already converted: $newfn\n"; return 1; } } print "INFO: Convert(tif): $filename -> $newfn\n"; if ($scale_relative) { my $per_scale = 100 * $scaleopt; dprint("nice -10 $converter -quality $jpeg_quality -scale $per_scale\% $basedir/$filename $dest_base_dir/$newfn 2>/dev/null\n"); return 1 if ($simulate); if (system("nice -10 $converter -quality $jpeg_quality -scale $per_scale\% '$basedir/$filename' '$dest_base_dir/$newfn' 2>/dev/null\n") != 0) { return 0; } } else { dprint("nice -10 $converter -quality $jpeg_quality -scale ${target_size}x${target_size} $basedir/$filename $dest_base_dir/$newfn 2>/dev/null\n"); return 1 if ($simulate); if (system("nice -10 $converter -quality $jpeg_quality -scale ${target_size}x${target_size} '$basedir/$filename' '$dest_base_dir/$newfn' 2>/dev/null\n") != 0) { return 0; } } chmod $file_perm, "$dest_base_dir/$newfn" or print "WARNING: unable to set permission on '$newfn'\n;"; return 1; } # # convert TIFF to PNG using netpbm tools (not used any more) # if ($pictype eq 'TIFF_old') { # convert tif -> png $newfn = $filename; $newfn =~ s/\.\w+$/.png/; if (-f "$dest_base_dir/$newfn") { dprint "INFO: CONV file exists: $newfn\n"; if ($dont_overwrite) { print "INFO: File already converted: $newfn\n"; return 1; } } print "INFO: Convert(tif): $filename -> $newfn\n"; return 1 if ($simulate); dprint("nice -10 $tiffloader $basedir/$filename 2>/dev/null | nice -10 $quantizer 2 2 2>/dev/null | nice -10 $scaler $scaleopt 2>/dev/null | nice -10 $pngwriter > $dest_base_dir/$newfn 2>/dev/null\n"); if (system("nice -10 $tiffloader $basedir/$filename 2>/dev/null | nice -10 $quantizer 2 2 2>/dev/null | nice -10 $scaler $scaleopt 2>/dev/null | nice -10 $pngwriter > $dest_base_dir/$newfn 2>/dev/null") != 0) { return 0; } chmod $file_perm, "$dest_base_dir/$newfn" or print "WARNING: unable to set permission on '$newfn'\n;"; return 1; } print "WARNING: unknown file type: '$basedir/$filename'\n;"; return 0; } # # walk_convert_dir($dirname) # # Descend recursively through $dirname and work on all files # sub walk_convert_dir { my($workdir) = @_; my $errcnt = 0; my $newfn; my $basedir = findir(\@source_base_dirs, $workdir); opendir WORKDIR, "$basedir/$workdir" or do { print "ERROR: Unable to open directory $basedir/$workdir!\n"; return 0; }; my @dirlist = readdir(WORKDIR); closedir WORKDIR; if ($do_descend) { foreach (sort @dirlist) { if (/^[.]+$/) { next; } if (-d "$basedir/$workdir/$_") { walk_convert_dir("$workdir/$_"); } } } print "INFO: Working on $workdir\n"; print "INFO: Reading from $basedir.\n"; print "INFO: Writing to $dest_base_dir\n"; if (not ($simulate)) { mmkdir("$dest_base_dir/$workdir") or do { print "ERROR: unable to create directory '$dest_base_dir/$workdir'\n;"; $errcnt++; return 0; }; if ($dont_overwrite == 0) { foreach (@imgfile_ext) { system("rm -f $dest_base_dir/$workdir/*.$_"); } } } foreach (sort @dirlist) { if (/^[.]+.*$/) { next; } if (-f "$basedir/$workdir/$_") { if (convert_file($basedir, "$workdir/$_") == 0) { $errcnt++; } } } if ($errcnt) { print "INFO: There were errors converting $workdir!\n"; } else { print "INFO: Finished converting $workdir!\n"; } return 1; } # # convert_dir($from_dir) # # Convert directory "from_dir" and its subdirectories # sub convert_dir { my ($workdir) = @_; print "INFO: ** Converting Scans **\n"; print "INFO: Starting in directory '$workdir'\n"; dir_ok($workdir) or die("ABORT: Illegal directory name '$workdir'!\n"); walk_convert_dir($workdir); # touch source directory so digilib rescans the thumbnails #print "DEBUG:/usr/bin/touch $source_base_dirs[0]/$workdir\n"; system("/usr/bin/touch $source_base_dirs[0]/$workdir"); print "DONE: ** Finished converting scans **\n"; return 1; } ############################################################### ## Main if ($#ARGV < 0) { print "Scale-O-Mat $version\n"; print " use: scaleomat.pl hires-dir dest-base size [quality] [--replace]\n"; print " - if hires-dir starts with '/' then it's absolute.\n"; print " - if size starts with 'x' then it's magnification factor.\n"; print " - quality is JPEG quality (0-100)\n"; print " - --replace replaces existing files (default=skip).\n"; exit 1; } # test software installation checksoft; # parameter 1 is destination dir if ($#ARGV > 0) { $dest_base_dir = $ARGV[1]; } # parameter 2 is destination size (or factor when starting with "x") if ($#ARGV > 1) { if ($ARGV[2] =~ /^x([\d.]+)/) { $scale_relative = 1; $target_size = $1; print "INFO: scaling relative by factor $target_size\n"; } else { $scale_relative = 0; $target_size = $ARGV[2]; print "INFO: scaling absolute to size $target_size\n"; } } # optional parameters are JPEG quality or --replace if ($#ARGV > 2) { for ($i = 3; $i <= $#ARGV; $i++) { $s = $ARGV[$i]; if ($s eq "--replace") { print "INFO: set to overwrite existing files!\n"; $dont_overwrite = 0; } else { print "INFO: JPEG quality set to '$s'!\n"; $jpeg_quality = $s; } } } # convert all files in the directory my $srcdir = $ARGV[0]; if ($srcdir =~ /^\//) { # if source dir starts with / then ist's absolute $source_base_dirs[0] = "/"; } convert_dir($srcdir);