commit 6e9abff2e11f6dd37852889a86a3008690c265b1 Author: Danny Berger Date: Tue Apr 8 14:29:15 2014 -0600 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca60d37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/vendor +/composer.lock +/composer.phar diff --git a/README.md b/README.md new file mode 100644 index 0000000..689797d --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +Installation... + + $ php composer.phar install + +You might also need PHP 5.5. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..fe66677 --- /dev/null +++ b/composer.json @@ -0,0 +1,7 @@ +{ + "require": { + "imagine/imagine": "0.5.0", + "symfony/console": "2.4.3", + "symfony/yaml": "2.4.3" + } +} diff --git a/convert.php b/convert.php new file mode 100644 index 0000000..59f4796 --- /dev/null +++ b/convert.php @@ -0,0 +1,235 @@ +register('run') + ->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 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'), + ] + ) + ->setDescription('Parse a YAML-like gallery configuration and export it.') + ->setHelp(' +The export option will accept values like: + 200x110 - photo will outset the boundary with the dimensions being 200x110 + 1280 - photo will inset with the largest dimension being 1280 +') + ->setCode( + function (InputInterface $input, OutputInterface $output) { + $gallery = $input->getArgument('name'); + $assetPath = $input->getArgument('assetdir') . '/' . $gallery; + $renderPath = $input->getArgument('mdowndir') . '/' . $gallery; + $layout = $input->getOption('layout'); + $exports = $input->getOption('export'); + + $stdin = stream_get_contents(STDIN); + + $imagine = new Imagine\Gd\Imagine(); + + if (!is_dir($assetPath)) { + mkdir($assetPath, 0700, true); + } + + if (!is_dir($renderPath)) { + mkdir($renderPath, 0700, true); + } + + $stdinPhotos = explode('------------', trim($stdin)); + $photos = []; + + // load data + + foreach ($stdinPhotos as $i => $photoRaw) { + $photoSplit = explode('------', trim($photoRaw), 2); + + if (empty($photoSplit[0])) { + continue; + } + + $photo = array_merge( + [ + 'ordering' => $i, + 'comment' => isset($photoSplit[1]) ? $photoSplit[1] : null, + ], + Yaml::parse($photoSplit[0]) + ); + + $photo['id'] = substr(sha1_file($photo['path']), 0, 7) . '-' . preg_replace('/(-| )+/', '-', preg_replace('/[^a-z0-9 ]/i', '-', preg_replace('/\'/', '', strtolower(preg_replace('/\p{Mn}/u', '', Normalizer::normalize($photo['title'], Normalizer::FORM_KD)))))); + + $photo['date'] = \DateTime::createFromFormat( + 'l, F j, Y \a\t g:i:s A', + $photo['date'] + ); + + $photo['exif'] = exif_read_data($photo['path']); + + $photos[] = $photo; + } + + // manipulate + + foreach ($photos as $i => $photo) { + $output->write($photo['id'] . '...'); + + // image exports + if (0 < count($exports)) { + $sourceJpg = $imagine->open($photo['path']); + $sourceSize = $sourceJpg->getSize(); + + if (isset($photo['exif']['Orientation'])) { + switch ($photo['exif']['Orientation']) { + case 2: + $sourceJpg->mirror(); + + break; + + case 3: + $sourceJpg->rotate(180); + + break; + + case 4: + $sourceJpg->rotate(180)->mirror(); + + break; + + case 5: + $sourceJpg->rotate(90)->mirror(); + + break; + + case 6: + $sourceJpg->rotate(90); + + break; + + case 7: + $sourceJpg->rotate(-90)->mirror(); + + break; + + case 8: + $sourceJpg->rotate(-90); + + break; + } + } + + foreach ($exports as $export) { + $output->write('' . $export . '...'); + + if (false !== strpos($export, 'x')) { + list($w, $h) = explode('x', $export); + + $exportImage = $sourceJpg->thumbnail( + new \Imagine\Image\Box($w, $h), + \Imagine\Image\ImageInterface::THUMBNAIL_OUTBOUND + ); + } else { + if ($sourceSize->getWidth() == max($sourceSize->getWidth(), $sourceSize->getHeight())) { + $mx = (int) $export; + $r = $mx / $sourceSize->getWidth(); + $my = $sourceSize->getHeight() * $r; + } elseif ($sourceSize->getHeight() == max($sourceSize->getWidth(), $sourceSize->getHeight())) { + $my = (int) $export; + $r = $my / $sourceSize->getHeight(); + $mx = $sourceSize->getWidth() * $r; + } + + $exportImage = $sourceJpg->thumbnail( + new \Imagine\Image\Box(ceil($mx), ceil($my)), + \Imagine\Image\ImageInterface::THUMBNAIL_INSET + ); + } + + $exportPath = $assetPath . '/' . $photo['id'] . '~' . $export . '.jpg'; + + file_put_contents( + $exportPath, + $exportImage->get('jpeg', [ 'quality' => 90 ]) + ); + + touch($exportPath, $photo['date']->getTimestamp()); + + $exportImage = null; + } + + $sourceJpg = null; + } + + $output->write('mdown...'); + + $matter = [ + 'layout' => $layout, + 'title' => $photo['title'], + 'date' => $photo['date']->format('Y-m-d H:i:s'), + 'ordering' => $photo['ordering'], + ]; + + if ($photo['exif']) { + $matter['exif'] = [ + 'make' => $photo['exif']['Make'], + 'model' => $photo['exif']['Model'], + 'aperture' => $photo['exif']['COMPUTED']['ApertureFNumber'], + 'exposure' => $photo['exif']['ExposureTime'], + ]; + } + + if (isset($photos[$i - 1])) { + $matter['previous'] = '/gallery/' . $gallery . '/' . $photos[$i - 1]['id']; + } + + if (isset($photos[$i + 1])) { + $matter['next'] = '/gallery/' . $gallery . '/' . $photos[$i + 1]['id']; + } + + if ($photo['latitude']) { + $matter['location'] = [ + 'latitude' => $photo['latitude'], + 'longitude' => $photo['longitude'], + ]; + } + + ksort_recursive($matter); + + file_put_contents( + $renderPath . '/' . $photo['id'] . '.md', + '---' . "\n" . Yaml::dump($matter, 4, 2) . '---' . "\n" . ((!empty($photo['comment'])) ? ($photo['comment'] . "\n") : '') + ); + + $output->writeln('done'); + } + } + ) + ; + +$console->run(new ArgvInput(array_merge([ $_SERVER['argv'][0], 'run' ], array_slice($_SERVER['argv'], 1)))); + +function ksort_recursive (&$array, $sort_flags = SORT_REGULAR) { + if (!is_array($array)) { + return false; + } + + foreach ($array as &$subarray) { + ksort_recursive($subarray, $sort_flags); + } + + ksort($array, $sort_flags); + + return true; +} diff --git a/export-iphoto.applescript b/export-iphoto.applescript new file mode 100644 index 0000000..14cc6b7 --- /dev/null +++ b/export-iphoto.applescript @@ -0,0 +1,31 @@ +on run argv + tell application "iPhoto" + set vAlbum to first item of (get every album whose name is (item 1 of argv)) + set vPhotos to get every photo in vAlbum + + set output to "" + + repeat with vPhoto in vPhotos + set output to output & Â + "altitude: " & altitude of vPhoto & " +" & Â + "latitude: " & latitude of vPhoto & " +" & Â + "longitude: " & longitude of vPhoto & " +" & Â + "name: " & name of vPhoto & " +" & Â + "date: " & date of vPhoto & " +" & Â + "path: " & original path of vPhoto & " +" & Â + "title: " & title of vPhoto & " +------ +" & comment of vPhoto & " +------------ +" + end repeat + + return output + end tell +end run \ No newline at end of file