diff --git a/leaf.php b/leaf.php index c5c0e9f..8df032b 100644 --- a/leaf.php +++ b/leaf.php @@ -2,9 +2,10 @@ /dev/null & ",$cmd)." & wait"; - echo $echo."\n"; + echo $echo; + if (strlen($echo) > 1) { + echo "\n"; + } exec($exec); } } @@ -141,9 +145,15 @@ $help = "Leaf $version USAGE: leaf [mode] [-options] directory Modes: +clean remove scratch files crop define EXIF crop values using template files -crops= specify how many files to use desort remove image sequence prefix +deskew detect rotation angles + -max= angles greater than this value are ignored, default .4 + -pad= pixels to pad around crop area, default 80 + -contrast= contrast boost, default 20 + -size= size in pixels of dmap, default 2200 divide wrapper for imagemagick Divide_Src -map= specify brightness file -adjust= levels adjustment (ex. \"0%,98%,.9\") @@ -158,6 +168,9 @@ resort reorder image sequence by adding a new image -file= file to insert -x= position of inserted file review print a table of image dimension statistics +rotate batch transform rotate (lossy) + -x= rotation angle, default=90 + -q=<0-100> jpeg quality, default read from source or 95 setdpi set image dpi with exiftool -x= specify dpi -height= calculate dpi from specified height @@ -169,6 +182,68 @@ strip strip exif crop values from images with exiftool echo $help; fin(); +//////////////////////////////////////////////////////////////////////////////////////////////// +// Note: Clean +////////////////////// +} elseif (args("app") == "clean") { +echo Welcome("Remove scratch dir"); +///////////////////////////////////////////////////////////////////////// + +msg("Remove scratch files?",2); +if (!is_dir("scratch")) { + msg("Problem with scratch dir",2); + } else { + foreach (glob("scratch/*.*") as $file) { + unlink($file); + } + } + +fin(); + +//////////////////////////////////////////////////////////////////////////////////////////////// +// Note: Rotate +////////////////////// +} elseif (args("app") == "rotate") { +echo Welcome("Batch rotate (lossy)"); +///////////////////////////////////////////////////////////////////////// + +$default_quality = 95; + +$files = glob(args("dir")."*.{jpg,JPG,tif,TIF}", GLOB_BRACE); + +if (args("x")) { + $angle = args("x"); + } else { + $angle = 90; + } + +$dest = rtrim(args("dir"), '/')."_rotated"; +if (count(glob($dest."/*.*"))) { + msg("Files already exist in destination ".$dest,1); + } elseif (!is_dir($dest)) { + mkdir($dest); + } + +foreach ($files as $file) { + $ext = pathinfo($file,PATHINFO_EXTENSION); + $output = $dest."/".basename($file,$ext)."jpg"; + if (args("q")) { + $quality = args("q"); + } elseif (strtolower($ext) == "jpg") { + $quality = @exec("identify -format '%Q' ".$file); + } else { + $quality = $default_quality; + } + $msg = "Rotating ".$file." ".$angle." to ".$output." with Q=".$quality; + $cmd = "convert -rotate ".$angle." -quality ".$quality." ".$file." ".$output; + $thread[] = array($msg, $cmd); + } + +msg("Beginning multithreaded convert with ".$xt." threads"); +multiexec($thread,$xt); + +fin(); + //////////////////////////////////////////////////////////////////////////////////////////////// // Note: Profile ////////////////////// @@ -666,7 +741,6 @@ fin(); echo Welcome("Composite image from brightness map"); ///////////////////////////////////////////////////////////////////////// -$xt = 8; $files = glob(args("dir")."*.{jpg,JPG,tif}", GLOB_BRACE); if (!args("map")) { @@ -800,62 +874,170 @@ fin(); echo Welcome("Detect skew angle and apply to EXIF tags"); ///////////////////////////////////////////////////////////////////////// -$deskew_max_angle = ".4"; -$deskew_padding = 80; -$deskew_contrast = 20; -$deskew_size = 2200; +if (args("max")) { + $deskew_max_angle = args("max"); + } else { + $deskew_max_angle = .4; + } -$files = glob(args("dir")."*.jpg"); +if (null !== args("pad")) { + $deskew_padding = args("pad"); + echo "pad = ".args("pad"); + } else { + $deskew_padding = 80; + } + +if (null !== args("contrast")) { + $deskew_contrast = args("contrast"); + } else { + $deskew_contrast = 20; + } + +if (args("size")) { + $deskew_size = args("size"); + } else { + $deskew_size = 2200; + } + +die; + +$files = glob(args("dir")."*.{jpg,JPG,dng,DNG}", GLOB_BRACE); + +echo "Scanning for crop values: "; if (!args("nomap")) { - msg("Creating dmaps..."); + foreach ($files as $file) { + + $ext = pathinfo($file,PATHINFO_EXTENSION); + $dmfile = "scratch/".basename($file, ".".$ext)."_dmap.jpg"; + + if (!file_exists($dmfile)) { + + $parts = chop(shell_exec("exiftool -s -s -s -XMP-crs:CropTop -XMP-crs:CropRight -XMP-crs:CropLeft -XMP-crs:CropBottom -ImageWidth -ImageHeight ".$file." 2>&1")); + @list($top, $right, $left, $bottom, $check_width, $check_height) = explode("\n", $parts); + if (!$top | !$right | !$left | !$bottom) { msg($file." missing crop information!",1); } + + $jpeg_width = $check_height; + $jpeg_height = $check_width; + + $top_pixels = floor( $jpeg_width * $top ); + $right_pixels = $jpeg_height - floor( $right * $jpeg_height ); + $left_pixels = floor( $jpeg_height * $left ); + $bottom_pixels = $jpeg_width - floor( $bottom * $jpeg_width ); + + $width = $jpeg_width - ( $top_pixels + $bottom_pixels ); + $height = $jpeg_height - ( $left_pixels + $right_pixels ); + + $area_left = ( $width + $deskew_padding*2 )."x".( $height + $deskew_padding*2 )."+".( $bottom_pixels - $deskew_padding )."+".( $left_pixels - $deskew_padding ); + $area_right = ( $width + $deskew_padding*2 )."x".( $height + $deskew_padding*2 )."+".( $top_pixels - $deskew_padding )."+".( $right_pixels - $deskew_padding ); + + //echo "\n\n(Area left = ".$area_left.", Area right = ".$area_right.")"; + + $size = $deskew_size."x".$deskew_size; + + if (substr(basename($file), 0, 3) % 2 == 0) { + $cmd = "convert ".$file." -auto-orient -crop ".$area_right." -level ".$deskew_contrast."%,".(100-$deskew_contrast)."% -colorspace Gray -resize ".$size." ".$dmfile; + } else { + $cmd = "convert ".$file." -auto-orient -crop ".$area_left." -level ".$deskew_contrast."%,".(100-$deskew_contrast)."% -colorspace Gray -resize ".$size." ".$dmfile; + } + + $msg = "Creating dmap for ".$file; + $thread[] = array($msg, $cmd); + + echo "."; + + } else { + + $thread[] = array("Dmap for ".$file." already exists", "true"); + + echo "o"; + + } + } + + echo "\n\n"; + + if (is_array($thread)) { + + msg("Creating dmaps with ".$xt." threads"); + multiexec($thread,$xt); + + } } else { msg("Skipping dmap creation"); } - -if (shell_exec("exiftool -s -s -s -CropAngle ".$files[0]." 2>&1")) { - msg("Crop angle detected on ".$files[0].", continue?",2); - } - + +$thread = null; + +echo "\n"; +msg("Detecting skew..."); + foreach ($files as $file) { - + if (args("nomap")) { $dmfile = $file; } else { - $dmfile = "scratch/".basename($file, ".jpg")."_dmap.jpg"; + $ext = pathinfo($file,PATHINFO_EXTENSION); + $dmfile = "scratch/".basename($file, ".".$ext)."_dmap.jpg"; } $result = shell_exec("deskew -o /tmp/null -l 99 \"".$dmfile."\" 2>&1"); $arr = explode("Skew angle found: ", $result); $angle = substr($arr[1], 0, 4); - echo $file.": ".$angle; + $msg = $file.": ".$angle; if ($angle > $deskew_max_angle | $angle < ($deskew_max_angle*-1)) { - echo " (too big)"; + $msg .= " (too big)"; } else { $angles[$file] = $angle; } - echo "\n"; + msg($msg); } + +echo "\n\n"; + +echo "Checking for existing rotation: "; + +foreach ($files as $file) { -// echo "\nWriting angles to EXIF: "; -// -// foreach ($files as $file) { -// -// if (isset($angles[$file])) { -// exec("exiftool -overwrite_original -XMP-crs:CropAngle=".$angles[$file]." ".$file); -// echo "."; -// } else { -// // erase top edge crop to indicate rotation was not applied -// exec("exiftool -overwrite_original -XMP-crs:CropTop=0 ".$file." 2>&1"); -// } -// } + if(shell_exec("exiftool -s -s -s -CropAngle ".$file." 2>&1")) { + + $msg = $file." already has a CropAngle"; + $cmd = "true"; + echo "o"; + + } else { + + if (isset($angles[$file])) { + + $msg = "Writing CropAngle ".$angles[$file]." to ".$file; + $cmd = "exiftool -overwrite_original -XMP-crs:CropAngle=".$angles[$file]." ".$file; + echo "."; + + } else { + + $msg = "No CropAngle for ".$file.", writing Rating=1"; + $cmd = "exiftool -overwrite_original -Rating=1 ".$file; + echo ","; + + } + } + + $thread[] = array($msg, $cmd); + + } -// } +echo "\n\n"; +if (is_array($thread)) { + + msg("Writing EXIF tags with ".$xt." threads"); + //multiexec($thread,$xt); + + } //////////////////////////////////////////////////////////////////////////////////////////////// // Elif @@ -867,135 +1049,6 @@ echo Welcome("Program name \"".$argv[1]."\" not found"); die; - - - - - - - - - - - -// Settings - -$tif_dir = "null"; -$input_dir = "avision_jpg"; -$xmp_profile = "avision_null.xmp"; -$compare_threshold = "1"; -$deskew_max_angle = ".4"; -$deskew_padding = 80; -$deskew_contrast = 20; -$deskew_size = 2200; -$multicrops = 8; - - -if (file_exists($tif_dir)) { - echo "Checking jpegs: "; - foreach (glob($tif_dir."/*") as $file) { - $jpegfile = str_replace("tif", "jpg", $file); - if (!file_exists($jpegfile)) { - exec("convert -quality 95 ".$file." ".$jpegfile); - echo "."; - } else { - echo "o"; - } - } - echo "\n\n"; - } - -$files = glob($input_dir."/*.jpg"); - - - -//Deskew - -echo "Creating dmaps: "; - -foreach ($files as $file) { - - $dmfile = "scratch/".basename($file, ".jpg")."_dmap.jpg"; - - if (file_exists($dmfile)) { - - echo "o"; - - } else { - - //$jpeg_width = "7228"; - //$jpeg_height = "9000"; - - $parts = chop(shell_exec("exiftool -s -s -s -XMP-crs:CropTop -XMP-crs:CropRight -XMP-crs:CropLeft -XMP-crs:CropBottom ".$file." 2>&1")); - list($top, $right, $left, $bottom) = explode("\n", $parts); - if (!$top | !$right | !$left | !$bottom) { echo $file." missing crop information!\n"; die; } - - $jpeg_width = chop(shell_exec("exiftool -s -s -s -ImageWidth ".$files[0]." 2>&1")); - $jpeg_height = chop(shell_exec("exiftool -s -s -s -ImageHeight ".$files[0]." 2>&1")); - - $top_pixels = floor( $jpeg_height * $top ); - $bottom_pixels = $jpeg_height - floor( $bottom * $jpeg_height ); - $left_pixels = floor( $jpeg_width * $left ); - - $width = $jpeg_width - $left_pixels; - $height = $jpeg_height - ( $top_pixels + $bottom_pixels ); - - $area_left = ( $width + $deskew_padding )."x".( $height + $deskew_padding*2 )."+0+".( $bottom_pixels - $deskew_padding ); - $area_right = ( $width + $deskew_padding )."x".( $height + $deskew_padding*2 )."+".( $left_pixels - $deskew_padding )."+".( $top_pixels - $deskew_padding ); - - //echo "(Area left = ".$area_left.", "; - //echo "Area right = ".$area_right.")"; - - $size = $deskew_size."x".$deskew_size; - - if (substr(basename($file), 0, 3) % 2 == 0) { - exec("convert ".$file." -auto-orient -crop ".$area_right." -level ".$deskew_contrast."%,".(100-$deskew_contrast)."% -colorspace Gray -resize ".$size." ".$dmfile); - } else { - exec("convert ".$file." -auto-orient -crop ".$area_left." -level ".$deskew_contrast."%,".(100-$deskew_contrast)."% -colorspace Gray -resize ".$size." ".$dmfile); - } - echo "."; - } - - } - -echo "\n\n"; - -if (shell_exec("exiftool -s -s -s -CropAngle ".$files[0]." 2>&1")) { - echo "CropAngle detected, skipping deskew.\n"; - } else { - - foreach ($files as $file) { - - $dmfile = "scratch/".basename($file, ".jpg")."_dmap.jpg"; - $result = shell_exec("deskew -o /tmp/null -l 99 \"".$dmfile."\" 2>&1"); - $arr = explode("Skew angle found: ", $result); - $angle = substr($arr[1], 0, 4); - echo $file.": ".$angle; - if ($angle > $deskew_max_angle | $angle < ($deskew_max_angle*-1)) { - echo " (too big)"; - } else { - $angles[$file] = $angle; - } - echo "\n"; - } - - echo "\nWriting angles to EXIF: "; - - foreach ($files as $file) { - - if (isset($angles[$file])) { - exec("exiftool -overwrite_original -XMP-crs:CropAngle=".$angles[$file]." ".$file); - echo "."; - } else { - // erase top edge crop to indicate rotation was not applied - exec("exiftool -overwrite_original -XMP-crs:CropTop=0 ".$file." 2>&1"); - } - } - - } - - - // check bridge labels // for i in *; do exiftool -s -s -s -Label $i; done