Оквадрачивание всех картинок внутри директории
Date January 20th, 2012 Author Vitaly Agapov
Взгляни на его форму: квадрат, воплощение коварства!
Возникла необходимость сделать все изображения в одной директории квадратными, причём таким образом, чтобы не нарушить центровку изображений. В моём случае это была директория с файлами изображений Drupal, поэтому задача разбивается на две части. Первая часть – универсальная – как автоматически отредактировать все изображения. Вторая часть – для Drupal – как обновить данные о новых изображениях в базе данных.
Пользоваться будем нашим любимым Perl и его модулем для работы с библиотекой ImageMagick.
Часть 1. Оквадрачиваем
Для достижения цели я набросал такой вот скрипт quad.pl:
#!/usr/bin/perl use Image::Magick; use POSIX; my $path="/var/www/drupal/sites/default/files"; # Пробежимся по всем файлам и для каждого вызовем функцию quad_image() my @files = <$path/*.jpg>; foreach $file (@files) { quad_image($file, $file); } exit(0); sub quad_image { my ($in_img, $out_img) = @_; if ( !(-f "$in_img") ) { die ("Image file not found"); } my $q; # Создадим новый объект Image::Magick $q = Image::Magick->new; $q->Read("$in_img"); # Узнаем ширину и высоту изображения my ($x_size, $y_size) = $q->Get('width', 'height'); # Если один из параметро нулевой, то файл - битый if ($x_size == 0 || $y_size == 0){ return ("Unable to get filesize: $in_img."); } my $width; if ( $x_size > $y_size ) { $width=$x_size; my $yoffset = floor( ($x_size - $y_size)*0.5 ); # Растягиваем высоту до значения ширины $q->Extent(geometry=>$x_size."x".$y_size."+0-".$yoffset, width=>$width, height=>$width); } elsif ( $y_size > $x_size ) { $width=$y_size; my $xoffset = floor( ($y_size - $x_size)*0.5 ); # Растягиваем ширину до значения высоты $q->Extent(geometry=>$x_size."x".$y_size."-".$xoffset."+0", width=>$width, height=>$width); } if ( $width ) { # Небольшой необязательный кусок. Здесь мы добавляем надпись на преобразованное изображение # Вычисляем размер букв my $pointsize = floor( $width*0.04 ); # Вычисляем координаты надписи my $x = floor( $width*0.06 ); my $y = $width - $x; my $text = 'my watermark'; # Вставляем надпись $q->Annotate(x=>$x, y=>$y, pointsize=>$pointsize, fill=>'grey', text=>$text); # Дальше устанавливаем качество JPEG-файла $q->Set(quality=>75); # И записываем файл $q->Write("$out_img"); } }
С комментариями внутри скрипта должно вроде бы бть всё ясно.
Часть 2. Подгоняем Drupal
Вторую часть можно не читать тем, кому просто был интересен механизм преобразования изображений. У меня же была задача сделать квадратными все изображения товаров и каталогов Ubercart. Если просто оквадратить вышеприведённым скриптом все изображения и удалить все стили изображений из поддиректории styles, то пропорции всех выводимых изображений на странице исказятся. Это всё оттого, что ширина и высота изображений хранятся в базе данных и используются для установки атрибутов при выводе изображений на страницу.
Поэтому, когда я обнаружил такой вот эффект, пришлось срочно писать ещё один скрипт, исправляющий всё это безобразие. Скрипт просматривает все изображения в директории, сравнивает их размер со значением поля filesize таблицы file_managed и если находит несоответствие, то исправляет это значение на новое и заодно правит значения width и height во всех полях таблиц, ссылающихся на fid этого файла.
Вот и сам скрипт repair_drupal.pl.
#!/usr/bin/perl use Image::Magick; use POSIX; use DBI(); my $path="/var/www/drupal/sites/default/files"; glob $db="mydb"; glob $dbuser="myuser"; glob $dbpwd="pypwd"; $dbh = DBI->connect("DBI:mysql:database=$db;host=localhost",$dbuser,$dbpwd,{'RaiseError' => 1}); $dbh->do("SET NAMES utf8"); $dbh->do("SET CHARACTER SET utf8"); my @files = <$path/*.jpg>; foreach $file (@files) { repair_drupal($file); } exit(0); sub repair_drupal { my $in_img = $_[0]; if ( !(-f "$in_img") ) { die ("Image file not found"); } # Откусываем название файла от пути $in_img =~ /([^\/]+)$/; my $filename = $1; # Получаем размер файла в байтах my $filesize = -s $in_img; my $q; $q = Image::Magick->new; $q->Read("$in_img"); my ($x_size, $y_size) = $q->Get('width', 'height'); if ($x_size == 0 || $y_size == 0){ return ("Unable to get filesize: $in_img."); } # Получаем размер этого файла, который указан в базе данных my $sql = "SELECT fid,filesize FROM file_managed WHERE filename = '".$filename."'"; print $sql."\n"; my $sth=$dbh->prepare($sql); $sth->execute(); if ( $ref = $sth->fetchrow_hashref() ) { # Если размеры не совпадают, то проворачиваем все нужные действия if ( $ref->{filesize} != $filesize ) { print "Filesizes differ! (".$ref->{filesize}."->".$filesize.")\n"; $sql = "UPDATE file_managed SET filesize=".$filesize; print $sql."\n"; $dbh->do($sql); # Если речь не про Ubercart, то # Вместо uc_product и uc_catalog будут другие таблицы $sql = "UPDATE field_data_uc_product_image SET uc_product_image_width = ".$x_size.",uc_product_image_height=".$y_size." WHERE uc_product_image_fid=".$ref->{fid}; print $sql."\n"; $dbh->do($sql); $sql = "UPDATE field_revision_uc_product_image SET uc_product_image_width = ".$x_size.",uc_product_image_height=".$y_size." WHERE uc_product_image_fid=".$ref->{fid}; print $sql."\n"; $dbh->do($sql); $sql = "UPDATE field_data_uc_catalog_image SET uc_catalog_image_width = ".$x_size.",uc_catalog_image_height=".$y_size." WHERE uc_catalog_image_fid=".$ref->{fid}; print $sql."\n"; $dbh->do($sql); $sql = "UPDATE field_revision_uc_catalog_image SET uc_catalog_image_width = ".$x_size.",uc_catalog_image_height=".$y_size." WHERE uc_catalog_image_fid=".$ref->{fid}; print $sql."\n"; $dbh->do($sql); } else { print "Filesizes OK\n"; } } else { print "\n!!!!! No such file! \n"; } }
Итак, чтобы сделать квадратными все изображения в Drupal, надо сделать следующее:
- Преобразовать все картинки в sites/default/files скриптом из первой части.
- Удалить все миниатюры и прочие стили изображений из sites/default/files/styles.
- Поправить информацию о параметрах изображений в базе данных скриптом из второй части.
- Очистить кэш.
Ссылки
Документация по модулю Image::Magic
http://www.imagemagick.org/script/perl-magick.php
Tags: Drupal, Perl
Category:
Drupal, Perl |
No comments »