Jump to content

Preserving metadata in resized image using PHP


Go to solution Solved by pewe,

Recommended Posts

I have a PHP script which scans a directory for images, resizes any it finds and saves them back overwriting the originals. It works well except for the fact that it strips the metadata from the image.

I found a Toolkit which can manipulate Metadata including extracting and writing it to images. On this page it explains how to do this (at the bottom of the page).

So I added it to my code but am having problems - it does not write the metadata to the resized image. I am obviously missing something but can't seem to figure out what (probably my lack of coding skill) and wondered if someone can spot my error and suggest a correction.

Here is the relevant part of the code:

This code is first used just to confirm what images are found in the directory and contain metadata - by printing it in an html format

echo " $file <br> " ;
        $filename = $file;
        $exif_data = get_EXIF_JPEG( $filename );
        echo Interpret_EXIF_to_HTML( get_EXIF_JPEG( $filename ), $filename );

Here is the code which then resizes the image and saves it, and should write the metadata to it - but doesn't seem to work

$new_image = imagecreatetruecolor($new_width,$new_height);
        ImageCopyResized($new_image, $tmp_image,0,0,0,0, $new_width, $new_height, $width, $height);
        //Grab new image
        imagejpeg($new_image, $target_path);
        $image_buffer = ob_get_contents();
        ImageDestroy($new_image);
        ImageDestroy($tmp_image);
        echo " $file resized to $new_width x $new_height <br> \n";
        echo str_pad('',4096)."\n";
        $jpeg_header_data = put_EXIF_JPEG( $exif_data, $jpeg_header_data );
        put_jpeg_header_data( $filename, $filename, $jpeg_header_data );
        ob_flush();
        flush();

Is this a case of having put the rewrite code in the wrong place - or something else?

Thanks for any suggestions which may help.

 

Can't help but notice you're saving the thumbnail to $target_path and putting the metadata in $filename.

Forgive me , but my coding knowledge is somewhat limited, the original resize script was written for me and I cannot get hold of the coder.

 

However, as the resized image is overwriting the original it will have the same name as it did originally. I therefore concluded that as the first part of the script is reading and displaying the Exif Data using $filename, that when writing the data using $filename should find the file also.

 

This is the full script:

The parts marked 'For Testing Only' are where the exif is printed from the photo (this will be removed in final working script). The first time it is used it is running on the original image and it displays content. The second time it is run it should be running on the same photo, just resized - but nothing is displayed, and when I check the file the data has not been written back to it.

<?php
// added for exif extraction and re-writing
 // Change: Allow this example file to be easily relocatable - as of version 1.11
                        $Toolkit_Dir = "./";     // Ensure dir name includes trailing slash

                        // Hide any unknown EXIF tags
                        $GLOBALS['HIDE_UNKNOWN_TAGS'] = TRUE;

                        include $Toolkit_Dir . 'Toolkit_Version.php';          // Change: added as of version 1.11
                        include $Toolkit_Dir . 'JPEG.php';                     // Change: Allow this example file to be easily relocatable - as of version 1.11
                        include $Toolkit_Dir . 'JFIF.php';
                        include $Toolkit_Dir . 'PictureInfo.php';
                        include $Toolkit_Dir . 'XMP.php';
                        include $Toolkit_Dir . 'Photoshop_IRB.php';
                        include $Toolkit_Dir . 'EXIF.php';


// original resize script
//use this line if you get the error message of using too much memory (strip '//')
//ini_set ( "memory_limit", "48M");
 
$percent = 0.5; // specify propotion for resized image here


