aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs/Photo/PhotoImagick.php
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs/Photo/PhotoImagick.php')
-rw-r--r--Zotlabs/Photo/PhotoImagick.php200
1 files changed, 200 insertions, 0 deletions
diff --git a/Zotlabs/Photo/PhotoImagick.php b/Zotlabs/Photo/PhotoImagick.php
new file mode 100644
index 000000000..a7026e8ca
--- /dev/null
+++ b/Zotlabs/Photo/PhotoImagick.php
@@ -0,0 +1,200 @@
+<?php
+
+namespace Zotlabs\Photo;
+
+/**
+ * @brief ImageMagick photo driver.
+ */
+class PhotoImagick extends PhotoDriver {
+
+ public function supportedTypes() {
+ return [
+ 'image/jpeg' => 'jpg',
+ 'image/png' => 'png',
+ 'image/gif' => 'gif',
+ ];
+ }
+
+ private function get_FormatsMap() {
+ return [
+ 'image/jpeg' => 'JPG',
+ 'image/png' => 'PNG',
+ 'image/gif' => 'GIF',
+ ];
+ }
+
+
+ protected function load($data, $type) {
+ $this->valid = false;
+ $this->image = new \Imagick();
+
+ if(! $data)
+ return;
+
+ try {
+ $this->image->readImageBlob($data);
+ } catch(\Exception $e) {
+ logger('Imagick readImageBlob() exception:' . print_r($e, true));
+ return;
+ }
+
+ /*
+ * Setup the image to the format it will be saved to
+ */
+
+ $map = $this->get_FormatsMap();
+ $format = $map[$type];
+
+ if($this->image) {
+ $this->image->setFormat($format);
+
+ // Always coalesce, if it is not a multi-frame image it won't hurt anyway
+ $this->image = $this->image->coalesceImages();
+
+ $this->valid = true;
+ $this->setDimensions();
+
+ /*
+ * setup the compression here, so we'll do it only once
+ */
+ switch($this->getType()) {
+ case 'image/png':
+ $quality = get_config('system', 'png_quality');
+ if((! $quality) || ($quality > 9))
+ $quality = PNG_QUALITY;
+ /*
+ * From http://www.imagemagick.org/script/command-line-options.php#quality:
+ *
+ * 'For the MNG and PNG image formats, the quality value sets
+ * the zlib compression level (quality / 10) and filter-type (quality % 10).
+ * The default PNG "quality" is 75, which means compression level 7 with adaptive PNG filtering,
+ * unless the image has a color map, in which case it means compression level 7 with no PNG filtering'
+ */
+ $quality = $quality * 10;
+ $this->image->setCompressionQuality($quality);
+ break;
+ case 'image/jpeg':
+ $quality = get_config('system', 'jpeg_quality');
+ if((! $quality) || ($quality > 100))
+ $quality = JPEG_QUALITY;
+ $this->image->setCompressionQuality($quality);
+ default:
+ break;
+ }
+ }
+ }
+
+ protected function destroy() {
+ if($this->is_valid()) {
+ $this->image->clear();
+ $this->image->destroy();
+ }
+ }
+
+ protected function setDimensions() {
+ $this->width = $this->image->getImageWidth();
+ $this->height = $this->image->getImageHeight();
+ }
+
+ /**
+ * @brief Strips the image of all profiles and comments.
+ *
+ * Keep ICC profile for better colors.
+ *
+ * @see \Zotlabs\Photo\PhotoDriver::clearexif()
+ */
+ public function clearexif() {
+ $profiles = $this->image->getImageProfiles('icc', true);
+
+ $this->image->stripImage();
+
+ if(! empty($profiles)) {
+ $this->image->profileImage('icc', $profiles['icc']);
+ }
+ }
+
+
+ /**
+ * @brief Return a \Imagick object of the current image.
+ *
+ * @see \Zotlabs\Photo\PhotoDriver::getImage()
+ *
+ * @return boolean|\Imagick
+ */
+ public function getImage() {
+ if(! $this->is_valid())
+ return false;
+
+ $this->image = $this->image->deconstructImages();
+ return $this->image;
+ }
+
+ public function doScaleImage($dest_width, $dest_height) {
+ /*
+ * If it is not animated, there will be only one iteration here,
+ * so don't bother checking
+ */
+ // Don't forget to go back to the first frame
+ $this->image->setFirstIterator();
+ do {
+ $this->image->scaleImage($dest_width, $dest_height);
+ } while($this->image->nextImage());
+
+ $this->setDimensions();
+ }
+
+ public function rotate($degrees) {
+ if(! $this->is_valid())
+ return false;
+
+ $this->image->setFirstIterator();
+ do {
+ // ImageMagick rotates in the opposite direction of imagerotate()
+ $this->image->rotateImage(new \ImagickPixel(), -$degrees);
+ } while($this->image->nextImage());
+
+ $this->setDimensions();
+ }
+
+ public function flip($horiz = true, $vert = false) {
+ if(! $this->is_valid())
+ return false;
+
+ $this->image->setFirstIterator();
+ do {
+ if($horiz) $this->image->flipImage();
+ if($vert) $this->image->flopImage();
+ } while($this->image->nextImage());
+
+ $this->setDimensions(); // Shouldn't really be necessary
+ }
+
+ public function cropImageRect($maxx, $maxy, $x, $y, $w, $h) {
+ if(! $this->is_valid())
+ return false;
+
+ $this->image->setFirstIterator();
+ do {
+ $this->image->cropImage($w, $h, $x, $y);
+ /*
+ * We need to remove the canvas,
+ * or the image is not resized to the crop:
+ * http://php.net/manual/en/imagick.cropimage.php#97232
+ */
+ $this->image->setImagePage(0, 0, 0, 0);
+ } while($this->image->nextImage());
+
+ $this->doScaleImage($maxx, $maxy);
+ }
+
+ public function imageString() {
+ if(! $this->is_valid())
+ return false;
+
+ /* Clean it */
+ $this->image = $this->image->deconstructImages();
+
+ return $this->image->getImagesBlob();
+ }
+
+}