Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

honour exif data for jpg thumbnails (aka, prevent thumbnails showing up sideways) #168

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 156 additions & 16 deletions Model/Behavior/UploadBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,7 @@ protected function _resizeImagick(Model $model, $field, $path, $size, $geometry,
}

$image->readImage($srcFile);
$this->_exifRotateImagick($image);
$height = $image->getImageHeight();
$width = $image->getImageWidth();

Expand Down Expand Up @@ -1065,22 +1066,7 @@ protected function _resizePhp(Model $model, $field, $path, $size, $geometry, $th

copy($srcFile, $destFile);
$src = null;
$createHandler = null;
$outputHandler = null;
switch (strtolower($pathInfo['extension'])) {
case 'gif':
$createHandler = 'imagecreatefromgif';
break;
case 'jpg':
case 'jpeg':
$createHandler = 'imagecreatefromjpeg';
break;
case 'png':
$createHandler = 'imagecreatefrompng';
break;
default:
return false;
}

$supportsThumbnailQuality = false;
$adjustedThumbnailQuality = $this->settings[$model->alias][$field]['thumbnailQuality'];
Expand All @@ -1103,7 +1089,9 @@ protected function _resizePhp(Model $model, $field, $path, $size, $geometry, $th
return false;
}

if ($src = $createHandler($destFile)) {
$src = $this->_createImageResource($destFile, $pathInfo);
if ($src) {

$srcW = imagesx($src);
$srcH = imagesy($src);

Expand Down Expand Up @@ -1192,6 +1180,158 @@ protected function _resizePhp(Model $model, $field, $path, $size, $geometry, $th
return false;
}

protected function _createImageResource($filename, $pathInfo) {
switch (strtolower($pathInfo['extension'])) {
case 'gif':
$src = imagecreatefromgif($filename);
break;
case 'jpg':
case 'jpeg':
$src = $this->_imagecreatefromjpegexif($filename);
break;
case 'png':
$src = imagecreatefrompng($filename);
break;
default:
return false;
}

return $src;
}

/**
* Same as imagecreatefromjpeg, but honouring the file's Exif data.
* See http://www.php.net/manual/en/function.imagecreatefromjpeg.php#112902
*/
protected function _imagecreatefromjpegexif($filename) {
$image = imagecreatefromjpeg($filename);
$exif = exif_read_data($filename);
if ($image && $exif && isset($exif['Orientation'])) {
$ort = $exif['Orientation'];
} else {
return $image;
}

$trans = $this->_exifOrientationTransformations($ort);

if ($trans['flip_vert']) {
$image = $this->_flipImage($image,'vert');
}

if ($trans['flip_horz']) {
$image = $this->_flipImage($image,'horz');
}

if ($trans['rotate_clockwise']) {
$image = imagerotate($image, -1 * $trans['rotate_clockwise'], 0);
}

return $image;
}

/**
* Determine what transformations need to be applied to an image,
* in order to maintain it's orientation and get rid of it's Exif Orientation data
* http://www.impulseadventure.com/photo/exif-orientation.html
* @param int $orientation The exif orientation of the image
* @return array of transformations - array keys are:
* 'flip_vert' - true if the image needs to be flipped vertically
* 'flip_horz' - true if the image needs to be flipped horizontally
* 'rotate_clockwise' - number of degrees image needs to be rotated, clockwise
*/
protected function _exifOrientationTransformations($orientation) {
$trans = array(
'flip_vert' => false,
'flip_horz' => false,
'rotate_clockwise' => 0,
);

switch($orientation) {
case 1:
break;

case 2:
$trans['flip_horz'] = true;
break;

case 3:
$trans['rotate_clockwise'] = 180;
break;

case 4:
$trans['flip_vert'] = true;
break;

case 5:
$trans['flip_vert'] = true;
$trans['rotate_clockwise'] = 90;
break;

case 6:
$trans['rotate_clockwise'] = 90;
break;

case 7:
$trans['flip_horz'] = true;
$trans['rotate_clockwise'] = 90;
break;

case 8:
$trans['rotate_clockwise'] = -90;
break;
}

return $trans;
}

/**
* Flip an image object. Code from http://www.roscripts.com/snippets/show/55
* @param resource $img An image resource, such as one returned by imagecreatefromjpeg()
* @param string $type 'horz' or 'vert'
* @return resource The flipped image
*/
protected function _flipImage($img, $type) {
$width = imagesx($img);
$height = imagesy($img);
$dest = imagecreatetruecolor($width, $height);
switch($type){
case 'vert':
for ($i = 0; $i < $height; $i++) {
imagecopy($dest, $img, 0, ($height - $i - 1), 0, $i, $width, 1);
}
break;
case 'horz':
for ($i = 0; $i < $width; $i++) {
imagecopy($dest, $img, ($width - $i - 1), 0, $i, 0, 1, $height);
}
break;
}
return $dest;
}

/**
* rotate an imagick object based on it's exif data.
* @param imagick $image an instance of imagick
*/
protected function _exifRotateImagick($image) {
$orientation = $image->getImageOrientation();
$trans = $this->_exifOrientationTransformations($orientation);

if ($trans['flip_vert']) {
$image->flopImage();
}

if ($trans['flip_horz']) {
$image->flipImage();
}

if ($trans['rotate_clockwise']) {
$image->rotateimage("#000", $trans['rotate_clockwise']);
}

$image->setImageOrientation(imagick::ORIENTATION_TOPLEFT);
}

protected function _getPath(Model $model, $field) {
$path = $this->settings[$model->alias][$field]['path'];
$pathMethod = $this->settings[$model->alias][$field]['pathMethod'];
Expand Down