diff --git a/inc/toolbox.php b/inc/toolbox.php index c35722a..865a1ed 100755 --- a/inc/toolbox.php +++ b/inc/toolbox.php @@ -174,7 +174,7 @@ class ToolBox return $iCount > 1; } - public static function createThumbnail($sInPath, $iMaxWidth, $iMaxHeight=0, $sOutPath='', $bDeleteIn=false, $asImageExts=array('jpg', 'jpeg', 'gif', 'png'), $bCrop=false) + public static function createThumbnail($sInPath, $iMaxWidth, $iMaxHeight=0, $sOutPath='', $bDeleteIn=false, $asImageExts=array('jpg', 'jpeg', 'gif', 'png'), $bCrop=false, $bCopyExif=false) { $asResult = array('error'=>''); @@ -194,7 +194,24 @@ class ToolBox elseif($iMaxWidth==0 && $iMaxHeight==0) $asResult['error'] = 'At least one dimension must be resized (width and/or height)'; else { + //Recalculate max width/height in case of rotated picture + $sRotate = 0; + $asExif = @exif_read_data($sInPath); + if($asExif && array_key_exists('Orientation', $asExif)) { + switch($asExif['Orientation']) + { + case 3: $sRotate = 180; break; //Flip over + case 6: $sRotate = -90; break; //Clockwise + case 8: $sRotate = 90; break; //Trigo + } + } + list($iWidth, $iHeight) = getimagesize($sInPath); + if(abs($sRotate) == 90) { + $iTempWidth = $iWidth; + $iWidth = $iHeight; + $iHeight = $iTempWidth; + } //Limit on only 1 parameter if($iMaxWidth==0) $iMaxWidth = $iWidth * $iMaxHeight / $iHeight; @@ -256,6 +273,9 @@ class ToolBox { //create image from source $oSource = call_user_func('imagecreatefrom'.$sImageExt, $sInPath); + + //Fix rotation + if($sRotate) $oSource = imagerotate($oSource, $sRotate, 0); //Resize $oThumb = imagecreatetruecolor($iThumbWidth, $iThumbHeight); @@ -267,6 +287,7 @@ class ToolBox { $asResult['error'] = 'Unable to create thumbnail : '.$sOutPath; } + imagedestroy($oThumb); } } elseif($sInPath != $sOutPath) @@ -280,11 +301,75 @@ class ToolBox $asResult['out'] = $sOutPath; } + if($bCopyExif && $asResult['error'] == '') self::copyExif($sInPath, $sOutPath); if($bDeleteIn && $asResult['error'] == '' && $sInPath != $sOutPath) unlink($sInPath); return $asResult; } + public function copyExif($srcfile, $destfile) { + // Function transfers EXIF (APP1) and IPTC (APP13) from $srcfile and adds it to $destfile + // JPEG file has format 0xFFD8 + [APP0] + [APP1] + ... [APP15] + where [APPi] are optional + // Segment APPi (where i=0x0 to 0xF) has format 0xFFEi + 0xMM + 0xLL + (where 0xMM is + // most significant 8 bits of (strlen() + 2) and 0xLL is the least significant 8 bits + // of (strlen() + 2) + + if (file_exists($srcfile) && file_exists($destfile)) { + $srcsize = @getimagesize($srcfile, $imageinfo); + // Prepare EXIF data bytes from source file + $exifdata = (is_array($imageinfo) && key_exists("APP1", $imageinfo)) ? $imageinfo['APP1'] : null; + if ($exifdata) { + $exiflength = strlen($exifdata) + 2; + if ($exiflength > 0xFFFF) return false; + // Construct EXIF segment + $exifdata = chr(0xFF) . chr(0xE1) . chr(($exiflength >> 8) & 0xFF) . chr($exiflength & 0xFF) . $exifdata; + } + // Prepare IPTC data bytes from source file + $iptcdata = (is_array($imageinfo) && key_exists("APP13", $imageinfo)) ? $imageinfo['APP13'] : null; + if ($iptcdata) { + $iptclength = strlen($iptcdata) + 2; + if ($iptclength > 0xFFFF) return false; + // Construct IPTC segment + $iptcdata = chr(0xFF) . chr(0xED) . chr(($iptclength >> 8) & 0xFF) . chr($iptclength & 0xFF) . $iptcdata; + } + $destfilecontent = @file_get_contents($destfile); + if (!$destfilecontent) return false; + if (strlen($destfilecontent) > 0) { + $destfilecontent = substr($destfilecontent, 2); + $portiontoadd = chr(0xFF) . chr(0xD8); // Variable accumulates new & original IPTC application segments + $exifadded = !$exifdata; + $iptcadded = !$iptcdata; + + while ((substr($destfilecontent, 0, 2) & 0xFFF0) === 0xFFE0) { + $segmentlen = (substr($destfilecontent, 2, 2) & 0xFFFF); + $iptcsegmentnumber = (substr($destfilecontent, 1, 1) & 0x0F); // Last 4 bits of second byte is IPTC segment # + if ($segmentlen <= 2) return false; + $thisexistingsegment = substr($destfilecontent, 0, $segmentlen + 2); + if ((1 <= $iptcsegmentnumber) && (!$exifadded)) { + $portiontoadd .= $exifdata; + $exifadded = true; + if (1 === $iptcsegmentnumber) $thisexistingsegment = ''; + } + if ((13 <= $iptcsegmentnumber) && (!$iptcadded)) { + $portiontoadd .= $iptcdata; + $iptcadded = true; + if (13 === $iptcsegmentnumber) $thisexistingsegment = ''; + } + $portiontoadd .= $thisexistingsegment; + $destfilecontent = substr($destfilecontent, $segmentlen + 2); + } + if (!$exifadded) $portiontoadd .= $exifdata; // Add EXIF data if not added already + if (!$iptcadded) $portiontoadd .= $iptcdata; // Add IPTC data if not added already + $outputfile = fopen($destfile, 'w'); + if ($outputfile) return fwrite($outputfile, $portiontoadd . $destfilecontent); else return false; + } else { + return false; + } + } else { + return false; + } + } + public static function utf8_compliant($sText) { if(strlen($sText) == 0) return true;