/dev/null | grep 'Total Number of Cores' | cut -d: -f2 | tr -d ' '")); if (in_array($cores,$reasonable_cores)) { $xt = $cores; } else { $xt = 2; } // Simple log $message = date("Y-m-d_H-i-s", time())." (".$version.")\n".implode(" ",$argv); file_put_contents("leaf.log",$message,FILE_APPEND); // Functions function crop_imgk_to_xmp($cwidth, $cheight, $xoff, $yoff, $width, $height) { $top = $yoff/$height; $right = (($xoff+$cwidth)/$width); $left = $xoff/$width; $bottom = (($yoff+$cheight)/$height); return array(number_format($top,6), number_format($right,6), number_format($left,6), number_format($bottom,6)); } function crop_xmp_to_imgk($parts, $deskew_padding) { @list($top, $right, $left, $bottom, $check_width, $check_height, $orientation) = explode("\n", $parts); if (!$top || !$right || !$left || !$bottom || !$check_width || !$check_height || ! $orientation) { return null; } $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 ); if ($orientation == "Rotate 90 CW") { return ( $width + $deskew_padding*2 )."x".( $height + $deskew_padding*2 )."+".( $bottom_pixels - $deskew_padding )."+".( $left_pixels - $deskew_padding ); } elseif ($orientation == "Rotate 270 CW") { return ( $width + $deskew_padding*2 )."x".( $height + $deskew_padding*2 )."+".( $top_pixels - $deskew_padding )."+".( $right_pixels - $deskew_padding ); } else { return null; } } function levels_ps_to_imgk($string) { $parts = explode(",", $string); if (count($parts) != 3) { msg("Invalid levels string",1); } else { $black = (number_format(($parts[0]/253),5)*100)."%"; $white = (number_format(($parts[2]/255),5)*100)."%"; $gamma = $parts[1]; return $black.",".$white.",".$gamma; } } function olevels_ps_to_imgk($string) { $parts = explode(",", $string); if (count($parts) != 2) { msg("Invalid levels string",1); } else { $black = (number_format(($parts[0]/253),5)*100)."%"; $white = (number_format(($parts[1]/255),5)*100)."%"; return $black.",".$white; } } function unsharp_ps_to_imgk($string) { $parts = explode(",", $string); if (count($parts) != 3) { msg("Invalid levels string",1); } else { $radius = "0x".($parts[1]+1); $amount = $parts[0]/100; $threshold = $parts[2]/255; return $radius."+".$amount."+".$threshold; } } function multiexec($thread, $x, $null = true) { global $debug; $batch = array_chunk($thread,$x); foreach ($batch as $group) { $msg = array(); $cmd = array(); foreach ($group as $parts) { $msg[] = $parts[0]; $cmd[] = $parts[1]; } if (strlen($msg[0]) > 1) { $echo = implode("\n", $msg)."\n"; } else { $echo = implode("", $msg); } if ($debug || !$null) { $pipe = ""; } else { $pipe = " 2>&1"; } $exec = implode($pipe." & ",$cmd).$pipe." & wait"; echo $echo; if ($debug) { echo "\n".str_replace($pipe." & ", "\n\n", $exec)."\n\n"; } @exec($exec); } } function getdng($jpg) { $ext = pathinfo($jpg,PATHINFO_EXTENSION); $check = glob("*/".basename($jpg,$ext)."DNG"); if (isset($check[0])) { return $check[0]; } else { return null; } } function getjpg($dng) { $ext = pathinfo($dng,PATHINFO_EXTENSION); $check = glob("*/".basename($dng,$ext)."JPG"); if (isset($check[0])) { return $check[0]; } else { return null; } } function fin($print = null) { if (isset($print)) { echo "\n".$print; } $finished = "\nFinished in ".floor($time = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"])." seconds\n\n"; file_put_contents("leaf.log",$finished,FILE_APPEND); die; } function ask($text) { echo $text."\n"; return trim(fgets(fopen("php://stdin","r"))); } function msg($text, $action = null) { if ($action == 1) { echo bashcolor($text."\n","red"); die; } elseif ($action == 2) { echo bashcolor($text." (Y/n)\n","blue"); $line = strtolower(trim(fgets(fopen("php://stdin","r")))); $line = $line ?: "y"; if($line != "y"){ echo bashcolor("Exiting!\n","red"); die; } } else { echo $text."\n"; } } function args($query) { global $argv; foreach ($argv as $value) { $parts = explode("=", $value); $opt[trim($parts[0],"-")] = isset($parts[1]) ? $parts[1] : 1; } if ($query == "app" && isset($argv[1])) { return $argv[1]; } elseif ($query == "dir" && count($argv) > 2) { return chop($argv[count($argv)-1], "/")."/"; } elseif ($query == "levels" && isset($opt['levels'])) { return levels_ps_to_imgk($opt['levels']); } elseif ($query == "plevels" && isset($opt['plevels'])) { return levels_ps_to_imgk($opt['plevels']); } elseif ($query == "olevels" && isset($opt['olevels'])) { return olevels_ps_to_imgk($opt['olevels']); } elseif ($query == "unsharp" && isset($opt['unsharp'])) { return unsharp_ps_to_imgk($opt['unsharp']); } elseif (isset($opt[$query])) { return $opt[$query]; } else { return null; } } function Welcome($msg) { global $version; global $debug; if ($debug) { $out .= bashcolor("Leaf Version: ".$version." debug", "white", "red")." ".shell_exec("date"); } else { $out = "\033[1;1H\033[2J"; // clear screen $out .= bashcolor("Leaf Version: ".$version, "white", "magenta")." ".shell_exec("date"); } $out .= $msg."\n\n"; return $out; } function getClosest($search, $arr) { $closest = null; foreach ($arr as $item) { if ($closest === null || abs($search - $closest) > abs($item - $search)) { $closest = $item; } } return $closest; } $colors = array_merge(array("blue","green","cyan","red","purple","brown","yellow","light blue","light green", "light cyan", "light red", "light purple"),array_fill(0, 500, "light gray")); function bashcolor($str,$fgcolor="white",$bgcolor=null) { static $fgcolors = array('black' => '0;30', 'dark gray' => '1;30', 'blue' => '0;34', 'light blue' => '1;34', 'green' => '0;32', 'light green' => '1;32', 'cyan' => '0;36', 'light cyan' => '1;36', 'red' => '0;31', 'light red' => '1;31', 'purple' => '0;35', 'light purple' => '1;35', 'brown' => '0;33', 'yellow' => '1;33', 'light gray' => '0;37', 'white' => '1;37', 'underline' => '4'); static $bgcolors = array('black' => '40', 'red' => '41', 'green' => '42', 'yellow' => '43', 'blue' => '44', 'magenta' => '45', 'cyan' => '46', 'light gray' => '47'); $out=""; if (!isset($fgcolors[$fgcolor])) { $fgcolor='white'; } if (!isset($bgcolors[$bgcolor])) { $bgcolor=null; } if ($fgcolor) { $out .= "\033[{$fgcolors[$fgcolor]}m"; } if ($bgcolor) { $out .= "\033[{$bgcolors[$bgcolor]}m"; } $out .= $str."\033[0m"; return $out; } // Checks if (args("dir") && !is_dir(args("dir"))) { msg("Problem with working dir: ".args("dir"), 1); } if (!is_dir("scratch")) { mkdir("scratch"); } if (args("debug")) { $debug = 1; } else { $debug = 0; } //////////////////////////////////////////////////////////////////////////////////////////////// // Note: Help ////////////////////// if (!args("app") | args("app") == "help" | args("app") == "-help" | args("app") == "--help") { ///////////////////////////////////////////////////////////////////////// $help = "Leaf $version USAGE: leaf [mode] [-options] directory Modes: autocrop crop using row/column brightness method -levels= levels adjustment for resulting image (ex. \"0-253,0-2,0-255\") -trim= pixels to trim from top, right, left, bottom build combine images into a pdf with img2pdf clean remove scratch files crop define EXIF crop values using template files -crops= (6) specify how many files to use desort remove image sequence prefix deskew detect rotation angles -max= (.4) angles greater than this value are ignored -pad= (80) pixels to pad around crop area -contrast= (20) levels attenuation -size= (2200) dmap size in pixels -nomap don't use dmaps depaper divide page with itself using mask (better despine) -mask= mask file for spine-left image -mpush= levels for divide map (ex. \"0-253,0-2,0-255\") -mix=<0-100> (null) percentage mix with original (90% = mostly og) -skip=