Размер и сжимать изображения с imagick


Я строю PHP-функцию, чтобы управлять и создать серию изображений Imagick. Цель состоит в том, чтобы сделать отзывчивые изображения с <picture> элемент.

В основном это то, что он делает:

  • Проверяет, является ли исходное изображение существует.
  • Проверьте, если миниатюры уже существует и создает <picture> элемент.
    В противном случае:
    • Изменение размера изображений; из исходного изображения он создает 10 миниатюр
    • Обжать миниатюры
    • Сохраняет эскизы
    • Создать <picture> элемент с эскизами

Функция использует массив в качестве параметров, который выглядит следующим образом:

$params = array(
  'thumbWidth'  => array( 500,    750,    1000,     1600,     2000),
  'thumbHeight' => array( 333,    500,    667,     1067,     1500),
  'breakPoints' => array(     500,    750,    1000,     1600),
  'quality'     => 65
);

В thumbHeight массива могут иметь значение null, поэтому функция только изменяет tumbnails по ширине. Сохраняя пропорции.

Это функция:

<?php
public static function picturebuilder($imgUrl, $imageAlt, $params) {
    // check if the image exists
    if (!file_exists($imgUrl)) {
      echo "<script>console.log( 'Cannot find : " . $imgUrl . "' );</script>";
      return false;
    }


    // Get the original image info
    $imgInfo = pathinfo($imgUrl);
    $imgName = $imgInfo['filename'];
    $imgExtension = '.' . $imgInfo['extension'];
    $thumbDir = 'image_thumbs/' . $imgInfo['dirname'];

    // set HD upscale ratio
    $upscale_HD_images = 1.5;
    $thumbQuality = $params['quality'];
    $breakPoints = $params['breakPoints'];

    // Build the Thumb width array
    $paramWidths = $params['thumbWidth'];
    $thumbWidths = array();
    foreach ($paramWidths as $paramWidth) {
      array_push($thumbWidths, $paramWidth);
      array_push($thumbWidths, floor($paramWidth * $upscale_HD_images));
    }

    // Build the thumb height array
    $paramHeights = $params['thumbHeight'];
    $thumbHeights = array();
    list($XLwidth, $XLheight) = getimagesize($imgUrl);
    if ($paramHeights) {
      $crop = true;
      // If height is specified get the width and height of image from params
      foreach ($paramHeights as $paramHeight) {
        array_push($thumbHeights, $paramHeight);
        array_push($thumbHeights, floor($paramHeight * $upscale_HD_images));
      }
    } else {
      // If no height is specified get the width and height of image form original file
      foreach ($thumbWidths as $thumbWidth) {
        $thumbHeight = floor($thumbWidth*$XLheight/$XLwidth);
        array_push($thumbHeights, $thumbHeight);
      }
    }

    // Create the thumb paths array
    $i = 0;
    $thumbPaths = array();
    foreach ($thumbWidths as $thumbWidth) {
      $thumbHeight = $thumbHeights[$i];
      $thumbPath = $thumbDir . '/' . $imgName . '-' . $thumbWidth . 'x' . $thumbHeight . 'q' . $thumbQuality . $imgExtension;
      array_push($thumbPaths,$thumbPath);
      $i++;
    }


    // Generate thumbnails if the number 8 doesn't exist
    if(!file_exists($thumbPaths[8])){
      // Create folders if they don't exixt
      if (!file_exists($thumbDir)) {
        mkdir($thumbDir, 0777, true);
      }

      $i = 0;
      if($crop) {
        foreach ($thumbWidths as $thumbWidth) {
          $imagick = new imagick($imgUrl);
          $thumbHeight = $thumbHeights[$i];
          $imagick->cropThumbnailImage($thumbWidth,$thumbHeight);
          $imagick->setImageCompressionQuality($thumbQuality);
          $imagick->writeImage($thumbPaths[$i]);
          $imagick->clear();
          $imagick->destroy();
          $i++;
        }
      } else {
        foreach ($thumbWidths as $thumbWidth) {
          $imagick = new imagick($imgUrl);
          $thumbHeight = $thumbHeights[$i];
          $imagick->resizeImage($thumbWidth,$thumbHeight,imagick::FILTER_LANCZOS, 1, true);
          $imagick->setImageCompressionQuality($thumbQuality);
          $imagick->writeImage($thumbPaths[$i]);
          $imagick->clear();
          $imagick->destroy();
          $i++;
        }
      }
    }
    ?>

    <picture>
      <source  srcset="<?php echo $thumbPaths[9] . ' 2x,' . $thumbPaths[8]; ?>"  media="(min-width: <?php echo $breakPoints[3]; ?>px)"/>
      <source  srcset="<?php echo $thumbPaths[7] . ' 2x,' . $thumbPaths[6]; ?>"  media="(min-width: <?php echo $breakPoints[2]; ?>px) and (max-width: <?php echo $breakPoints[3] - 1; ?>px)"/>
      <source  srcset="<?php echo $thumbPaths[5] . ' 2x,' . $thumbPaths[4]; ?>"  media="(min-width: <?php echo $breakPoints[1]; ?>px) and (max-width: <?php echo $breakPoints[2] - 1; ?>px)"/>
      <source  srcset="<?php echo $thumbPaths[3] . ' 2x,' . $thumbPaths[2]; ?>"  media="(min-width: <?php echo $breakPoints[0]; ?>px) and (max-width: <?php echo $breakPoints[1] - 1; ?>px)"/>
      <source  srcset="<?php echo $thumbPaths[1] . ' 2x,' . $thumbPaths[0]; ?>"  media="(max-width: <?php echo $breakPoints[0] - 1; ?>px)"/>
      <img src="<?php echo $thumbPaths[8]; ?>"
        srcset="<?php echo $thumbPaths[9] . ' 2x,' . $thumbPaths[8]; ?>"
        alt="<?php echo $imageAlt; ?>"
        width="<?php echo $thumbWidths[8]; ?>"
        height="<?php echo $thumbHeights[8]; ?>"
      />
    </picture>
    <?php
  }
  ?>

