Jump to content

Recommended Posts

Metadata Exif

Version 0.9.0  (currently a WIP) for PW 2.8.+ / 3.0+

This is a new attempt to add easy EXIF reading support to ProcessWire. It should be an easy and less error prone API task. Thats why the module internally uses lowercase key names for all EXIF keys and all of your requested key names. But you are not forced to use lowercase key names, you can use any mixed chars for it as you like. You will get back an array or object with keynames / properties named the same (casesensitive) way as you have passed them in with your request.

API

The module adds one hook to the Pageimage: getExif($options = null)

Without any $options passed to the method, it returns all EXIF data in a RAW multidim array.

Passing a simple list with requested key names as array to it returns an array with only the values of those requested keynames.

If you want change the output from array to object, you can use the a boolean "toObject" set to true. Additionally to this and / or any other option, you need to put your requested keynames list to the option "keys".

$rawArray = $image->getExif();

$options = array('Whitebalance', 'Flash', 'ISOSpeedRatings', 'FNumber', 'UserComment');
$array = $image->getExif($options);

$options = array('toObject' => true, 'keys' => array('whitebalance', 'flash', 'isospeedratings', 'fnumber', 'usercomment'));
$object = $image->getExif($options);

 

Possible options are

Quote

              keys = array,
                       a list with case insensitive keynames

              thumbnail = bool,
                       you can set thumbnail explicitly as own option,
                       or you can add thumbnail as keyname to keys

              toObject = bool,
                       if is false or missing, an array is returned

              unformatted = bool,
                       if explicitly set to true, you will get back unformatted (raw) values

              returnRaw = bool,
                       when no $options are set, or no $options['keys'] are set,
                       or explicitly this param is set to true,
                       the complete RAW EXIF data is returned

 

A working example

    $options = array(
        'keys' => array('ISOSpeedRatings', 'FNumber', 'Flash')
    );
    echo "<table><tr>";
    foreach($options['keys'] as $key) echo "<th>{$key}</th>";
    echo "</tr>";
    foreach($page->images as $image) {
        $exif = $image->getExif($options);
        echo "<tr>";
        foreach($exif as $value) echo "<td>$value</td>";
        echo "</tr>";
    }
    echo "</table>";

 

This will output something like:

Quote
ISOSpeedRatings    FNumber    Flash
320    f/2.2    Flash did not fire, compulsory flash mode
100    f/4.0    Flash did not fire, compulsory flash mode

 

With the boolean option "unformatted" passed as true, the output would look like:

Quote
ISOSpeedRatings    FNumber    Flash
320    11/5    16
100    40/10    16

 

For some keys, that only store something like integer values, what are not very meaningful to most of us, the module contain xyzFormatted methods. This way, it is easy to enhance and maintain the module in the future. :)

 

Help wanted

It would be nice if some of you test the module and report back if the intended API suites your needs. And you are very welcome to post suggestions for which keys you want to have a ...Formatted method.

 

Thank you!

https://github.com/horst-n/MetadataExif

 

  • Like 12

Share this post


Link to post
Share on other sites

Hi, Thanks for the great module.

I'm trying to use this for a single image, however, i'm unable to get this to work for just the first image in multi-image field.

Share this post


Link to post
Share on other sites

how does your code look like for getting the (first) image from your field and getting the exif information?

Share this post


Link to post
Share on other sites

and what is the outcome?

can you try

var_dump($page->galleryimages->first()->getExif('FNumber'));

 

Share this post


Link to post
Share on other sites
5 minutes ago, horst said:

var_dump($page->galleryimages->first()->getExif('FNumber'));

returns NULL

Share this post


Link to post
Share on other sites
var_dump(count($page->galleryimages));
$image = $page->galleryimages->first();
var_dump($image->url);
var_dump($image->getExif());

please verify that:

  • your field has at least one image
  • that the image is of type jpeg
  • that it (the original version) contains EXIF-data
  • that it contain an entry FNumber

 

Share this post


Link to post
Share on other sites
1 minute ago, horst said:

please verify that:

  • your field has at least one image
  • that the image is of type jpeg
  • that it (the original version) contains EXIF-data
  • that it contain an entry FNumber

 

Yes I can confirm all of this. The multi-image field has two images. Using your example array from the first post of this thread I can see Exif information being returned for both. Both files are jpg type files.

See array information returned from your working example code below.

 

Screenshot at Nov 27 17-12-27.png

Share this post


Link to post
Share on other sites
17 minutes ago, horst said:

var_dump(count($page->galleryimages));

returns - int(2)

Quote

$image = $page->galleryimages->first();

Returns - nothing.
 

Quote

var_dump($page->galleryimages->url);

