Pull to refresh

Превью и Resize картинок на лету

Reading time5 min
Views2.3K
Переделывал сайт заказчику на Netcat и с удивлением обнаружил, что кто-то ещё использует загрузку отдельных картинок для оригиналов и для превьюшек и как следствие отдельные столбцы в таблице БД. Куда ещё не шло создавать превьюшки на стороне сервера после загрузки оригинала.

Идея простая и не новая. C таким подходом я в первые столкнулся в UMI-CMS, а использовал в RubyOnRails. Смысл в том, что превью создаются только когда они нужны и какого угодно размера, а В БД храниться только название оригинала.

Если Вам необходимо вывести превью картинки вы вызываете функцию типа:
  1. @thumbs = Photo.view_thumbs('originals_name_file.jpg', '100', 'auto')
где второй и третий параметр это нужный размер в пикселах (auto значит автоматическая подгонка под массштаб).

Метод view_thumbs проверяет в папке (например "/images/cache") наличие файла originals_name_file_100xauto.jpg. Если находит то возвращает строку «originals_name_file_100xauto.jpg», если не находит, то создаёт файл нужных размеров на лету и возвращает то же самое.

Достоинства подхода очевидны:
  1. Не создаётся мусора в виде большого количества превьюшек на диске. Все превью храняться в одной папке «cache» и могут периодически удаляться для освобождения места.
  2. Неограниченное количество превьюшек разных размеров. Достаточно только задать нужные параметры в методе.
Для cakePHP есть хелпер images.php который можно выдернуть из Bakesale (автоматической подгонки нет). Ниже представлен метод на RubyOnRails реализующий данный подход.

  1. require 'RMagick'

  2. class Photo < ActiveRecord::Base
  3.  
  4.   def self.view_thumbs(image, width = 'auto', height = 'auto')
  5.         img_arr = image.split(".")
  6.     img, img_type = img_arr[0], img_arr[1]
  7.  
  8.     img_thumbs = "#{img}_#{width}x#{height}"
  9.     img_main_dir = "#{RAILS_ROOT}/public/images/"
  10.     img_thumbs_dir = "#{RAILS_ROOT}/public/images/cache/"

  11.     begin
  12.       img_thumbs = Magick::Image.read("#{img_thumbs_dir}/#{img_thumbs}.#{img_type}")
  13.     rescue Magick::ImageMagickError  # Вся соль тут. Если нет нужного тхумбса, то после чтения вываливается ошибка, которую мы спасаем. Если всё нормально, то код далее не выполняется
  14.       img_orig = Magick::Image.read("#{img_main_dir}/#{image}").first
  15.       img_size = {:main =>{:cols => img_orig.columns,:rows => img_orig.rows},
  16.         :thumb =>{:cols =>0.0, :rows =>0.0}
  17.       }
  18.       if 'auto' == width and 'auto' == height
  19.         img_size[:thumb][:rows] = img_size[:main][:rows]
  20.         img_size[:thumb][:cols] = img_size[:main][:cols]
  21.       end
  22.       if 'auto' != width and 'auto' == height
  23.         img_size[:thumb][:rows] = ((width.to_f/img_size[:main][:cols])*img_size[:main][:rows]).to_i
  24.         img_size[:thumb][:cols] = width.to_i
  25.       end
  26.       if 'auto' == width and 'auto' != height
  27.         img_size[:thumb][:rows] = height.to_i
  28.         img_size[:thumb][:cols] = ((height.to_f/img_size[:main][:rows])*img_size[:main][:cols]).to_i
  29.       end
  30.       if 'auto' != width and 'auto' != height
  31.         img_size[:thumb][:rows] = height.to_i  
  32.         img_size[:thumb][:cols] = width.to_i        
  33.       end

  34.       img_new = img_orig.resize!(img_size[:thumb][:cols].to_i, img_size[:thumb][:rows].to_i)
  35.       img_new.write "#{img_thumbs_dir}/#{img_thumbs}.#{img_type}"
  36.     end
  37.     img_thumbs = x
  38.     return "#{img_thumbs}.#{img_type}"
  39.   end
  40. end

Практика показывает, что указывание только одного размера в методе с автоматическим подгоном другого недостаточно. Если вы ограничиваете только по ширине, то обязательно попадётся картинка слишком высокая и вся вёрстка может съехать. То же самое с высотой. А в приведённом выше коде при указании одновременно и высоты и ширины ресайз будет без сохранения масштаба. Ниже приведён кусок кода на php, который реализует ресайз с ограничением и по высоте и по ширине с сохранением массштаба.

  1. $img_size = array(
  2.                         'main'=>array('width'=>imagesx($img_src), 'height'=>imagesy($img_src)),
  3.                         'thumb'=>array('width'=>0, 'height'=>0)
  4.                 );
  5.                
  6.                 if ('auto' == $width && 'auto' == $height) {
  7.                         $img_size['thumb']['height'] =(int) $img_size['main']['height'];
  8.                         $img_size['thumb']['width'] =(int) $img_size['main']['width'];
  9.                 }
  10.                 else if ('auto' != $width && 'auto' == $height) {
  11.                         $img_size['thumb']['width'] = (($img_size['main']['width'] <= $width) ? $img_size['main']['width'] : $width);
  12.                         $img_size['thumb']['height'] = (int) round(($img_size['thumb']['width']/$img_size['main']['width'])*$img_size['main']['height']);
  13.                 }
  14.                 else if ('auto' == $width && 'auto' != $height) {
  15.                         $img_size['thumb']['height'] = (($img_size['main']['height'] <= $height) ? $img_size['main']['height'] : $height);
  16.                         $img_size['thumb']['width'] = (int) round(($height/$img_size['main']['height'])*$img_size['main']['width']);
  17.                 }
  18.                 else if ('auto' != $width && 'auto' != $height) {
  19.                         $img_size['thumb']['height'] = (($img_size['main']['height'] <= $height) ? $img_size['main']['height'] : $height);
  20.                         $img_size['thumb']['width'] = (($img_size['main']['width'] <= $width) ? $img_size['main']['width'] : $width);
  21.                         $Kt = $img_size['thumb']['height']/$img_size['thumb']['width'];//5/1
  22.                         $Km = $img_size['main']['height']/$img_size['main']['width'];//5/1

  23.                         if ($Kt > $Km){
  24.                                 $img_size['thumb']['height'] = $img_size['thumb']['width']*$Km;
  25.                         }
  26.                         else if ($Kt < $Km) {
  27.                                 $img_size['thumb']['width'] = $img_size['thumb']['height']/$Km;
  28.                         }
  29.                 }
______________________
Текст подготовлен в Хабра Редакторе от © SoftCoder.ru

Tags:
Hubs:
+2
Comments14

Articles