if (ob_get_level() == 0) ob_start();
if ($handle = opendir('.')) {
  while (false !== ($file = readdir($handle))) {
    if ($file != "." && $file != "..") {
      $destination_path = './';
      $target_path = $destination_path . basename($file);
	  $extension = pathinfo($target_path);
      $allowed_ext = "jpg, gif, png, bmp, jpeg, JPG";
      $extension = $extension[extension];
      $allowed_paths = explode(", ", $allowed_ext);
      $ok = 0;
      for($i = 0; $i < count($allowed_paths); $i++) {
        if ($allowed_paths[$i] == "$extension") {
          $ok = "1";
        }
      }

      if ($ok == "1") {

        if($extension == "jpg" || $extension == "jpeg" || $extension == "JPG"){
          $tmp_image=imagecreatefromjpeg($target_path);
        }

        if($extension == "png") {
          $tmp_image=imagecreatefrompng($target_path);
        }

        if($extension == "gif") {
          $tmp_image=imagecreatefromgif($target_path);
        }

        $width = imagesx($tmp_image);
        $height = imagesy($tmp_image);

        //calculate the image ratio not used if using proportion rather than new physical sizes
        $imgratio = ($width / $height);

        if ($imgratio>1) {
          $new_width = $width * $percent;
          $new_height = $height * $percent;
        } else {
         $new_width = $width * $percent;
          $new_height = $height * $percent;
        }
        
        // For testing only
        // Print value held by $file - and use to create variable $filename - print exif from $filename to confirm it exists. 
        echo " $file <br> " ;
        $filename = $file;
        $exif_data = get_EXIF_JPEG( $filename );
        echo Interpret_EXIF_to_HTML( get_EXIF_JPEG( $filename ), $filename );
        // end of testing

        $new_image = imagecreatetruecolor($new_width,$new_height);
        ImageCopyResized($new_image, $tmp_image,0,0,0,0, $new_width, $new_height, $width, $height);
        
        //Grab new image
        imagejpeg($new_image, $target_path);
        $image_buffer = ob_get_contents();
        ImageDestroy($new_image);
        ImageDestroy($tmp_image);
        echo " $file resized to $new_width x $new_height <br> \n";
        echo str_pad('',4096)."\n";
        $jpeg_header_data = put_EXIF_JPEG( $exif_data, $jpeg_header_data );
        put_jpeg_header_data( $filename, $filename, $jpeg_header_data ); 
// For testing only        
$exif_data = get_EXIF_JPEG( $filename );
        echo Interpret_EXIF_to_HTML( get_EXIF_JPEG( $filename ), $filename );
// end of testing
        ob_flush();
        flush();
      }
    }
  }
  closedir($handle);
  echo "Done.";
  ob_end_flush();
}
?>
Edited by pewe

Did you change the code or just post your entire code here again?

 

 

My first post was an extract of the parts I added to my original resize script to :

- check the metadata in the original image by displaying it

- write the metadata to the resized image (which was saved using the same name and overwriting the original image.

 

My second post was the complete resize script including the additions.

 

 

If you're saving the new file as a.png and saving the metadata to b.png, why would you think a.png would get the metadata?

 

As I mentioned in my original post, my coding skills are very basic so I guess you are saying that the code is not right.

 

The variable $filename contains the name of the original image before resizing and from which the metatada is taken using

$exif_data = get_EXIF_JPEG( $filename );

So as the image is saved over the original using the same name I thought that the code to write it back to this file would be

$jpeg_header_data = put_EXIF_JPEG( $exif_data, $jpeg_header_data );
put_jpeg_header_data( $filename, $filename, $jpeg_header_data );

Obviously this is not correct as it does not work, and I'm not sure what it needs to be changed to.

  • Solution

I resolved the problem which was (apparently) a simple but crucial oversight.

I needed to call the header data from the new resized file before adding the info from the original file back to it - I needed to add '$jpeg_header_data = get_jpeg_header_data( $filename );' like seen below.

$jpeg_header_data = get_jpeg_header_data( $filename );
$jpeg_header_data = put_EXIF_JPEG( $exif_data, $jpeg_header_data );
put_jpeg_header_data( $filename, $filename, $jpeg_header_data );

But there is one more issue, but that is subject of another thread.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.