returns - string(36) "/photography/site/assets/files/1031/" 

Quote

var_dump($page->galleryimages->getExif());

returns - array(2) { ["apc_0046.jpg"]=> NULL ["img_0335.jpg"]=> NULL }

Share this post


Link to post
Share on other sites

your url does not contain an image name, it only points to the folder.

and the last var_dump should get the EXIf from the single image, not from the image collection!!

Share this post


Link to post
Share on other sites
Quote

var_dump($page->galleryimages->first()->getExif());

Notice: Undefined offset: 0 in /Applications/XAMPP/xamppfiles/htdocs/photography/site/modules/MetadataExif/MetadataExif.module on line 44
array(5) { ["FILE"]=> array(6) { ["FileName"]=> string(12) "apc_0046.jpg" ["FileDateTime"]=> int(1511813872) ["FileSize"]=> int(1160717) ["FileType"]=> int(2) ["MimeType"]=> string(10) "image/jpeg" ["SectionsFound"]=> string(30) "ANY_TAG, IFD0, THUMBNAIL, EXIF" } ["COMPUTED"]=> array(9) { ["html"]=> string(26) "width="2797" height="3496"" ["Height"]=> int(3496) ["Width"]=> int(2797) ["IsColor"]=> int(1) ["ByteOrderMotorola"]=> int(0) ["ApertureFNumber"]=> string(5) "f/2.2" ["Copyright"]=> string(20) "photography" ["Thumbnail.FileType"]=> int(2) ["Thumbnail.MimeType"]=> string(10) "image/jpeg" } ["IFD0"]=> array(10) { ["ImageDescription"]=> string(36) "time flies" ["Make"]=> string(5) "Apple" ["Model"]=> string(14) "iPhone 6s Plus" ["XResolution"]=> string(5) "240/1" ["YResolution"]=> string(5) "240/1" ["ResolutionUnit"]=> int(2) ["Software"]=> string(49) "Adobe Photoshop Lightroom Classic 7.0 (Macintosh)" ["DateTime"]=> string(19) "2017:11:27 16:17:21" ["Copyright"]=> string(20) "j.sobers.photography" ["Exif_IFD_Pointer"]=> int(302) } ["THUMBNAIL"]=> array(6) { ["Compression"]=> int(6) ["XResolution"]=> string(4) "72/1" ["YResolution"]=> string(4) "72/1" ["ResolutionUnit"]=> int(2) ["JPEGInterchangeFormat"]=> int(896) ["JPEGInterchangeFormatLength"]=> int(17303) } ["EXIF"]=> array(26) { ["ExposureTime"]=> string(6) "1/2400" ["FNumber"]=> string(5) "22/10" ["ExposureProgram"]=> int(2) ["ISOSpeedRatings"]=> int(25) ["ExifVersion"]=> string(4) "0230" ["DateTimeOriginal"]=> string(19) "2017:07:10 11:47:22" ["DateTimeDigitized"]=> string(19) "2017:07:10 11:47:22" ["ShutterSpeedValue"]=> string(16) "11228819/1000000" ["ApertureValue"]=> string(15) "2275007/1000000" ["BrightnessValue"]=> string(8) "8488/781" ["ExposureBiasValue"]=> string(3) "0/1" ["MeteringMode"]=> int(5) ["Flash"]=> int(16) ["FocalLength"]=> string(5) "83/20" ["SubjectLocation"]=> array(4) { [0]=> int(2015) [1]=> int(1511) [2]=> int(2217) [3]=> int(1330) } ["SubSecTimeOriginal"]=> string(3) "208" ["SubSecTimeDigitized"]=> string(3) "208" ["ColorSpace"]=> int(1) ["SensingMethod"]=> int(2) ["SceneType"]=> string(1) "" ["ExposureMode"]=> int(0) ["WhiteBalance"]=> int(0) ["FocalLengthIn35mmFilm"]=> int(29) ["UndefinedTag:0xA432"]=> array(4) { [0]=> string(5) "83/20" [1]=> string(5) "83/20" [2]=> string(4) "11/5" [3]=> string(4) "11/5" } ["UndefinedTag:0xA433"]=> string(5) "Apple" ["UndefinedTag:0xA434"]=> string(39) "iPhone 6s Plus back camera 4.15mm f/2.2" } }

 

Quote

 

var_dump($page->galleryimages->first()->url);

 

 

string(48) "/photography/site/assets/files/1031/apc_0046.jpg"

 

Sorry about that, i corrected my mistake. see above.

Share this post


Link to post
Share on other sites

Sorry, now I see that you are using a single value string as $options. This is not possible.

Please refer to the examples above: you need to pass an array to the function, also if you want to retrieve a single value:

