0.6.9
This commit is contained in:
369
leaf.php
369
leaf.php
@@ -2,9 +2,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Leaf - Tools for Book Scans
|
// Leaf - Tools for Book Scans
|
||||||
$version = "0.6.8";
|
$version = "0.6.9";
|
||||||
$time_start = microtime(true);
|
$time_start = microtime(true);
|
||||||
date_default_timezone_set("America/Los_Angeles");
|
date_default_timezone_set("America/Los_Angeles");
|
||||||
|
$xt = 3; // threads
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
@@ -19,7 +20,10 @@ function multiexec($thread, $x) {
|
|||||||
}
|
}
|
||||||
$echo = implode("\n", $msg);
|
$echo = implode("\n", $msg);
|
||||||
$exec = implode(" > /dev/null & ",$cmd)." & wait";
|
$exec = implode(" > /dev/null & ",$cmd)." & wait";
|
||||||
echo $echo."\n";
|
echo $echo;
|
||||||
|
if (strlen($echo) > 1) {
|
||||||
|
echo "\n";
|
||||||
|
}
|
||||||
exec($exec);
|
exec($exec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,9 +145,15 @@ $help = "Leaf $version
|
|||||||
USAGE: leaf [mode] [-options] directory
|
USAGE: leaf [mode] [-options] directory
|
||||||
|
|
||||||
Modes:
|
Modes:
|
||||||
|
clean remove scratch files
|
||||||
crop define EXIF crop values using template files
|
crop define EXIF crop values using template files
|
||||||
-crops=<num> specify how many files to use
|
-crops=<num> specify how many files to use
|
||||||
desort remove image sequence prefix
|
desort remove image sequence prefix
|
||||||
|
deskew detect rotation angles
|
||||||
|
-max=<num> angles greater than this value are ignored, default .4
|
||||||
|
-pad=<num> pixels to pad around crop area, default 80
|
||||||
|
-contrast=<num> contrast boost, default 20
|
||||||
|
-size=<num> size in pixels of dmap, default 2200
|
||||||
divide wrapper for imagemagick Divide_Src
|
divide wrapper for imagemagick Divide_Src
|
||||||
-map=<file> specify brightness file
|
-map=<file> specify brightness file
|
||||||
-adjust=<params> levels adjustment (ex. \"0%,98%,.9\")
|
-adjust=<params> levels adjustment (ex. \"0%,98%,.9\")
|
||||||
@@ -158,6 +168,9 @@ resort reorder image sequence by adding a new image
|
|||||||
-file=<file> file to insert
|
-file=<file> file to insert
|
||||||
-x=<num> position of inserted file
|
-x=<num> position of inserted file
|
||||||
review print a table of image dimension statistics
|
review print a table of image dimension statistics
|
||||||
|
rotate batch transform rotate (lossy)
|
||||||
|
-x=<angle> rotation angle, default=90
|
||||||
|
-q=<0-100> jpeg quality, default read from source or 95
|
||||||
setdpi set image dpi with exiftool
|
setdpi set image dpi with exiftool
|
||||||
-x=<dpi> specify dpi
|
-x=<dpi> specify dpi
|
||||||
-height=<inches> calculate dpi from specified height
|
-height=<inches> calculate dpi from specified height
|
||||||
@@ -169,6 +182,68 @@ strip strip exif crop values from images with exiftool
|
|||||||
echo $help;
|
echo $help;
|
||||||
fin();
|
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
|
// Note: Profile
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@@ -666,7 +741,6 @@ fin();
|
|||||||
echo Welcome("Composite image from brightness map");
|
echo Welcome("Composite image from brightness map");
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
$xt = 8;
|
|
||||||
$files = glob(args("dir")."*.{jpg,JPG,tif}", GLOB_BRACE);
|
$files = glob(args("dir")."*.{jpg,JPG,tif}", GLOB_BRACE);
|
||||||
|
|
||||||
if (!args("map")) {
|
if (!args("map")) {
|
||||||
@@ -800,16 +874,96 @@ fin();
|
|||||||
echo Welcome("Detect skew angle and apply to EXIF tags");
|
echo Welcome("Detect skew angle and apply to EXIF tags");
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
$deskew_max_angle = ".4";
|
if (args("max")) {
|
||||||
$deskew_padding = 80;
|
$deskew_max_angle = args("max");
|
||||||
$deskew_contrast = 20;
|
} else {
|
||||||
$deskew_size = 2200;
|
$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")) {
|
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 {
|
} else {
|
||||||
|
|
||||||
@@ -817,45 +971,73 @@ if (!args("nomap")) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shell_exec("exiftool -s -s -s -CropAngle ".$files[0]." 2>&1")) {
|
$thread = null;
|
||||||
msg("Crop angle detected on ".$files[0].", continue?",2);
|
|
||||||
}
|
echo "\n";
|
||||||
|
msg("Detecting skew...");
|
||||||
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
|
|
||||||
if (args("nomap")) {
|
if (args("nomap")) {
|
||||||
$dmfile = $file;
|
$dmfile = $file;
|
||||||
} else {
|
} 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");
|
$result = shell_exec("deskew -o /tmp/null -l 99 \"".$dmfile."\" 2>&1");
|
||||||
$arr = explode("Skew angle found: ", $result);
|
$arr = explode("Skew angle found: ", $result);
|
||||||
$angle = substr($arr[1], 0, 4);
|
$angle = substr($arr[1], 0, 4);
|
||||||
echo $file.": ".$angle;
|
$msg = $file.": ".$angle;
|
||||||
if ($angle > $deskew_max_angle | $angle < ($deskew_max_angle*-1)) {
|
if ($angle > $deskew_max_angle | $angle < ($deskew_max_angle*-1)) {
|
||||||
echo " (too big)";
|
$msg .= " (too big)";
|
||||||
} else {
|
} else {
|
||||||
$angles[$file] = $angle;
|
$angles[$file] = $angle;
|
||||||
}
|
}
|
||||||
echo "\n";
|
msg($msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// echo "\nWriting angles to EXIF: ";
|
echo "\n\n";
|
||||||
//
|
|
||||||
// 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");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
echo "Checking for existing rotation: ";
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
|
||||||
|
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
|
// Elif
|
||||||
@@ -867,135 +1049,6 @@ echo Welcome("Program name \"".$argv[1]."\" not found");
|
|||||||
|
|
||||||
die;
|
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
|
// check bridge labels
|
||||||
// for i in *; do exiftool -s -s -s -Label $i; done
|
// for i in *; do exiftool -s -s -s -Label $i; done
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user