Bug #54173 [Opn->Ver]: Repeated iptcembed() corrupts JPEG file
| From: | cmb@php.net | Date: | Sat, 18 Jul 2015 00:11:39 +0000 |
| Subject: | Bug #54173 [Opn->Ver]: Repeated iptcembed() corrupts JPEG file | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-194523@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=54173&edit=1
ID: 54173
Updated by: cmb@php.net
Reported by: axelgauffre at gmail dot com
-Summary: After you write IPTC several times in the same JPEG
file, the file is corrupted
+Summary: Repeated iptcembed() corrupts JPEG file
-Status: Open
+Status: Verified
Type: Bug
Package: GD related
-Operating System: Vista 64
+Operating System: *
-PHP Version: 5.3.5
+PHP Version: 5.6.11
-Assigned To:
+Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
Confirmed.
Previous Comments:
------------------------------------------------------------------------
[2011-03-06 11:27:50] axelgauffre at gmail dot com
Description:
------------
Sometimes writing IPTC in a JPEG file seems to corrupt it.
This behaviour happens after you write several times in the same file (after 10 to
20 times or so...).
The consequence is that the next call to GetImageSize on this file will fail.
I don't know if the problem comes from iptcembed or from GetImageSize.
I am using Wampserver 2 with PHP 5.3.0 on Vista 64.
Test script:
---------------
<?php
$file_path_and_name="020SC_BF0196D001_M.jpg";
$iptc_field_to_modify="2#005";
//Read IPTC from file
if (!GetImageSize($file_path_and_name, $getimagesize_result))
{
echo("GetImageSize error<br />");
die();
}
//Handle return from GetImageSize
if (!isset($getimagesize_result["APP13"]))
$iptc_array=array();
else
{
//Get APP13
$iptcparse_result=iptcparse($getimagesize_result["APP13"]);
if ($iptcparse_result===false)
{
echo("iptcparse error<br />");
die();
}
//Handle iptcparse result
$iptc_array=array();
foreach ($iptcparse_result as $iptcparse_index => &$iptcparse_value)
{
$iptc_array[$iptcparse_index]="";
for($i=0;$i<count($iptcparse_value);$i++)
$iptc_array[$iptcparse_index].=($i<count($iptcparse_value)-1)?$iptcparse_value[$i].",":$iptcparse_value[$i];
}
}
//foreach($iptc_array as $index => $value)
// echo($index." ".$value."<br />");
if (isset($iptc_array["2#005"]))
echo($iptc_array["2#005"]."<br />");
//Modify the value in the IPTC array
$iptc_array[$iptc_field_to_modify]=rand (1, 1000);
//Transform the the IPTC array into a string to be used by iptcembed
$string_for_iptcembed="";
foreach($iptc_array as $iptc_array_index => &$iptc_array_value)
{
$iptc_array_index=substr($iptc_array_index, 2);
$length = strlen($iptc_array_value);
$retval = chr(0x1C).chr(2).chr($iptc_array_index);
if($length < 0x8000)
$retval .= chr($length >> 8).chr($length& 0xFF);
else{
$retval .= chr(0x80).chr(0x04).
chr(($length >> 24)& 0xFF).
chr(($length >> 16)& 0xFF).
chr(($length >> 8)& 0xFF).
chr($length& 0xFF);
}
$string_for_iptcembed.=$retval.$iptc_array_value;
}
//Call to iptcembed
$binary_data=iptcembed($string_for_iptcembed, $file_path_and_name);
if ($binary_data===false)
{
echo("iptcembed error<br />");
die();
}
//TODO ??? It doesn't solve the problem anyway...
//@unlink($file_path_and_name);//delete if exists
//Open file for writing
if (DIRECTORY_SEPARATOR=="/")
$file = fopen($file_path_and_name, "w");//linux
else if (DIRECTORY_SEPARATOR=="\\")
$file = fopen($file_path_and_name, "wb");//windows
if(!$file)
{
echo("fopen error<br />");
die();
}
//Writing
if (false===fwrite($file, $binary_data))
{
echo("fwrite error<br />");
if(fclose($file)===false)
echo("fclose error<br />");
die();
}
//Close file
if(fclose($file)===false)
{
echo("fclose error<br />");
die();
}
//Let's check that everything went fine:
//Sometimes writing IPTC in a JPEG file seems to corrupt it.
//This behaviour happens after you write several times in the same file (after 10 to 20 times or
so...).
//The only solution I found to fix the problem: create a new file with imagecreatefromjpeg. But this
has 2 main inconvenients:
// - it takes long (3 to 4 seconds with a high res file)
// - you loose every other metadata: XMP, EXIF...
if(false===GetImageSize($file_path_and_name, $bogus))
{
echo("!!!!!!!!!!!!!!!!!!!!!! GetImageSize error !!!!!!!!!!!!!!!!!!!!!!!!!!!<br
/>");
$image = imagecreatefromjpeg($file_path_and_name);
if ($image===false)
{
echo("imagecreatefromjpeg error<br />");
die();
}
if (false===imagejpeg($image, $file_path_and_name))
{
echo("imagejpeg error<br />");
die();
}
}
?>
Expected result:
----------------
Each call should do exactly the same as the previous one : read and write IPTC
metadata.
Actual result:
--------------
After several times, GetImageSize returns false.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=54173&edit=1