Автоматическая обрезка изображения в браузере

#php #javascript #jquery

#php #JavaScript #jquery

Вопрос:

Как я могу автоматически обрезать изображение в процессе загрузки? Есть ли функция php для этого?

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

Или есть идеи?

Ответ №1:

Автоматическая обрезка была бы затруднена, если бы вы не знали, где находится объект. Может быть, вы можете попытаться получить внутренний прямоугольник с центром, как на картинке:

Изображение внутреннего прямоугольника показывает прямоугольник внутри другого

Первое, что нужно сделать, это найти исходные размеры изображения и тип файла. Вы не должны доверять расширению изображения и вместо этого использовать getimagesize для этого. Несмотря на имя getimagesize , возвращает не только размер, но и тип файла.

 //width is at index 0, height at index 1, mime type at ['mime'] key
$original = getimagesize($filename); 
  

Затем вы должны создать внутреннюю структуру данных PHP для хранения исходного изображения в памяти, чтобы вы могли манипулировать им, используя imagecreatefromjpeg или imagecreatefrompng или imagecreatefromgif , в зависимости от типа изображения. Например:

 $srcImage = imagecreatefromjpeg($filename);
  

Затем вы должны выделить другую структуру данных для хранения целевого изображения. В этом случае у нас нет изображения для начала, поэтому я выделяю пустое изображение.

 $dstImage = imagecreatetruecolor($newWidth, $newHeight);
  

Далее вы должны скопировать часть исходного изображения в целевое изображение. Если вы не хотите изменять размер, используйте imagecopy , в противном случае, если вы хотите обрезать и изменить размер, вы можете рассмотреть imagecopyresampled .

 imagecopy(dstImage, $srcImage, 0, 0, $srcX, $srcY, $srcW, $srcH);
  

Где $ srcX — начальная точка X в исходном изображении, $ srcY — начальная точка Y, $ srcW — ширина для копирования из начальной точки X, $ srcH — высота копируемой области.

Наконец, вы можете либо сохранить изображение с помощью:

 imagejpeg($this->dstImage, $filename, 90);
  

или вы можете вывести его в браузер с помощью:

 imagejpeg($this->dstImage);
  

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

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

Основываясь на описанных концепциях, я написал небольшой класс:

 class ImageCrop {

    //Image resources
    private $srcImage, $dstImage;

    //original width and height
    private $width, $height;

    /**
    * Read an image from disk.
    * @return true in case of success, false otherwise.
    */
    public function openImage($filename) {
        if (!file_exists($filename)) {
            return false;
        }
        $original = getimagesize($filename);
        switch ($original['mime']) {
        case 'image/jpeg':
            $this->srcImage = imagecreatefromjpeg($filename);
            break;
        case 'image/png':
            $this->srcImage = imagecreatefrompng($filename);
            break;
        case 'image/gif':
            $this->srcImage = imagecreatefromgif($filename);
            break;
        default:
            return false;
        }
        $this->width = $original[0];
        $this->height = $original[1];
        return true;
    }

    /**
    * Crop an image to the new specified dimension trying to get an 
    * internal rectangle of the original image. No crop is done if the 
    * original dimension is already smaller than $newWidth or $newHeight.
    */
    public function crop($newWidth, $newHeight) {
        $this->dstImage = imagecreatetruecolor($newWidth, $newHeight);
        $srcX = $srcY;
        $srcW = $this->width;
        $srcH = $this->height;
        $extraWidth = $this->width - $newWidth;
        if ($extraWidth > 0) {
            $srcX = $extraWidth / 2;        
        }
        $extraHeight = $this->height - $newHeight;
        if ($extraHeight > 0) {
            $srcY = $extraHeight / 2;
        }
        imagecopy($this->dstImage, $this->srcImage, 0, 0, 
            $srcX, $srcY, $srcW, $srcH);
    }

    /**
     * Save the destination image, the crop function should have been 
     * called already.
     */
    public function save($filename) {
        imagejpeg($this->dstImage, $filename, 90);
    }

    /**
    * Output the destination image to the browser.
    */
    public function output() {
        imagejpeg($this->dstImage);
    }

}
  

Сохраните класс в ImageCrop.php , пример использования:

 require_once 'ImageCrop.php';

$imageCrop = new ImageCrop();
if ($imageCrop->openImage('big.jpg')) {
    $imageCrop->crop(200, 300); //newWidth, newHeight
    $imageCrop->save('small.jpg');
}
  

