skip to Main Content

Our server is saving EXIF data to every file saved with imagejpeg(). As far as I know, this is not the default behavior (or even possible, from what I’ve read). But, it is occurring, and due to the FileDateTime information being included (and using the time of save), it is breaking functionality in our upload/approval system (md5_file() returns a different value for the exact same image due to FileDateTime always being different).

Is there a way to prevent imagejpeg() from saving EXIF data for images by default?

Server Information

  • CentOS 5
  • Parallels Plesk Panel 10.4.4
  • GD Version: bundled (2.0.34 compatible)
  • PHP 5.3

Code

<?php
public function upload_book_cover($book, $cover, $filename = NULL, $approved = NULL){
    global $c_consummo, $user;
    $approved = bool($approved, true, true);
    if(filesize($cover)>5242880){
        return false; // Too large;
    }
    $max_width = 450;
    $cover_info = getimagesize($cover);
    if(!$this->is_valid_book_cover_type($cover_info['mime'])){
        return false; // Invalid image type
    }
    $width = $cover_info[0];
    $height = $cover_info[1];
    if($width<200){
        return false; // Too small
    } elseif($width>1500){
        return false; // Too wide
    }
    $original_cover = false;
    switch($cover_info[2]){
        case IMAGETYPE_GIF:
            $original_cover = imagecreatefromgif($cover);
            break;
        case IMAGETYPE_JPEG:
            $original_cover = imagecreatefromjpeg($cover);
            break;
        case IMAGETYPE_PNG:
            $original_cover = imagecreatefrompng($cover);
            break;
        case IMAGETYPE_BMP:
            $original_cover = imagecreatefrombmp($cover);
            break;
    }
    if(!$original_cover){
        return false; // Unsupported type
    }
    if($width>$max_width){
        $new_width = $max_width;
    } else {
        $new_width = $width;
    }
    $new_height = round($height*($new_width/$width));
    $new_cover = imagecreatetruecolor($new_width, $new_height);
    if(!$new_cover){
        return false; // Could not create true color image
    }
    if(!imagecopyresampled($new_cover, $original_cover, 0, 0, 0, 0, $new_width, $new_height, $width, $height)){
        return false; // Could not copy image
    }
    if(!imagejpeg($new_cover, $cover, 100)){
        return false; // Image could not be saved to tmp file
        // This is adding *new* EXIF data to images by itself
    }
    $file_hash = md5_file($cover);
    $duplicate_book_cover = $this->find_duplicate_book_cover($book, $file_hash);
    if($duplicate_book_cover){
        return $duplicate_book_cover;
    }
    $file_id = $c_consummo->upload_file($cover, $filename);
    ...
}

10

Answers


  1. You could possibly convert the jpeg to a gif first, then convert the gif back to a jpeg. In doing so, my understanding is that you would destroy the EXIF data. It’s a hack, but it should work.

    Login or Signup to reply.
  2. You could try using imagecreatefromjpeg on the image created with imagejpeg and replacing with the newly created one.

    Login or Signup to reply.
  3. $res = imagecreatefromjpeg($filename) to load the image, then imagejpeg($res, $filename, QUALITY)to rerender it.

    You can use imagemagick too:

    $img = new Imagick($image);
        $img->stripImage();
        $img->writeImage($image);
        $img->clear();
        $img->destroy();
    
    Login or Signup to reply.
  4. It looks like you have tried several things here, but lets try one more.
    Do you EVER need EXIF information in your application?
    If not lets take out support for EXIF and see if that completely removes it.

    If it does not remove it, then perhaps the functions are reading it from the existing photos and then just blindly including it in the file that is written.
    You can know for sure by printing out the EXIF information at each step of process

    Login or Signup to reply.
  5. No idea why EXIF data is being written – so the following may help you remove it.

    One suggestion is to run something as a command on the server – it will need some installation: http://hacktux.com/read/remove/exif – then run throuhg EXEC from PHP.

    There’s also solution posted here that uses ImageMagick if you also have that installed (or cen get it installed: Remove EXIF data from JPG using PHP (but note warning about colour)

    Otherwise, the other suggestion is as above, try turning off the EXIT extension.

    Sorry if they don’t help, but you did ask for any suggestions.

    Login or Signup to reply.
  6. The only thing that spring to mind is, that you could ignore the EXIF data and just make your hash from something else? My suggestion would be to try either hashing the raw output without saving to a file (here outputting in gif format -which makes a smaller, 8-bit image for performance- to an output buffer and hashing the buffer content)

    if(!imagecopyresampled(...)) {...}
    ob_start();
    imagegif($new_cover);
    $file_hash = md5(ob_get_contents());
    ob_end_clean();
    if(!imagejpeg($new_cover, $cover, 100)) {...}
    

    Or you could build a string containing only the pixel information and hash that (here done by accessing each pixel and appending its value to a string, in reverse for performance)

    $pixels = '';
    for($x=$new_width-1; $x>=0; $x--) {
      for($y=$new_height-1; $y>=0; $y--) {
        $pixels .= imagecolorat($new_cover, $x, $y);
      }
    }
    $file_hash = md5($pixels);
    

    For performance, you could also choose only to take samples from the image, as this should work just as well or maybe even better (here sampling every 5th pixel of every 5th row)

    $pixels = '';
    for($x=$new_width-1; $x>=0; $x-=5) {
      for($y=$new_height-1; $y>=0; $y-=5) {
        $pixels .= imagecolorat($new_cover, $x, $y);
      }
    }
    $file_hash = md5($pixels);
    

    I hope some of this will work (as I can’t test it right now) or at least will help you find the way that works for you 🙂

    Login or Signup to reply.
  7. This is a bit of a hack, but it will work, just do this after your switch() statement:

    $original_cover = imagerotate($original_cover,360,0);
    

    GD will strip any EXIF data out, as it doesn’t support it.

    Login or Signup to reply.
  8. Your PHP must be compiled in with --enable-exif.

    Try to disable globally EXIF functionality by recompiling PHP without this option.

    Login or Signup to reply.
  9. Apparently, GD doesn’t like when the path to the input / output file is the same, but the credit isn’t mine. To fix, use a new (tmp) file to save the newly created image to:

    <?php
    ...
    if(!imagecopyresampled($new_cover, $original_cover, 0, 0, 0, 0, $new_width, $new_height, $width, $height)){
     return false; // Could not copy image
    }
    // Create a tmp file.
    $cover_new = tempnam('/tmp', 'cover-');
    // Use $cover_new instead of $cover
    if(!imagejpeg($new_cover, $cover_new, 100)){
     return false; // Image could not be saved to tmp file
    }
    // Use $cover_new instead of $cover
    $file_hash = md5_file($cover_new);
    $duplicate_book_cover = $this->find_duplicate_book_cover($book, $file_hash);
    if($duplicate_book_cover){
     return $duplicate_book_cover;
    }
    // Use $cover_new instead of $cover
    $file_id = $c_consummo->upload_file($cover_new, $filename);
    ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search