Это что вызов функции выглядит (я использую это в CMS):

$params = array(
  'thumbWidth'  => array( 500,    750,    1000,     1600,     2000),
  'thumbHeight' => null,
  'breakPoints' => array(     500,    750,    1000,     1600),
  'quality'     => 65
);
$imgUrl = 'images/my-big-image.jpg';
$alt= 'Alternative text for my big image';
echo plgContentPicturebuilder::picturebuilder($imgUrl,$alt,$params);

Я успешно протестировал эту функцию, но я беспокоюсь о производительности. В зависимости от количества изображений на странице, эта функция может быть вызвана более 20 раз при первой загрузке страницы и быть предложено для создания более 200 эскизов.
Это когда она становится очень медленной и генерирует 504 шлюз тайм-аут ошибки на моем сервере.



541
3
задан 14 марта 2018 в 06:03 Источник Поделиться
Комментарии
1 ответ

Ниже отзыв, вероятно, не предотвратить тайм-аут ошибки, но, надеюсь, будет убирать код.

Описание-Код рассогласования

Повествование в вашем посте говорится:


В основном это то, что он делает :


  • проверки, если изображение существует. Если это не создает <picture> элемент.


Но первые несколько строк функции:


public static function picturebuilder($imgUrl, $imageAlt, $params) {
// check if the image exists
if (!file_exists($imgUrl)) {
echo "<script>console.log( 'Cannot find : " . $imgUrl . "' );</script>";
return false;
}

Поэтому код, кажется, на самом деле добавить JavaScript console.log() вызов на стороне клиента, вместо того, чтобы добавить <picture> элемент...

Вывод JavaScript с echo

Если вы собираетесь добавить JavaScript на стороне клиента и Эхо путь (т. е. $imgUrl) целесообразно санировать, что значение так, он не сломается на JavaScript. Один из способов-это использовать json_encode()
или htmlspecialchars().

echo "<script>console.log( 'Cannot find : " . htmlspecialchars($imgUrl) . "' );</script>";

Вы не указали, какая файловая система файлы, но некоторые системы позволяют одинарные кавычки и точку с запятой в именах файлов (например, МС файловой системы NT - см. Этот ответ на резюме).

Так что может показаться маловероятным, но возможно, что именем как следующие будут переданы:

$imgUrl = "photo1';compressed.png";

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


Непойманные синтаксис ошибка: отсутствует ) после списка аргументов