или, чтобы отправить вывод непосредственно в браузер, используйте $imageCrop->output(); .

Комментарии:

1. Спасибо за редактирование моего поста, прошу прощения за мой плохой английский. 🙂 Нет, я не хочу изменять его размер, я просто хочу его обрезать. Поэтому, когда пользователь загружает изображение, размеры которого превышают разрешенные мной, оно будет обрезано автоматически. Не могли бы вы рассказать мне идею о «внутреннем прямоугольнике»? спасибо в расширенном.

2. Обновил свой пост, теперь я обрезаю внутренний прямоугольник с центром.

3. Хорошо, Стивло. Это кажется очень интересным, позвольте мне попробовать это на некоторое время. Я отправлю вам несколько ответов позже.

4. Привет, вот мое обещание. Стивло.. Хорошая работа! Я протестировал ваш класс, и он работает нормально. Спасибо большое. Ваш ответ очень хорош, потому что он сопровождается концепцией и прямой реализацией. Я проголосую за ваш ответ. 🙂

5. Я ценю ваш код stivlo и химию между вами, ребята, Philips Tel и stivlo … но единственная проблема, которую я вижу в этом коде, заключается в том, что вы должны указать ширину и высоту, чтобы обрезать реальное изображение, чтобы сгенерированное изображение могло быть искажено, в то время как мое вы должны указать максимальный размер (ширину или высоту), т.Е. Если вашконтейнер изображения имеет портретную ширину или, если он имеет альбомную форму, дает высоту. Вот и все…..

Ответ №2:

Скажите это как max_size.php

 <?php header('Content-type: image/jpeg');
function resampleimage($maxsize, $sourcefile, $imgcomp=0){
$g_imgcomp=100-$imgcomp;
    if(file_exists($sourcefile)){
    $g_is=getimagesize($sourcefile);
        if($g_is[0] <= $maxsize amp;amp; $g_is[1] <= $maxsize){
            $new_width=$g_is[0];
            $new_height=$g_is[1];
        } else {
            $w_adjust = ($maxsize / $g_is[0]);
            $h_adjust = ($maxsize / $g_is[1]);
      if($w_adjust <= $h_adjust){
          $new_width=($g_is[0]*$w_adjust);
          $new_height=($g_is[1]*$w_adjust);
      } else {
          $new_width=($g_is[0]*$h_adjust);
          $new_height=($g_is[1]*$h_adjust);
      }
    }
    $image_type = strtolower(strrchr($sourcefile, "."));

    switch($image_type) {
      case '.jpg':
         $img_src = imagecreatefromjpeg($sourcefile);
         break;
      case '.jpeg':
         $img_src = imagecreatefromjpeg($sourcefile);
         break;
      case '.png':
         $img_src = imagecreatefrompng($sourcefile);
         break;
      case '.gif':
         $img_src = imagecreatefromgif($sourcefile);
         break;
      default:
         echo("Error Invalid Image Type");
         die;
         break;
   }
  $img_dst=imagecreatetruecolor($new_width,$new_height);
  imagecopyresampled($img_dst, $img_src, 0, 0, 0, 0, $new_width, $new_height, $g_is[0], $g_is[1]);
  imagejpeg($img_dst);
  imagedestroy($img_dst);
  return true;
  } else {
  return false;
  }
}
resampleimage($_GET['maxsize'], $_GET['source']);
?>
  

На странице, где у вас есть изображение

 <img id="img" src="max_size.php?maxsize=152amp;source=[some image path]" />
  

Комментарии:

1. Хм … Спасибо за быстрый ответ! Я думаю, что приведенный выше сценарий просто создает эскиз изображения с одинаковым размером как по высоте, так и по ширине. Тем не менее, это отличная идея. 🙂

2. Ваше первое утверждение верно. Он создает миниатюру правильно, но не одинаковой ширины и высоты.. Это похоже на то, что он создаст thumb, но в том же соотношении с источником только максимальный размер будет для ширины в альбомной ориентации, а в портретной — для высоты… Также вы хотели, чтобы что-то создавалось автоматически… Так или иначе, многие сценарии обрезки доступны для jquery, но не автоматические…

3. Большинство доступных сценариев обрезки, похоже, требуют, чтобы мы обрезали изображение вручную. Я думаю, что есть другие способы сделать это в «небе».