1
0
mirror of https://github.com/mosbth/cimage.git synced 2025-08-01 05:50:12 +02:00

Cleaning up code #23, added rotate and autoRotate #36

This commit is contained in:
Mikael Roos
2014-08-31 23:57:34 +02:00
parent 67524bd090
commit c96ed10f80
13 changed files with 480 additions and 167 deletions

4
.gitignore vendored
View File

@@ -1,4 +1,4 @@
# Cache files #
######################
cache/_*

cache/*

View File

@@ -151,24 +151,31 @@ class CImage
private $jpegOptimize;
/**
* Image dimensions, calculated from loaded image.
*/
private $width; // Calculated from source image
private $height; // Calculated from source image
/**
* New image dimensions, incoming as argument or calculated.
*/
private $newWidth;
private $newWidthOrig; // Save original value
private $newHeight;
private $newHeightOrig; // Save original value
/**
* Properties (clean up these)
*/
private $offset;
public $keepRatio;
public $cropToFit;
public $crop;
/**
* Properties
*/
public $newWidth;
public $newHeight;
private $cropWidth;
private $cropHeight;
public $crop_x;
@@ -315,6 +322,10 @@ class CImage
// Pre-processing, before resizing is done
'scale' => null,
'rotateBefore' => null,
// General options
'bgColor' => 0,
// Post-processing, after resizing is done
'palette' => null,
@@ -322,6 +333,8 @@ class CImage
'sharpen' => null,
'emboss' => null,
'blur' => null,
'rotateAfter' => null,
'autoRotate' => false,
// Options for saving
//'quality' => null,
@@ -375,6 +388,9 @@ class CImage
$this->{$key} = $args[$key];
}
$this->newWidthOrig = $this->newWidth;
$this->newHeightOrig = $this->newHeight;
return $this;
}
@@ -405,9 +421,9 @@ class CImage
'pixelate' => array('id'=>11, 'argc'=>2, 'type'=>IMG_FILTER_PIXELATE),
);
if (isset($map[$name]))
if (isset($map[$name])) {
return $map[$name];
else {
} else {
throw new Exception('No such filter.');
}
}
@@ -415,13 +431,12 @@ class CImage
/**
* Init new width and height and do some sanity checks on constraints, before any
* processing can be done.
* Load image details from original image file.
*
* @return $this
* @throws Exception
*/
public function initDimensions()
public function loadImageDetails()
{
is_readable($this->pathToImage)
or $this->raiseError('Image file does not exist.');
@@ -436,6 +451,20 @@ class CImage
$this->log("Image filesize: " . filesize($this->pathToImage) . " bytes.");
}
return $this;
}
/**
* Init new width and height and do some sanity checks on constraints, before any
* processing can be done.
*
* @return $this
* @throws Exception
*/
public function initDimensions()
{
// width as %
if ($this->newWidth[strlen($this->newWidth)-1] == '%') {
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
@@ -539,11 +568,16 @@ class CImage
// Calculate new width and height if keeping aspect-ratio.
if ($this->keepRatio) {
$this->log("Keep aspect ratio.");
// Crop-to-fit and both new width and height are set.
if ($this->cropToFit && isset($this->newWidth) && isset($this->newHeight)) {
// Use newWidth and newHeigh as width/height, image should fit in box.
;
$this->log("Use newWidth and newHeigh as width/height, image should fit in box.");
} elseif (isset($this->newWidth) && isset($this->newHeight)) {
// Both new width and height are set.
// Use newWidth and newHeigh as max width/height, image should not be larger.
$ratioWidth = $width / $this->newWidth;
@@ -551,18 +585,27 @@ class CImage
$ratio = ($ratioWidth > $ratioHeight) ? $ratioWidth : $ratioHeight;
$this->newWidth = round($width / $ratio);
$this->newHeight = round($height / $ratio);
$this->log("New width and height was set.");
} elseif (isset($this->newWidth)) {
// Use new width as max-width
$factor = (float)$this->newWidth / (float)$width;
$this->newHeight = round($factor * $height);
$this->log("New width was set.");
} elseif (isset($this->newHeight)) {
// Use new height as max-hight
$factor = (float)$this->newHeight / (float)$height;
$this->newWidth = round($factor * $width);
$this->log("New height was set.");
}
// Use newWidth and newHeigh as defined width/height, image should fit the area.
if ($this->cropToFit) {
$this->log("Crop to fit.");
$ratioWidth = $width / $this->newWidth;
$ratioHeight = $height / $this->newHeight;
$ratio = ($ratioWidth < $ratioHeight) ? $ratioWidth : $ratioHeight;
@@ -573,6 +616,7 @@ class CImage
// Crop, ensure to set new width and height
if ($this->crop) {
$this->log("Crop.");
$this->newWidth = round(isset($this->newWidth) ? $this->newWidth : $this->crop['width']);
$this->newHeight = round(isset($this->newHeight) ? $this->newHeight : $this->crop['height']);
}
@@ -587,6 +631,26 @@ class CImage
/**
* Re-calculate image dimensions when original image dimension has changed.
*
* @return $this
*/
public function reCalculateDimensions()
{
$this->log("Re-calculate image dimensions, newWidth x newHeigh was: " . $this->newWidth . " x " . $this->newHeight);
$this->newWidth = $this->newWidthOrig;
$this->newHeight = $this->newHeightOrig;
$this->initDimensions()
->calculateNewWidthAndHeight();
return $this;
}
/**
* Set extension for filename to save as.
*
@@ -677,6 +741,10 @@ class CImage
&& !$this->quality
&& !$this->compress
&& !$this->saveAs
&& !$this->rotateBefore
&& !$this->rotateAfter
&& !$this->autoRotate
&& !$this->bgColor
) {
$this->log("Using original image.");
$this->output($this->pathToImage);
@@ -700,8 +768,11 @@ class CImage
$crop_x = $this->crop_x ? "_x{$this->crop_x}" : null;
$crop_y = $this->crop_y ? "_y{$this->crop_y}" : null;
$scale = $this->scale ? "_s{$this->scale}" : null;
$bgColor = $this->bgColor ? "_bgc{$this->bgColor}" : null;
$quality = $this->quality ? "_q{$this->quality}" : null;
$compress = $this->compress ? "_co{$this->compress}" : null;
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$offset = isset($this->offset)
? '_o' . $this->offset['top'] . '-' . $this->offset['right'] . '-' . $this->offset['bottom'] . '-' . $this->offset['left']
@@ -728,6 +799,8 @@ class CImage
$blur = $this->blur ? 'b' : null;
$palette = $this->palette ? 'p' : null;
$autoRotate = $this->autoRotate ? 'ar' : null;
$this->extension = isset($this->extension)
? $this->extension
: $parts['extension'];
@@ -746,7 +819,7 @@ class CImage
$file = $subdir . '_' . $parts['filename'] . '_' . round($this->newWidth) . '_'
. round($this->newHeight) . $offset . $crop . $cropToFit . $crop_x . $crop_y
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $optimize
. $scale . '.' . $this->extension;
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor . '.' . $this->extension;
return $this->setTarget($file, $base);
}
@@ -955,6 +1028,20 @@ class CImage
{
$this->log("Pre-process before resizing");
// Rotate image
if ($this->rotateBefore) {
$this->log("Rotating image.");
$this->rotate($this->rotateBefore, $this->bgColor)
->reCalculateDimensions();
}
// Auto-rotate image
if ($this->autoRotate) {
$this->log("Auto rotating image.");
$this->rotateExif()
->reCalculateDimensions();
}
// Scale the original image before starting
if (isset($this->scale)) {
$this->log("Scale by {$this->scale}%");
@@ -1055,6 +1142,12 @@ class CImage
{
$this->log("Post-process after resizing");
// Rotate image
if ($this->rotateAfter) {
$this->log("Rotating image.");
$this->rotate($this->rotateAfter, $this->bgColor);
}
// Apply filters
if (isset($this->filters) && is_array($this->filters)) {
@@ -1115,6 +1208,73 @@ class CImage
/**
* Rotate image using angle.
*
* @param float $angle to rotate image.
* @param int $anglebgColor to fill image with if needed.
*
* @return $this
*/
public function rotate($angle, $bgColor)
{
$this->log("Rotate image " . $angle . " degrees with filler color " . $bgColor);
$this->image = imagerotate($this->image, $angle, $bgColor);
$this->width = imagesx($this->image);
$this->height = imagesy($this->image);
$this->log("New image dimension width x height: " . $this->width . " x " . $this->height);
return $this;
}
/**
* Rotate image using information in EXIF.
*
* @return $this
*/
public function rotateExif()
{
if (!in_array($this->fileExtension, array('jpg', 'jpeg'))) {
$this->log("Autorotate ignored, EXIF not supported by this filetype.");
return $this;
}
$exif = exif_read_data($this->pathToImage);
if (!empty($exif['Orientation'])) {
switch ($exif['Orientation']) {
case 3:
$this->log("Autorotate 180.");
$this->rotate(180, $this->bgColor);
break;
case 6:
$this->log("Autorotate -90.");
$this->rotate(-90, $this->bgColor);
break;
case 8:
$this->log("Autorotate 90.");
$this->rotate(90, $this->bgColor);
break;
default:
$this->log("Autorotate ignored, unknown value as orientation.");
}
} else {
$this->log("Autorotate ignored, no orientation in EXIF.");
}
return $this;
}
/**
* Convert true color image to palette image, keeping alpha.
* http://stackoverflow.com/questions/5752514/how-to-convert-png-to-8-bit-png-using-php-gd-library

View File

@@ -133,6 +133,13 @@ Revision history
v0.5.x (latest)
* Broke API when `initDimensions()` split into two methods, new `initDimensions()` and `loadImageDetails()`.
* Added `autoRotate,`aro` to auto rotate image based on EXIF information.
* Added `bgColor,`bgc` to use as backgroundcolor when needing a filler color.
* Added `rotate,`r` as an alias to `rotateAfter`.
* Added `rotateBefore,`rb` to rotate image a certain angle before processing.
* Added `rotateAfter,`ra` to rotate image a certain angle after processing.
* Cleaned up code formatting, removed trailing spaces.
* Removed @ from opening images, better to display correct warning when failing #34, but put it back again.
* Setting gd.jpeg_ignore_warning to true as default #34.
* `webroot/check_system.php` now outputs version of PHP and GD.

View File

@@ -306,7 +306,7 @@ verbose("save as = $saveAs");
$scale = get(array('scale', 's'));
is_null($scale)
or ($scale >= 0 and $quality <= 400)
or ($scale >= 0 and $scale <= 400)
or errorPage('Scale out of range');
verbose("scale = $scale");
@@ -349,6 +349,68 @@ verbose("blur = $blur");
/**
* rotate - Rotate the image with an angle, before processing
*/
/*
$rotate = get(array('rotate', 'r'));
is_null($rotate)
or ($rotate >= -360 and $rotate <= 360)
or errorPage('Rotate out of range');
verbose("rotate = $rotate");
*/
/**
* rotateBefore - Rotate the image with an angle, before processing
*/
$rotateBefore = get(array('rotateBefore', 'rb'));
is_null($rotateBefore)
or ($rotateBefore >= -360 and $rotateBefore <= 360)
or errorPage('RotateBefore out of range');
verbose("rotateBefore = $rotateBefore");
/**
* rotateAfter - Rotate the image with an angle, before processing
*/
$rotateAfter = get(array('rotateAfter', 'ra', 'rotate', 'r'));
is_null($rotateAfter)
or ($rotateAfter >= -360 and $rotateAfter <= 360)
or errorPage('RotateBefore out of range');
verbose("rotateAfter = $rotateAfter");
/**
* bgColor - Default background color to use
*/
$bgColor = hexdec(get(array('bgColor', 'bgc')));
is_null($bgColor)
or ($bgColor >= 0 and $bgColor <= hexdec("FFFFFF"))
or errorPage('Background color needs a hex value');
verbose("bgColor = $bgColor");
/**
* autoRotate - Auto rotate based on EXIF information
*/
$autoRotate = getDefined(array('autoRotate', 'aro'), true, false);
verbose("autoRotate = $autoRotate");
/**
* filter, f, f0-f9 - Processing option, post filter for various effects using imagefilter()
*/
@@ -411,6 +473,10 @@ $img->setVerbose($verbose)
// Pre-processing, before resizing is done
'scale' => $scale,
'rotateBefore' => $rotateBefore,
// General processing options
'bgColor' => $bgColor,
// Post-processing, after resizing is done
'palette' => $palette,
@@ -418,8 +484,11 @@ $img->setVerbose($verbose)
'sharpen' => $sharpen,
'emboss' => $emboss,
'blur' => $blur,
'rotateAfter' => $rotateAfter,
'autoRotate' => $autoRotate,
)
)
->loadImageDetails()
->initDimensions()
->calculateNewWidthAndHeight()
->setSaveAsExtension($saveAs)

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

77
webroot/test_issue36.php Normal file
View File

@@ -0,0 +1,77 @@
<!doctype html>
<head>
<meta charset='utf-8'/>
<title>Testing img for issue 36</title>
<style>
body {background-color: #ccc;}
</style>
</head>
<body>
<h1>Testing issue 36</h1>
<?php
error_reporting(-1); // Report all type of errors
ini_set('display_errors', 1); // Display all errors
ini_set('output_buffering', 0); // Do not buffer outputs, write directly
$imgphp = "img.php?src=";
$images = array(
'issue36/me-0.jpg',
'issue36/me-90.jpg',
'issue36/me-180.jpg',
'issue36/me-270.jpg',
'issue36/flower-0.jpg',
'issue36/flower-90.jpg',
'issue36/flower-180.jpg',
'issue36/flower-270.jpg',
);
$testcase = array(
'&aro&nc',
'&aro&nc&w=200',
'&aro&nc&h=200',
'&aro&nc&w=200&h=200&cf',
);
?>
<h2>Images used in test</h2>
<p>The following images are used for this test.</p>
<?php foreach($images as $image) : ?>
<p><code><a href="img/<?=$image?>"><?=$image?></a></code><br>
<img src="<?=$imgphp . $image?>"></p>
<?php endforeach; ?>
<h2>Testcases used for each image</h2>
<p>The following testcases are used for each image.</p>
<?php foreach($testcase as $tc) : ?>
<code><?=$tc?></code><br>
<?php endforeach; ?>
<h2>Applying testcase for each image</h2>
<?php foreach($images as $image) : ?>
<h3><?=$image?></h3>
<p><code><a href="img/<?=$image?>"><?=$image?></a></code><br>
<img src="<?=$imgphp . $image?>"></p>
<?php foreach($testcase as $tc) : ?>
<h4><?=$tc?></h4>
<p><code><a href="<?=$imgphp . $image . $tc?>"><?=$image . $tc?></a></code><br>
<img src="<?=$imgphp . $image . $tc?>"></p>
<?php endforeach; ?>
<?php endforeach; ?>