Оквадрачивание всех картинок внутри директории

Date January 20th, 2012 Author Vitaly Agapov

Взгляни на его форму: квадрат, воплощение коварства!

— м/ф «SpongeBob SquarePants»

Возникла необходимость сделать все изображения в одной директории квадратными, причём таким образом, чтобы не нарушить центровку изображений. В моём случае это была директория с файлами изображений 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, надо сделать следующее:

  1. Преобразовать все картинки в sites/default/files скриптом из первой части.
  2. Удалить все миниатюры и прочие стили изображений из sites/default/files/styles.
  3. Поправить информацию о параметрах изображений в базе данных скриптом из второй части.
  4. Очистить кэш.

Ссылки

Документация по модулю Image::Magic
http://www.imagemagick.org/script/perl-magick.php

Tags: ,
Category: Drupal, Perl | No comments »

Comments

Leave a comment

 Comment Form