Added Exif + Auto generation of meta.yaml files (#1472)

* Added Exif + Auto generation of meta.yaml files

* Added twig function

* Put a check in for `exif_read_data` function
This commit is contained in:
Andy Miller
2017-05-12 16:20:22 -06:00
committed by GitHub
parent a9f1ca429a
commit 82f223248e
9 changed files with 203 additions and 60 deletions

View File

@@ -2,6 +2,8 @@
## mm/dd/2017
1. [](#new)
* Added EXIF support with automatic generation of Page Media metafiles
* Added Twig function to get EXIF data on any image file
* Added `Pages::baseUrl()`, `Pages::homeUrl()` and `Pages::url()` functions
* Added `base32_encode`, `base32_decode`, `base64_encode`, `base64_decode` Twig filters
* Added `Debugger::getCaller()` to figure out where the method was called from

View File

@@ -30,7 +30,8 @@
"ext-curl": "*",
"ext-zip": "*",
"league/climate": "^3.2",
"antoligy/dom-string-iterators": "^1.0"
"antoligy/dom-string-iterators": "^1.0",
"miljar/php-exif": "^0.6.3"
},
"require-dev": {
"codeception/codeception": "^2.1",

174
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "ac28b87fd76873a857a604de772e1e72",
"content-hash": "550adaab2ad1daea868cb5568ccbe19d",
"packages": [
{
"name": "antoligy/dom-string-iterators",
@@ -697,6 +697,61 @@
],
"time": "2017-01-05T08:46:19+00:00"
},
{
"name": "miljar/php-exif",
"version": "v0.6.3",
"source": {
"type": "git",
"url": "https://github.com/PHPExif/php-exif.git",
"reference": "e43cc30608824d7f3466653b52bbbb71874b5b02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPExif/php-exif/zipball/e43cc30608824d7f3466653b52bbbb71874b5b02",
"reference": "e43cc30608824d7f3466653b52bbbb71874b5b02",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpmd/phpmd": "~2.2",
"phpunit/phpunit": "3.7.*",
"satooshi/php-coveralls": "~0.6",
"sebastian/phpcpd": "1.4.*@stable",
"squizlabs/php_codesniffer": "1.4.*@stable"
},
"suggest": {
"ext-exif": "Use exif PHP extension as adapter",
"lib-exiftool": "Use perl lib exiftool as adapter"
},
"type": "library",
"autoload": {
"psr-0": {
"PHPExif": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tom Van Herreweghe",
"homepage": "http://theanalogguy.be",
"role": "Developer"
}
],
"description": "Object-Oriented EXIF parsing",
"keywords": [
"IPTC",
"exif",
"exiftool",
"jpeg",
"tiff"
],
"time": "2017-02-06T14:40:26+00:00"
},
{
"name": "monolog/monolog",
"version": "1.22.1",
@@ -966,16 +1021,16 @@
},
{
"name": "symfony/console",
"version": "v2.8.19",
"version": "v2.8.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "86407ff20855a5eaa2a7219bd815e9c40a88633e"
"reference": "2cfcbced8e39e2313ed4da8896fc8c59a56c0d7e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/86407ff20855a5eaa2a7219bd815e9c40a88633e",
"reference": "86407ff20855a5eaa2a7219bd815e9c40a88633e",
"url": "https://api.github.com/repos/symfony/console/zipball/2cfcbced8e39e2313ed4da8896fc8c59a56c0d7e",
"reference": "2cfcbced8e39e2313ed4da8896fc8c59a56c0d7e",
"shasum": ""
},
"require": {
@@ -1023,7 +1078,7 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2017-04-03T20:37:06+00:00"
"time": "2017-04-26T01:38:53+00:00"
},
{
"name": "symfony/debug",
@@ -1084,16 +1139,16 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v2.8.19",
"version": "v2.8.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "88b65f0ac25355090e524aba4ceb066025df8bd2"
"reference": "7fc8e2b4118ff316550596357325dfd92a51f531"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/88b65f0ac25355090e524aba4ceb066025df8bd2",
"reference": "88b65f0ac25355090e524aba4ceb066025df8bd2",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7fc8e2b4118ff316550596357325dfd92a51f531",
"reference": "7fc8e2b4118ff316550596357325dfd92a51f531",
"shasum": ""
},
"require": {
@@ -1140,7 +1195,7 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2017-04-03T20:37:06+00:00"
"time": "2017-04-26T16:56:54+00:00"
},
{
"name": "symfony/polyfill-iconv",
@@ -1262,16 +1317,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v2.8.19",
"version": "v2.8.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "f8ff23ad5352f96e66c1df5468d492d2f37f3ac4"
"reference": "18ab1b833d2d82eb40a707bc002cbe62a1c22d0b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/f8ff23ad5352f96e66c1df5468d492d2f37f3ac4",
"reference": "f8ff23ad5352f96e66c1df5468d492d2f37f3ac4",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/18ab1b833d2d82eb40a707bc002cbe62a1c22d0b",
"reference": "18ab1b833d2d82eb40a707bc002cbe62a1c22d0b",
"shasum": ""
},
"require": {
@@ -1282,9 +1337,11 @@
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
},
"require-dev": {
"ext-iconv": "*",
"twig/twig": "~1.20|~2.0"
},
"suggest": {
"ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
"ext-symfony_debug": ""
},
"type": "library",
@@ -1324,20 +1381,20 @@
"debug",
"dump"
],
"time": "2017-03-12T16:01:59+00:00"
"time": "2017-04-28T06:26:40+00:00"
},
{
"name": "symfony/yaml",
"version": "v2.8.19",
"version": "v2.8.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "286d84891690b0e2515874717e49360d1c98a703"
"reference": "93ccdde79f4b079c7558da4656a3cb1c50c68e02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/286d84891690b0e2515874717e49360d1c98a703",
"reference": "286d84891690b0e2515874717e49360d1c98a703",
"url": "https://api.github.com/repos/symfony/yaml/zipball/93ccdde79f4b079c7558da4656a3cb1c50c68e02",
"reference": "93ccdde79f4b079c7558da4656a3cb1c50c68e02",
"shasum": ""
},
"require": {
@@ -1373,7 +1430,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2017-03-20T09:41:44+00:00"
"time": "2017-05-01T14:31:55+00:00"
},
{
"name": "twig/twig",
@@ -1500,16 +1557,16 @@
},
{
"name": "codeception/codeception",
"version": "2.2.10",
"version": "2.2.11",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Codeception.git",
"reference": "c32a3f92834db08ceedb4666ea2265c3aa43396e"
"reference": "a8681b416921ae282ccca2c485d75a3ed6756080"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/c32a3f92834db08ceedb4666ea2265c3aa43396e",
"reference": "c32a3f92834db08ceedb4666ea2265c3aa43396e",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/a8681b416921ae282ccca2c485d75a3ed6756080",
"reference": "a8681b416921ae282ccca2c485d75a3ed6756080",
"shasum": ""
},
"require": {
@@ -1520,9 +1577,10 @@
"guzzlehttp/guzzle": ">=4.1.4 <7.0",
"guzzlehttp/psr7": "~1.0",
"php": ">=5.4.0 <8.0",
"phpunit/php-code-coverage": ">=2.2.4 <5.0",
"phpunit/php-code-coverage": ">=2.2.4 <6.0",
"phpunit/phpunit": ">4.8.20 <6.0",
"sebastian/comparator": "~1.1",
"phpunit/phpunit-mock-objects": ">2.3 <5.0",
"sebastian/comparator": ">1.1 <3.0",
"sebastian/diff": "^1.4",
"stecman/symfony-console-completion": "^0.7.0",
"symfony/browser-kit": ">=2.7 <4.0",
@@ -1589,7 +1647,7 @@
"functional testing",
"unit testing"
],
"time": "2017-03-25T03:19:52+00:00"
"time": "2017-05-11T21:07:05+00:00"
},
{
"name": "doctrine/instantiator",
@@ -1647,16 +1705,16 @@
},
{
"name": "facebook/webdriver",
"version": "1.4.0",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/facebook/php-webdriver.git",
"reference": "3ea034c056189e11c0ce7985332a9f4b5b2b5db2"
"reference": "eadb0b7a7c3e6578185197fd40158b08c3164c83"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/3ea034c056189e11c0ce7985332a9f4b5b2b5db2",
"reference": "3ea034c056189e11c0ce7985332a9f4b5b2b5db2",
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/eadb0b7a7c3e6578185197fd40158b08c3164c83",
"reference": "eadb0b7a7c3e6578185197fd40158b08c3164c83",
"shasum": ""
},
"require": {
@@ -1695,7 +1753,7 @@
"selenium",
"webdriver"
],
"time": "2017-03-22T10:56:03+00:00"
"time": "2017-04-28T14:54:49+00:00"
},
{
"name": "fzaninotto/faker",
@@ -2977,16 +3035,16 @@
},
{
"name": "symfony/browser-kit",
"version": "v3.2.7",
"version": "v3.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
"reference": "2fe0caa60c1a1dfeefd0425741182687a9b382b8"
"reference": "9fab1ab6f77b77f3df5fc5250fc6956811699b57"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/2fe0caa60c1a1dfeefd0425741182687a9b382b8",
"reference": "2fe0caa60c1a1dfeefd0425741182687a9b382b8",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/9fab1ab6f77b77f3df5fc5250fc6956811699b57",
"reference": "9fab1ab6f77b77f3df5fc5250fc6956811699b57",
"shasum": ""
},
"require": {
@@ -3030,20 +3088,20 @@
],
"description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com",
"time": "2017-02-21T09:12:04+00:00"
"time": "2017-04-12T14:13:17+00:00"
},
{
"name": "symfony/css-selector",
"version": "v3.2.7",
"version": "v3.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "a48f13dc83c168f1253a5d2a5a4fb46c36244c4c"
"reference": "02983c144038e697c959e6b06ef6666de759ccbc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/a48f13dc83c168f1253a5d2a5a4fb46c36244c4c",
"reference": "a48f13dc83c168f1253a5d2a5a4fb46c36244c4c",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/02983c144038e697c959e6b06ef6666de759ccbc",
"reference": "02983c144038e697c959e6b06ef6666de759ccbc",
"shasum": ""
},
"require": {
@@ -3083,20 +3141,20 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
"time": "2017-02-21T09:12:04+00:00"
"time": "2017-05-01T14:55:58+00:00"
},
{
"name": "symfony/dom-crawler",
"version": "v3.2.7",
"version": "v3.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "403944e294cf4ceb3b8447f54cbad88ea7b99cee"
"reference": "f1ad34e8af09ed17570e027cf0c58a12eddec286"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/403944e294cf4ceb3b8447f54cbad88ea7b99cee",
"reference": "403944e294cf4ceb3b8447f54cbad88ea7b99cee",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/f1ad34e8af09ed17570e027cf0c58a12eddec286",
"reference": "f1ad34e8af09ed17570e027cf0c58a12eddec286",
"shasum": ""
},
"require": {
@@ -3139,20 +3197,20 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
"time": "2017-02-21T09:12:04+00:00"
"time": "2017-04-12T14:13:17+00:00"
},
{
"name": "symfony/finder",
"version": "v3.2.7",
"version": "v3.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "b20900ce5ea164cd9314af52725b0bb5a758217a"
"reference": "9cf076f8f492f4b1ffac40aae9c2d287b4ca6930"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/b20900ce5ea164cd9314af52725b0bb5a758217a",
"reference": "b20900ce5ea164cd9314af52725b0bb5a758217a",
"url": "https://api.github.com/repos/symfony/finder/zipball/9cf076f8f492f4b1ffac40aae9c2d287b4ca6930",
"reference": "9cf076f8f492f4b1ffac40aae9c2d287b4ca6930",
"shasum": ""
},
"require": {
@@ -3188,20 +3246,20 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2017-03-20T09:32:19+00:00"
"time": "2017-04-12T14:13:17+00:00"
},
{
"name": "symfony/process",
"version": "v3.2.7",
"version": "v3.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "57fdaa55827ae14d617550ebe71a820f0a5e2282"
"reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/57fdaa55827ae14d617550ebe71a820f0a5e2282",
"reference": "57fdaa55827ae14d617550ebe71a820f0a5e2282",
"url": "https://api.github.com/repos/symfony/process/zipball/999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0",
"reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0",
"shasum": ""
},
"require": {
@@ -3237,7 +3295,7 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2017-03-27T18:07:02+00:00"
"time": "2017-04-12T14:13:17+00:00"
},
{
"name": "webmozart/assert",

View File

@@ -930,6 +930,17 @@ form:
validate:
type: bool
media.auto_metadata_exif:
type: toggle
label: PLUGIN_ADMIN.ENABLE_AUTO_METADATA
help: PLUGIN_ADMIN.ENABLE_AUTO_METADATA_HELP
highlight: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
media.allowed_fallback_types:

View File

@@ -125,6 +125,7 @@ media:
upload_limit: 0 # Set maximum upload size in bytes (0 is unlimited)
unsupported_inline_types: [] # Array of supported media types to try to display inline
allowed_fallback_types: [] # Array of allowed media types of files found if accessed via Page route
auto_metadata_exif: false # Automatically create metadata files from Exif data where possible
session:
enabled: true # Enable Session support

View File

@@ -45,6 +45,7 @@ class Grav extends Container
'Grav\Common\Service\PageServiceProvider',
'Grav\Common\Service\OutputServiceProvider',
'browser' => 'Grav\Common\Browser',
'exif' => 'Grav\Common\Helpers\Exif',
'Grav\Common\Service\StreamsServiceProvider',
'Grav\Common\Service\ConfigServiceProvider',
'inflector' => 'Grav\Common\Inflector',

View File

@@ -0,0 +1,27 @@
<?php
/**
* @package Grav.Common.Helpers
*
* @copyright Copyright (C) 2014 - 2017 RocketTheme, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Common\Helpers;
use Grav\Common\Grav;
class Exif
{
public $reader;
public function __construct()
{
if (function_exists('exif_read_data')) {
$this->reader = \PHPExif\Reader\Reader::factory(\PHPExif\Reader\Reader::TYPE_NATIVE);
} else {
if (Grav::instance()['config']->get('system.media.auto_metadata_exif')) {
throw new \Exception('Please enable the Exif extension for PHP or disable Exif support in Grav system configuration');
}
}
}
}

View File

@@ -8,9 +8,12 @@
namespace Grav\Common\Page;
use Grav\Common\Grav;
use Grav\Common\Page\Medium\AbstractMedia;
use Grav\Common\Page\Medium\GlobalMedia;
use Grav\Common\Page\Medium\MediumFactory;
use RocketTheme\Toolbox\File\File;
use Symfony\Component\Yaml\Yaml;
class Media extends AbstractMedia
{
@@ -58,6 +61,8 @@ class Media extends AbstractMedia
*/
protected function init()
{
$config = Grav::instance()['config'];
$exif = Grav::instance()['exif'];
// Handle special cases where page doesn't exist in filesystem.
if (!is_dir($this->path)) {
@@ -71,7 +76,7 @@ class Media extends AbstractMedia
/** @var \DirectoryIterator $info */
foreach ($iterator as $path => $info) {
// Ignore folders and Markdown files.
if (!$info->isFile() || $info->getExtension() == 'md' || $info->getBasename()[0] === '.') {
if (!$info->isFile() || $info->getExtension() === 'md' || $info->getBasename()[0] === '.') {
continue;
}
@@ -116,6 +121,19 @@ class Media extends AbstractMedia
continue;
}
// Read/store Exif metadata as required
if (!empty($types['base']) && $medium->get('mime') === 'image/jpeg' && empty($types['meta']) && $config->get('system.media.auto_metadata_exif')) {
$file_path = $types['base']['file'];
$meta_path = $file_path . '.meta.yaml';
$meta = $exif->reader->read($file_path);
if ($meta) {
$file = File::instance($meta_path);
$file->save(Yaml::dump($meta->getData()));
$types['meta']['file'] = $meta_path;
}
}
if (!empty($types['meta'])) {
$medium->addMetaFile($types['meta']['file']);
}

View File

@@ -125,6 +125,7 @@ class TwigExtension extends \Twig_Extension
new \Twig_SimpleFunction('redirect_me', [$this, 'redirectFunc']),
new \Twig_SimpleFunction('range', [$this, 'rangeFunc']),
new \Twig_SimpleFunction('isajaxrequest', [$this, 'isAjaxFunc']),
new \Twig_SimpleFunction('exif', [$this, 'exifFunc']),
];
}
@@ -956,4 +957,27 @@ class TwigExtension extends \Twig_Extension
!empty($_SERVER['HTTP_X_REQUESTED_WITH'])
&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
}
/**
* Get's the Exif data for a file
*
* @param $image
* @param bool $raw
* @return mixed
*/
public function exifFunc($image, $raw = false)
{
if (file_exists($image)) {
$exif_data = $this->grav['exif']->reader->read($image);
if ($exif_data) {
if ($raw) {
return $exif_data->getRawData();
} else {
return $exif_data->getData();
}
}
}
}
}