|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653 |
- <?php
- if (!defined('DEDEINC')) exit ('dedebiz');
- /**
- * 图片缩放尺寸
- *
- * @version $id:imageresize.class.php 2022年1月16日 tianya $
- * @package DedeBIZ.Libraries
- * @copyright Copyright (c) 2022 DedeBIZ.COM
- * @license GNU GPL v2 (https://www.dedebiz.com/license)
- * @link https://www.dedebiz.com
- * maintained by Gumlet.com
- */
- class ImageResizeException extends \Exception
- {
- }
- /**
- * PHP class to resize and scale images
- */
- class ImageResize
- {
- const CROPTOP = 1;
- const CROPCENTRE = 2;
- const CROPCENTER = 2;
- const CROPBOTTOM = 3;
- const CROPLEFT = 4;
- const CROPRIGHT = 5;
- const CROPTOPCENTER = 6;
- const IMG_FLIP_HORIZONTAL = 0;
- const IMG_FLIP_VERTICAL = 1;
- const IMG_FLIP_BOTH = 2;
- public $quality_jpg = 85;
- public $quality_webp = 85;
- public $quality_png = 6;
- public $quality_truecolor = true;
- public $gamma_correct = false;
- public $interlace = 1;
- public $source_type;
- protected $source_image;
- protected $original_w;
- protected $original_h;
- protected $dest_x = 0;
- protected $dest_y = 0;
- protected $source_x;
- protected $source_y;
- protected $dest_w;
- protected $dest_h;
- protected $source_w;
- protected $source_h;
- protected $source_info;
- protected $filters = [];
- /**
- * Create instance from a strng
- *
- * @param string $image_data
- * @return ImageResize
- * @throws ImageResizeException
- */
- public static function createFromString($image_data)
- {
- if (empty($image_data) || $image_data === null) {
- throw new ImageResizeException('image_data must not be empty');
- }
- $resize = new self('data://application/octet-stream;base64,'.base64_encode($image_data));
- return $resize;
- }
- /**
- * Add filter function for use right before save image to file.
- *
- * @param callable $filter
- * @return $this
- */
- public function addFilter(callable $filter)
- {
- $this->filters[] = $filter;
- return $this;
- }
- /**
- * Apply filters.
- *
- * @param $image resource an image resource identifier
- * @param $filterType filter type and default value is IMG_FILTER_NEGATE
- */
- protected function applyFilter($image, $filterType = IMG_FILTER_NEGATE)
- {
- foreach ($this->filters as $function) {
- $function($image, $filterType);
- }
- }
- /**
- * Loads image source and its properties to the instanciated object
- *
- * @param string $filename
- * @return ImageResize
- * @throws ImageResizeException
- */
- public function __construct($filename)
- {
- if (!defined('IMAGETYPE_WEBP')) {
- define('IMAGETYPE_WEBP', 18);
- }
- if (!defined('IMAGETYPE_BMP')) {
- define('IMAGETYPE_BMP', 6);
- }
- if ($filename === null || empty($filename) || (substr($filename, 0, 5) !== 'data:' && !is_file($filename))) {
- throw new ImageResizeException('File does not exist');
- }
- $finfo = finfo_open(FILEINFO_MIME_TYPE);
- $checkWebp = false;
- if (strstr(finfo_file($finfo, $filename), 'image') === false) {
- if (version_compare(PHP_VERSION, '7.0.0', '<=') && strstr(file_get_contents($filename), 'WEBPVP8') !== false) {
- $checkWebp = true;
- $this->source_type = IMAGETYPE_WEBP;
- } else {
- throw new ImageResizeException('Unsupported file type');
- }
- } elseif(strstr(finfo_file($finfo, $filename), 'image/webp') !== false) {
- $checkWebp = true;
- $this->source_type = IMAGETYPE_WEBP;
- }
- if (!$image_info = getimagesize($filename, $this->source_info)) {
- $image_info = getimagesize($filename);
- }
- if (!$checkWebp) {
- if (!$image_info) {
- if (strstr(finfo_file($finfo, $filename), 'image') !== false) {
- throw new ImageResizeException('Unsupported image type');
- }
- throw new ImageResizeException('Could not read file');
- }
- $this->original_w = $image_info[0];
- $this->original_h = $image_info[1];
- $this->source_type = $image_info[2];
- }
- switch ($this->source_type) {
- case IMAGETYPE_GIF:
- $this->source_image = imagecreatefromgif($filename);
- break;
- case IMAGETYPE_JPEG:
- $this->source_image = $this->imageCreateJpegfromExif($filename);
- // set new width and height for image, maybe it has changed
- $this->original_w = imagesx($this->source_image);
- $this->original_h = imagesy($this->source_image);
- break;
- case IMAGETYPE_PNG:
- $this->source_image = imagecreatefrompng($filename);
- break;
- case IMAGETYPE_WEBP:
- $this->source_image = imagecreatefromwebp($filename);
- $this->original_w = imagesx($this->source_image);
- $this->original_h = imagesy($this->source_image);
- break;
- case IMAGETYPE_BMP:
- if (version_compare(PHP_VERSION, '7.2.0', '<')) {
- throw new ImageResizeException('For bmp support PHP >= 7.2.0 is required');
- }
- $this->source_image = imagecreatefrombmp($filename);
- break;
- default:
- throw new ImageResizeException('Unsupported image type');
- }
- if (!$this->source_image) {
- throw new ImageResizeException('Could not load image');
- }
- finfo_close($finfo);
- return $this->resize($this->getSourceWidth(), $this->getSourceHeight());
- }
- //http://stackoverflow.com/a/28819866
- public function imageCreateJpegfromExif($filename)
- {
- $img = imagecreatefromjpeg($filename);
- if (!function_exists('exif_read_data') || !isset($this->source_info['APP1']) || strpos($this->source_info['APP1'], 'Exif') !== 0) {
- return $img;
- } try {
- $exif = @exif_read_data($filename);
- } catch (Exception $e) {
- $exif = null;
- }
- if (!$exif || !isset($exif['Orientation'])) {
- return $img;
- }
- $orientation = $exif['Orientation'];
- if ($orientation === 6 || $orientation === 5) {
- $img = imagerotate($img, 270, 0);
- } elseif ($orientation === 3 || $orientation === 4) {
- $img = imagerotate($img, 180, 0);
- } elseif ($orientation === 8 || $orientation === 7) {
- $img = imagerotate($img, 90, 0);
- }
- if ($orientation === 5 || $orientation === 4 || $orientation === 7) {
- imageflip($img, IMG_FLIP_HORIZONTAL);
- }
- return $img;
- }
- /**
- * Saves new image
- *
- * @param string $filename
- * @param integer $image_type
- * @param integer $quality
- * @param integer $permissions
- * @param boolean $exact_size
- * @return static
- */
- public function save($filename, $image_type = null, $quality = null, $permissions = null, $exact_size = false)
- {
- $image_type = $image_type ?: $this->source_type;
- $quality = is_numeric($quality) ? (int) abs($quality) : null;
- switch ($image_type) {
- case IMAGETYPE_GIF:
- if (!empty($exact_size) && is_array($exact_size)) {
- $dest_image = imagecreatetruecolor($exact_size[0], $exact_size[1]);
- } else {
- $dest_image = imagecreatetruecolor($this->getDestWidth(), $this->getDestHeight());
- }
- $background = imagecolorallocatealpha($dest_image, 255, 255, 255, 1);
- imagecolortransparent($dest_image, $background);
- imagefill($dest_image, 0, 0, $background);
- imagesavealpha($dest_image, true);
- break;
- case IMAGETYPE_JPEG:
- if (!empty($exact_size) && is_array($exact_size)) {
- $dest_image = imagecreatetruecolor($exact_size[0], $exact_size[1]);
- $background = imagecolorallocate($dest_image, 255, 255, 255);
- imagefilledrectangle($dest_image, 0, 0, $exact_size[0], $exact_size[1], $background);
- } else {
- $dest_image = imagecreatetruecolor($this->getDestWidth(), $this->getDestHeight());
- $background = imagecolorallocate($dest_image, 255, 255, 255);
- imagefilledrectangle($dest_image, 0, 0, $this->getDestWidth(), $this->getDestHeight(), $background);
- }
- break;
- case IMAGETYPE_WEBP:
- if (version_compare(PHP_VERSION, '5.5.0', '<')) {
- throw new ImageResizeException('For WebP support PHP >= 5.5.0 is required');
- }
- if (!empty($exact_size) && is_array($exact_size)) {
- $dest_image = imagecreatetruecolor($exact_size[0], $exact_size[1]);
- $background = imagecolorallocate($dest_image, 255, 255, 255);
- imagefilledrectangle($dest_image, 0, 0, $exact_size[0], $exact_size[1], $background);
- } else {
- $dest_image = imagecreatetruecolor($this->getDestWidth(), $this->getDestHeight());
- $background = imagecolorallocate($dest_image, 255, 255, 255);
- imagefilledrectangle($dest_image, 0, 0, $this->getDestWidth(), $this->getDestHeight(), $background);
- }
- imagealphablending($dest_image, false);
- imagesavealpha($dest_image, true);
- break;
- case IMAGETYPE_PNG:
- if (!$this->quality_truecolor || !imageistruecolor($this->source_image)) {
- if (!empty($exact_size) && is_array($exact_size)) {
- $dest_image = imagecreate($exact_size[0], $exact_size[1]);
- } else {
- $dest_image = imagecreate($this->getDestWidth(), $this->getDestHeight());
- }
- } else {
- if(!empty($exact_size) && is_array($exact_size)) {
- $dest_image = imagecreatetruecolor($exact_size[0], $exact_size[1]);
- } else {
- $dest_image = imagecreatetruecolor($this->getDestWidth(), $this->getDestHeight());
- }
- }
- imagealphablending($dest_image, false);
- imagesavealpha($dest_image, true);
- $background = imagecolorallocatealpha($dest_image, 255, 255, 255, 127);
- imagecolortransparent($dest_image, $background);
- imagefill($dest_image, 0, 0, $background);
- break;
- case IMAGETYPE_BMP:
- if (version_compare(PHP_VERSION, '7.2.0', '<')) {
- throw new ImageResizeException('For WebP support PHP >= 7.2.0 is required');
- }
- if (!empty($exact_size) && is_array($exact_size)) {
- $dest_image = imagecreatetruecolor($exact_size[0], $exact_size[1]);
- $background = imagecolorallocate($dest_image, 255, 255, 255);
- imagefilledrectangle($dest_image, 0, 0, $exact_size[0], $exact_size[1], $background);
- } else {
- $dest_image = imagecreatetruecolor($this->getDestWidth(), $this->getDestHeight());
- $background = imagecolorallocate($dest_image, 255, 255, 255);
- imagefilledrectangle($dest_image, 0, 0, $this->getDestWidth(), $this->getDestHeight(), $background);
- }
- break;
- }
- imageinterlace($dest_image, $this->interlace);
- if ($this->gamma_correct) {
- imagegammacorrect($this->source_image, 2.2, 1.0);
- }
- if (!empty($exact_size) && is_array($exact_size)) {
- if ($this->getSourceHeight() < $this->getSourceWidth()) {
- $this->dest_x = 0;
- $this->dest_y = ($exact_size[1] - $this->getDestHeight()) / 2;
- }
- if ($this->getSourceHeight() > $this->getSourceWidth()) {
- $this->dest_x = ($exact_size[0] - $this->getDestWidth()) / 2;
- $this->dest_y = 0;
- }
- }
- imagecopyresampled(
- $dest_image,
- $this->source_image,
- $this->dest_x,
- $this->dest_y,
- $this->source_x,
- $this->source_y,
- $this->getDestWidth(),
- $this->getDestHeight(),
- $this->source_w,
- $this->source_h
- );
- if ($this->gamma_correct) {
- imagegammacorrect($dest_image, 1.0, 2.2);
- }
- $this->applyFilter($dest_image);
- switch ($image_type) {
- case IMAGETYPE_GIF:
- imagegif($dest_image, $filename);
- break;
- case IMAGETYPE_JPEG:
- if ($quality === null || $quality > 100) {
- $quality = $this->quality_jpg;
- }
- imagejpeg($dest_image, $filename, $quality);
- break;
- case IMAGETYPE_WEBP:
- if (version_compare(PHP_VERSION, '5.5.0', '<')) {
- throw new ImageResizeException('For WebP support PHP >= 5.5.0 is required');
- }
- if ($quality === null) {
- $quality = $this->quality_webp;
- }
- imagewebp($dest_image, $filename, $quality);
- break;
- case IMAGETYPE_PNG:
- if ($quality === null || $quality > 9) {
- $quality = $this->quality_png;
- }
- imagepng($dest_image, $filename, $quality);
- break;
- case IMAGETYPE_BMP:
- imagebmp($dest_image, $filename, $quality);
- break;
- }
- if ($permissions) {
- chmod($filename, $permissions);
- }
- imagedestroy($dest_image);
- return $this;
- }
- /**
- * Convert the image to string
- *
- * @param int $image_type
- * @param int $quality
- * @return string
- */
- public function getImageAsString($image_type = null, $quality = null)
- {
- $string_temp = tempnam(sys_get_temp_dir(), '');
- $this->save($string_temp, $image_type, $quality);
- $string = file_get_contents($string_temp);
- unlink($string_temp);
- return $string;
- }
- /**
- * Convert the image to string with the current settings
- *
- * @return string
- */
- public function __toString()
- {
- return $this->getImageAsString();
- }
- /**
- * Outputs image to browser
- * @param string $image_type
- * @param integer $quality
- */
- public function output($image_type = null, $quality = null)
- {
- $image_type = $image_type ?: $this->source_type;
- header('Content-Type: '.image_type_to_mime_type($image_type));
- $this->save(null, $image_type, $quality);
- }
- /**
- * Resizes image according to the given short side (short side proportional)
- *
- * @param integer $max_short
- * @param boolean $allow_enlarge
- * @return static
- */
- public function resizeToShortSide($max_short, $allow_enlarge = false)
- {
- if ($this->getSourceHeight() < $this->getSourceWidth()) {
- $ratio = $max_short / $this->getSourceHeight();
- $long = (int) ($this->getSourceWidth() * $ratio);
- $this->resize($long, $max_short, $allow_enlarge);
- } else {
- $ratio = $max_short / $this->getSourceWidth();
- $long = (int) ($this->getSourceHeight() * $ratio);
- $this->resize($max_short, $long, $allow_enlarge);
- }
- return $this;
- }
- /**
- * Resizes image according to the given long side (short side proportional)
- *
- * @param integer $max_long
- * @param boolean $allow_enlarge
- * @return static
- */
- public function resizeToLongSide($max_long, $allow_enlarge = false)
- {
- if ($this->getSourceHeight() > $this->getSourceWidth()) {
- $ratio = $max_long / $this->getSourceHeight();
- $short = (int) ($this->getSourceWidth() * $ratio);
- $this->resize($short, $max_long, $allow_enlarge);
- } else {
- $ratio = $max_long / $this->getSourceWidth();
- $short = (int) ($this->getSourceHeight() * $ratio);
- $this->resize($max_long, $short, $allow_enlarge);
- }
- return $this;
- }
- /**
- * Resizes image according to the given height (width proportional)
- *
- * @param integer $height
- * @param boolean $allow_enlarge
- * @return static
- */
- public function resizeToHeight($height, $allow_enlarge = false)
- {
- $ratio = $height / $this->getSourceHeight();
- $width = (int) ($this->getSourceWidth() * $ratio);
- $this->resize($width, $height, $allow_enlarge);
- return $this;
- }
- /**
- * Resizes image according to the given width (height proportional)
- *
- * @param integer $width
- * @param boolean $allow_enlarge
- * @return static
- */
- public function resizeToWidth($width, $allow_enlarge = false)
- {
- $ratio = $width / $this->getSourceWidth();
- $height = (int) ($this->getSourceHeight() * $ratio);
- $this->resize($width, $height, $allow_enlarge);
- return $this;
- }
- /**
- * Resizes image to best fit inside the given dimensions
- *
- * @param integer $max_width
- * @param integer $max_height
- * @param boolean $allow_enlarge
- * @return static
- */
- public function resizeToBestFit($max_width, $max_height, $allow_enlarge = false)
- {
- if ($this->getSourceWidth() <= $max_width && $this->getSourceHeight() <= $max_height && $allow_enlarge === false) {
- return $this;
- }
- $ratio = $this->getSourceHeight() / $this->getSourceWidth();
- $width = $max_width;
- $height = (int) ($width * $ratio);
- if ($height > $max_height) {
- $height = $max_height;
- $width = (int) ($height / $ratio);
- }
- return $this->resize($width, $height, $allow_enlarge);
- }
- /**
- * Resizes image according to given scale (proportionally)
- *
- * @param integer|float $scale
- * @return static
- */
- public function scale($scale)
- {
- $width = (int) ($this->getSourceWidth() * $scale / 100);
- $height = (int) ($this->getSourceHeight() * $scale / 100);
- $this->resize($width, $height, true);
- return $this;
- }
- /**
- * Resizes image according to the given width and height
- *
- * @param integer $width
- * @param integer $height
- * @param boolean $allow_enlarge
- * @return static
- */
- public function resize($width, $height, $allow_enlarge = false)
- {
- if (!$allow_enlarge) {
- // if the user hasn't explicitly allowed enlarging,
- // but either of the dimensions are larger then the original,
- // then just use original dimensions - this logic may need rethinking
- if ($width > $this->getSourceWidth() || $height > $this->getSourceHeight()) {
- $width = $this->getSourceWidth();
- $height = $this->getSourceHeight();
- }
- }
- $this->source_x = 0;
- $this->source_y = 0;
- $this->dest_w = $width;
- $this->dest_h = $height;
- $this->source_w = $this->getSourceWidth();
- $this->source_h = $this->getSourceHeight();
- return $this;
- }
- /**
- * Crops image according to the given width, height and crop position
- *
- * @param integer $width
- * @param integer $height
- * @param boolean $allow_enlarge
- * @param integer $position
- * @return static
- */
- public function crop($width, $height, $allow_enlarge = false, $position = self::CROPCENTER)
- {
- if (!$allow_enlarge) {
- // this logic is slightly different to resize(),
- // it will only reset dimensions to the original
- // if that particular dimenstion is larger
- if ($width > $this->getSourceWidth()) {
- $width = $this->getSourceWidth();
- }
- if ($height > $this->getSourceHeight()) {
- $height = $this->getSourceHeight();
- }
- }
- $ratio_source = $this->getSourceWidth() / $this->getSourceHeight();
- $ratio_dest = $width / $height;
- if ($ratio_dest < $ratio_source) {
- $this->resizeToHeight($height, $allow_enlarge);
- $excess_width = (int) (($this->getDestWidth() - $width) * $this->getSourceWidth() / $this->getDestWidth());
- $this->source_w = $this->getSourceWidth() - $excess_width;
- $this->source_x = $this->getCropPosition($excess_width, $position);
- $this->dest_w = $width;
- } else {
- $this->resizeToWidth($width, $allow_enlarge);
- $excess_height = (int) (($this->getDestHeight() - $height) * $this->getSourceHeight() / $this->getDestHeight());
- $this->source_h = $this->getSourceHeight() - $excess_height;
- $this->source_y = $this->getCropPosition($excess_height, $position);
- $this->dest_h = $height;
- }
- return $this;
- }
- /**
- * Crops image according to the given width, height, x and y
- *
- * @param integer $width
- * @param integer $height
- * @param integer $x
- * @param integer $y
- * @return static
- */
- public function freecrop($width, $height, $x = false, $y = false)
- {
- if ($x === false || $y === false) {
- return $this->crop($width, $height);
- }
- $this->source_x = $x;
- $this->source_y = $y;
- if ($width > $this->getSourceWidth() - $x) {
- $this->source_w = $this->getSourceWidth() - $x;
- } else {
- $this->source_w = $width;
- }
- if ($height > $this->getSourceHeight() - $y) {
- $this->source_h = $this->getSourceHeight() - $y;
- } else {
- $this->source_h = $height;
- }
- $this->dest_w = $width;
- $this->dest_h = $height;
- return $this;
- }
- /**
- * Gets source width
- *
- * @return integer
- */
- public function getSourceWidth()
- {
- return $this->original_w;
- }
- /**
- * Gets source height
- *
- * @return integer
- */
- public function getSourceHeight()
- {
- return $this->original_h;
- }
- /**
- * Gets width of the destination image
- *
- * @return integer
- */
- public function getDestWidth()
- {
- return $this->dest_w;
- }
- /**
- * Gets height of the destination image
- * @return integer
- */
- public function getDestHeight()
- {
- return $this->dest_h;
- }
- /**
- * Gets crop position (X or Y) according to the given position
- *
- * @param integer $expectedSize
- * @param integer $position
- * @return integer
- */
- protected function getCropPosition($expectedSize, $position = self::CROPCENTER)
- {
- $size = 0;
- switch ($position) {
- case self::CROPBOTTOM:
- case self::CROPRIGHT:
- $size = $expectedSize;
- break;
- case self::CROPCENTER:
- case self::CROPCENTRE:
- $size = $expectedSize / 2;
- break;
- case self::CROPTOPCENTER:
- $size = $expectedSize / 4;
- break;
- }
- return (int) $size;
- }
- /**
- * Enable or not the gamma color correction on the image, enabled by default
- *
- * @param bool $enable
- * @return static
- */
- public function gamma($enable = false)
- {
- $this->gamma_correct = $enable;
- return $this;
- }
- }
- ?>
|