summaryrefslogtreecommitdiffstats
path: root/application/libraries/Image.php
diff options
context:
space:
mode:
authorFlorian Pritz <bluewind@xinu.at>2014-10-03 01:53:27 +0200
committerFlorian Pritz <bluewind@xinu.at>2014-10-03 14:22:34 +0200
commitc3b75b7edba5c56cd4dab24a323167b23814c6bc (patch)
tree7108009090ea773c7024fde57dd6e0be0396a206 /application/libraries/Image.php
parent9b0b9a0e6082b3375ebdadc651c971671c922ebc (diff)
Rework image manipulation class
This is the first of hopefully more classes using namespaces and proper classes that can be used as objects rather than CI's singleton approach. The namespace is mainly used to gain nice autoloading capabilities and it's not really yet used for separation. Signed-off-by: Florian Pritz <bluewind@xinu.at>
Diffstat (limited to 'application/libraries/Image.php')
-rw-r--r--application/libraries/Image.php267
1 files changed, 267 insertions, 0 deletions
diff --git a/application/libraries/Image.php b/application/libraries/Image.php
new file mode 100644
index 000000000..6d6c9e563
--- /dev/null
+++ b/application/libraries/Image.php
@@ -0,0 +1,267 @@
+<?php
+/*
+ * Copyright 2014 Florian "Bluewind" Pritz <bluewind@server-speed.net>
+ *
+ * Licensed under AGPLv3
+ * (see COPYING for full license text)
+ *
+ */
+
+namespace libraries;
+
+/**
+ * This class deals with a single image and provides useful operations that
+ * operate on this image.
+ */
+class Image {
+ private $img;
+ private $source_type;
+ private $exif;
+
+ /**
+ * Create a new object and load the contents of file.
+ * @param file file to read
+ */
+ public function __construct($file)
+ {
+ $this->read($file);
+ }
+
+ /**
+ * Replace the current image by reading in a file
+ * @param file file to read
+ */
+ public function read($file)
+ {
+ $img = imagecreatefromstring(file_get_contents($file));
+ if ($img === false) {
+ show_error("Unsupported image type");
+ }
+ $this->set_img_object($img);
+ $this->fix_alpha();
+
+ $this->source_type = getimagesize($file)[2];
+
+ switch ($this->source_type) {
+ case IMAGETYPE_JPEG:
+ $this->exif = exif_read_data($file);
+ break;
+ default:
+ }
+ }
+
+ /**
+ * Return the current image rendered to a specific format. Passing null as
+ * the target_type returns the image in the format of the source image
+ * (loaded with read()).
+ *
+ * @param target_type one of IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG or null
+ * @return binary image data
+ */
+ public function get($target_type = null)
+ {
+ if ($target_type === null) {
+ $target_type = $this->source_type;
+ }
+
+ ob_start();
+ switch ($target_type) {
+ case IMAGETYPE_GIF:
+ $ret = imagegif($this->img);
+ break;
+ case IMAGETYPE_JPEG:
+ $ret = imagejpeg($this->img);
+ break;
+ case IMAGETYPE_PNG:
+ $ret = imagepng($this->img);
+ break;
+ default:
+ assert(0);
+ }
+ $result = ob_get_clean();
+
+ if (!$ret) {
+ show_error("Failed to create thumbnail");
+ }
+
+ return $result;
+ }
+
+ /**
+ * Resize the image.
+ * @param width
+ * @param height
+ */
+ public function resize($width, $height)
+ {
+ $temp_gdim = imagecreatetruecolor($width, $height);
+ $this->fix_alpha();
+ imagecopyresampled(
+ $temp_gdim,
+ $this->img,
+ 0, 0,
+ 0, 0,
+ $width, $height,
+ imagesx($this->img), imagesy($this->img)
+ );
+
+ $this->set_img_object($temp_gdim);
+ }
+
+ /**
+ * Crop the image to the area defined by x, y, width and height.
+ *
+ * @param x starting coordinate
+ * @param y starting coordinate
+ * @param width width of the area
+ * @param height height of the area
+ */
+ public function crop($x, $y, $width, $height)
+ {
+ $thumb = imagecreatetruecolor($width, $height);
+ $this->fix_alpha();
+ imagecopy(
+ $thumb,
+ $this->img,
+ 0, 0,
+ $x, $y,
+ $width, $height
+ );
+
+ $this->set_img_object($thumb);
+ }
+
+ /**
+ * Crop/resize the image to fit into the desired size. This also rotates
+ * the image if the source image had an EXIF orientation tag.
+ *
+ * @param width width of the resulting image
+ * @param height height of the resulting image
+ */
+ // Source: http://salman-w.blogspot.co.at/2009/04/crop-to-fit-image-using-aspphp.html
+ public function makeThumb($target_width, $target_height)
+ {
+ $source_aspect_ratio = imagesx($this->img) / imagesy($this->img);
+ $desired_aspect_ratio = $target_width / $target_height;
+
+ if ($source_aspect_ratio > $desired_aspect_ratio) {
+ // Triggered when source image is wider
+ $temp_height = $target_height;
+ $temp_width = round(($target_height * $source_aspect_ratio));
+ } else {
+ // Triggered otherwise (i.e. source image is similar or taller)
+ $temp_width = $target_width;
+ $temp_height = round(($target_width / $source_aspect_ratio));
+ }
+
+ $this->resize($temp_width, $temp_height);
+
+ $x0 = ($temp_width - $target_width) / 2;
+ $y0 = ($temp_height - $target_height) / 2;
+ $this->crop($x0, $y0, $target_width, $target_height);
+
+ $this->apply_exif_orientation();
+ }
+
+ static public function get_exif_orientation($file)
+ {
+ $type = getimagesize($file)[2];
+ switch ($type) {
+ case IMAGETYPE_JPEG:
+ $exif = exif_read_data($file);
+ if (isset($exif["Orientation"])) {
+ return $exif["Orientation"];
+ }
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * Rotate the image according to the sources EXIF orientation tag if any.
+ */
+ public function apply_exif_orientation()
+ {
+ if (isset($this->exif['Orientation'])) {
+ $mirror = false;
+ $deg = 0;
+
+ switch ($this->exif['Orientation']) {
+ case 2:
+ $mirror = true;
+ break;
+ case 3:
+ $deg = 180;
+ break;
+ case 4:
+ $deg = 180;
+ $mirror = true;
+ break;
+ case 5:
+ $deg = 270;
+ $mirror = true;
+ break;
+ case 6:
+ $deg = 270;
+ break;
+ case 7:
+ $deg = 90;
+ $mirror = true;
+ break;
+ case 8:
+ $deg = 90;
+ break;
+ }
+
+ if ($deg) {
+ $this->set_img_object(imagerotate($this->img, $deg, 0));
+ }
+
+ if ($mirror) {
+ $this->mirror();
+ }
+ }
+ }
+
+ /**
+ * Mirror the image along the x axis.
+ */
+ public function mirror()
+ {
+ $width = imagesx($this->img);
+ $height = imagesy($this->img);
+
+ $src_x = $width -1;
+ $src_y = 0;
+ $src_width = -$width;
+ $src_height = $height;
+
+ $imgdest = imagecreatetruecolor($width, $height);
+ imagealphablending($imgdest,false);
+ imagesavealpha($imgdest,true);
+
+ imagecopyresampled($imgdest, $this->img, 0, 0, $src_x, $src_y, $width, $height, $src_width, $src_height);
+ $this->set_img_object($imgdest);
+ }
+
+ private function set_img_object($new)
+ {
+ assert($new !== false);
+
+ $old = $this->img;
+ $this->img = $new;
+
+ if ($old != null) {
+ imagedestroy($old);
+ }
+ }
+
+ private function fix_alpha()
+ {
+ imagealphablending($this->img,false);
+ imagesavealpha($this->img,true);
+ }
+
+}