Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
Gd.php
1<?php
10
12
13class Gd extends Engine
14{
15 protected $resource;
16 protected $format;
17
21 public function load()
22 {
23 $this->clear();
24
25 $info = $this->getInfo();
26
27 if ($info && $info->isSupported())
28 {
29 $this->format = $info->getFormat();
30 $resource = null;
31
32 switch ($this->format)
33 {
34 case File\Image::FORMAT_GIF:
35 $resource = imagecreatefromgif($this->file);
36 break;
37 case File\Image::FORMAT_PNG:
38 $resource = imagecreatefrompng($this->file);
39 break;
40 case File\Image::FORMAT_WEBP:
41 $resource = imagecreatefromwebp($this->file);
42 break;
43 case File\Image::FORMAT_BMP:
44 $resource = imagecreatefrombmp($this->file);
45 break;
46 case File\Image::FORMAT_JPEG:
47 ini_set('gd.jpeg_ignore_warning', 1);
48 $resource = imagecreatefromjpeg($this->file);
49 break;
50 }
51
52 if ($resource)
53 {
54 $this->resource = $resource;
55 return true;
56 }
57 }
58 return false;
59 }
60
64 public function rotate($angle, Color $bgColor)
65 {
66 if ($this->resource === null)
67 {
68 return false;
69 }
70
71 $angle = 360 - $angle;
72 $alpha = (1.0 - $bgColor->getAlpha()) * 127;
73 $color = imagecolorallocatealpha($this->resource, $bgColor->getRed(), $bgColor->getGreen(), $bgColor->getBlue(), $alpha);
74
75 $resource = imagerotate($this->resource, $angle, $color);
76
77 if ($resource === false)
78 {
79 return false;
80 }
81
82 $this->clear();
83 $this->resource = $resource;
84
85 return true;
86 }
87
91 public function flipVertical()
92 {
93 if ($this->resource === null)
94 {
95 return false;
96 }
97
98 return imageflip($this->resource, IMG_FLIP_VERTICAL);
99 }
100
104 public function flipHorizontal()
105 {
106 if ($this->resource === null)
107 {
108 return false;
109 }
110
111 return imageflip($this->resource, IMG_FLIP_HORIZONTAL);
112 }
113
117 public function setOrientation($orientation)
118 {
119 // not implemented
120 return true;
121 }
122
126 public function resize(Rectangle $source, Rectangle $destination)
127 {
128 if ($this->resource === null)
129 {
130 return false;
131 }
132
133 $destinationWidth = $destination->getWidth();
134 $destinationHeight = $destination->getHeight();
135
136 if (($picture = imagecreatetruecolor($destinationWidth, $destinationHeight)))
137 {
138 $transparentColor = -1;
139
140 imagealphablending($picture, false);
141
142 if ($this->format == File\Image::FORMAT_PNG || $this->format == File\Image::FORMAT_WEBP)
143 {
144 $color = imagecolorallocatealpha($picture, 0, 0, 0, 127);
145 imagefilledrectangle($picture, 0, 0, $destinationWidth, $destinationHeight, $color);
146 }
147 elseif ($this->format == File\Image::FORMAT_GIF)
148 {
149 // save transparency
150 $transparentColor = $this->getTransparentColor();
151 if ($transparentColor >= 0)
152 {
153 $rgb = imagecolorsforindex($this->resource, $transparentColor);
154 $transparentColor = imagecolorallocatealpha($picture, $rgb['red'], $rgb['green'], $rgb['blue'], 127);
155 imagefilledrectangle($picture, 0, 0, $destinationWidth, $destinationHeight, $transparentColor);
156 }
157 }
158
159 if (imagecopyresampled($picture, $this->resource, 0, 0, $source->getX(), $source->getY(), $destinationWidth, $destinationHeight, $source->getWidth(), $source->getHeight()))
160 {
161 $this->clear();
162 $this->resource = $picture;
163
164 // restore transparency
165 if ($transparentColor >= 0)
166 {
167 $this->restoreTransparency($transparentColor);
168 }
169
170 return true;
171 }
172 }
173 return false;
174 }
175
179 public function filter(Mask $mask)
180 {
181 if ($this->resource === null)
182 {
183 return false;
184 }
185
186 $transparentColor = -1;
187 if ($this->format == File\Image::FORMAT_GIF)
188 {
189 // Process transparency for GIFs
190 $transparentColor = $this->getTransparentColor();
191 }
192
193 // Fix left top corner
194 $newPixel = $this->calculatePixel($mask, 0, 0);
195
196 $result = imageconvolution($this->resource, $mask->getValue(), 1, 0);
197
198 if ($result)
199 {
200 // Fix left top corner
201 imagealphablending($this->resource, false);
202 imagesetpixel($this->resource, 0, 0, $newPixel);
203
204 // restore transparency
205 if ($transparentColor >= 0)
206 {
207 $this->restoreTransparency($transparentColor);
208 }
209 }
210 return $result;
211 }
212
213 protected function getTransparentColor(): int
214 {
215 $transparentColor = imagecolortransparent($this->resource);
216 if ($transparentColor < 0 || $transparentColor >= imagecolorstotal($this->resource))
217 {
218 return -1;
219 }
220 return $transparentColor;
221 }
222
223 protected function restoreTransparency($transparentColor)
224 {
225 imagecolortransparent($this->resource, $transparentColor);
226
227 $width = $this->getWidth();
228 $height = $this->getHeight();
229
230 for ($y = 0; $y < $height; ++$y)
231 {
232 for ($x = 0; $x < $width; ++$x)
233 {
234 if (((imagecolorat($this->resource, $x, $y) >> 24) & 0x7F) >= 100)
235 {
236 imagesetpixel($this->resource, $x, $y, $transparentColor);
237 }
238 }
239 }
240 }
241
248 protected function calculatePixel($mask, $x, $y)
249 {
250 $width = $this->getWidth();
251 $height = $this->getHeight();
252
253 $alpha = (imagecolorat($this->resource, $x, $y) >> 24) & 0xFF;
254 $newR = $newG = $newB = 0;
255
256 for ($j = 0; $j < 3; ++$j)
257 {
258 $yv = $y - 1 + $j;
259 if ($yv < 0)
260 {
261 $yv = 0;
262 }
263 elseif ($yv >= $height)
264 {
265 $yv = $height - 1;
266 }
267
268 for ($i = 0; $i < 3; ++$i)
269 {
270 $xv = $x - 1 + $i;
271 if ($xv < 0)
272 {
273 $xv = 0;
274 }
275 elseif ($xv >= $width)
276 {
277 $xv = $width - 1;
278 }
279
280 $m = $mask[$j][$i];
281 $rgb = imagecolorat($this->resource, $xv, $yv);
282
283 $newR += (($rgb >> 16) & 0xFF) * $m;
284 $newG += (($rgb >> 8) & 0xFF) * $m;
285 $newB += ($rgb & 0xFF) * $m;
286 }
287 }
288
289 $newR = ($newR > 255 ? 255 : ($newR < 0 ? 0 : $newR));
290 $newG = ($newG > 255 ? 255 : ($newG < 0 ? 0 : $newG));
291 $newB = ($newB > 255 ? 255 : ($newB < 0 ? 0 : $newB));
292
293 return imagecolorallocatealpha($this->resource, $newR, $newG, $newB, $alpha);
294 }
295
299 public function drawTextWatermark(TextWatermark $watermark)
300 {
301 if ($this->resource === null)
302 {
303 return false;
304 }
305
306 $font = $watermark->getFont();
307
308 if (!file_exists($font))
309 {
310 return false;
311 }
312
313 $utfText = $watermark->getUtfText();
314
315 $width = $this->getWidth();
316 $height = $this->getHeight();
317
318 if (($textWidth = $watermark->getWidth()) > 0)
319 {
320 $textBox = imagettfbbox(20, 0, $font, $utfText);
321 if (!is_array($textBox))
322 {
323 return false;
324 }
325
326 $scale = $textWidth / ($textBox[2] - $textBox[0]);
327 $fontSize = 20 * $scale;
328
329 $position = new Rectangle($textWidth, ($textBox[0] - $textBox[7]) * $scale);
330 }
331 else
332 {
333 $fontSize = $watermark->getFontSize($width);
334
335 $textBox = imagettfbbox($fontSize, 0, $font, $utfText);
336
337 $position = new Rectangle(($textBox[2] - $textBox[0]), ($textBox[0] - $textBox[7]));
338 }
339
340 $watermark->alignPosition($width, $height, $position);
341
342 $color = $watermark->getColor();
343 $textColor = imagecolorallocate($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue());
344
346 {
347 // Try to take into consideration font's descenders.
348 // Coordinates in imagettftext are for font's *baseline*.
349 // Let the descenders be 20% of the font size.
350 $descender = $fontSize * 0.2;
351 $y = $position->getY() + $position->getHeight() - $descender; // baseline
352 }
353 else
354 {
355 $y = $position->getY() + $fontSize; // baseline
356 }
357
358 $result = imagettftext($this->resource, $fontSize, 0, $position->getX(), $y, $textColor, $font, $utfText);
359
360 return ($result !== false);
361 }
362
366 public function drawImageWatermark(ImageWatermark $watermark)
367 {
368 if ($this->resource === null)
369 {
370 return false;
371 }
372
373 if (($image = $this->loadWatermark($watermark)) === null)
374 {
375 return false;
376 }
377
378 $width = $this->getWidth();
379 $height = $this->getHeight();
380
381 $watermarkWidth = $image->getWidth();
382 $watermarkHeight = $image->getHeight();
383
384 $position = new Rectangle($watermarkWidth, $watermarkHeight);
385
386 $watermark->alignPosition($width, $height, $position);
387
388 $watermarkX = $position->getX();
389 $watermarkY = $position->getY();
390
391 $watermarkAlpha = $watermark->getAlpha();
392 $repeat = ($watermark->getMode() == ImageWatermark::MODE_REPEAT);
393
394 for ($y = 0; $y < $watermarkHeight; $y++)
395 {
396 for ($x = 0; $x < $watermarkWidth; $x++)
397 {
398 $posY = $watermarkY + $y;
399 while (true)
400 {
401 $posX = $watermarkX + $x;
402 while (true)
403 {
404 $alpha = $watermarkAlpha;
405
406 $mainRgb = imagecolorsforindex($this->resource, imagecolorat($this->resource, $posX, $posY));
407 $watermarkRgb = imagecolorsforindex($image->resource, imagecolorat($image->resource, $x, $y));
408
409 if ($watermarkRgb['alpha'] == 127)
410 {
411 $pixel = $mainRgb;
412 }
413 else
414 {
415 if ($watermarkRgb['alpha'])
416 {
417 $alpha = round((( 127 - $watermarkRgb['alpha']) / 127), 2);
418 $alpha = $alpha * $watermarkAlpha;
419 }
420
421 $pixel = [];
422 foreach (['red', 'green', 'blue', 'alpha'] as $k)
423 {
424 $pixel[$k] = round(($mainRgb[$k] * (1 - $alpha)) + ($watermarkRgb[$k] * $alpha));
425 }
426 }
427
428 $color = imagecolorexactalpha($this->resource, $pixel['red'], $pixel['green'], $pixel['blue'], $pixel['alpha']);
429 if ($color == -1)
430 {
431 $color = imagecolorallocatealpha($this->resource, $pixel['red'], $pixel['green'], $pixel['blue'], $pixel['alpha']);
432 if ($color === false)
433 {
434 $color = imagecolorclosestalpha($this->resource, $pixel['red'], $pixel['green'], $pixel['blue'], $pixel['alpha']);
435 }
436 }
437
438 imagesetpixel($this->resource, $posX, $posY, $color);
439
440 $posX += $watermarkWidth;
441
442 if (!$repeat || $posX > $width)
443 {
444 break;
445 }
446 }
447
448 $posY += $watermarkHeight;
449
450 if (!$repeat || $posY > $height)
451 {
452 break;
453 }
454 }
455 }
456 }
457
458 $image->clear();
459
460 return true;
461 }
462
466 public function save($file, $quality = 95, $format = null)
467 {
468 if ($this->resource === null)
469 {
470 return false;
471 }
472
473 if ($format === null)
474 {
476 }
477
478 $result = false;
479
480 switch ($format)
481 {
482 case File\Image::FORMAT_GIF:
483 $result = imagegif($this->resource, $file);
484 break;
485 case File\Image::FORMAT_PNG:
486 imagealphablending($this->resource, true);
487 imagesavealpha($this->resource, true);
488 $result = imagepng($this->resource, $file);
489 break;
490 case File\Image::FORMAT_WEBP:
491 imagealphablending($this->resource, true);
492 imagesavealpha($this->resource, true);
493 $result = imagewebp($this->resource, $file, $quality);
494 break;
495 case File\Image::FORMAT_BMP:
496 $result = imagebmp($this->resource, $file);
497 break;
498 case File\Image::FORMAT_JPEG:
499 $result = imagejpeg($this->resource, $file, $quality);
500 break;
501 }
502
503 return $result;
504 }
505
509 public function getWidth()
510 {
511 return imagesx($this->resource);
512 }
513
517 public function getHeight()
518 {
519 return imagesy($this->resource);
520 }
521
525 public function clear()
526 {
527 if ($this->resource !== null)
528 {
529 imagedestroy($this->resource);
530 $this->resource = null;
531 }
532 }
533
538 public function setResource($resource)
539 {
540 $this->resource = $resource;
541 }
542
546 public function getResource()
547 {
548 return $this->resource;
549 }
550}
getInfo($flashEnabled=false)
Definition Engine.php:57
loadWatermark(ImageWatermark $watermark)
Definition Engine.php:222
rotate($angle, Color $bgColor)
Definition Gd.php:64
setResource($resource)
Definition Gd.php:538
calculatePixel($mask, $x, $y)
Definition Gd.php:248
drawTextWatermark(TextWatermark $watermark)
Definition Gd.php:299
save($file, $quality=95, $format=null)
Definition Gd.php:466
drawImageWatermark(ImageWatermark $watermark)
Definition Gd.php:366
filter(Mask $mask)
Definition Gd.php:179
setOrientation($orientation)
Definition Gd.php:117
resize(Rectangle $source, Rectangle $destination)
Definition Gd.php:126
restoreTransparency($transparentColor)
Definition Gd.php:223
alignPosition($width, $height, Rectangle $position)
Definition Watermark.php:61