initial commit
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/vendor
|
||||||
|
/composer.lock
|
||||||
|
/composer.phar
|
||||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Installation...
|
||||||
|
|
||||||
|
$ php composer.phar install
|
||||||
|
|
||||||
|
You might also need PHP 5.5.
|
||||||
7
composer.json
Normal file
7
composer.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"imagine/imagine": "0.5.0",
|
||||||
|
"symfony/console": "2.4.3",
|
||||||
|
"symfony/yaml": "2.4.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
235
convert.php
Normal file
235
convert.php
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Application;
|
||||||
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
$console = new Application();
|
||||||
|
|
||||||
|
$console
|
||||||
|
->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('<info>' . $export . '</info>...');
|
||||||
|
|
||||||
|
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('<info>mdown</info>...');
|
||||||
|
|
||||||
|
$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;
|
||||||
|
}
|
||||||
31
export-iphoto.applescript
Normal file
31
export-iphoto.applescript
Normal file
@@ -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 & <EFBFBD>
|
||||||
|
"altitude: " & altitude of vPhoto & "
|
||||||
|
" & <EFBFBD>
|
||||||
|
"latitude: " & latitude of vPhoto & "
|
||||||
|
" & <EFBFBD>
|
||||||
|
"longitude: " & longitude of vPhoto & "
|
||||||
|
" & <EFBFBD>
|
||||||
|
"name: " & name of vPhoto & "
|
||||||
|
" & <EFBFBD>
|
||||||
|
"date: " & date of vPhoto & "
|
||||||
|
" & <EFBFBD>
|
||||||
|
"path: " & original path of vPhoto & "
|
||||||
|
" & <EFBFBD>
|
||||||
|
"title: " & title of vPhoto & "
|
||||||
|
------
|
||||||
|
" & comment of vPhoto & "
|
||||||
|
------------
|
||||||
|
"
|
||||||
|
end repeat
|
||||||
|
|
||||||
|
return output
|
||||||
|
end tell
|
||||||
|
end run
|
||||||
Reference in New Issue
Block a user