高效的JPEG图像在PHP中的大小调整。

时间:2022-09-25 21:19:50

What's the most efficient way to resize large images in PHP?

在PHP中,调整大图像大小最有效的方法是什么?

I'm currently using the GD function imagecopyresampled to take high resolution images, and cleanly resize them down to a size for web viewing (roughly 700 pixels wide by 700 pixels tall).

我目前正在使用GD函数imagecopysampling来获取高分辨率的图像,并且干净地将它们的大小调整为web view的大小(大约700像素宽,700像素高)。

This works great on small (under 2 MB) photos and the entire resize operation takes less than a second on the server. However, the site will eventually service photographers who may be uploading images up to 10 MB in size (or images up to 5000x4000 pixels in size).

这对于小(小于2 MB)的照片非常有效,整个调整大小操作在服务器上只需要不到一秒。然而,该网站最终将服务于摄影师,他们上传的图片大小可达10mb(或者图片大小可达5000x4000像素)。

Doing this kind of resize operation with large images tends to increase the memory usage by a very large margin (larger images can spike the memory usage for the script past 80 MB). Is there any way to make this resize operation more efficient? Should I be using an alternate image library such as ImageMagick?

使用大图像执行这种调整大小的操作会增加很大的内存使用量(较大的图像会增加超过80 MB的脚本的内存使用量)。有没有什么方法可以使调整大小的操作更有效?我应该使用另一个图像库(比如ImageMagick)吗?

Right now, the resize code looks something like this

现在,resize代码看起来是这样的。

