При загрузке и изменении размера изображения PHP не хватает памяти (96 МБ памяти) - PullRequest
0 голосов
/ 01 марта 2012

Я занимаюсь разработкой веб-сайта, на котором пользователи могут загружать несколько изображений на сервер / веб-сайт. В моем сценарии загрузки я установил ограничение на размер изображения в 10 МБ. Это потому, что я думал, что многие современные камеры делают большие снимки.

Скрипт загрузки берет каждое изображение, по одному, и изменяет размер до 3 различных версий, 900x600, 600x450 и уменьшенного миниатюры, а также помещает изображение водяного знака поверх двух больших изображений.

Я установил свой php.ini memory_limit на 96 МБ, что, как я предполагал, будет достаточно легко.

После небольшого тестирования я загружал изображение jpg размером 6,38 МБ и разрешением 6143 x 3855 пикселей. Я получил сообщение об ошибке «Неустранимая ошибка: допустимый объем памяти 100663296 байт исчерпан (попытался выделить 24572 байт)»

Как вы думаете, разумно ли вам так много памяти загружать и обрабатывать изображение такого размера? или вы думаете, это скорее проблема с кодировкой в ​​моем скрипте?

96 МБ ограничение памяти мне кажется большим. Какой опыт других людей имеет дело с загрузкой больших изображений? Должен ли я установить ограничение памяти 128 МБ или выше? или я должен смотреть на переписывание моего сценария загрузки?

