377 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			377 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace Gregwar\Image\Adapter;
 | |
| 
 | |
| abstract class Common extends Adapter
 | |
| {
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function zoomCrop($width, $height, $background = 'transparent', $xPosLetter = 'center', $yPosLetter = 'center')
 | |
|     {
 | |
|         // Calculate the different ratios
 | |
|         $originalRatio = $this->width() / $this->height();
 | |
|         $newRatio = $width / $height;
 | |
| 
 | |
|         // Compare ratios
 | |
|         if ($originalRatio > $newRatio) {
 | |
|             // Original image is wider
 | |
|             $newHeight = $height;
 | |
|             $newWidth = (int) $height * $originalRatio;
 | |
|         } else {
 | |
|             // Equal width or smaller
 | |
|             $newHeight = (int) $width / $originalRatio;
 | |
|             $newWidth = $width;
 | |
|         }
 | |
| 
 | |
|         // Perform resize
 | |
|         $this->resize($newWidth, $newHeight, $background, true);
 | |
| 
 | |
|         // Define x position
 | |
|         switch ($xPosLetter) {
 | |
|             case 'L':
 | |
|             case 'left':
 | |
|                 $xPos = 0;
 | |
|                 break;
 | |
|             case 'R':
 | |
|             case 'right':
 | |
|                 $xPos = (int) $newWidth - $width;
 | |
|                 break;
 | |
|             default:
 | |
|                 $xPos = (int) ($newWidth - $width) / 2;
 | |
|         }
 | |
| 
 | |
|         // Define y position
 | |
|         switch ($yPosLetter) {
 | |
|             case 'T':
 | |
|             case 'top':
 | |
|                 $yPos = 0;
 | |
|                 break;
 | |
|             case 'B':
 | |
|             case 'bottom':
 | |
|                 $yPos = (int) $newHeight - $height;
 | |
|                 break;
 | |
|             default:
 | |
|                 $yPos = (int) ($newHeight - $height) / 2;
 | |
|         }
 | |
| 
 | |
|         // Crop image to reach desired size
 | |
|         $this->crop($xPos, $yPos, $width, $height);
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Resizes the image forcing the destination to have exactly the
 | |
|      * given width and the height.
 | |
|      *
 | |
|      * @param int $w  the width
 | |
|      * @param int $h  the height
 | |
|      * @param int $bg the background
 | |
|      */
 | |
|     public function forceResize($width = null, $height = null, $background = 'transparent')
 | |
|     {
 | |
|         return $this->resize($width, $height, $background, true);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function scaleResize($width = null, $height = null, $background = 'transparent', $crop = false)
 | |
|     {
 | |
|         return $this->resize($width, $height, $background, false, true, $crop);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function cropResize($width = null, $height = null, $background = 'transparent')
 | |
|     {
 | |
|         return $this->resize($width, $height, $background, false, false, true);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Fix orientation using Exif informations.
 | |
|      */
 | |
|     public function fixOrientation()
 | |
|     {
 | |
|         if (!in_array(exif_imagetype($this->source->getInfos()), array(IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM))) {
 | |
|             return $this;
 | |
|         }
 | |
| 
 | |
|         if (!extension_loaded('exif')) {
 | |
|             throw new \RuntimeException('You need to EXIF PHP Extension to use this function');
 | |
|         }
 | |
| 
 | |
|         $exif = @exif_read_data($this->source->getInfos());
 | |
| 
 | |
|         if ($exif === false || !array_key_exists('Orientation', $exif)) {
 | |
|             return $this;
 | |
|         }
 | |
| 
 | |
|         switch ($exif['Orientation']) {
 | |
|             case 1:
 | |
|                 break;
 | |
| 
 | |
|             case 2:
 | |
|                 $this->flip(false, true);
 | |
|                 break;
 | |
| 
 | |
|             case 3: // 180 rotate left
 | |
|                 $this->rotate(180);
 | |
|                 break;
 | |
| 
 | |
|             case 4: // vertical flip
 | |
|                 $this->flip(true, false);
 | |
|                 break;
 | |
| 
 | |
|             case 5: // vertical flip + 90 rotate right
 | |
|                 $this->flip(true, false);
 | |
|                 $this->rotate(-90);
 | |
|                 break;
 | |
| 
 | |
|             case 6: // 90 rotate right
 | |
|                 $this->rotate(-90);
 | |
|                 break;
 | |
| 
 | |
|             case 7: // horizontal flip + 90 rotate right
 | |
|                 $this->flip(false, true);
 | |
|                 $this->rotate(-90);
 | |
|                 break;
 | |
| 
 | |
|             case 8: // 90 rotate left
 | |
|                 $this->rotate(90);
 | |
|                 break;
 | |
|         }
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Opens the image.
 | |
|      */
 | |
|     abstract protected function openGif($file);
 | |
| 
 | |
|     abstract protected function openJpeg($file);
 | |
| 
 | |
|     abstract protected function openPng($file);
 | |
| 
 | |
|     /**
 | |
|      * Creates an image.
 | |
|      */
 | |
|     abstract protected function createImage($width, $height);
 | |
| 
 | |
|     /**
 | |
|      * Creating an image using $data.
 | |
|      */
 | |
|     abstract protected function createImageFromData($data);
 | |
| 
 | |
|     /**
 | |
|      * Loading image from $resource.
 | |
|      */
 | |
|     protected function loadResource($resource)
 | |
|     {
 | |
|         $this->resource = $resource;
 | |
|     }
 | |
| 
 | |
|     protected function loadFile($file, $type)
 | |
|     {
 | |
|         if (!$this->supports($type)) {
 | |
|             throw new \RuntimeException('Type '.$type.' is not supported by GD');
 | |
|         }
 | |
| 
 | |
|         if ($type == 'jpeg') {
 | |
|             $this->openJpeg($file);
 | |
|         }
 | |
| 
 | |
|         if ($type == 'gif') {
 | |
|             $this->openGif($file);
 | |
|         }
 | |
| 
 | |
|         if ($type == 'png') {
 | |
|             $this->openPng($file);
 | |
|         }
 | |
| 
 | |
|         if (false === $this->resource) {
 | |
|             throw new \UnexpectedValueException('Unable to open file ('.$file.')');
 | |
|         } else {
 | |
|             $this->convertToTrueColor();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function init()
 | |
|     {
 | |
|         $source = $this->source;
 | |
| 
 | |
|         if ($source instanceof \Gregwar\Image\Source\File) {
 | |
|             $this->loadFile($source->getFile(), $source->guessType());
 | |
|         } elseif ($source instanceof \Gregwar\Image\Source\Create) {
 | |
|             $this->createImage($source->getWidth(), $source->getHeight());
 | |
|         } elseif ($source instanceof \Gregwar\Image\Source\Data) {
 | |
|             $this->createImageFromData($source->getData());
 | |
|         } elseif ($source instanceof \Gregwar\Image\Source\Resource) {
 | |
|             $this->loadResource($source->getResource());
 | |
|         } else {
 | |
|             throw new \Exception('Unsupported image source type '.get_class($source));
 | |
|         }
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function deinit()
 | |
|     {
 | |
|         $this->resource = null;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function resize($width = null, $height = null, $background = 'transparent', $force = false, $rescale = false, $crop = false)
 | |
|     {
 | |
|         $current_width = $this->width();
 | |
|         $current_height = $this->height();
 | |
|         $new_width = 0;
 | |
|         $new_height = 0;
 | |
|         $scale = 1.0;
 | |
| 
 | |
|         if ($height === null && preg_match('#^(.+)%$#mUsi', $width, $matches)) {
 | |
|             $width = round($current_width * ((float) $matches[1] / 100.0));
 | |
|             $height = round($current_height * ((float) $matches[1] / 100.0));
 | |
|         }
 | |
| 
 | |
|         if (!$rescale && (!$force || $crop)) {
 | |
|             if ($width != null && $current_width > $width) {
 | |
|                 $scale = $current_width / $width;
 | |
|             }
 | |
| 
 | |
|             if ($height != null && $current_height > $height) {
 | |
|                 if ($current_height / $height > $scale) {
 | |
|                     $scale = $current_height / $height;
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             if ($width != null) {
 | |
|                 $scale = $current_width / $width;
 | |
|                 $new_width = $width;
 | |
|             }
 | |
| 
 | |
|             if ($height != null) {
 | |
|                 if ($width != null && $rescale) {
 | |
|                     $scale = max($scale, $current_height / $height);
 | |
|                 } else {
 | |
|                     $scale = $current_height / $height;
 | |
|                 }
 | |
|                 $new_height = $height;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (!$force || $width == null || $rescale) {
 | |
|             $new_width = round($current_width / $scale);
 | |
|         }
 | |
| 
 | |
|         if (!$force || $height == null || $rescale) {
 | |
|             $new_height = round($current_height / $scale);
 | |
|         }
 | |
| 
 | |
|         if ($width == null || $crop) {
 | |
|             $width = $new_width;
 | |
|         }
 | |
| 
 | |
|         if ($height == null || $crop) {
 | |
|             $height = $new_height;
 | |
|         }
 | |
| 
 | |
|         $this->doResize($background, $width, $height, $new_width, $new_height);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Trim background color arround the image.
 | |
|      *
 | |
|      * @param int $bg the background
 | |
|      */
 | |
|     protected function _trimColor($background = 'transparent')
 | |
|     {
 | |
|         $width = $this->width();
 | |
|         $height = $this->height();
 | |
| 
 | |
|         $b_top = 0;
 | |
|         $b_lft = 0;
 | |
|         $b_btm = $height - 1;
 | |
|         $b_rt = $width - 1;
 | |
| 
 | |
|         //top
 | |
|         for (; $b_top < $height; ++$b_top) {
 | |
|             for ($x = 0; $x < $width; ++$x) {
 | |
|                 if ($this->getColor($x, $b_top) != $background) {
 | |
|                     break 2;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // bottom
 | |
|         for (; $b_btm >= 0; --$b_btm) {
 | |
|             for ($x = 0; $x < $width; ++$x) {
 | |
|                 if ($this->getColor($x, $b_btm) != $background) {
 | |
|                     break 2;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // left
 | |
|         for (; $b_lft < $width; ++$b_lft) {
 | |
|             for ($y = $b_top; $y <= $b_btm; ++$y) {
 | |
|                 if ($this->getColor($b_lft, $y) != $background) {
 | |
|                     break 2;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // right
 | |
|         for (; $b_rt >= 0; --$b_rt) {
 | |
|             for ($y = $b_top; $y <= $b_btm; ++$y) {
 | |
|                 if ($this->getColor($b_rt, $y) != $background) {
 | |
|                     break 2;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         ++$b_btm;
 | |
|         ++$b_rt;
 | |
| 
 | |
|         $this->crop($b_lft, $b_top, $b_rt - $b_lft, $b_btm - $b_top);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Resizes the image to an image having size of $target_width, $target_height, using
 | |
|      * $new_width and $new_height and padding with $bg color.
 | |
|      */
 | |
|     abstract protected function doResize($bg, $target_width, $target_height, $new_width, $new_height);
 | |
| 
 | |
|     /**
 | |
|      * Gets the color of the $x, $y pixel.
 | |
|      */
 | |
|     abstract protected function getColor($x, $y);
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function enableProgressive()
 | |
|     {
 | |
|         throw new \Exception('The Adapter '.$this->getName().' does not support Progressive Image loading');
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This does nothing, but can be used to tag a ressource for instance (having a final image hash
 | |
|      * for the cache different depending on the tag)
 | |
|      */
 | |
|     public function tag($tag)
 | |
|     {
 | |
|     }
 | |
| }
 |