$image->getExif( array('FNumber') );

 

Share this post


Link to post
Share on other sites
Quote

echo $page->galleryimages->first()->getExif( array('FNumber') );

Returned :

Quote

Notice: Array to string conversion in /Applications/XAMPP/xamppfiles/htdocs/photography/site/templates/clientgallery.php on line 9
Array

 

Share this post


Link to post
Share on other sites

you need to echo out your desired array key, or object property, depending on what you choosed.

You choosed an array for the return, therefore you need to output the key "FNumber" of the array:

$result = $page->galleryimages->first()->getExif( array('FNumber') );

// output the value for one key of the returned array
echo $result['FNumber'];

// if you have choosen the result as object, you would use
echo $result->FNumber;

This all you can read in the initial post of this thread.

  • Thanks 1

Share this post


Link to post
Share on other sites

Hi Horst,

With your instructions and help, I got it to work.

Thanks again for working with me in understanding proper methods for rendering the values I needed.

 

For Future reference for anyone else(including myself if I forget )... There are two methods for rendering data from Metadata EXIF module.

Array Method:

// output the value for one key of the returned array
$firstGalleryImage = $page->galleryimages->first()->getExif( array('FNumber') );
echo $firstGalleryImage['FNumber'];

Object Method:

// if you have choosen the result as object, you would use
$options = array('toObject' => true, 'keys' => array('FNumber'));
$object = $page->galleryimages->first()->getExif($options);
echo $object->FNumber; 

 

  • Like 1

Share this post


Link to post
Share on other sites

Hi @horst,

Thanks for this module!

It would be great if the module alerted the user somehow if the required PHP exif extension is not installed. I spent some time trying to work out why I couldn't get any data back from images and it wasn't until I saw this in the module code...

if(!function_exists('exif_read_data')) return null;

...that I realised my local WAMP stack didn't have the exif extension enabled.

Share this post


Link to post
Share on other sites
10 hours ago, Robin S said:

It would be great if the module alerted the user somehow if the required PHP exif extension is not installed.

What do you think would be the best way? Returning false or throwing an exception?

 

Share this post


Link to post
Share on other sites
7 hours ago, horst said:

Returning false or throwing an exception?

I think the getExif() method should throw an exception if the module requirements aren't met.

But the module could also check for this when it's installed. Unfortunately I don't think it's possible to include PHP extensions in the "requires" item of getModuleInfo() but the Module documentation says (after correcting typo):

Quote

If the install() method determines that the module cannot be installed for some reason, it should throw a WireException.

So the install method could be this:

public function ___install() {
	if(!function_exists('exif_read_data')) {
		throw new WireException('MetadataExif requires the PHP exif extension.');
	};
}

 

Share this post


Link to post
Share on other sites

Many thanks for the suggestions, @Robin S

I think the main check / exception must be in the getExif method. 