Мой код добавлен ниже:

      //If a new image has been added, resize and upload to filesystem
      if ($_FILES['new_image']['name'] !=''){

          $allowed_types=array(
            'image/gif' => '.gif',
            'image/jpeg' => '.jpg',
            'image/png' => '.png',
            'image/x-png' => '.png',
            'image/pjpeg' => '.jpg'
          );

          $img = $_FILES['new_image'];

          // Check the file to be uploaded is the correct file type and is under 9MB              

          if ((array_key_exists($img['type'], $allowed_types)) && ($img['size'] < 9000000))              {
          // File to be uploaded is Valid


          // File to be uploaded is Valid

          $imagename = stripslashes($_FILES['new_image']['name']);

          // make the random file name
          $randName = md5(rand() * time());
          $ext = pathinfo($imagename, PATHINFO_EXTENSION); 


          $imagename = $randName . "." . $ext;
          $source = $_FILES['new_image']['tmp_name'];


          // Check if Directory Exists, if not create it
          if(!file_exists("images/breeds/".$trimmed['profile_id']))
          { 
               mkdir("images/breeds/".$trimmed['profile_id']) or die("Could not create images folder for article ".$trimmed['profile_id']);
          } 

          // Check if thumbnail Directory Exists
          if(!file_exists("images/breeds/".$trimmed['profile_id']."/thumbs")) 
          { 
              mkdir("images/breeds/".$trimmed['profile_id']."/thumbs") or die("Could not create thumbnail folder for article ".$trimmed['profile_id']);
          } 

          // Check if thumbnail Directory Exists
          if(!file_exists("images/breeds/".$trimmed['profile_id']."/large")) 
          { 
              mkdir("images/breeds/".$trimmed['profile_id']."/large") or die("Could not create thumbnail folder for article ".$trimmed['profile_id']);
          } 


          $LargeImage = "images/breeds/".$trimmed['profile_id']."/large/".$imagename;
          $NormalImage = "images/breeds/".$trimmed['profile_id']."/".$imagename;
          $SmallImage = "images/breeds/".$trimmed['profile_id']."/thumbs/".$imagename;

          //uploaded temp file
          $file = $_FILES['new_image']['tmp_name'];


          //Get Image size info
          list($width, $height, $image_type) = getimagesize($file);

          //SourceImage
          switch ($image_type) 
          {
            case 1: $image = imagecreatefromgif($file); break;
            case 2: $image = imagecreatefromjpeg($file);  break;
            case 3: $image = imagecreatefrompng($file); break;
            default:  trigger_error('Unsupported filetype!', E_USER_WARNING);  break;
          }


          // Constraints for Large Image 
          $max_width = 900; 
          $max_height = 600; 
          $ratioh = $max_height/$height; 
          $ratiow = $max_width/$width; 
          $ratio = min($ratioh, $ratiow); 

          if (($height < $max_height) && ($width < $max_width)) {
           //keep same dimensions
           $modwidth = $width;
           $modheight = $height;
          } else {
          // New dimensions 
          $modwidth = intval($ratio*$width); 
          $modheight = intval($ratio*$height);
          }

          $tmpLarge = imagecreatetruecolor( $modwidth, $modheight );

          imagecopyresampled($tmpLarge, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height) ; 

          // Add Watermark to large image at top right

          $wm = "images/p4h-wm-200.png";
          $wmImage = imagecreatefrompng($wm); 
          $wmW = imagesx($wmImage); 
          $wmH = imagesy($wmImage); 

          $photoW = imagesx($tmpLarge); 
          $photoH = imagesy($tmpLarge);
          $dest_x = $photoW - $wmW - 10; 
          $dest_y = 10;

          // imagecopymerge($tn, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH, 100); 
          imagecopy($tmpLarge, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH);


          switch ($image_type) 
          {
             case 1: imagegif($tmpLarge,$LargeImage); break;
             case 2: imagejpeg($tmpLarge,$LargeImage, 80);  break;
             case 3: imagepng($tmpLarge,$LargeImage, 0); break;
             default:  trigger_error('Failed resize image!', E_USER_WARNING);  break;
          }


          // Destroy tmp images to free memory
          imagedestroy($tmpLarge);
          imagedestroy($wmImage);


          // Constraints for Normal Image 
          $max_width = 550; 
          $max_height = 413; 
          $ratioh = $max_height/$height; 
          $ratiow = $max_width/$width; 
          $ratio = min($ratioh, $ratiow); 

          if (($height < $max_height) && ($width < $max_width)) {
           //keep same dimensions
           $modwidth = $width;
           $modheight = $height;
          } else {
          // New dimensions 
          $modwidth = intval($ratio*$width); 
          $modheight = intval($ratio*$height);
          }

          $tmpNormal = imagecreatetruecolor( $modwidth, $modheight );

          imagecopyresampled($tmpNormal, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height) ; 

          // Add Watermark to large image at top right

          $wm = "images/p4h-wm-150.png";
          $wmImage = imagecreatefrompng($wm); 
          $wmW = imagesx($wmImage); 
          $wmH = imagesy($wmImage); 

          $photoW = imagesx($tmpNormal); 
          $photoH = imagesy($tmpNormal);
          $dest_x = $photoW - $wmW - 10; 
          $dest_y = 10;

          // imagecopymerge($tn, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH, 100); 
          imagecopy($tmpNormal, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH);

          switch ($image_type) 
          {
             case 1: imagegif($tmpNormal,$NormalImage); break;
             case 2: imagejpeg($tmpNormal,$NormalImage, 90);  break;
             case 3: imagepng($tmpNormal,$NormalImage, 0); break;
             default:  trigger_error('Failed resize image!', E_USER_WARNING);  break;
          }

          // Destroy tmp images to free memory
          imagedestroy($tmpNormal);
          imagedestroy($wmImage);


          // Now that the full size image has been saved, resize the thumbnail one to a fixed size for homepage display
          // Constraints 
          $thumb_width = 150; 
          $thumb_height = 112.5; 

         // Calculate stuff and resize image accordingly     
         $src_ratio = $width/$height;
         $dst_ratio = $thumb_width/$thumb_height;
         if($src_ratio < $dst_ratio) // trim top and bottom
         {
            $ratio = $width/$thumb_width;
            $crop_height = $thumb_height*$ratio;
            $src_y = round(($height-$crop_height)/2);
            $crop_width = $width;
            $src_x = 0;
         }
         else // trim left and right
         {
            $ratio = $height/$thumb_height;
            $crop_width = $thumb_width*$ratio;
            $src_x = round(($width-$crop_width)/2);
            $crop_height = $height;
            $src_y = 0;
         }


          $tmpSmall = imagecreatetruecolor( $thumb_width, $thumb_height );

          imagecopyresampled($tmpSmall, $image, 0, 0, $src_x, $src_y, $thumb_width, $thumb_height, $crop_width, $crop_height);

          switch ($image_type) 
          {
             case 1: imagegif($tmpSmall,$SmallImage); break;
             case 2: imagejpeg($tmpSmall,$SmallImage, 90);  break;
             case 3: imagepng($tmpSmall,$SmallImage, 0); break;
             default:  trigger_error('Failed resize image!', E_USER_WARNING);  break;
          }

        // Destroy images to free memory
        imagedestroy($image);
        imagedestroy($tmpSmall);

Ответы [ 3 ]

0 голосов
/ 01 марта 2012

Вам, вероятно, нужно дать больше подсказок PHP о том, когда память может быть освобождена. Обычно достаточно простого $some_variable = null;.

Как только вы закончите работу с изображением (основным изображением и каждым из его эскизов), установите переменную ссылки на null, чтобы освободить память.

В противном случае попробуйте распечатать или зарегистрировать результаты memory_get_usage() (http://www.php.net/manual/en/function.memory-get-usage.php) в верхней части вашего скрипта и в разных местах по всему вашему скрипту, чтобы отследить, где память перегружена.

0 голосов
/ 01 марта 2012

Для изображения 6143x3855 потребуется ПО МЕНЬШЕ 71 043 795 байт памяти только для необработанных данных пикселей (3 байта на пиксель). Затем вы создаете серию других изображений для хранения версий оригинала с измененными размерами и т. Д. *

Не удивительно, что вам не хватает памяти.

0 голосов
/ 01 марта 2012

jpg составляет 6,38 МБ, но для преобразования изображения используется внутреннее представление без сжатия.

Ваше изображение имеет размер 23,6 мегапикселя

его несжатое представление может быть 32-битным (4Bytes) на пиксель, то есть: 4 * 23.6MBytes = 94 MBytes.

Итак, я бы сказал, нужно ли обрабатывать такие большие изображения?

если да, поместите memory_limit вышеесли нет, ограничьте размер загружаемого изображения чем-то более разумным для обработки в настройках вашей памяти.

...