увеличивая счетчик переменной внутри foreach

В foreach высказывание "два синтаксиса"1 и потому, что массив индексов $thumbWidths несколько цифр, второй может быть использован, чтобы иметь значение $i обновляется автоматически (т. е. для каждого числового индекса назначается , начиная с 0), снижение первоначального присвоения переменной счетчика (т. е. $i = 0;) и обновление значения счетчика в конце каждого блока (т. е. $i++;).

foreach (array_expression as $key => $value)

Так что таких блоков, как:


$i = 0;
$thumbPaths = array();
foreach ($thumbWidths as $thumbWidth) {
$thumbHeight = $thumbHeights[$i];
$thumbPath = $thumbDir . '/' . $imgName . '-' . $thumbWidth . 'x' . $thumbHeight . 'q' . $thumbQuality . $imgExtension;
array_push($thumbPaths,$thumbPath);
$i++;
}

Можно упростить вот так:

$thumbPaths = array();
foreach ($thumbWidths as $i => $thumbWidth) {
$thumbHeight = $thumbHeights[$i];
$thumbPath = $thumbDir . '/' . $imgName . '-' . $thumbWidth . 'x' . $thumbHeight . 'q' . $thumbQuality . $imgExtension;
array_push($thumbPaths,$thumbPath);
}

И array_map() мог также позволить ему быть упрощена еще больше, хотя переменные вне foreach петли должны быть импортированы в функцию обратного вызова с use заявление, которое может показаться немного занудной:

$prefix = $thumbDir . '/' . $imgName . '-';
$suffix = 'q' . $thumbQuality . $imgExtension
$thumbPaths = array_map(function($thumbWidth, $i) use ($thumbHeights, $prefix, $suffix) {
$thumbHeight = $thumbHeights[$i];
return $prefix . $thumbWidth . 'x' . $thumbHeight . $suffix;
}, $thumbWidths, array_keys($thumbWidths));

Повторяющегося кода при записи изображений

Код в if-else блоки ближе к концу очень идентичны... единственное, что меняется, если $crop значение true то есть призыв к cropThumbnailImage()иначе resizeImage() называется. Кроме этого, остальная часть кода выглядит идентично:


if($crop) {
foreach ($thumbWidths as $thumbWidth) {
$imagick = new imagick($imgUrl);
$thumbHeight = $thumbHeights[$i];
$imagick->cropThumbnailImage($thumbWidth,$thumbHeight);
$imagick->setImageCompressionQuality($thumbQuality);
$imagick->writeImage($thumbPaths[$i]);
$imagick->clear();
$imagick->destroy();
$i++;
}
} else {
foreach ($thumbWidths as $thumbWidth) {
$imagick = new imagick($imgUrl);
$thumbHeight = $thumbHeights[$i];
$imagick->resizeImage($thumbWidth,$thumbHeight,imagick::FILTER_LANCZOS, 1, true);
$imagick->setImageCompressionQuality($thumbQuality);
$imagick->writeImage($thumbPaths[$i]);
$imagick->clear();
$imagick->destroy();
$i++;
}
}

Так что можно упростить следующим образом (также использует числовой индекс массива синтаксис - см. выше):

foreach ($thumbWidths as $i => $thumbWidth) {
$imagick = new imagick($imgUrl);
$thumbHeight = $thumbHeights[$i];
if ($crop) {
$imagick->cropThumbnailImage($thumbWidth,$thumbHeight);
}
else {
$imagick->resizeImage($thumbWidth,$thumbHeight,imagick::FILTER_LANCZOS, 1, true);
}
$imagick->setImageCompressionQuality($thumbQuality);
$imagick->writeImage($thumbPaths[$i]);
$imagick->clear();
$imagick->destroy();
}

2
ответ дан 14 марта 2018 в 09:03 Источник Поделиться