복붙노트

효율적인 JPEG 이미지 크기 조정

PHP

효율적인 JPEG 이미지 크기 조정

PHP에서 큰 이미지의 크기를 조절하는 가장 효율적인 방법은 무엇입니까?

나는 현재 고해상도 이미지를 찍기 위해 imagecopyresampled GD 함수를 사용하고 있으며 웹보기 (약 700 픽셀, 가로 700 픽셀) 크기로 크기를 줄입니다.

작은 크기 (2MB 미만)의 사진에서 효과가 있으며 전체 크기 조정 작업은 서버에서 1 초 이내에 완료됩니다. 그러나 사이트는 궁극적으로 최대 10MB의 이미지 (또는 최대 5000x4000 픽셀 크기의 이미지)를 업로드 할 수있는 사진 작가에게 서비스를 제공합니다.

큰 이미지를 사용하여 이러한 종류의 크기 조정 작업을 수행하면 메모리 사용량이 매우 크게 증가하는 경향이 있습니다 (큰 이미지는 스크립트 사용시 80MB를 초과하는 메모리 사용량을 유발할 수 있습니다). 이 크기 조정 작업을보다 효율적으로 만들 수있는 방법이 있습니까? 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);

해결법

  1. ==============================

    1.사람들은 ImageMagick이 훨씬 빠릅니다. 기껏해야 두 라이브러리를 비교하고이를 측정하십시오.

    사람들은 ImageMagick이 훨씬 빠릅니다. 기껏해야 두 라이브러리를 비교하고이를 측정하십시오.

    다른 모든 사람들에게 가장 좋은 것을 당신에게 줄 수는 없습니다.

    또한, 제 생각에는 ImageMagick 훨씬 더 나은 API 인터페이스가 있습니다.

  2. ==============================

    2.다음은 php.net 문서에서 발췌 한 내용으로 프로젝트에서 사용하고 잘 작동합니다.

    다음은 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

  3. ==============================

    3.phpThumb은 가능할 때마다 ImageMagick을 사용합니다 (필요한 경우 GD로 되돌아갑니다). 서버의 부하를 줄이기 위해 캐싱하는 것처럼 보입니다. 그래픽 파일 이름과 출력 크기가 포함 된 GET 쿼리를 사용하여 phpThumb.php를 호출하기 때문에 이미지를 크기를 조정하기에 매우 가벼워서 필요에 맞는지 확인할 수 있습니다.

    phpThumb은 가능할 때마다 ImageMagick을 사용합니다 (필요한 경우 GD로 되돌아갑니다). 서버의 부하를 줄이기 위해 캐싱하는 것처럼 보입니다. 그래픽 파일 이름과 출력 크기가 포함 된 GET 쿼리를 사용하여 phpThumb.php를 호출하기 때문에 이미지를 크기를 조정하기에 매우 가벼워서 필요에 맞는지 확인할 수 있습니다.

  4. ==============================

    4.큰 이미지의 경우 ImageJagick에서 이미지로드의 크기를 조정하여 메모리 사용을 줄이고 성능을 향상 시키려면 libjpeg을 사용합니다. GD에서는 불가능합니다.

    큰 이미지의 경우 ImageJagick에서 이미지로드의 크기를 조정하여 메모리 사용을 줄이고 성능을 향상 시키려면 libjpeg을 사용합니다. 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. ==============================

    5.당신 질문에서, 당신은 GD에 좀 새로운 것 같아요, 나는 내 경험을 공유 할 것입니다, 어쩌면이 주제와 조금 다를 수도 있지만, GD를 처음 접한 사람에게 도움이 될 것 같습니다.

    당신 질문에서, 당신은 GD에 좀 새로운 것 같아요, 나는 내 경험을 공유 할 것입니다, 어쩌면이 주제와 조금 다를 수도 있지만, 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.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, 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 함수 imagecopyresampled ()에 대한 크기 조정 인수를 얻는 것입니다. 코드는 다소 길지만 훌륭하게 작동하며 세 가지 옵션도 있습니다. 스트레칭, 수축 및 채우기.

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

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

    나는 사용자 업로드 파일 형식을 변환하지 않는 것이 좋습니다, 당신은 많은 문제를 만날 것입니다.

  6. ==============================

    6.다음 행을 따라 작업 해 보시기 바랍니다.

    다음 행을 따라 작업 해 보시기 바랍니다.

    백그라운드에서 ImageMagick을 사용하려면 업로드 된 파일을 임시 폴더로 이동하고 모든 파일을 jpeg로 "변환"하고 그에 따라 크기를 조정하는 CRON 작업을 예약하십시오. 다음 위치에서 명령 구문을 참조하십시오. imagemagick-command line processing

    파일 업로드 및 처리 예정을 사용자에게 알릴 수 있습니다. CRON 작업은 특정 간격으로 매일 실행되도록 예약 될 수 있습니다. 이미지가 두 번 처리되지 않도록 처리 한 후 소스 이미지를 삭제할 수 있습니다.

  7. ==============================

    7.불행히도 필자는 Imagick 라이브러리에 대한 큰 이야기를 들었습니다. 안타깝게도 직장 컴퓨터 나 집에서는 설치할 수 없었습니다. (그리고 저를 신뢰하십시오. 모든 종류의 포럼에서 몇 시간을 보냈습니다.)

    불행히도 필자는 Imagick 라이브러리에 대한 큰 이야기를 들었습니다. 안타깝게도 직장 컴퓨터 나 집에서는 설치할 수 없었습니다. (그리고 저를 신뢰하십시오. 모든 종류의 포럼에서 몇 시간을 보냈습니다.)

    이후, 나는이 PHP 클래스를 사용하기로 결정했다.

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

    그것은 아주 차갑고 모든 종류의 이미지의 크기를 조정할 수 있습니다 (JPG로 변환 할 수도 있음).

  8. ==============================

    8.ImageMagick은 멀티 스레드이므로 더 빠르지 만 실제로 GD보다 더 많은 리소스를 사용합니다. GD를 사용하여 PHP 스크립트를 여러 개 병렬로 실행 한 경우 ImageMagick이 속도가 빨라져 간단한 조작이 가능합니다. ExactImage는 ImageMagick보다 덜 강력하지만 PHP를 통해 사용할 수는 없지만 서버에 설치하고 exec를 통해 실행해야합니다.

    ImageMagick은 멀티 스레드이므로 더 빠르지 만 실제로 GD보다 더 많은 리소스를 사용합니다. GD를 사용하여 PHP 스크립트를 여러 개 병렬로 실행 한 경우 ImageMagick이 속도가 빨라져 간단한 조작이 가능합니다. ExactImage는 ImageMagick보다 덜 강력하지만 PHP를 통해 사용할 수는 없지만 서버에 설치하고 exec를 통해 실행해야합니다.

  9. ==============================

    9.더 큰 이미지를 보려면 phpThumb ()을 사용하십시오. 사용 방법은 다음과 같습니다. http://abcoder.com/php/problem-with-resizing-corrupted-images-using-php-image-functions/. 또한 큰 손상된 이미지에도 적용됩니다.

    더 큰 이미지를 보려면 phpThumb ()을 사용하십시오. 사용 방법은 다음과 같습니다. http://abcoder.com/php/problem-with-resizing-corrupted-images-using-php-image-functions/. 또한 큰 손상된 이미지에도 적용됩니다.

  10. from https://stackoverflow.com/questions/12661/efficient-jpeg-image-resizing-in-php by cc-by-sa and MIT license