From c4dac0c76cf9b64bed17c8c66ca47d13df772cb0 Mon Sep 17 00:00:00 2001 From: Rik Veenboer Date: Sun, 20 Dec 2015 00:58:30 +0000 Subject: [PATCH] Read files directly from gallery or dedicated yaml file --- convert.php | 160 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 115 insertions(+), 45 deletions(-) diff --git a/convert.php b/convert.php index 84e445a..2d7678c 100644 --- a/convert.php +++ b/convert.php @@ -9,13 +9,43 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Yaml\Yaml; +function writeMetaYaml($sDir) { + $aMeta['dir'] = rtrim($sDir, '"\'/\\'); + $aMeta['files'] = array(); + if (file_exists($aMeta['dir'])) { + $aFiles = glob($aMeta['dir'] . '/*.jpg'); + foreach ($aFiles as $sFile) { + $aMeta['files'][basename($sFile)] = ['title' => '', 'comment' => '']; + } + } + $sYaml = str_replace("''", null, Yaml::dump($aMeta, 4, 2)); + file_put_contents($sDir . '/meta.yaml', $sYaml); +} +// writeMetaYaml('C:\Users\Rik\Downloads\Blog\jekyll-gallery\in'); + + +// $sTest = <<register('run') - ->setDefinition([ + ->setDefinition([ new InputOption('export', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Target image export sizes'), - new InputOption('layout', null, InputOption::VALUE_REQUIRED, 'Rendering layout for individual photos', 'gallery-photo'), + new InputOption('layout', null, InputOption::VALUE_REQUIRED, 'Rendering layout for individual images', 'gallery-photo'), + new InputOption('importdir', null, InputOption::VALUE_REQUIRED, 'Directory to scan for images'), new InputArgument('name', null, InputArgument::REQUIRED, 'Gallery name'), new InputArgument('assetdir', InputArgument::OPTIONAL, 'Asset directory for exported images', 'asset/gallery'), new InputArgument('mdowndir', InputArgument::OPTIONAL, 'Markdown directory for dumping individual photo details', 'gallery'), @@ -28,57 +58,79 @@ $oConsole ') ->setCode( function (InputInterface $oInput, OutputInterface $oOutput) { + // Get input arguments and options $sGallery = $oInput->getArgument('name'); $sAssetPath = $oInput->getArgument('assetdir') . '/' . $sGallery; $sRenderPath = $oInput->getArgument('mdowndir') . '/' . $sGallery; + $sImportDir = $oInput->getOption('importdir'); $sLayout = $oInput->getOption('layout'); $sExports = $oInput->getOption('export'); - $sStdin = stream_get_contents(STDIN); - $oImagine = new Imagine\Gd\Imagine(); + // Initialize directories if (!is_dir($sAssetPath)) { mkdir($sAssetPath, 0700, true); } - if (!is_dir($sRenderPath)) { mkdir($sRenderPath, 0700, true); } - $sStdinPhotos = explode('------------', trim($sStdin)); + if (isset($sImportDir)) { + // Use provided directory + $sImportDir = rtrim($oInput->getOption('importdir'), '/\\'); + } else { + // Get directory and metadata from yaml + $sStdin = stream_get_contents(STDIN); + $aYaml = Yaml::parse($sStdin); + $sImportDir = rtrim($aYaml['dir'], '"\'/\\'); + $aMeta = $aYaml['files']; + if (!isset($aYaml['all'])) { + $aFiles = array_keys($aYaml['files']); + } + } + + // Scan import directory for images + if (!isset($aFiles)) { + $aFiles = array_map('basename', glob($sImportDir . '/*.jpg')); + } + + // Loop over files $aPhotos = []; + foreach ($aFiles as $i => $sFile) { + // Build photo information + $aPhoto = [ + 'path' => $sImportDir . '/' . $sFile, + 'ordering' => $i, + 'name' => isset($aMeta[$sFile]['name']) ? $aMeta[$sFile]['name'] : null, + 'comment' => isset($aMeta[$sFile]['comment']) ? $aMeta[$sFile]['comment'] : null + ]; - // load data - foreach ($sStdinPhotos as $i => $aPhotoRaw) { - $aPhotoSplit = explode('------', trim($aPhotoRaw), 2); - - if (empty($aPhotoSplit[0])) { - continue; + // Generate id from file contents + $aPhoto['id'] = substr(sha1_file($aPhoto['path']), 0, 7); + if (isset($aPhoto['title'])) { + $aPhoto['id'] .= '-' . preg_replace('/(-| )+/', '-', preg_replace('/[^a-z0-9 ]/i', '-', preg_replace('/\'/', '', strtolower(preg_replace('/\p{Mn}/u', '', Normalizer::normalize($aPhoto['title'], Normalizer::FORM_KD)))))); } - $aPhoto = array_merge([ - 'ordering' => $i, - 'comment' => isset($aPhotoSplit[1]) ? $aPhotoSplit[1] : null, - ], Yaml::parse($aPhotoSplit[0])); - - $aPhoto['id'] = substr(sha1_file($aPhoto['path']), 0, 7) . '-' . preg_replace('/(-| )+/', '-', preg_replace('/[^a-z0-9 ]/i', '-', preg_replace('/\'/', '', strtolower(preg_replace('/\p{Mn}/u', '', Normalizer::normalize($aPhoto['title'], Normalizer::FORM_KD)))))); - $aPhoto['date'] = \DateTime::createFromFormat( - 'l, F j, Y \a\t g:i:s A', - $aPhoto['date'] - ); - + // Parse selected EXIF data $aPhoto['exif'] = exif_read_data($aPhoto['path']); + if (isset($aPhoto['exif']['GPSLongitude'])) { + $aPhoto = array_merge($aPhoto, [ + 'longitude' => coordinateToDegrees($aPhoto['exif']['GPSLongitude'], $aPhoto['exif']['GPSLongitudeRef']), + 'latitude' => coordinateToDegrees($aPhoto['exif']['GPSLatitude'], $aPhoto['exif']['GPSLatitudeRef']), + 'altitude' => fractionToFloat($aPhoto['exif']['GPSAltitude']), + 'direction' => fractionToFloat($aPhoto['exif']['GPSImgDirection'])]); + } + $aPhoto['date'] = new DateTime($aPhoto['exif']['DateTimeOriginal']); $aPhotos[] = $aPhoto; } - // manipulate + // Manipulate foreach ($aPhotos as $i => $aPhoto) { $oOutput->write('' . $aPhoto['id'] . ''); - $aPhoto['sizes'] = []; - // image exports + // Image exports if (0 < count($sExports)) { $oSourceJpg = $oImagine->open($aPhoto['path']); if (isset($aPhoto['exif']['Orientation'])) { @@ -108,10 +160,10 @@ $oConsole } $oSourceSize = $oSourceJpg->getSize(); - $oOutput->write('[' . $oSourceSize->getWidth() . 'x' . $oSourceSize->getHeight() . ']...'); + $oOutput->writeln(' [' . $oSourceSize->getWidth() . 'x' . $oSourceSize->getHeight() . ']...'); foreach ($sExports as $sExport) { - $oOutput->write('' . $sExport . ''); + $oOutput->write(' ' . $sExport . ''); if (false !== strpos($sExport, 'x')) { list($iW, $iH) = explode('x', $sExport); @@ -146,10 +198,10 @@ $oConsole 'height' => $sExportsize->getHeight(), ]; - $oOutput->write('[' . $sExportsize->getWidth() . 'x' . $sExportsize->getHeight() . ']'); - + $oOutput->writeln(' [' . $sExportsize->getWidth() . 'x' . $sExportsize->getHeight() . ']'); $sExportPath = $sAssetPath . '/' . $aPhoto['id'] . '~' . $sExport . '.jpg'; + // Write converted image file_put_contents( $sExportPath, $sExportImage->get('jpeg', ['quality' => 90]) @@ -157,21 +209,19 @@ $oConsole touch($sExportPath, $aPhoto['date']->getTimestamp()); $sExportImage = null; - $oOutput->write('...'); } $oSourceJpg = null; } - $oOutput->write('markdown...'); - + $oOutput->write(' markdown'); $aMatter = [ 'layout' => $sLayout, - 'title' => $aPhoto['title'], + 'title' => isset($aPhoto['title']) ? $aPhoto['title'] : null, 'date' => $aPhoto['date']->format('Y-m-d H:i:s'), 'ordering' => $aPhoto['ordering'] ]; - if ($aPhoto['exif']) { + if (isset($aPhoto['exif']['Make'])) { $aMatter['exif'] = [ 'make' => $aPhoto['exif']['Make'], 'model' => $aPhoto['exif']['Model'], @@ -188,7 +238,7 @@ $oConsole $aMatter['next'] = '/gallery/' . $sGallery . '/' . $aPhotos[$i + 1]['id']; } - if ($aPhoto['latitude']) { + if (isset($aPhoto['latitude'])) { $aMatter['location'] = [ 'latitude' => $aPhoto['latitude'], 'longitude' => $aPhoto['longitude'], @@ -200,7 +250,6 @@ $oConsole } ksort_recursive($aMatter); - uasort( $aMatter['sizes'], function ($aA, $aB) { @@ -208,18 +257,20 @@ $oConsole $iSurfaceB = $aB['width'] * $aB['height']; return $iSurfaceA == $iSurfaceB ? 0 - : (($aa > $bb)? -1 : 1); + : (($iSurfaceA > $iSurfaceB)? -1 : 1); } ); - file_put_contents( - $sRenderPath . '/' . $aPhoto['id'] . '.md', - '---' . "\n" . Yaml::dump($aMatter, 4, 2) . '---' . "\n" . ((!empty($aPhoto['comment'])) ? ($aPhoto['comment'] . "\n") : '') - ); + // Write Markdown file + file_put_contents( + $sRenderPath . '/' . $aPhoto['id'] . '.md', + '---' . "\n" . Yaml::dump($aMatter, 4, 2) . '---' . "\n" . ((!empty($aPhoto['comment'])) ? ($aPhoto['comment'] . "\n") : '') + ); - $oOutput->writeln('done'); - } - }); + $oOutput->writeln(' done'); + } + } +); $oConsole->run(new ArgvInput(array_merge([$_SERVER['argv'][0], 'run' ], array_slice($_SERVER['argv'], 1)))); @@ -233,3 +284,22 @@ function ksort_recursive(&$aArray, $mSortFlags = SORT_REGULAR) { ksort($aArray, $mSortFlags); return true; } + +function coordinateToDegrees($aCoordinate, $sHemisphere) { + $aCoordinate = array_map('fractionToFloat', $aCoordinate); + $aDegrees = array_map(function ($a, $b) { + return $a / $b; + }, $aCoordinate, array(1, 60, 3600)); + $iFlip = ($sHemisphere == 'W' or $sHemisphere == 'S') ? -1 : 1; + return $iFlip * array_sum($aDegrees); +} + +function fractionToFloat($sFraction) { + $aParts = explode('/', $sFraction); + $iParts = count($aParts); + return $iParts + ? ($iParts > 1 + ? floatval($aParts[0]) / floatval($aParts[1]) + : $aParts[0]) + : 0; +} \ No newline at end of file