当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《PHP中高效的JPEG图像大小调整》经验,为你挑选了5个好方法。

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

我目前正在使用GD功能imagecopyresampled来拍摄高分辨率图像,并将它们干净地调整到适合网页查看的大小(大约700像素宽,700像素高).

这适用于小(2 MB以下)的照片,整个调整大小操作在服务器上只需不到一秒钟.但是,该网站最终将为可能上传最大10 MB图像的摄影师提供服务(或者图像尺寸最大为5000x4000像素).

使用大图像执行此类调整大小操作往往会大幅增加内存使用量(较大的图像会使脚本的内存使用量超过80 MB).有没有办法让这个调整大小操作更有效率?我应该使用像ImageMagick这样的替代图像库吗?

现在,调整大小代码看起来像这样

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);

Grzegorz Gie.. 45

人们说ImageMagick要快得多.最好只比较两个库并测量它.

    准备1000张典型图像.

    写两个脚本 - 一个用于GD,一个用于ImageMagick.

    两次运行它们.

    比较结果(总执行时间,CPU和I/O使用情况,结果图像质量).

其他人最好的东西,对你来说不是最好的.

另外,在我看来,ImageMagick有更好的API接口.



1> Grzegorz Gie..:

人们说ImageMagick要快得多.最好只比较两个库并测量它.

    准备1000张典型图像.

    写两个脚本 - 一个用于GD,一个用于ImageMagick.

    两次运行它们.

    比较结果(总执行时间,CPU和I/O使用情况,结果图像质量).

其他人最好的东西,对你来说不是最好的.

另外,在我看来,ImageMagick有更好的API接口.


在我曾经使用的服务器上,GD经常耗尽内存和崩溃,而ImageMagick从未这样做.

2> Kevin..:

这是我在项目中使用的php.net文档的一个片段,工作正常:


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


从建议的编辑中复制/粘贴:这是此功能的作者Tim Eckel.$ quality + 1是正确的,它用于避免一个像素宽的黑色边框,而不是改变质量.此外,此函数与imagecopyresampled插件兼容,因此有关语法的问题,请参阅imagecopyresampled命令,它是相同的.

3> phenry..:

phpThumb尽可能使用ImageMagick来提高速度(必要时回退到GD)并且似乎缓存很好以减少服务器上的负载.尝试它是非常轻量级的(调整图像大小,只需用包含图形文件名和输出尺寸的GET查询调用phpThumb.php),这样你就可以试一试它是否符合你的需求.



4> Steve-o..:

对于较大的图像,使用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> nut..:

从你的问题来看,你似乎对GD有点新意,我会分享一些我的经历,也许这有点偏离主题,但我认为对你这样的新人来说会有所帮助:

第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']);

步骤2,获取文件格式尝试使用finfo扩展的以下函数来检查文件的文件格式(内容).你会说为什么不用它$_FILES["image"]["type"]来检查文件格式?由于它检查文件的扩展名而不是文件内容,如果有人重命名原名文件world.pngworld.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,获取GD资源从我们之前的内容中获取GD资源:

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

第4步,获取图像尺寸现在,您可以使用以下简单代码获取图像尺寸:

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

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

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

步骤5,计算调整大小的图像参数这一步与你的问题有关,以下函数的目的是为GD函数获取resize参数imagecopyresampled(),代码有点长,但它工作得很好,它甚至有三个选项:stretch,shrink ,并填写.

stretch:输出图像的尺寸与您设置的新尺寸相同.不会保持高/宽比.

缩小:输出图像的尺寸不会超过您给出的新尺寸,并保持图像的高度/宽度比.

填充:输出图像的尺寸与您给出的新尺寸相同,如果需要,它将裁剪并调整图像大小,并保持图像高/宽比.您可以在问题中使用此选项.

   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');

步骤6,调整图像使用$args,$width,$height,$format我们从上面钻进了以下功能和$资源,并得到调整后的图像的新资源:

   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);

步骤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);

步骤8获取扩展,使用以下函数从图像格式获取扩展(注意,图像格式不等于图像扩展名):

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

步骤9保存图像如果我们有一个名为mike的用户,您可以执行以下操作,它将保存到与此php脚本相同的文件夹中:

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

步骤10破坏资源不要忘记破坏GD资源!

imagedestroy($newresource);

或者您可以将所有代码写入类中,只需使用以下代码:

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

提示

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

推荐阅读
wangtao
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有