function makeThumbnail($sourcefile, $endfile, $thumbwidth, $thumbheight, $quality) {
    // Takes the sourcefile (path/to/image.jpg) and makes a thumbnail from it
    // and places it at endfile (path/to/thumb.jpg).

    // Load image and get image size.
    $img = imagecreatefromjpeg($sourcefile);
    $width = imagesx( $img );
    $height = imagesy( $img );

    if ($width > $height) {
        $newwidth = $thumbwidth;
        $divisor = $width / $thumbwidth;
        $newheight = floor( $height / $divisor);
    } else {
        $newheight = $thumbheight;
        $divisor = $height / $thumbheight;
        $newwidth = floor( $width / $divisor );
    }

    // Create a new temporary image.
    $tmpimg = imagecreatetruecolor( $newwidth, $newheight );

    // Copy and resize old image into new image.
    imagecopyresampled( $tmpimg, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height );

    // Save thumbnail into a file.
    imagejpeg( $tmpimg, $endfile, $quality);

    // release the memory
    imagedestroy($tmpimg);
    imagedestroy($img);

9 个解决方案

#1


44  

People say that ImageMagick is much faster. At best just compare both libraries and measure that.

人们说ImageMagick要快得多。最好只是比较这两个库并进行度量。

  1. Prepare 1000 typical images.
  2. 准备1000年典型的图像。
  3. Write two scripts -- one for GD, one for ImageMagick.
  4. 写两个脚本——一个用于GD,一个用于ImageMagick。
  5. Run both of them a few times.
  6. 同时运行它们几次。
  7. Compare results (total execution time, CPU and I/O usage, result image quality).
  8. 比较结果(总执行时间、CPU和I/O使用情况、结果图像质量)。

Something which the best everyone else, could not be the best for you.

对你来说,最好的每个人都不是最好的。

Also, in my opinion, ImageMagick has much better API interface.

而且,在我看来,ImageMagick有更好的API接口。

#2


19  

Here's a snippet from the php.net docs that I've used in a project and works fine:

以下是我在一个项目中使用的php.net文档的一个片段,效果很好:

<?
function fastimagecopyresampled (&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 3) {
    // Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled.
    // Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled".
    // Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting.
    // Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain.
    //
    // Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero.
    // Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect.
    // 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized.
    // 2 = Up to 95 times faster.  Images appear a little sharp, some prefer this over a quality of 3.
    // 3 = Up to 60 times faster.  Will give high quality smooth results very close to imagecopyresampled, just faster.
    // 4 = Up to 25 times faster.  Almost identical to imagecopyresampled for most images.
    // 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled.

    if (empty($src_image) || empty($dst_image) || $quality <= 0) { return false; }
    if ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) {
        $temp = imagecreatetruecolor ($dst_w * $quality + 1, $dst_h * $quality + 1);
        imagecopyresized ($temp, $src_image, 0, 0, $src_x, $src_y, $dst_w * $quality + 1, $dst_h * $quality + 1, $src_w, $src_h);
        imagecopyresampled ($dst_image, $temp, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $dst_w * $quality, $dst_h * $quality);
        imagedestroy ($temp);
    } else imagecopyresampled ($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
    return true;
}
?>

http://us.php.net/manual/en/function.imagecopyresampled.php#77679

http://us.php.net/manual/en/function.imagecopyresampled.php # 77679

#3


11  

phpThumb uses ImageMagick whenever possible for speed (falling back to GD if necessary) and seems to cache pretty well to reduce the load on the server. It's pretty lightweight to try out (to resize an image, just call phpThumb.php with a GET query that includes the graphic filename and output dimensions), so you might give it a shot to see if it meets your needs.

phpThumb尽可能地使用ImageMagick来提高速度(如果需要,可以回到GD),并且似乎可以很好地缓存,以减少服务器上的负载。它是相当轻量级的尝试(要调整图像的大小,只需调用phpThumb。php的GET查询包含图形文件名和输出维度),因此您可以尝试查看它是否满足您的需求。

#4


9  

For larger images use libjpeg to resize on image load in ImageMagick and thereby significantly reducing memory usage and improving performance, it is not possible with GD.

对于较大的图像,使用libjpeg在ImageMagick中调整图像负载的大小,从而显著减少内存使用并提高性能,使用GD是不可能的。

$im = new Imagick();
try {
  $im->pingImage($file_name);
} catch (ImagickException $e) {
  throw new Exception(_('Invalid or corrupted image file, please try uploading another image.'));
}

$width  = $im->getImageWidth();
$height = $im->getImageHeight();
if ($width > $config['width_threshold'] || $height > $config['height_threshold'])
{
  try {
/* send thumbnail parameters to Imagick so that libjpeg can resize images
 * as they are loaded instead of consuming additional resources to pass back
 * to PHP.
 */
    $fitbyWidth = ($config['width_threshold'] / $width) > ($config['height_threshold'] / $height);
    $aspectRatio = $height / $width;
    if ($fitbyWidth) {
      $im->setSize($config['width_threshold'], abs($width * $aspectRatio));
    } else {
      $im->setSize(abs($height / $aspectRatio), $config['height_threshold']);
    }
    $im->readImage($file_name);

/* Imagick::thumbnailImage(fit = true) has a bug that it does fit both dimensions
 */
//  $im->thumbnailImage($config['width_threshold'], $config['height_threshold'], true);

// workaround:
    if ($fitbyWidth) {
      $im->thumbnailImage($config['width_threshold'], 0, false);
    } else {
      $im->thumbnailImage(0, $config['height_threshold'], false);
    }

    $im->setImageFileName($thumbnail_name);
    $im->writeImage();
  }
  catch (ImagickException $e)
  {
    header('HTTP/1.1 500 Internal Server Error');
    throw new Exception(_('An error occured reszing the image.'));
  }
}

/* cleanup Imagick
 */
$im->destroy();

#5


8  

From you quesion, it seems you are kinda new to GD, I will share some experence of mine, maybe this is a bit off topic, but I think it will be helpful to someone new to GD like you:

从你的问题来看,你似乎对GD有点陌生,我将分享一些我的经验,也许这有点偏离主题,但是我认为它会对像你这样的GD新人有帮助:

Step 1, validate file. Use the following function to check if the $_FILES['image']['tmp_name'] file is valid file:

步骤1、验证文件。使用以下函数检查$_FILES['image']['tmp_name']文件是否为有效文件:

   function getContentsFromImage($image) {
      if (@is_file($image) == true) {
         return file_get_contents($image);
      } else {
         throw new \Exception('Invalid image');
      }
   }
   $contents = getContentsFromImage($_FILES['image']['tmp_name']);

Step 2, get file format Try the following function with finfo extension to check file format of the file(contents). You would say why don't you just use $_FILES["image"]["type"] to check file format? Because it ONLY check file extension not file contents, if someone rename a file originally called world.png to world.jpg, $_FILES["image"]["type"] will return jpeg not png, so $_FILES["image"]["type"] may return wrong result.

第二步,获取文件格式请尝试使用finfo扩展名来检查文件(内容)的文件格式。你会说为什么不使用$_FILES["image"]["type"]来检查文件格式?因为它只检查文件扩展名而不是文件内容,如果有人重新命名了一个名为world的文件。png到world.jpg, $_FILES["image"]["type"]将返回jpeg而不是png,因此$_FILES["image"]["type"]可能返回错误的结果。

   function getFormatFromContents($contents) {
      $finfo = new \finfo();
      $mimetype = $finfo->buffer($contents, FILEINFO_MIME_TYPE);
      switch ($mimetype) {
         case 'image/jpeg':
            return 'jpeg';
            break;
         case 'image/png':
            return 'png';
            break;
         case 'image/gif':
            return 'gif';
            break;
         default:
            throw new \Exception('Unknown or unsupported image format');
      }
   }
   $format = getFormatFromContents($contents);

Step.3, Get GD resource Get GD resource from contents we have before:

第3步,获取GD资源从我们之前的内容中获取GD资源:

   function getGDResourceFromContents($contents) {
      $resource = @imagecreatefromstring($contents);
      if ($resource == false) {
         throw new \Exception('Cannot process image');
      }
      return $resource;
   }
   $resource = getGDResourceFromContents($contents);

Step 4, get image dimension Now you can get image dimension with the following simple code:

第4步,获得图像尺寸,现在你可以用下面的简单代码得到图像维数:

  $width = imagesx($resource);
  $height = imagesy($resource);

Now, Let's see what variable we got from the original image then:

现在,让我们看看我们从原始图像中得到了什么变量:

       $contents, $format, $resource, $width, $height
       OK, lets move on

Step 5, calculate resized image arguments This step is related to your question, the purpose of the following function is to get resize arguments for GD function imagecopyresampled(), the code is kinda long, but it works great, it even has three options: stretch, shrink, and fill.

第5步,计算调整大小的图像参数这一步与您的问题有关,下面函数的目的是为GD函数imagecopysampling()获取调整大小的参数,代码有点长,但是它工作得很好,它甚至有三个选项:拉伸、收缩和填充。

stretch: output image's dimension is the same as the new dimension you set. Won't keep height/width ratio.

拉伸:输出图像的尺寸与您设置的新尺寸相同,不会保持高/宽比。

shrink: output image's dimension won't exceed the new dimension you give, and keep image height/width ratio.

收缩:输出图像的尺寸不会超过你给的新尺寸,保持图像的高度/宽度比。

fill: output image's dimension will be the same as new dimension you give, it will crop & resize image if needed, and keep image height/width ratio. This option is what you need in your question.

填充:输出图像的尺寸将与您提供的新尺寸相同,如果需要,它将对图像进行裁剪和调整大小,并保持图像的高度/宽度比。这个选项是您在问题中需要的。

   function getResizeArgs($width, $height, $newwidth, $newheight, $option) {
      if ($option === 'stretch') {
         if ($width === $newwidth && $height === $newheight) {
            return false;
         }
         $dst_w = $newwidth;
         $dst_h = $newheight;
         $src_w = $width;
         $src_h = $height;
         $src_x = 0;
         $src_y = 0;
      } else if ($option === 'shrink') {
         if ($width <= $newwidth && $height <= $newheight) {
            return false;
         } else if ($width / $height >= $newwidth / $newheight) {
            $dst_w = $newwidth;
            $dst_h = (int) round(($newwidth * $height) / $width);
         } else {
            $dst_w = (int) round(($newheight * $width) / $height);
            $dst_h = $newheight;
         }
         $src_x = 0;
         $src_y = 0;
         $src_w = $width;
         $src_h = $height;
      } else if ($option === 'fill') {
         if ($width === $newwidth && $height === $newheight) {
            return false;
         }
         if ($width / $height >= $newwidth / $newheight) {
            $src_w = (int) round(($newwidth * $height) / $newheight);
            $src_h = $height;
            $src_x = (int) round(($width - $src_w) / 2);
            $src_y = 0;
         } else {
            $src_w = $width;
            $src_h = (int) round(($width * $newheight) / $newwidth);
            $src_x = 0;
            $src_y = (int) round(($height - $src_h) / 2);
         }
         $dst_w = $newwidth;
         $dst_h = $newheight;
      }
      if ($src_w < 1 || $src_h < 1) {
         throw new \Exception('Image width or height is too small');
      }
      return array(
          'dst_x' => 0,
          'dst_y' => 0,
          'src_x' => $src_x,
          'src_y' => $src_y,
          'dst_w' => $dst_w,
          'dst_h' => $dst_h,
          'src_w' => $src_w,
          'src_h' => $src_h
      );
   }
   $args = getResizeArgs($width, $height, 150, 170, 'fill');

Step 6, resize image Use $args, $width, $height, $format and $resource we got from above into the following function and get the new resource of the resized image:

第6步,使用$args、$width、$height、$format和$resource对图像进行调整,我们从上面获得如下的函数,得到调整后的图像的新资源:

   function runResize($width, $height, $format, $resource, $args) {
      if ($args === false) {
         return; //if $args equal to false, this means no resize occurs;
      }
      $newimage = imagecreatetruecolor($args['dst_w'], $args['dst_h']);
      if ($format === 'png') {
         imagealphablending($newimage, false);
         imagesavealpha($newimage, true);
         $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
         imagefill($newimage, 0, 0, $transparentindex);
      } else if ($format === 'gif') {
         $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
         imagefill($newimage, 0, 0, $transparentindex);
         imagecolortransparent($newimage, $transparentindex);
      }
      imagecopyresampled($newimage, $resource, $args['dst_x'], $args['dst_y'], $args['src_x'], $args['src_y'], $args['dst_w'], $args['dst_h'], $args['src_w'], $args['src_h']);
      imagedestroy($resource);
      return $newimage;
   }
   $newresource = runResize($width, $height, $format, $resource, $args);

Step 7, get new contents, Use the following function to get contents from the new GD resource:

步骤7,获取新的内容,使用以下函数从新的GD资源中获取内容:

   function getContentsFromGDResource($resource, $format) {
      ob_start();
      switch ($format) {
         case 'gif':
            imagegif($resource);
            break;
         case 'jpeg':
            imagejpeg($resource, NULL, 100);
            break;
         case 'png':
            imagepng($resource, NULL, 9);
      }
      $contents = ob_get_contents();
      ob_end_clean();
      return $contents;
   }
   $newcontents = getContentsFromGDResource($newresource, $format);

Step 8 get extension, Use the following function to get extension of from image format(note, image format is not equal to image extension):

step8 get extension,使用以下函数从图像格式得到扩展(注意,图像格式不等于图像扩展):

   function getExtensionFromFormat($format) {
      switch ($format) {
         case 'gif':
            return 'gif';
            break;
         case 'jpeg':
            return 'jpg';
            break;
         case 'png':
            return 'png';
      }
   }
   $extension = getExtensionFromFormat($format);

Step 9 save image If we have a user named mike, you can do the following, it will save to the same folder as this php script:

步骤9保存图片如果我们有一个叫mike的用户,你可以做以下的操作,它会保存到和这个php脚本相同的文件夹:

$user_name = 'mike';
$filename = $user_name . '.' . $extension;
file_put_contents($filename, $newcontents);

Step 10 destroy resource Don't forget destroy GD resource!

10 .破坏资源不要忘记破坏GD资源!

imagedestroy($newresource);

or you can write all your code into a class, and simply use the following:

或者你可以把你所有的代码写进一个类中,简单地使用下面的代码:

   public function __destruct() {
      @imagedestroy($this->resource);
   }

TIPS

提示

I recommend not to convert file format that user upload, you will meet many problems.

我建议不要转换用户上传的文件格式,你会遇到很多问题。

#6


3  

I suggest that you work something along these lines:

我建议你沿着这条线工作:

  1. Perform a getimagesize( ) on the uploaded file to check image type and size
  2. 对上传的文件执行getimagesize()检查图像类型和大小
  3. Save any uploaded JPEG image smaller than 700x700px in to the destination folder "as-is"
  4. 将上传的小于700x700px的JPEG图像保存到目标文件夹“原样”
  5. Use GD library for medium size images (see this article for code sample: Resize Images Using PHP and GD Library)
  6. 对于中等大小的图像使用GD库(参见本文的代码示例:使用PHP和GD库调整图像大小)
  7. Use ImageMagick for large images. You can use ImageMagick in background if you prefer.
  8. 对大型图像使用ImageMagick。如果您愿意,可以在后台使用ImageMagick。

To use ImageMagick in background, move the uploaded files to a temporary folder and schedule a CRON job that "convert"s all files to jpeg and resizes them accordingly. See command syntax at: imagemagick-command line processing

要在后台使用ImageMagick,请将上传的文件移动到临时文件夹,并安排一个CRON作业,将所有文件“转换”为jpeg并相应地调整大小。参见命令语法:imagemagick-命令行处理

You can prompt the user that file is uploaded and scheduled to be processed. The CRON job could be scheduled to run daily at a specific interval. The source image could be deleted after processing to assure that an image is not processed twice.

您可以提示用户文件被上传并计划被处理。CRON作业可以安排在特定的时间间隔内每天运行。处理后可以删除源映像,以确保不会对映像进行两次处理。

#7


2  

I've heard big things about the Imagick library, unfortunately I couldn't install it at my work computer and neither at home (and trust me, I spent hours and hours on all kinds of forums).

我听说过关于Imagick图书馆的大事情,不幸的是,我不能在我的工作电脑上安装它,也不能在家里(相信我,我花了好几个小时在各种各样的论坛上)。

Afterwords, I've decided to try this PHP class:

最后,我决定尝试这个PHP类:

http://www.verot.net/php_class_upload.htm

http://www.verot.net/php_class_upload.htm

It's pretty cool and I can resize all kinds of images (I can convert them to JPG also).

它很酷,我可以调整各种图片的大小(我也可以把它们转换成JPG格式)。

#8


2  

ImageMagick is multithreaded, so it appears to be faster, but actually uses a lot more resources than GD. If you ran several PHP scripts in parallel all using GD then they'd beat ImageMagick in speed for simple operations. ExactImage is less powerful than ImageMagick but a lot faster, though not available through PHP, you'll have to install it on the server and run it through exec.

ImageMagick是多线程的,所以它看起来更快,但是实际上比GD使用更多的资源。如果您使用GD并行运行多个PHP脚本,那么对于简单的操作来说,它们的速度将超过ImageMagick。ExactImage不如ImageMagick强大,但是速度要快得多,虽然不能通过PHP获得,但是您必须将它安装在服务器上并通过exec运行。

#9


1  

For larger images use phpThumb(). Here is how to use it: http://abcoder.com/php/problem-with-resizing-corrupted-images-using-php-image-functions/. It also works for large corrupted images.

对于较大的图像,使用phpThumb()。这里是如何使用它的:http://abcoder.com/php/problem with-resizing- -image- use -php-image-functions/。它也适用于大的损坏图像。

#1


44  

People say that ImageMagick is much faster. At best just compare both libraries and measure that.

人们说ImageMagick要快得多。最好只是比较这两个库并进行度量。

  1. Prepare 1000 typical images.
  2. 准备1000年典型的图像。
  3. Write two scripts -- one for GD, one for ImageMagick.
  4. 写两个脚本——一个用于GD,一个用于ImageMagick。
  5. Run both of them a few times.
  6. 同时运行它们几次。
  7. Compare results (total execution time, CPU and I/O usage, result image quality).
  8. 比较结果(总执行时间、CPU和I/O使用情况、结果图像质量)。

Something which the best everyone else, could not be the best for you.

对你来说,最好的每个人都不是最好的。

Also, in my opinion, ImageMagick has much better API interface.

而且,在我看来,ImageMagick有更好的API接口。

#2


19  

Here's a snippet from the php.net docs that I've used in a project and works fine:

以下是我在一个项目中使用的php.net文档的一个片段,效果很好:

<?
function fastimagecopyresampled (&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 3) {
    // Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled.
    // Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled".
    // Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting.
    // Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain.
    //
    // Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero.
    // Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect.
    // 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized.
    // 2 = Up to 95 times faster.  Images appear a little sharp, some prefer this over a quality of 3.
    // 3 = Up to 60 times faster.  Will give high quality smooth results very close to imagecopyresampled, just faster.
    // 4 = Up to 25 times faster.  Almost identical to imagecopyresampled for most images.
    // 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled.

    if (empty($src_image) || empty($dst_image) || $quality <= 0) { return false; }
    if ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) {
        $temp = imagecreatetruecolor ($dst_w * $quality + 1, $dst_h * $quality + 1);
        imagecopyresized ($temp, $src_image, 0, 0, $src_x, $src_y, $dst_w * $quality + 1, $dst_h * $quality + 1, $src_w, $src_h);
        imagecopyresampled ($dst_image, $temp, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $dst_w * $quality, $dst_h * $quality);
        imagedestroy ($temp);
    } else imagecopyresampled ($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
    return true;
}
?>

http://us.php.net/manual/en/function.imagecopyresampled.php#77679

http://us.php.net/manual/en/function.imagecopyresampled.php # 77679

#3


11  

phpThumb uses ImageMagick whenever possible for speed (falling back to GD if necessary) and seems to cache pretty well to reduce the load on the server. It's pretty lightweight to try out (to resize an image, just call phpThumb.php with a GET query that includes the graphic filename and output dimensions), so you might give it a shot to see if it meets your needs.

phpThumb尽可能地使用ImageMagick来提高速度(如果需要,可以回到GD),并且似乎可以很好地缓存,以减少服务器上的负载。它是相当轻量级的尝试(要调整图像的大小,只需调用phpThumb。php的GET查询包含图形文件名和输出维度),因此您可以尝试查看它是否满足您的需求。

#4


9  

For larger images use libjpeg to resize on image load in ImageMagick and thereby significantly reducing memory usage and improving performance, it is not possible with GD.

对于较大的图像,使用libjpeg在ImageMagick中调整图像负载的大小,从而显著减少内存使用并提高性能,使用GD是不可能的。

$im = new Imagick();
try {
  $im->pingImage($file_name);
} catch (ImagickException $e) {
  throw new Exception(_('Invalid or corrupted image file, please try uploading another image.'));
}

$width  = $im->getImageWidth();
$height = $im->getImageHeight();
if ($width > $config['width_threshold'] || $height > $config['height_threshold'])
{
  try {
/* send thumbnail parameters to Imagick so that libjpeg can resize images
 * as they are loaded instead of consuming additional resources to pass back
 * to PHP.
 */
    $fitbyWidth = ($config['width_threshold'] / $width) > ($config['height_threshold'] / $height);
    $aspectRatio = $height / $width;
    if ($fitbyWidth) {
      $im->setSize($config['width_threshold'], abs($width * $aspectRatio));
    } else {
      $im->setSize(abs($height / $aspectRatio), $config['height_threshold']);
    }
    $im->readImage($file_name);

/* Imagick::thumbnailImage(fit = true) has a bug that it does fit both dimensions
 */
//  $im->thumbnailImage($config['width_threshold'], $config['height_threshold'], true);

// workaround:
    if ($fitbyWidth) {
      $im->thumbnailImage($config['width_threshold'], 0, false);
    } else {
      $im->thumbnailImage(0, $config['height_threshold'], false);
    }

    $im->setImageFileName($thumbnail_name);
    $im->writeImage();
  }
  catch (ImagickException $e)
  {
    header('HTTP/1.1 500 Internal Server Error');
    throw new Exception(_('An error occured reszing the image.'));
  }
}

/* cleanup Imagick
 */
$im->destroy();

#5


8  

From you quesion, it seems you are kinda new to GD, I will share some experence of mine, maybe this is a bit off topic, but I think it will be helpful to someone new to GD like you:

从你的问题来看,你似乎对GD有点陌生,我将分享一些我的经验,也许这有点偏离主题,但是我认为它会对像你这样的GD新人有帮助:

Step 1, validate file. Use the following function to check if the $_FILES['image']['tmp_name'] file is valid file:

步骤1、验证文件。使用以下函数检查$_FILES['image']['tmp_name']文件是否为有效文件:

   function getContentsFromImage($image) {
      if (@is_file($image) == true) {
         return file_get_contents($image);
      } else {
         throw new \Exception('Invalid image');
      }
   }
   $contents = getContentsFromImage($_FILES['image']['tmp_name']);

Step 2, get file format Try the following function with finfo extension to check file format of the file(contents). You would say why don't you just use $_FILES["image"]["type"] to check file format? Because it ONLY check file extension not file contents, if someone rename a file originally called world.png to world.jpg, $_FILES["image"]["type"] will return jpeg not png, so $_FILES["image"]["type"] may return wrong result.

第二步,获取文件格式请尝试使用finfo扩展名来检查文件(内容)的文件格式。你会说为什么不使用$_FILES["image"]["type"]来检查文件格式?因为它只检查文件扩展名而不是文件内容,如果有人重新命名了一个名为world的文件。png到world.jpg, $_FILES["image"]["type"]将返回jpeg而不是png,因此$_FILES["image"]["type"]可能返回错误的结果。

   function getFormatFromContents($contents) {
      $finfo = new \finfo();
      $mimetype = $finfo->buffer($contents, FILEINFO_MIME_TYPE);
      switch ($mimetype) {
         case 'image/jpeg':
            return 'jpeg';
            break;
         case 'image/png':
            return 'png';
            break;
         case 'image/gif':
            return 'gif';
            break;
         default:
            throw new \Exception('Unknown or unsupported image format');
      }
   }
   $format = getFormatFromContents($contents);

Step.3, Get GD resource Get GD resource from contents we have before:

第3步,获取GD资源从我们之前的内容中获取GD资源:

   function getGDResourceFromContents($contents) {
      $resource = @imagecreatefromstring($contents);
      if ($resource == false) {
         throw new \Exception('Cannot process image');
      }
      return $resource;
   }
   $resource = getGDResourceFromContents($contents);

Step 4, get image dimension Now you can get image dimension with the following simple code:

第4步,获得图像尺寸,现在你可以用下面的简单代码得到图像维数:

  $width = imagesx($resource);
  $height = imagesy($resource);

Now, Let's see what variable we got from the original image then:

现在,让我们看看我们从原始图像中得到了什么变量:

       $contents, $format, $resource, $width, $height
       OK, lets move on

Step 5, calculate resized image arguments This step is related to your question, the purpose of the following function is to get resize arguments for GD function imagecopyresampled(), the code is kinda long, but it works great, it even has three options: stretch, shrink, and fill.

第5步,计算调整大小的图像参数这一步与您的问题有关,下面函数的目的是为GD函数imagecopysampling()获取调整大小的参数,代码有点长,但是它工作得很好,它甚至有三个选项:拉伸、收缩和填充。

stretch: output image's dimension is the same as the new dimension you set. Won't keep height/width ratio.

拉伸:输出图像的尺寸与您设置的新尺寸相同,不会保持高/宽比。

shrink: output image's dimension won't exceed the new dimension you give, and keep image height/width ratio.

收缩:输出图像的尺寸不会超过你给的新尺寸,保持图像的高度/宽度比。

fill: output image's dimension will be the same as new dimension you give, it will crop & resize image if needed, and keep image height/width ratio. This option is what you need in your question.

填充:输出图像的尺寸将与您提供的新尺寸相同,如果需要,它将对图像进行裁剪和调整大小,并保持图像的高度/宽度比。这个选项是您在问题中需要的。

   function getResizeArgs($width, $height, $newwidth, $newheight, $option) {
      if ($option === 'stretch') {
         if ($width === $newwidth && $height === $newheight) {
            return false;
         }
         $dst_w = $newwidth;
         $dst_h = $newheight;
         $src_w = $width;
         $src_h = $height;
         $src_x = 0;
         $src_y = 0;
      } else if ($option === 'shrink') {
         if ($width <= $newwidth && $height <= $newheight) {
            return false;
         } else if ($width / $height >= $newwidth / $newheight) {
            $dst_w = $newwidth;
            $dst_h = (int) round(($newwidth * $height) / $width);
         } else {
            $dst_w = (int) round(($newheight * $width) / $height);
            $dst_h = $newheight;
         }
         $src_x = 0;
         $src_y = 0;
         $src_w = $width;
         $src_h = $height;
      } else if ($option === 'fill') {
         if ($width === $newwidth && $height === $newheight) {
            return false;
         }
         if ($width / $height >= $newwidth / $newheight) {
            $src_w = (int) round(($newwidth * $height) / $newheight);
            $src_h = $height;
            $src_x = (int) round(($width - $src_w) / 2);
            $src_y = 0;
         } else {
            $src_w = $width;
            $src_h = (int) round(($width * $newheight) / $newwidth);
            $src_x = 0;
            $src_y = (int) round(($height - $src_h) / 2);
         }
         $dst_w = $newwidth;
         $dst_h = $newheight;
      }
      if ($src_w < 1 || $src_h < 1) {
         throw new \Exception('Image width or height is too small');
      }
      return array(
          'dst_x' => 0,
          'dst_y' => 0,
          'src_x' => $src_x,
          'src_y' => $src_y,
          'dst_w' => $dst_w,
          'dst_h' => $dst_h,
          'src_w' => $src_w,
          'src_h' => $src_h
      );
   }
   $args = getResizeArgs($width, $height, 150, 170, 'fill');

Step 6, resize image Use $args, $width, $height, $format and $resource we got from above into the following function and get the new resource of the resized image:

第6步,使用$args、$width、$height、$format和$resource对图像进行调整,我们从上面获得如下的函数,得到调整后的图像的新资源:

   function runResize($width, $height, $format, $resource, $args) {
      if ($args === false) {
         return; //if $args equal to false, this means no resize occurs;
      }
      $newimage = imagecreatetruecolor($args['dst_w'], $args['dst_h']);
      if ($format === 'png') {
         imagealphablending($newimage, false);
         imagesavealpha($newimage, true);
         $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
         imagefill($newimage, 0, 0, $transparentindex);
      } else if ($format === 'gif') {
         $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
         imagefill($newimage, 0, 0, $transparentindex);
         imagecolortransparent($newimage, $transparentindex);
      }
      imagecopyresampled($newimage, $resource, $args['dst_x'], $args['dst_y'], $args['src_x'], $args['src_y'], $args['dst_w'], $args['dst_h'], $args['src_w'], $args['src_h']);
      imagedestroy($resource);
      return $newimage;
   }
   $newresource = runResize($width, $height, $format, $resource, $args);

Step 7, get new contents, Use the following function to get contents from the new GD resource:

步骤7,获取新的内容,使用以下函数从新的GD资源中获取内容:

   function getContentsFromGDResource($resource, $format) {
      ob_start();
      switch ($format) {
         case 'gif':
            imagegif($resource);
            break;
         case 'jpeg':
            imagejpeg($resource, NULL, 100);
            break;
         case 'png':
            imagepng($resource, NULL, 9);
      }
      $contents = ob_get_contents();
      ob_end_clean();
      return $contents;
   }
   $newcontents = getContentsFromGDResource($newresource, $format);

Step 8 get extension, Use the following function to get extension of from image format(note, image format is not equal to image extension):

step8 get extension,使用以下函数从图像格式得到扩展(注意,图像格式不等于图像扩展):

   function getExtensionFromFormat($format) {
      switch ($format) {
         case 'gif':
            return 'gif';
            break;
         case 'jpeg':
            return 'jpg';
            break;
         case 'png':
            return 'png';
      }
   }
   $extension = getExtensionFromFormat($format);

Step 9 save image If we have a user named mike, you can do the following, it will save to the same folder as this php script:

步骤9保存图片如果我们有一个叫mike的用户,你可以做以下的操作,它会保存到和这个php脚本相同的文件夹:

$user_name = 'mike';
$filename = $user_name . '.' . $extension;
file_put_contents($filename, $newcontents);

Step 10 destroy resource Don't forget destroy GD resource!

10 .破坏资源不要忘记破坏GD资源!

imagedestroy($newresource);

or you can write all your code into a class, and simply use the following:

或者你可以把你所有的代码写进一个类中,简单地使用下面的代码:

   public function __destruct() {
      @imagedestroy($this->resource);
   }

TIPS

提示

I recommend not to convert file format that user upload, you will meet many problems.

我建议不要转换用户上传的文件格式,你会遇到很多问题。

#6


3  

I suggest that you work something along these lines:

我建议你沿着这条线工作:

  1. Perform a getimagesize( ) on the uploaded file to check image type and size
  2. 对上传的文件执行getimagesize()检查图像类型和大小
  3. Save any uploaded JPEG image smaller than 700x700px in to the destination folder "as-is"
  4. 将上传的小于700x700px的JPEG图像保存到目标文件夹“原样”
  5. Use GD library for medium size images (see this article for code sample: Resize Images Using PHP and GD Library)
  6. 对于中等大小的图像使用GD库(参见本文的代码示例:使用PHP和GD库调整图像大小)
  7. Use ImageMagick for large images. You can use ImageMagick in background if you prefer.
  8. 对大型图像使用ImageMagick。如果您愿意,可以在后台使用ImageMagick。

To use ImageMagick in background, move the uploaded files to a temporary folder and schedule a CRON job that "convert"s all files to jpeg and resizes them accordingly. See command syntax at: imagemagick-command line processing

要在后台使用ImageMagick,请将上传的文件移动到临时文件夹,并安排一个CRON作业,将所有文件“转换”为jpeg并相应地调整大小。参见命令语法:imagemagick-命令行处理

You can prompt the user that file is uploaded and scheduled to be processed. The CRON job could be scheduled to run daily at a specific interval. The source image could be deleted after processing to assure that an image is not processed twice.

您可以提示用户文件被上传并计划被处理。CRON作业可以安排在特定的时间间隔内每天运行。处理后可以删除源映像,以确保不会对映像进行两次处理。

#7


2  

I've heard big things about the Imagick library, unfortunately I couldn't install it at my work computer and neither at home (and trust me, I spent hours and hours on all kinds of forums).

我听说过关于Imagick图书馆的大事情,不幸的是,我不能在我的工作电脑上安装它,也不能在家里(相信我,我花了好几个小时在各种各样的论坛上)。

Afterwords, I've decided to try this PHP class:

最后,我决定尝试这个PHP类:

http://www.verot.net/php_class_upload.htm

http://www.verot.net/php_class_upload.htm

It's pretty cool and I can resize all kinds of images (I can convert them to JPG also).

它很酷,我可以调整各种图片的大小(我也可以把它们转换成JPG格式)。

#8


2  

ImageMagick is multithreaded, so it appears to be faster, but actually uses a lot more resources than GD. If you ran several PHP scripts in parallel all using GD then they'd beat ImageMagick in speed for simple operations. ExactImage is less powerful than ImageMagick but a lot faster, though not available through PHP, you'll have to install it on the server and run it through exec.

ImageMagick是多线程的,所以它看起来更快,但是实际上比GD使用更多的资源。如果您使用GD并行运行多个PHP脚本,那么对于简单的操作来说,它们的速度将超过ImageMagick。ExactImage不如ImageMagick强大,但是速度要快得多,虽然不能通过PHP获得,但是您必须将它安装在服务器上并通过exec运行。

#9


1  

For larger images use phpThumb(). Here is how to use it: http://abcoder.com/php/problem-with-resizing-corrupted-images-using-php-image-functions/. It also works for large corrupted images.

对于较大的图像,使用phpThumb()。这里是如何使用它的:http://abcoder.com/php/problem with-resizing- -image- use -php-image-functions/。它也适用于大的损坏图像。