Last active
July 30, 2016 01:16
-
-
Save lleaff/e39963432502dc543523a101cf77e7a3 to your computer and use it in GitHub Desktop.
Create a grid of images from those in a given webpage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env php | |
<?php | |
/* =Config | |
*------------------------------------------------------------*/ | |
$FONT_PATH = "OpenSans-Regular.ttf"; | |
/* pixels */ | |
$CELL_WIDTH_IDEAL = 100; | |
$CELL_HEIGHT_IDEAL = 100; | |
$CELL_WIDTH_MAX = 150; | |
$CELL_HEIGHT_MAX = 150; | |
$CELL_WIDTH_MIN = 32; | |
$CELL_HEIGHT_MIN = 32; | |
$GUTTER = 0; | |
$LEGEND_HEIGHT = 30; | |
/* Force square cells */ | |
$FORCE_SQUARE = FALSE; | |
$EXCLUDE_PATTERNS = array( | |
'/background/', | |
'/[^\/]+_bg_[^\/]+\.\w+/', | |
'/^bg_[^\/]*\.\w+/', | |
'/[^\/]*_bg\.\w+$/' | |
); | |
/* If not empty, keep only images matching patterns */ | |
$MATCH_PATTERNS = array(); | |
/* =Dynamic globals | |
*------------------------------------------------------------*/ | |
$foundCount = 0; | |
$excludedCount = 0; | |
$failedCount = 0; | |
$errors = array(); | |
/* =Utilities | |
*------------------------------------------------------------*/ | |
function nearestMultiple($of, $from) { | |
return $of / round($of / $from); | |
} | |
function identity($val) { return $val; } | |
function array_some($callback, $array) { | |
foreach ($array as $el) { | |
if ($callback($el)) { | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
function array_map_with_keys($callback, $array) { | |
$mapped = array(); | |
foreach ($array as $key => $val) { | |
$mapped[$key] = $callback($val, $key); | |
} | |
return $mapped; | |
} | |
function array_flatten_once($array) { | |
return array_reduce($array, array_merge, array()); | |
} | |
function array_filter_reset($array, $callback) { | |
return array_values(array_filter($array, $callback)); | |
} | |
function plural($count) { | |
return $count > 1 ? "s" : ""; | |
} | |
function color_string($color, $str) { | |
$colorCodes = array( | |
"red" => "0;31", | |
"green" => "0;32", | |
"brown" => "0;33", | |
"blue" => "0;34" | |
); | |
return "\033[" . $colorCodes[$c] . "m" . $str . "\033[0m"; | |
} | |
function fatal_error($msg) { | |
echo color_string("red", $msg . "\n"); | |
exit(1); | |
} | |
function log_error($msg) { | |
global $errors; | |
$errors[] = $msg; | |
} | |
function printLoggedErrors() { | |
global $errors; | |
if (!empty($errors)) { | |
$errorc = count($errors); | |
echo $errorc." erreur".plural($errorc).": \n"; | |
foreach ($errors as $error) { | |
echo color_string('red', $error)."\n"; | |
} | |
return 1; | |
} else { | |
return 0; | |
} | |
} | |
function is_url($str) { | |
return preg_match("/^https?:\/\//", $str) !== 0; | |
} | |
function url_exists($url) { | |
$curl = curl_init($url); | |
return (bool) $curl; | |
} | |
function get_url_content($url) { | |
if (!url_exists($url)) { fatal_error("Echec de lecture de la ressource: $url"); } | |
$curl = curl_init(); | |
curl_setopt_array($curl, array( | |
CURLOPT_RETURNTRANSFER => TRUE, | |
CURLOPT_URL => $url, | |
CURLOPT_FOLLOWLOCATION, TRUE | |
)); | |
$result = curl_exec($curl); | |
curl_close($curl); | |
if (!$result) { fatal_error("Echec de lecture du contenu: $url"); } | |
return $result; | |
} | |
function get_file_content($path) { | |
if (!file_exists($path)) { fatal_error("Le fichier n'existe pas: $path"); } | |
$file = fopen($path, "r"); | |
if (!$file) { fatal_error("Echec de lecture du fichier: $path"); } | |
$result = fread($file, filesize($path)); | |
if (!$result) { fatal_error("Echec de lecture du fichier: $path"); } | |
fclose($file); | |
return $result; | |
} | |
function normalized_extension_from_path($path) { | |
if (!preg_match('/.+\.(\w+)$/', $path, $match)) { return FALSE; } | |
if ($ext == "jpeg") { $ext = "jpg"; } | |
return strtolower($match[1]); | |
} | |
function getPathInfo($path) { | |
if (preg_match('/([\w\.]+)(?:\?.*$|$)/', $path, $match)) { $base = $match[1]; } | |
$filename = preg_replace('/\.[\w]+$/', '', $base ?: $path); | |
return array( | |
'path' => $path, | |
'basename' => $base ?: $path, | |
'filename' => $filename ?: $base, | |
'extension' => normalized_extension_from_path($base ?: $path)); | |
} | |
/* =Options | |
*------------------------------------------------------------*/ | |
$USAGE = <<<EOD | |
Usage: ./imagepanel.php [OPTIONS] HTML .. [SORTIE] | |
HTML: Un ou plusieurs chemins ou URLs vers des pages au format HTML contenant | |
des images a extraire. | |
SORTIE: Nom de fichier de la/les panel(s) produits | |
Options: | |
-g | |
-p | |
-j | |
Creer des images au format GIF, PNG ou JPEG, respectivement. | |
-L nombre Nombre maximal d'images recuperees. | |
-l nombre Nombre maximal d'images contenues dans un panel. | |
-n Afficher sous les images le nom de celles-ci (sans l'extension). | |
-N Afficher sous les images le nom de celles-ci (avec l'extension). | |
-W Largeur des images generees (en pixels) | |
-H Hauteur des images generees (en pixels) | |
-S Forcer dimensions carrees des miniatures | |
-G nombre Marge entre les images (en pixels) | |
--exclude regexp | |
Exclure les images dont le chemin est idientifie par le RegExp donne. | |
-b Ne pas utiliser les RegExps excluant les images de fond par defaut. | |
-m, --match | |
Ne prendre en compte que les images dont le chemin est identifie par | |
le RegExp donne. | |
-s Trier les images par orde alphabetique. | |
-h, --help Afficher ce message. | |
Notes: | |
Les arguments prenants des RegExps acceptent des expressions a la norme PCRE, sans | |
les delimiteurs (les '/' n'ont donc pas besoin d'etres echappes). | |
EOD; | |
$OPTS = getopt('gjl:L:nNpsbm:W:H:G:Sh', array('exclude:', 'match:', 'help')); | |
$OPTIONSWITHARGUMENTS = array('l','L','G','--exclude','m','W','H','--match'); | |
if (isset($OPTS['h']) || isset($OPTS['help'])) { | |
echo $USAGE; | |
exit(); | |
} | |
$EXT = call_user_func(function($OPTS) { | |
if (isset($OPTS['g'])) { | |
$EXT = 'gif'; | |
} else if (isset($OPTS['j'])) { | |
$EXT = 'jpg'; | |
} else if (isset($OPTS['p'])) { | |
$EXT = 'png'; | |
} else { | |
$EXT = 'png'; // default format | |
} | |
return $EXT; | |
}, $OPTS); | |
$DISPLAY_NAME = isset($OPTS['n']) || isset($OPTS['N']); | |
$DISPLAY_EXT = $DISPLAY_NAME && isset($OPTS['N']); | |
if (isset($OPTS['L'])) { | |
if (gettype($OPTS['L']) == "array") { $OPTS['l'] = end($OPTS['l']); } | |
$MAXIMAGES = intval($OPTS['l']); | |
if ($MAXIMAGES <= 0) { | |
fatal_error("L'option -L doit etre un entier superieur a 0"); | |
} | |
} else { | |
$MAXIMAGES = false; | |
} | |
if (isset($OPTS['l'])) { | |
if (gettype($OPTS['l']) == "array") { $OPTS['l'] = end($OPTS['l']); } | |
$MAXPANELIMAGES = intval($OPTS['l']); | |
if ($MAXPANELIMAGES <= 0) { | |
fatal_error("L'option -l doit etre un entier superieur a 0"); | |
} | |
} else { | |
$MAXPANELIMAGES = false; | |
} | |
if (isset($OPTS['G'])) { | |
if (gettype($OPTS['G']) == "array") { $OPTS['G'] = end($OPTS['G']); } | |
$GUTTER = intval($OPTS['G']); | |
if ($GUTTER < 0) { | |
fatal_error("L'option -g doit etre un entier superieur ou egal a 0"); | |
} | |
} | |
if (isset($OPTS['W'])) { | |
if (gettype($OPTS['W']) == "array") { $OPTS['W'] = end($OPTS['W']); } | |
$WIDTH = intval($OPTS['W']); | |
if ($WIDTH <= 0) { | |
fatal_error("L'option -W doit etre un entier superieur a 0"); | |
} | |
} else { | |
$WIDTH = false; | |
} | |
if (isset($OPTS['H'])) { | |
if (gettype($OPTS['H']) == "array") { $OPTS['H'] = end($OPTS['H']); } | |
$HEIGHT = intval($OPTS['H']); | |
if ($HEIGHT <= 0) { | |
fatal_error("L'option -H doit etre un entier superieur a 0"); | |
} | |
} else { | |
$HEIGHT = false; | |
} | |
if (isset($OPTS['S'])) { | |
$FORCE_SQUARE = TRUE; | |
} | |
if (isset($OPTS['b'])) { | |
$EXCLUDE_PATTERNS = array(); | |
} | |
if (isset($OPTS['exclude'])) { | |
if (gettype($OPTS['exclude']) != "array") { $OPTS['exclude'] = array($OPTS['exclude']); } | |
foreach ($OPTS['exclude'] as $excludePattern) { | |
$EXCLUDE_PATTERNS[] = '/' . preg_replace('/\//', '\/', $excludePattern) . '/'; | |
} | |
} | |
if (isset($OPTS['match'])) { | |
if (gettype($OPTS['match']) != "array") { $OPTS['match'] = array($OPTS['match']); } | |
foreach ($OPTS['match'] as $matchPattern) { | |
$MATCH_PATTERNS[] = '/' . preg_replace('/\//', '\/', $matchPattern) . '/'; | |
} | |
} | |
if (isset($OPTS['m'])) { | |
if (gettype($OPTS['m']) != "array") { $OPTS['m'] = array($OPTS['m']); } | |
foreach ($OPTS['m'] as $matchPattern) { | |
$MATCH_PATTERNS[] = '/' . preg_replace('/\//', '\/', $matchPattern) . '/'; | |
} | |
} | |
$SORT = isset($OPTS['s']); | |
/* =Parameters | |
*------------------------------------------------------------*/ | |
$PARAMS = call_user_func(function($argv, $argc) { | |
global $OPTIONSWITHARGUMENTS; | |
$optionsregexp = "/(".implode('|', $OPTIONSWITHARGUMENTS).")/"; | |
$PARAMS = array(); | |
for ($i = 1; $i < $argc; $i++) { | |
if ($argv[$i][0] != '-') { | |
$PARAMS[] = $argv[$i]; | |
} else { | |
if (preg_match($optionsregexp, $argv[$i])) { | |
$i++; | |
} | |
} | |
} | |
return $PARAMS; | |
}, $argv, $argc); | |
$OUTPUTBASE = array_pop($PARAMS); | |
$PATHS = $PARAMS; | |
if (!$OUTPUTBASE || !$PATHS) { | |
echo $USAGE; | |
exit(); | |
} | |
/* =HTML fetching | |
*------------------------------------------------------------*/ | |
function fetchHtmlPages($PATHS) { | |
$pages = array(); | |
foreach ($PATHS as $path) { | |
if (is_url($path)) { | |
$content = get_url_content($path); | |
} else { | |
$content .= get_file_content($path); | |
} | |
$pages[] = array( 'path' => $path, 'content' => $content); | |
} | |
return $pages; | |
} | |
/* =App functions | |
*------------------------------------------------------------*/ | |
function quit($matchedCount) { | |
global $foundCount; | |
global $excludedCount; | |
echo color_string("green", "$matchedCount images trouvees"); | |
if ($excludedCount) { echo ", $excludedCount images exclues"; } | |
echo ".\n"; | |
exit(); | |
} | |
function printSummary($panelCount) { | |
global $foundCount; | |
global $failedCount; | |
global $excludedCount; | |
echo "$foundCount image".plural($foundCount)." trouvee".plural($foundCount). | |
($failedCount ? | |
", $failedCount transfert".plural($failedCount)." echouee".plural($failedCount) : ""). | |
($excludedCount ? | |
", $excludedCount image".plural($excludedCount)." exclue".plural($excludedCount) : ""). | |
", $panelCount panel".$pluralPanel." cree".$pluralPanel. | |
".\n"; | |
}; | |
/* =Image paths | |
*------------------------------------------------------------*/ | |
$GDFORMATS = call_user_func(function() { | |
$gdinfo = gd_info(); | |
return array( | |
'png' => isset($gdinfo['PNG Support']) && $gdinfo['PNG Support'], | |
'jpg' => isset($gdinfo['JPEG Support']) && $gdinfo['JPEG Support'], | |
'gif' => isset($gdinfo['GIF Read Support']) && | |
$gdinfo['GIF Read Support'] && $gdinfo['GIF Create Support'] | |
); | |
}); | |
function get_protocol_from_path($path) { | |
$matches; | |
if (!preg_match('/^([a-z]+):\/\/.+/', $path, $matches)) { | |
log_error("Can't get protocol from path: $path"); | |
return; | |
} | |
return $matches[1]; | |
} | |
function domain_from_url($url) { | |
$pattern = "/(?:[a-z]+:\/\/)?[^\/]+/"; | |
$matches; | |
if (!preg_match($pattern, $url, $matches)) { | |
log_error("Impossible de recuperer le domaine a partir de :\"$url\""); | |
return; | |
} | |
return $matches[0]; | |
} | |
function dirname_from_url($url) { | |
$pattern = "/.*\//"; | |
if (substr_count($url, '/') < 3) { | |
$url = ensure_trailing_slash($url); | |
} | |
$matches; | |
if (!preg_match($pattern, $url, $matches)) { | |
log_error("Impossible de recuperer la base d'url a partir de :\"$url\""); | |
return; | |
} | |
return $matches[0]; | |
} | |
function ensure_trailing_slash($str) { | |
return rtrim($str, '/') . '/'; | |
} | |
function get_base_href($html) { | |
$matches = array(); | |
$pattern = '/<base[^>]+href="([^"<>]*)"/'; | |
if (!preg_match($pattern, $html, $matches)) { return FALSE; } | |
else { return ensure_trailing_slash($matches[1]); } | |
} | |
define('PATH_PROTOCOLRELATIVE', 1); | |
define('PATH_ROOT', 2); | |
define('PATH_ABSOLUTE', 3); | |
define('PATH_RELATIVE', 4); | |
function path_format($path) { | |
if (preg_match('/^\/\/.+/', $path)) { | |
return PATH_PROTOCOLRELATIVE; | |
} else if (preg_match('/^\/[^\/]+/', $path)) { | |
return PATH_ROOT; | |
} else if (preg_match('/^[a-z]+:\/\/.+/', $path)){ | |
return PATH_ABSOLUTE; | |
} else { | |
return PATH_RELATIVE; | |
} | |
} | |
function resolvePathFrom($url, $base = FALSE) { | |
return function($path) use ($url, $base) { | |
global $failedCount; | |
$isurl = is_url($url); | |
switch(path_format($path)) { | |
case PATH_PROTOCOLRELATIVE: | |
if (!$isurl) { $failedCount++; return FALSE; } | |
$resolved = get_protocol_from_path($url) . ':' . $path; | |
break; | |
case PATH_ROOT: | |
if ($isurl) { | |
$resolved = domain_from_url($url) . $path; | |
} else { | |
$resolved = $path; | |
} | |
break; | |
case PATH_RELATIVE: | |
$resolved = ($base ?: ensure_trailing_slash(dirname_from_url($url))) . $path; | |
break; | |
case PATH_ABSOLUTE: | |
$resolved = $path; | |
break; | |
} | |
return $resolved; | |
}; | |
} | |
function gdSupportsFormat($path) { | |
global $GDFORMATS; | |
$ext = normalized_extension_from_path($path); | |
return $GDFORMATS[$ext]; | |
} | |
function filterImagePath($path) { | |
global $EXCLUDE_PATTERNS; | |
global $MATCH_PATTERNS; | |
global $excludedCount; | |
if ($path === FALSE) { return FALSE; } | |
if (!gdSupportsFormat($path)) { return FALSE; } | |
foreach ($EXCLUDE_PATTERNS as $pattern) { | |
if (preg_match($pattern, $path)) { | |
$excludedCount++; | |
return FALSE; | |
} | |
} | |
if (empty($MATCH_PATTERNS)) { return TRUE; } | |
foreach ($MATCH_PATTERNS as $pattern) { | |
if (preg_match($pattern, $path)) { | |
return TRUE; | |
} | |
} | |
$excludedCount++; | |
return FALSE; | |
} | |
function formatImagePaths($pages, $MAXIMAGES) { | |
global $foundCount; | |
global $failedCount; | |
global $excludedCount; | |
$pattern = '/<img(?: |[^>]* )src="([^"<>]+)"/i'; | |
$imagePaths = array(); | |
foreach ($pages as $page) { | |
$currImagePaths = array(); | |
if (!preg_match_all($pattern, $page['content'], $currImagePaths)) { | |
continue; | |
} | |
$imagePaths = array_merge( | |
$imagePaths, | |
array_map(resolvePathFrom($page['path'], get_base_href($page['content'])), | |
$currImagePaths[1])); | |
} | |
$foundCount = count($imagePaths); | |
$imagePaths = array_filter_reset($imagePaths, filterImagePath); | |
$images = array_map(getPathInfo, $imagePaths); | |
if ($MAXIMAGES) { $images = array_slice($images, 0, $MAXIMAGES); } | |
return $images; | |
} | |
/* =Images fetching | |
*------------------------------------------------------------*/ | |
function createGDImage($path) { | |
$ext = normalized_extension_from_path($path); | |
switch ($ext) { | |
case "jpg": | |
return imagecreatefromjpeg($path); | |
case "gif": | |
return imagecreatefromgif($path); | |
case "png": | |
return imagecreatefrompng($path); | |
default: | |
log_error("Type d'image non supporte: $path"); | |
return FALSE; | |
} | |
} | |
function addImageData($images) { | |
//do { | |
// $folder = '.imagepanel-img-'.str_pad(rand(0, 1000), 3, '0', STR_PAD_LEFT).'~/'; | |
//} while (file_exists($folder)); | |
for ($i = 0; $i < count($images); $i++) { | |
$img = createGDImage($images[$i]['path']); | |
if ($img) { | |
$images[$i]['gd'] = $img; | |
} else { | |
$images[$i] = FALSE; | |
} | |
} | |
$images = array_filter_reset($images, identity); | |
return $images; | |
} | |
function addImageDimensions($images) { | |
for ($i = 0; $i < count($images); $i++) { | |
$images[$i]['width'] = imagesx($images[$i]['gd']); | |
$images[$i]['height'] = imagesy($images[$i]['gd']); | |
} | |
return $images; | |
} | |
/* =Grid dimensions | |
*------------------------------------------------------------*/ | |
function getAverage($getter) { | |
return function($array) use ($getter) { | |
$sum = 0; | |
foreach ($array as $item) { | |
$sum += $getter($item); | |
} | |
return $sum / count($array); | |
}; | |
} | |
$getAverageWidth = getAverage(function($img) { return $img['width']; }); | |
$getAverageHeight = getAverage(function($img) { return $img['height']; }); | |
$getAverageAspectRatio = getAverage(function($img) { return $img['width'] / $img['height']; }); | |
function guessAppropriateCellDimensions($images) { | |
global $CELL_WIDTH_IDEAL; | |
global $CELL_HEIGHT_IDEAL; | |
global $CELL_WIDTH_MAX; | |
global $CELL_HEIGHT_MAX; | |
global $FORCE_SQUARE; | |
global $WIDTH; | |
global $HEIGHT; | |
global $GUTTER; | |
global $LEGEND_HEIGHT; | |
global $DISPLAY_NAME; | |
global $DISPLAY_EXT; | |
global $getAverageWidth; | |
global $getAverageHeight; | |
global $getAverageAspectRatio; | |
$width = $CELL_WIDTH_IDEAL; | |
$height = $CELL_HEIGHT_IDEAL; | |
if (!$FORCE_SQUARE) { | |
// Adapt to aspect ratio | |
$averageAR = $getAverageAspectRatio($images); | |
if ($averageAR < 0.5) { /* images are in portrait orientation */ | |
$height = $CELL_HEIGHT_MAX; | |
$width = $height * $averageAR; | |
} else if ($averageAR > 2) { /* images are in landscape orientation */ | |
$width = $CELL_WIDTH_MAX; | |
$height = $width / $averageAR; | |
} | |
} | |
// Adapt to small dimensions | |
$averageWidth = $getAverageWidth($images); | |
$averageHeight = $getAverageHeight($images); | |
if ($averageWidth < $width) { | |
$width = $averageWidth; | |
} | |
if ($averageHeight < $height) { | |
$height = $averageHeight; | |
} | |
if ($FORCE_SQUARE) { | |
$width = min($height, $width); | |
$height = min($height, $width); | |
} | |
// Leave space for text | |
if ($DISPLAY_NAME) { | |
$width = max($width, 150); | |
$imgHeight = $height; | |
$height = $height + $LEGEND_HEIGHT; | |
} | |
// Adapt to forced canvas dimensions | |
if ($WIDTH) { | |
$width = nearestMultiple($WIDTH, $width) - $GUTTER; | |
} | |
if ($HEIGHT) { | |
$height = nearestMultiple($HEIGHT, $height) - $GUTTER; | |
} | |
$width = round($width); | |
$height = round($height); | |
return array( | |
'width' => $width, | |
'height' => $height, | |
'imgWidth' => $imgWidth ?: $width, | |
'imgHeight' => $imgHeight ?: $height, | |
); | |
} | |
function approximateColumnRowCount($cellDimensions, $cellCount) { | |
$cols = ceil(sqrt($cellCount)); | |
$rows = ceil($cellCount / $cols); | |
$calcAR = function($cols, $rows) use ($cellDimensions) { | |
$width = $cellDimensions['width'] * $cols; | |
$height = $cellDimensions['height'] * $rows; | |
return $width / $height; | |
}; | |
$delt = function($AR) { | |
return abs(1 - $AR); | |
}; | |
$prevAR = $AR = $calcAR($cols, $rows); | |
while ($AR != 1 && $delt($AR) <= $delt($prevAR)) { | |
$prevAR = $AR; | |
if ($AR < 1) { | |
if ($rows <= 1) { break; } | |
$cols += 1; | |
$rows -= 1; | |
} else { | |
if ($cols <= 1) { break; } | |
$rows += 1; | |
$cols -= 1; | |
} | |
$AR = $calcAR($cols, $rows); | |
} | |
return array( 'cols' => $cols, 'rows' => $rows ); | |
} | |
function calculatePanelDimensions($cellDimensions, $columnRowCount) { | |
global $GUTTER; | |
return array( | |
'width' => ($cellDimensions['width'] + $GUTTER) * $columnRowCount['cols'], | |
'height' => ($cellDimensions['height'] + $GUTTER) * $columnRowCount['rows'] ); | |
} | |
/* =Grid building | |
*------------------------------------------------------------*/ | |
function buildGridFrom($images, $columnRowCount) { | |
$grid = array(); | |
for ($r = 0, $j = 0; $r < $columnRowCount['rows']; $r++) { | |
$row = array(); | |
for ($c = 0; $c < $columnRowCount['cols'] && $j < count($images); $c++, $j++) { | |
$row[$c] = $images[$j]; | |
} | |
$grid[$r] = $row; | |
} | |
return $grid; | |
} | |
function setGridCoordinates($grid, $cellDimensions) { | |
return array_map_with_keys(function($row, $rowN) use ($cellDimensions) { | |
return array_map_with_keys(function($cell, $colN) use ($rowN, $cellDimensions) { | |
global $GUTTER; | |
$cell['x'] = round($GUTTER / 2) + $colN * ($cellDimensions['width'] + $GUTTER); | |
$cell['y'] = round($GUTTER / 2) + $rowN * ($cellDimensions['height'] + $GUTTER); | |
return $cell; | |
}, $row); | |
}, $grid); | |
} | |
/* =Drawing | |
*------------------------------------------------------------*/ | |
function calculateCroppedImage($img, $dimensions) { | |
$width = $img['width']; | |
$height = $img['height']; | |
$AR = $dimensions['width'] / $dimensions['height']; | |
$currAR = $img['width'] / $img['height']; | |
if ($AR > $currAR) { | |
$scale = ($height - $dimensions['height']); | |
$cropHeight = $height; | |
$cropWidth = $width / ($height/ $dimensions['height']) + $scale; | |
} else { | |
$scale = ($width - $dimensions['width']); | |
$cropWidth = $width; | |
$cropHeight = $height / ($width / $dimensions['width']) + $scale; | |
} | |
$offsetX = ($width - $cropWidth) / 2; | |
$offsetY = ($height - $cropHeight) / 2; | |
$img['cropWidth'] = $cropWidth; | |
$img['cropHeight'] = $cropHeight; | |
$img['cropX'] = $offsetX; | |
$img['cropY'] = $offsetY; | |
return $img; | |
} | |
function formatLegend($text, $height, $width, $fontsize) { | |
$text = str_split($text, round($width / $fontsize)); | |
$newText = array_slice($text, 0, round($height / $fontsize)); | |
if (count($newText) < count($text)) { | |
$newText[count($newText) - 1] .= "..." ; | |
} | |
$newText = implode("\n", $text); | |
return $newText; | |
} | |
function drawPanel($cells, $cellDimensions, $panelDimensions) { | |
global $LEGEND_HEIGHT; | |
global $DISPLAY_NAME; | |
global $DISPLAY_EXT; | |
global $FONT_PATH; | |
// Create transparent background image | |
$canvas = imagecreatetruecolor($panelDimensions['width'], $panelDimensions['height']); | |
imagealphablending($canvas, true); | |
$transparent = imagecolorallocatealpha($canvas, 255, 255, 255, 100); | |
$white = imagecolorallocate($canvas, 255, 255, 255); | |
$black = imagecolorallocate($canvas, 0, 0, 0); | |
imagefilledrectangle($canvas, 0, 0, | |
$panelDimensions['width'], $panelDimensions['height'], | |
$white); | |
imagealphablending($canvas, true); | |
$font = $FONT_PATH; | |
$fontsize = 9; | |
foreach ($cells as $cell) { | |
$cell = calculateCroppedImage($cell, $cellDimensions); | |
if (!imagecopyresampled( | |
$canvas, // dest | |
$cell['gd'], // src | |
$cell['x'], $cell['y'], // dest xy | |
$cell['cropX'], $cell['cropY'], // src xy | |
$cellDimensions['imgWidth'] + ($GUTTER / 2), // dest w | |
$cellDimensions['imgHeight'] + ($GUTTER / 2), // dest h | |
$cell['cropWidth'], $cell['cropHeight'] // src wh | |
)) { log_error('Echec de la copie de '.$cell['basename'].' sur le panel.'); } | |
if ($DISPLAY_NAME) { | |
$text = $DISPLAY_EXT ? $cell['basename'] : $cell['filename']; | |
imagettftext($canvas, | |
$fontsize, // font-size | |
0, // angle | |
$cell['x'] + 2, // x | |
$cell['y'] + $cellDimensions['imgHeight'] + 2 + $fontsize + ($GUTTER / 2), // y | |
$black, // color | |
$font, // font | |
formatLegend($text, $LEGEND_HEIGHT, $cellDimensions['width'], $fontsize) // text | |
); | |
} | |
} | |
imagesavealpha($canvas, true); | |
imagealphablending($canvas, true); | |
return $canvas; | |
} | |
/* =Output | |
*------------------------------------------------------------*/ | |
function saveImage($img, $name) { | |
global $EXT; | |
switch ($EXT) { | |
case 'jpg': | |
$savefn = imagejpeg; break; | |
case 'gif': | |
$savefn = imagegif; break; | |
case 'png': | |
$savefn = imagepng; break; | |
} | |
return $savefn($img, "$name.$EXT"); | |
} | |
function savePanels($panels) { | |
global $OUTPUTBASE; | |
global $EXT; | |
$name = $OUTPUTBASE; | |
$i = 1; | |
$multiple = count($panels) > 1; | |
while (file_exists($name.($multiple ? '' : ".$EXT"))) { | |
$name = $OUTPUTBASE."(".($i++).")" ; | |
} | |
if ($multiple) { | |
if (!mkdir($name)) { fatal_error("La creation du dossier \"$name\" a echouee"); } | |
} | |
foreach ($panels as $i => $panel) { | |
saveImage($panel, ($multiple ? $name.'/' : '').$name.($i ? $i : '')); | |
} | |
} | |
/* =Execution | |
*------------------------------------------------------------*/ | |
function createPanelFromImages($images) { | |
$cellDimensions = guessAppropriateCellDimensions($images); | |
$columnRowCount = approximateColumnRowCount($cellDimensions, count($images)); | |
$panelDimensions = calculatePanelDimensions($cellDimensions, $columnRowCount); | |
$grid = buildGridFrom($images, $columnRowCount); | |
$grid = setGridCoordinates($grid, $cellDimensions); | |
$cells = array_flatten_once($grid); | |
$panel = drawPanel($cells, $cellDimensions, $panelDimensions); | |
return $panel; | |
} | |
function processImages($images) { | |
global $MAXPANELIMAGES; | |
if ($MAXPANELIMAGES) { | |
$imagesSets = array_chunk($images, $MAXPANELIMAGES); | |
} else { | |
$imagesSets = array( $images ); | |
} | |
return array_map(createPanelFromImages, $imagesSets); | |
} | |
function app() { | |
global $PATHS; | |
global $MAXIMAGES; | |
global $OUTPUTBASE; | |
$pages = fetchHtmlPages($PATHS); | |
$images = formatImagePaths($pages, $MAXIMAGES); | |
$images = addImageData($images); | |
$images = addImageDimensions($images); | |
if (empty($images)) { fatal_error('Aucune image trouve.'); } | |
$panels = processImages($images); | |
savePanels($panels); | |
$hasErrors = printLoggedErrors(); | |
printSummary(count($panels)); | |
return $hasErrors; | |
} | |
exit(app()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment