PHP работа с изображениями
Здравствуйте, уважаемые читатели блога,
прошло много времени с публикации предыдущей статьи и вот у меня
появилось время пополнить коллекцию моих публикаций новым уникальным и
полезным контентом. В этом посте я хочу привести пример работы с изображениями на php. Данная статья навеяна мне задачами по разработке интернет магазина на Moguta.CMS.
PHP работа с изображениями описана во многих источниках с подробным
рассмотрением допустимых методов, но мне не встретилось ни одно
материала о их практическом применении.
Научившись применять основные из функций php библиотеки GD (Graphics Draw) я нашел ей применение в решении одной задачи, суть которой сводится к выравниванию масштаба всех изображений в наборе.
Дано: набор изображений для товаров интернет магазина.
Если внимательно посмотреть на приведенные изображения, то мы увидим,
что по габаритам они отличаются не только размерами холстов, на которых
расположена продукция, но и сами товары имеют разные размеры.
Задача: нормализовать все картинки и получить из выше приведенного набора следующий результат.
Получившиеся изображения товаров должны быть, все одного разрешения и одного масштаба.
Решение задачи ( PHP работа с изображениями )
На первый взгляд мы имеем довольно хитрую задача, требующую особого алгоритма в ее решении, но зная основы в PHP для работы с изображениями и четкое представление того, что должно получиться, задача становится менее проблемной.
Давайте определимся, какую последовательность действий нам нудно
выполнить, чтобы достичь желаемого результата, и выровнять все имеющиеся
изображения товаров в магазине.
- Вычислить размеры холста изображения;
- Вычислить ширину и высоту товара на изображении;
- Вычислить пропорции для сжатия холста вместе с изображением товара;
- Если товар на холсте меньше эталонного, то не сжимать его;
- Создать итоговый холст с нужными размерами и поместить в его центр получившуюся при сжатии картинку.
Выполнив каждый пункт текущего алгоритма, на выходе мы получим нормализованные картинки одинакового размера и масштаба.
Как вычислить размеры внутреннего рисунка на холсте
Самой сложной из подзадач является, поиск габаритов изображения:
На приведенном рисунке
- P0 – точка начала области изображения товара
- H1- высота товара
- W1- ширина товара
- H2- расстояние от верхней границы холста до точки P0
- W2- расстояние от левой границы холста до точки P0
- H3- высота всего изображения картинки товара
- W3- ширина всего изображения картинки товара
Чтобы определить все неизвестные нам параметры, мы воспользуемся как встроенными средствами PHP по работе с изображениями, так и собственным "велосипедом".
Найти H3 и W3 можно php функцией getimagesize(), но как бы нам вычислить H1 и W1? Что если мы вернемся к статье по распознаванию капчи? Возьмем из этой статьи алгоритм преобразования изображения в бинарную матрицу.
Бинарная матрица – это представления изображения в
виде единиц и нулей, все пикселы изображения отличающиеся от фонового
цвета получат значение = 0 , а пикселы составляющие само изображение
будут равны 1, в итоге мы получим такую матрицу:
Теперь мы можем запросто вычислить интервалы, в которых находятся 1-цы, о том как это сделать читайте в статье по распознаванию капчи.
После того как нам станут известны все необходимые параметры, можно будет выполнять наш алгоритм нормализации картинок.
В готовом виде PHP скрипт будет выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
| <?php
/**
* Класс нормальзующий картинку по заданному разрешению
*/
class imageWorker {
public $baseWidth = 150; // длина эталонного изображения (именно товара внутри картинки)
public $baseHeight = 119; // высота эталонного изображения (именно товара внутри картинки)
public $outImageWidth = 600; // длина изображения после обработки
public $outImageHeight = 400; // высота изображения после обработки
public $im = null; // дескриптор картитнки
public $binaryMartix = null; // матричное представление картитнки
public $saveBinaryMartixTofile = false; // сохранять матричное представление картитнки в файл
public $dir = 'image/source/'; // расположения набора картинок
public $saveMartix = false; // сохранять матричное представление картитнок
public $extensions = array("", "gif", "jpeg", "png"); // допустимые картинки
public $curImageWidth = 1; // ширина обрабатываемого изображения
public $curImageHeight = 1; // высота обрабатываемого изображения
public $imgFunctionProcess = "imagecreatefromjpeg"; // функция для работы с изображением
public $curExt = ""; // расширение картинки
public $curImageName = ""; // расширение картинки
public $dirUpload = 'image/result/'; // папка для выгрузки (должна быть создана)
function __construct($path, $w, $h) {
$this->outImageWidth = $w;
$this->outImageHeight = $h;
$this->curImageName = $path;
list($this->curImageWidth, $this->curImageHeight, $type) = getimagesize($this->dir.$path); // Получаем размеры и тип изображения (число)
$ext = $this->extensions[$type];
if ($ext) {
$this->imgFunctionProcess = 'imagecreatefrom'.$ext; // Получаем название функции, соответствующую типу, для создания изображения
$func = $this->imgFunctionProcess;
$this->curExt = $ext;
$this->im = $func($this->dir.$path); // Создаём дескриптор для работы с исходным изображением
if (!$this->im) {
return false;
}
} else {
echo 'Ошибка: Неизвестный формат изображения!';
return false;
}
$this->binaryMartix = $this->imageToMatrix($this->im, false);
if ($this->saveBinaryMartixTofile) {
$this->printMatrix($this->binaryMartix);
}
$res = $this->explodeMatrix($this->binaryMartix);
$width = $res['resultInterval'];
$cropX = $res['startInterval'];
$this->binaryMartix = $this->imageToMatrix($this->im, true);
$res = $this->explodeMatrix($this->binaryMartix);
$height = $res['resultInterval'];
$cropY = $res['startInterval'];
$result = "Размеры изображения (".$path.") <br/>width=".$this->curImageWidth."px; <br/> height=".$this->curImageHeight."px;";
$result .= "<br/>Размеры изделия внутри изображения <br/>width=".$width."px; <br/> height=".$height."px;";
$result .= "<br/>Коэффициенты сжатия <br/>width=".$this->baseWidth / $width."px; <br/> height=".$this->baseHeight / $height."px;";
$result .= "<br/>Отрезать картинку с точки <br/>cropX=".$cropX." <br/> cropY=".$cropY." ";
//$this->crop("2.png", $cropY, $cropX, $width, $height); // Вызываем функцию
//$this->reSizeImage($name, $ext, $tmp, 0.3);
echo $result;
if ($this->baseHeight < $height) {
$this->resizeImage($this->baseHeight / $height);
} else {
$this->resizeImage(1);
};
imagedestroy($this->im);
}
function explodeMatrix($binaryMartix) {
$temp = array();
// сложение столбцов для выявления интервалов
for ($i = 0; $i < count($binaryMartix); $i++) {
$sum = 0;
for ($j = 0; $j < count($binaryMartix[0]); $j++) {
$sum += $binaryMartix[$i][$j];
}
$temp[] = $sum ? 1 : 0;
}
// вычисление интервалов по полученной строке
$start = false;
$countPart = 0;
$arrayInterval = array();
foreach ($temp as $k => $v) {
if ($v == 1 && !$start) {
$arrayInterval[$countPart]['start'] = $k;
$start = true;
}
if ($v == 0 && $start) {
$arrayInterval[$countPart]['end'] = $k - 1;
$start = false;
$countPart++;
}
}
//отсеиваем помехи (мелкие интервалы), Большая картинка, всяко больше 20px.
$resultInterval = 1;
$startInterval = 1; // начало интервала
foreach ($arrayInterval as $key => $interval) {
if (($interval['end'] - $interval['start']) > 20) {
$resultInterval = $interval['end'] - $interval['start'];
$startInterval = $interval['start'];
}
}
return
array(
'resultInterval' => $resultInterval,
'startInterval' => $startInterval
);
}
/**
* Конвертация рисунка в бинарную матрицу
* Все пиксели отличные от фона получают значение 1
* @param imagecreatefrompng $im - картинка в формате PNG
* @param bool $rotate - горизонтальная или вертикальная матрица
*/
function imageToMatrix($im, $rotate = false) {
$height = imagesy($im);
$width = imagesx($im);
if ($rotate) {
$height = imagesx($im);
$width = imagesy($im);
}
$background = 0;
for ($i = 0; $i < $height; $i++)
for ($j = 0; $j < $width; $j++) {
if ($rotate) {
$rgb = imagecolorat($im, $i, $j);
} else {
$rgb = imagecolorat($im, $j, $i);
}
//получаем индексы цвета RGB
list($r, $g, $b) = array_values(imageColorsForIndex($im, $rgb));
//вычисляем индекс красного, для фона изображения
if ($i == 0 && $j == 0) {
$background = $r;
}
//echo "red=".$background;
$sensitivity = 15;
// если цвет пикселя не равен фоновому заполняем матрицу единицей
$binary[$i][$j] = ($r > $background - $sensitivity) ? 0 : 1;
}
return $binary;
}
/**
* Выводит матрицу на экран
* @param type $binaryMartix
*/
function printMatrix($binaryMartix) {
$return = '';
for ($i = 0; $i < count($binaryMartix); $i++) {
$return .= "\n";
for ($j = 0; $j < count($binaryMartix[0]); $j++) {
$return .= $binaryMartix[$i][$j]." ";
}
}
file_put_contents($this->dirUpload.$this->curImageName.".txt", $return);
}
/**
* Функция для ресайза картинки
* @paramint $koef коэффициент сжатия изображения
* @return void
*/
public function resizeImage($koef) {
// получение новых размеров
$newWidth = $koef * $this->curImageWidth;
$newHeight = $koef * $this->curImageHeight;
// ресэмплирование
$image_p = imagecreatetruecolor($this->outImageWidth, $this->outImageHeight);
//делаем фон изображения белым, иначе в png при прозрачных рисунках фон черный
$color = imagecolorallocate($image_p, 255, 255, 255);
imagefill($image_p, 0, 0, $color);
imagecopyresampled(
$image_p, $this->im, ($this->outImageWidth - $newWidth) / 2, ($this->outImageHeight - $newHeight) / 2, 0, 0, $newWidth, $newHeight, $this->curImageWidth, $this->curImageHeight
);
$func = "image".$this->curExt;
$func($image_p, $this->dirUpload.$this->curImageName);
imagedestroy($image_p);
}
}// конец тела класса
/**
* Массив имен файлов
*/
$imagesName = array(
'kameya_medium_1005858593.jpg',
'kameya_medium_1005862834.jpg',
'km0210-3_small.jpg',
'sd0201966_small.jpg',
);
/**
* Перебор массива имен файлов и нормализация изображений
*/
foreach ($imagesName as $image) {
if (file_exists('image/source/'.$image)) {
// каждую картинку нормальзуем и приведем к разрешению 200x200 пикселей
$encrypt = new imageWorker($image, 200, 200);
} else {
continue;
}
} |
Данный скрипт PHP работает с изображениями из папки image/source/ и по результату своего выполнения складывает нормализованные картинки в папку image/result/.
Выполнив поставленную задачу и на практике познакомившись с тем, как происходит в php работа с изображениями, мы получили опыт на основе, которого сможем приводить изображения товаров каталога в приятный вид.
|