A check during install will be useless when deploying a site folder from local to stage or live. But it is no harm to have it too. 👍

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By rushy
      Bit of a newbie type question, even though I've been using PW for quite a while, I've not had to manipulate assets from the front end before.  I now have a need to update image properties from the front end and I'm trying to update an image description and tags when clicking on a link. I get the selected image and for example I can delete it with the code below. But I am missing some basic understanding when updating image description field as nothing happens, no errors but the description field remains empty. Any idea what steps I am missing? Many thanks. 
      // how to update image description? $al = $pages->get($album); $pgfile = $al->images->getFile($file); $al->of(false); $pgfile->description = "Test description"; $al->save(); // to delete an image - this works $al->of(false); $al->images->delete($file); $al->save();  
    • By joshua
      This module is (yet another) way for implementing a cookie management solution.
      Of course there are several other possibilities:
      - https://processwire.com/talk/topic/22920-klaro-cookie-consent-manager/
      - https://github.com/webmanufaktur/CookieManagementBanner
      - https://github.com/johannesdachsel/cookiemonster
      - https://www.oiljs.org/
      - ... and so on ...
      In this module you can configure which kind of cookie categories you want to manage:

      You can also enable the support for respecting the Do-Not-Track (DNT) header to don't annoy users, who already decided for all their browsing experience.
      Currently there are four possible cookie groups:
      - Necessary (always enabled)
      - Statistics
      - Marketing
      - External Media
      All groups can be renamed, so feel free to use other cookie group names. I just haven't found a way to implement a "repeater like" field as configurable module field ...
      When you want to load specific scripts ( like Google Analytics, Google Maps, ...) only after the user's content to this specific category of cookies, just use the following script syntax:
      <script type="optin" data-type="text/javascript" data-category="statistics" data-src="/path/to/your/statistic/script.js"></script> <script type="optin" data-type="text/javascript" data-category="marketing" data-src="/path/to/your/mareketing/script.js"></script> <script type="optin" data-type="text/javascript" data-category="external_media" data-src="/path/to/your/external-media/script.js"></script> <script type="optin" data-type="text/javascript" data-category="marketing">console.log("Inline scripts are also working!");</script> The type has to be "optin" to get recognized by PrivacyWire, the data-attributes are giving hints, how the script shall be loaded, if the data-category is within the cookie consents of the user. These scripts are loaded asynchronously after the user made the decision.
      If you want to give the users the possibility to change their consent, you can use the following Textformatter:
      [[privacywire-choose-cookies]] It's planned to add also other Textformatters to opt-out of specific cookie groups or delete the whole consent cookie.
      You can also add a custom link to output the banner again with a link / button with following class:
      <a href="#" class="privacywire-show-options">Show Cookie Options</a> <button class="privacywire-show-options">Show Cookie Options</button> This module is still in development, but we already use it on several production websites.
      You find it here: PrivacyWire Git Repo
      Download as .zip
      I would love to hear your feedback 🙂
      CHANGELOG
      0.0.5 Multi-language support included completely (also in TextFormatter). Added possibility to async load other assets (e.g. <img type="optin" data-category="marketing" data-src="https://via.placeholder.com/300x300">) 0.0.4 Added possibility to add an imprint link to the banner 0.0.3 Multi-language support for module config (still in development) 0.0.2 First release 0.0.1 Early development
    • By MoritzLost
      This is a new module that provides a simple solution to clearing all your cache layers at once, and an extensible interface to perform various cache-related actions.
      The simple motivation behind this module was that I was tired of manually clearing caches in several places after deploying a change on a live site. The basic purpose of this module is a simple Clear all caches link in the Setup menu which clears out all caches, no matter where they hide. You can customize what exactly the module does through it's configuration menu:
      Expire or delete all cache entries in the database, or selectively clear caches by namespace ($cache API) Clear the the template render cache. Clear out specific folders inside your site's cache directory (/site/assets/cache) Refresh version strings for static assets to bust client-side browser caches (this requires some setup, see the full documentation for details). This is the basic function of the module. However, you can also add different cache management action through the API and execute them through the module's interface. For this advanced usage, the module provides:
      An interface to see all available cache actions and execute them. A system log and logging output on the module page to see verify what the module is doing. A CacheControlTools class with utility functions to clear out different caches. An API to add cache actions, execute them programmatically and even modify the default action. Permission management, allowing you granular control over which user roles can execute which actions. The complete documentation can be found in the module's README.
      Beta release
      Note that I consider this a Beta release. Since the module is relatively aggressive in deleting some caches, I would advise you to install in on a test environment before using it on a live site.
      Let me know if you're getting any errors, have trouble using the module or if you have suggestions for improvement!
      In particular, can someone let me know if this module causes any problems with the ProCache module? I don't own or use it, so I can't check. As far as I can tell, ProCache uses a folder inside the cache directory to cache static pages, so my module should be able to clear the ProCache site cache as well, I'd appreciate it if someone can test that for me.
      Future plans
      If there is some interest in this, I plan to expand this to a more general cache management solution. I particular, I would like to add additional cache actions. Some ideas that came to mind:
      Warming up the template render cache for publicly accessible pages. Removing all active user sessions. Let me know if you have more suggestions!
      Links
      https://github.com/MoritzLost/ProcessCacheControl ProcessCacheControl in the Module directory

    • By David Karich
      Admin Page Tree Multiple Sorting
      ClassName: ProcessPageListMultipleSorting
      Extend the ordinary sort of children of a template in the admin page tree with multiple properties. For each template, you can define your own rule. Write each template (template-name) in a row, followed by a colon and then the additional field names for sorting.
      Example: All children of the template "blog" to be sorted in descending order according to the date of creation, then descending by modification date, and then by title. Type:
      blog: -created, -modified, title  Installation
      Copy the files for this module to /site/modules/ProcessPageListMultipleSorting/ In admin: Modules > Check for new modules. Install Module "Admin Page Tree Multible Sorting". Alternative in ProcessWire 2.4+
      Login to ProcessWire backend and go to Modules Click tab "New" and enter Module Class Name: "ProcessPageListMultipleSorting" Click "Download and Install"   Compatibility   I have currently tested the module only under PW 2.6+, but think that it works on older versions too. Maybe someone can give a feedback.     Download   PW-Repo: http://modules.processwire.com/modules/process-page-list-multiple-sorting/ GitHub: https://github.com/FlipZoomMedia/Processwire-ProcessPageListMultipleSorting     I hope someone can use the module. Have fun and best regards, David
×
×
  • Create New...