‪TYPO3CMS  11.5
GraphicalFunctions.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
29 
37 {
43  public ‪$addFrameSelection = true;
44 
50  public ‪$gifExtension = 'gif';
51 
57  protected ‪$gdlibExtensions = [];
58 
64  protected ‪$colorspace = 'RGB';
65 
71  protected ‪$allowedColorSpaceNames = [
72  'CMY',
73  'CMYK',
74  'Gray',
75  'HCL',
76  'HSB',
77  'HSL',
78  'HWB',
79  'Lab',
80  'LCH',
81  'LMS',
82  'Log',
83  'Luv',
84  'OHTA',
85  'Rec601Luma',
86  'Rec601YCbCr',
87  'Rec709Luma',
88  'Rec709YCbCr',
89  'RGB',
90  'sRGB',
91  'Transparent',
92  'XYZ',
93  'YCbCr',
94  'YCC',
95  'YIQ',
96  'YCbCr',
97  'YUV',
98  ];
99 
105  public ‪$truecolorColors = 16777215;
106 
113  protected ‪$imageFileExt = ['gif', 'jpg', 'jpeg', 'png', 'tif', 'bmp', 'tga', 'pcx', 'ai', 'pdf', 'webp'];
114 
120  protected ‪$webImageExt = ['gif', 'jpg', 'jpeg', 'png'];
121 
127  protected ‪$processorEffectsEnabled = false;
128 
132  public ‪$cmds = [
133  'jpg' => '',
134  'jpeg' => '',
135  'gif' => '',
136  'png' => '',
137  ];
138 
143  protected ‪$processorEnabled;
144 
148  protected ‪$mayScaleUp = true;
149 
155  public ‪$filenamePrefix = '';
156 
163 
169  public ‪$dontCheckForExistingTempFile = false;
170 
176  public ‪$dontCompress = false;
177 
185  public ‪$alternativeOutputKey = '';
186 
192  public ‪$IM_commands = [];
193 
197  public ‪$workArea = [];
198 
204  protected ‪$saveAlphaLayer = false;
205 
211  public ‪$scalecmd = '-auto-orient -geometry';
212 
218  protected ‪$im5fx_blurSteps = '1x2,2x2,3x2,4x3,5x3,5x4,6x4,7x5,8x5,9x5';
219 
225  protected ‪$im5fx_sharpenSteps = '1x2,2x2,3x2,2x3,3x3,4x3,3x4,4x4,4x5,5x5';
226 
232  protected ‪$pixelLimitGif = 10000;
233 
239  protected ‪$colMap = [
240  'aqua' => [0, 255, 255],
241  'black' => [0, 0, 0],
242  'blue' => [0, 0, 255],
243  'fuchsia' => [255, 0, 255],
244  'gray' => [128, 128, 128],
245  'green' => [0, 128, 0],
246  'lime' => [0, 255, 0],
247  'maroon' => [128, 0, 0],
248  'navy' => [0, 0, 128],
249  'olive' => [128, 128, 0],
250  'purple' => [128, 0, 128],
251  'red' => [255, 0, 0],
252  'silver' => [192, 192, 192],
253  'teal' => [0, 128, 128],
254  'yellow' => [255, 255, 0],
255  'white' => [255, 255, 255],
256  ];
257 
263  protected ‪$csConvObj;
264 
268  protected ‪$jpegQuality = 85;
269 
273  public ‪$map = '';
274 
281  public ‪$setup = [];
282 
286  public ‪$w = 0;
287 
291  public ‪$h = 0;
292 
296  protected ‪$OFFSET;
297 
301  protected ‪$im;
302 
307  public function ‪__construct()
308  {
309  $gfxConf = ‪$GLOBALS['TYPO3_CONF_VARS']['GFX'];
310  if (function_exists('imagecreatefromjpeg') && function_exists('imagejpeg')) {
311  $this->gdlibExtensions[] = 'jpg';
312  $this->gdlibExtensions[] = 'jpeg';
313  }
314  if (function_exists('imagecreatefrompng') && function_exists('imagepng')) {
315  $this->gdlibExtensions[] = 'png';
316  }
317  if (function_exists('imagecreatefromgif') && function_exists('imagegif')) {
318  $this->gdlibExtensions[] = 'gif';
319  }
320 
321  if ($gfxConf['processor_colorspace'] && in_array($gfxConf['processor_colorspace'], $this->allowedColorSpaceNames, true)) {
322  $this->colorspace = $gfxConf['processor_colorspace'];
323  }
324 
325  $this->processorEnabled = (bool)$gfxConf['processor_enabled'];
326  // Setting default JPG parameters:
327  $this->jpegQuality = ‪MathUtility::forceIntegerInRange($gfxConf['jpg_quality'], 10, 100, 85);
328  $this->addFrameSelection = (bool)$gfxConf['processor_allowFrameSelection'];
329  if ($gfxConf['gdlib_png']) {
330  $this->gifExtension = 'png';
331  }
332  $this->imageFileExt = ‪GeneralUtility::trimExplode(',', $gfxConf['imagefile_ext']);
333 
334  // Boolean. This is necessary if using ImageMagick 5+.
335  // Effects in Imagemagick 5+ tends to render very slowly!!
336  // - therefore must be disabled in order not to perform sharpen, blurring and such.
337  $this->cmds['jpg'] = $this->cmds['jpeg'] = '-colorspace ' . $this->colorspace . ' -quality ' . ‪$this->jpegQuality;
338 
339  // ... but if 'processor_effects' is set, enable effects
340  if ($gfxConf['processor_effects']) {
341  $this->processorEffectsEnabled = true;
342  $this->cmds['jpg'] .= $this->‪v5_sharpen(10);
343  $this->cmds['jpeg'] .= $this->‪v5_sharpen(10);
344  }
345  // Secures that images are not scaled up.
346  $this->mayScaleUp = (bool)$gfxConf['processor_allowUpscaling'];
347  $this->csConvObj = GeneralUtility::makeInstance(CharsetConverter::class);
348  }
349 
350  /*************************************************
351  *
352  * Layering images / "IMAGE" GIFBUILDER object
353  *
354  *************************************************/
365  public function ‪maskImageOntoImage(&‪$im, $conf, ‪$workArea)
366  {
367  if ($conf['file'] && $conf['mask']) {
368  $imgInf = pathinfo($conf['file']);
369  $imgExt = strtolower($imgInf['extension']);
370  if (!in_array($imgExt, $this->gdlibExtensions, true)) {
371  $BBimage = $this->‪imageMagickConvert($conf['file'], $this->gifExtension);
372  } else {
373  $BBimage = $this->‪getImageDimensions($conf['file']);
374  }
375  $maskInf = pathinfo($conf['mask']);
376  $maskExt = strtolower($maskInf['extension']);
377  if (!in_array($maskExt, $this->gdlibExtensions, true)) {
378  $BBmask = $this->‪imageMagickConvert($conf['mask'], $this->gifExtension);
379  } else {
380  $BBmask = $this->‪getImageDimensions($conf['mask']);
381  }
382  if ($BBimage && $BBmask) {
383  ‪$w = imagesx(‪$im);
384  ‪$h = imagesy(‪$im);
385  $tmpStr = $this->‪randomName();
386  $theImage = $tmpStr . '_img.' . ‪$this->gifExtension;
387  $theDest = $tmpStr . '_dest.' . ‪$this->gifExtension;
388  $theMask = $tmpStr . '_mask.' . ‪$this->gifExtension;
389  // Prepare overlay image
390  $cpImg = $this->‪imageCreateFromFile($BBimage[3]);
391  $destImg = imagecreatetruecolor(‪$w, ‪$h);
392  // Preserve alpha transparency
393  if ($this->saveAlphaLayer) {
394  imagesavealpha($destImg, true);
395  $Bcolor = imagecolorallocatealpha($destImg, 0, 0, 0, 127);
396  imagefill($destImg, 0, 0, $Bcolor);
397  } else {
398  $Bcolor = imagecolorallocate($destImg, 0, 0, 0);
399  imagefilledrectangle($destImg, 0, 0, ‪$w, ‪$h, $Bcolor);
400  }
401  $this->‪copyGifOntoGif($destImg, $cpImg, $conf, ‪$workArea);
402  $this->‪ImageWrite($destImg, $theImage);
403  imagedestroy($cpImg);
404  imagedestroy($destImg);
405  // Prepare mask image
406  $cpImg = $this->‪imageCreateFromFile($BBmask[3]);
407  $destImg = imagecreatetruecolor(‪$w, ‪$h);
408  if ($this->saveAlphaLayer) {
409  imagesavealpha($destImg, true);
410  $Bcolor = imagecolorallocatealpha($destImg, 0, 0, 0, 127);
411  imagefill($destImg, 0, 0, $Bcolor);
412  } else {
413  $Bcolor = imagecolorallocate($destImg, 0, 0, 0);
414  imagefilledrectangle($destImg, 0, 0, ‪$w, ‪$h, $Bcolor);
415  }
416  $this->‪copyGifOntoGif($destImg, $cpImg, $conf, ‪$workArea);
417  $this->‪ImageWrite($destImg, $theMask);
418  imagedestroy($cpImg);
419  imagedestroy($destImg);
420  // Mask the images
421  $this->‪ImageWrite(‪$im, $theDest);
422  // Let combineExec handle maskNegation
423  $this->‪combineExec($theDest, $theImage, $theMask, $theDest);
424  // The main image is loaded again...
425  $backIm = $this->‪imageCreateFromFile($theDest);
426  // ... and if nothing went wrong we load it onto the old one.
427  if ($backIm) {
428  if (!$this->saveAlphaLayer) {
429  imagecolortransparent($backIm, -1);
430  }
431  ‪$im = $backIm;
432  }
433  // Unlink files from process
434  unlink($theDest);
435  unlink($theImage);
436  unlink($theMask);
437  }
438  }
439  }
440 
450  public function ‪copyImageOntoImage(&‪$im, $conf, ‪$workArea)
451  {
452  if ($conf['file']) {
453  if (!in_array($conf['BBOX'][2], $this->gdlibExtensions, true)) {
454  $conf['BBOX'] = $this->‪imageMagickConvert($conf['BBOX'][3], $this->gifExtension);
455  $conf['file'] = $conf['BBOX'][3];
456  }
457  $cpImg = $this->‪imageCreateFromFile($conf['file']);
458  $this->‪copyGifOntoGif(‪$im, $cpImg, $conf, ‪$workArea);
459  imagedestroy($cpImg);
460  }
461  }
462 
472  public function ‪copyGifOntoGif(&‪$im, $cpImg, $conf, ‪$workArea)
473  {
474  $cpW = imagesx($cpImg);
475  $cpH = imagesy($cpImg);
476  $tile = ‪GeneralUtility::intExplode(',', $conf['tile'] ?? '');
477  $tile[0] = ‪MathUtility::forceIntegerInRange($tile[0], 1, 20);
478  $tile[1] = ‪MathUtility::forceIntegerInRange($tile[1] ?? 0, 1, 20);
479  $cpOff = $this->‪objPosition($conf, ‪$workArea, [$cpW * $tile[0], $cpH * $tile[1]]);
480  for ($xt = 0; $xt < $tile[0]; $xt++) {
481  $Xstart = $cpOff[0] + $cpW * $xt;
482  // If this image is inside of the workArea, then go on
483  if ($Xstart + $cpW > ‪$workArea[0]) {
484  // X:
485  if ($Xstart < ‪$workArea[0]) {
486  $cpImgCutX = ‪$workArea[0] - $Xstart;
487  $Xstart = ‪$workArea[0];
488  } else {
489  $cpImgCutX = 0;
490  }
491  ‪$w = $cpW - $cpImgCutX;
492  if ($Xstart > ‪$workArea[0] + ‪$workArea[2] - ‪$w) {
493  ‪$w = ‪$workArea[0] + ‪$workArea[2] - $Xstart;
494  }
495  // If this image is inside of the workArea, then go on
496  if ($Xstart < ‪$workArea[0] + ‪$workArea[2]) {
497  // Y:
498  for ($yt = 0; $yt < $tile[1]; $yt++) {
499  $Ystart = $cpOff[1] + $cpH * $yt;
500  // If this image is inside of the workArea, then go on
501  if ($Ystart + $cpH > ‪$workArea[1]) {
502  if ($Ystart < ‪$workArea[1]) {
503  $cpImgCutY = ‪$workArea[1] - $Ystart;
504  $Ystart = ‪$workArea[1];
505  } else {
506  $cpImgCutY = 0;
507  }
508  ‪$h = $cpH - $cpImgCutY;
509  if ($Ystart > ‪$workArea[1] + ‪$workArea[3] - ‪$h) {
510  ‪$h = ‪$workArea[1] + ‪$workArea[3] - $Ystart;
511  }
512  // If this image is inside of the workArea, then go on
513  if ($Ystart < ‪$workArea[1] + ‪$workArea[3]) {
514  $this->‪imagecopyresized(‪$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, ‪$w, ‪$h, ‪$w, ‪$h);
515  }
516  }
517  }
518  }
519  }
520  }
521  }
522 
551  public function ‪imagecopyresized(&$dstImg, $srcImg, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight)
552  {
553  if (!$this->saveAlphaLayer) {
554  // Make true color image
555  $tmpImg = imagecreatetruecolor(imagesx($dstImg), imagesy($dstImg));
556  // Copy the source image onto that
557  ‪imagecopyresized($tmpImg, $dstImg, 0, 0, 0, 0, imagesx($dstImg), imagesy($dstImg), imagesx($dstImg), imagesy($dstImg));
558  // Then copy the source image onto that (the actual operation!)
559  ‪imagecopyresized($tmpImg, $srcImg, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
560  // Set the destination image
561  $dstImg = $tmpImg;
562  } else {
563  ‪imagecopyresized($dstImg, $srcImg, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
564  }
565  }
566 
567  /********************************
568  *
569  * Text / "TEXT" GIFBUILDER object
570  *
571  ********************************/
580  public function ‪makeText(&‪$im, $conf, ‪$workArea)
581  {
582  // Spacing
583  [$spacing, $wordSpacing] = $this->‪calcWordSpacing($conf);
584  // Position
585  $txtPos = $this->‪txtPosition($conf, ‪$workArea, $conf['BBOX']);
586  $theText = $conf['text'] ?? '';
587  if (($conf['imgMap'] ?? false) && is_array($conf['imgMap.'] ?? null)) {
588  $this->‪addToMap($this->‪calcTextCordsForMap($conf['BBOX'][2], $txtPos, $conf['imgMap.']), $conf['imgMap.']);
589  }
590  if (!($conf['hideButCreateMap'] ?? false)) {
591  // Font Color:
592  $cols = $this->‪convertColor($conf['fontColor']);
593  // NiceText is calculated
594  if (!($conf['niceText'] ?? false)) {
595  $Fcolor = imagecolorallocate(‪$im, $cols[0], $cols[1], $cols[2]);
596  // antiAliasing is setup:
597  $Fcolor = $conf['antiAlias'] ? $Fcolor : -$Fcolor;
598  for ($a = 0; $a < $conf['iterations']; $a++) {
599  // If any kind of spacing applies, we use this function:
600  if ($spacing || $wordSpacing) {
601  $this->‪SpacedImageTTFText(‪$im, $conf['fontSize'], $conf['angle'] ?? 0, $txtPos[0], $txtPos[1], $Fcolor, GeneralUtility::getFileAbsFileName($conf['fontFile']), $theText, $spacing, $wordSpacing, $conf['splitRendering.']);
602  } else {
603  $this->‪renderTTFText(‪$im, $conf['fontSize'], $conf['angle'] ?? 0, $txtPos[0], $txtPos[1], $Fcolor, $conf['fontFile'], $theText, $conf['splitRendering.'] ?? [], $conf);
604  }
605  }
606  } else {
607  // NICETEXT::
608  // options anti_aliased and iterations is NOT available when doing this!!
609  ‪$w = imagesx(‪$im);
610  ‪$h = imagesy(‪$im);
611  $tmpStr = $this->‪randomName();
612  $fileMenu = $tmpStr . '_menuNT.' . ‪$this->gifExtension;
613  $fileColor = $tmpStr . '_colorNT.' . ‪$this->gifExtension;
614  $fileMask = $tmpStr . '_maskNT.' . ‪$this->gifExtension;
615  // Scalefactor
616  $sF = ‪MathUtility::forceIntegerInRange(($conf['niceText.']['scaleFactor'] ?? 2), 2, 5);
617  $newW = (int)ceil($sF * imagesx(‪$im));
618  $newH = (int)ceil($sF * imagesy(‪$im));
619  // Make mask
620  $maskImg = imagecreatetruecolor($newW, $newH);
621  $Bcolor = imagecolorallocate($maskImg, 255, 255, 255);
622  imagefilledrectangle($maskImg, 0, 0, $newW, $newH, $Bcolor);
623  $Fcolor = imagecolorallocate($maskImg, 0, 0, 0);
624  // If any kind of spacing applies, we use this function:
625  if ($spacing || $wordSpacing) {
626  $this->‪SpacedImageTTFText($maskImg, $conf['fontSize'], $conf['angle'] ?? 0, $txtPos[0], $txtPos[1], $Fcolor, GeneralUtility::getFileAbsFileName($conf['fontFile']), $theText, $spacing, $wordSpacing, $conf['splitRendering.'], $sF);
627  } else {
628  $this->‪renderTTFText($maskImg, $conf['fontSize'], $conf['angle'] ?? 0, $txtPos[0], $txtPos[1], $Fcolor, $conf['fontFile'], $theText, $conf['splitRendering.'] ?? [], $conf, $sF);
629  }
630  $this->‪ImageWrite($maskImg, $fileMask);
631  imagedestroy($maskImg);
632  // Downscales the mask
633  if (!$this->processorEffectsEnabled) {
634  $command = trim($this->scalecmd . ' ' . ‪$w . 'x' . ‪$h . '! -negate');
635  } else {
636  $command = trim(($conf['niceText.']['before'] ?? '') . ' ' . $this->scalecmd . ' ' . ‪$w . 'x' . ‪$h . '! ' . ($conf['niceText.']['after'] ?? '') . ' -negate');
637  if (isset($conf['niceText.']['sharpen'])) {
638  $command .= $this->‪v5_sharpen($conf['niceText.']['sharpen']);
639  }
640  }
641  $this->‪imageMagickExec($fileMask, $fileMask, $command);
642  // Make the color-file
643  $colorImg = imagecreatetruecolor(‪$w, ‪$h);
644  $Ccolor = imagecolorallocate($colorImg, $cols[0], $cols[1], $cols[2]);
645  imagefilledrectangle($colorImg, 0, 0, ‪$w, ‪$h, $Ccolor);
646  $this->‪ImageWrite($colorImg, $fileColor);
647  imagedestroy($colorImg);
648  // The mask is applied
649  // The main pictures is saved temporarily
650  $this->‪ImageWrite(‪$im, $fileMenu);
651  $this->‪combineExec($fileMenu, $fileColor, $fileMask, $fileMenu);
652  // The main image is loaded again...
653  $backIm = $this->‪imageCreateFromFile($fileMenu);
654  // ... and if nothing went wrong we load it onto the old one.
655  if ($backIm) {
656  if (!$this->saveAlphaLayer) {
657  imagecolortransparent($backIm, -1);
658  }
659  ‪$im = $backIm;
660  }
661  // Deleting temporary files;
662  unlink($fileMenu);
663  unlink($fileColor);
664  unlink($fileMask);
665  }
666  }
667  }
668 
679  public function ‪txtPosition($conf, ‪$workArea, $BB)
680  {
681  $angle = (int)($conf['angle'] ?? 0) / 180 * M_PI;
682  $conf['angle'] = 0;
683  $straightBB = $this->‪calcBBox($conf);
684  // offset, align, valign, workarea
685  // [0]=x, [1]=y, [2]=w, [3]=h
686  $result = [];
687  $result[2] = $BB[0];
688  $result[3] = $BB[1];
689  ‪$w = ‪$workArea[2];
690  $alignment = $conf['align'] ?? '';
691  switch ($alignment) {
692  case 'right':
693 
694  case 'center':
695  $factor = abs(cos($angle));
696  $sign = cos($angle) < 0 ? -1 : 1;
697  $len1 = $sign * $factor * $straightBB[0];
698  $len2 = $sign * $BB[0];
699  $result[0] = ‪$w - ceil($len2 * $factor + (1 - $factor) * $len1);
700  $factor = abs(sin($angle));
701  $sign = sin($angle) < 0 ? -1 : 1;
702  $len1 = $sign * $factor * $straightBB[0];
703  $len2 = $sign * $BB[1];
704  $result[1] = ceil($len2 * $factor + (1 - $factor) * $len1);
705  break;
706  }
707  switch ($alignment) {
708  case 'right':
709  break;
710  case 'center':
711  $result[0] = round($result[0] / 2);
712  $result[1] = round($result[1] / 2);
713  break;
714  default:
715  $result[0] = 0;
716  $result[1] = 0;
717  }
718  $result = $this->‪applyOffset($result, ‪GeneralUtility::intExplode(',', $conf['offset'] ?? ''));
719  $result = $this->‪applyOffset($result, ‪$workArea);
720  return $result;
721  }
722 
732  public function ‪calcBBox($conf)
733  {
734  $sF = $this->‪getTextScalFactor($conf);
735  [$spacing, $wordSpacing] = $this->‪calcWordSpacing($conf, $sF);
736  $theText = $conf['text'];
737  $charInf = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'] ?? 0, $conf['fontFile'], $theText, ($conf['splitRendering.'] ?? []), $sF);
738  $theBBoxInfo = $charInf;
739  if ($conf['angle'] ?? false) {
740  $xArr = [$charInf[0], $charInf[2], $charInf[4], $charInf[6]];
741  $yArr = [$charInf[1], $charInf[3], $charInf[5], $charInf[7]];
742  $x = max($xArr) - min($xArr);
743  $y = max($yArr) - min($yArr);
744  } else {
745  $x = $charInf[2] - $charInf[0];
746  $y = $charInf[1] - $charInf[7];
747  }
748  // Set original lineHeight (used by line breaks):
749  $theBBoxInfo['lineHeight'] = $y;
750  if (!empty($conf['lineHeight'])) {
751  $theBBoxInfo['lineHeight'] = (int)$conf['lineHeight'];
752  }
753 
754  if ($spacing) {
755  $x = 0;
756  $utf8Chars = $this->csConvObj->utf8_to_numberarray($theText);
757  // For each UTF-8 char, do:
758  foreach ($utf8Chars as $char) {
759  $charInf = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $char, $conf['splitRendering.'], $sF);
760  $charW = $charInf[2] - $charInf[0];
761  $x += $charW + ($char === ' ' ? $wordSpacing : $spacing);
762  }
763  } elseif ($wordSpacing) {
764  $x = 0;
765  $bits = explode(' ', $theText);
766  foreach ($bits as $word) {
767  $word .= ' ';
768  $wordInf = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $word, $conf['splitRendering.'], $sF);
769  $wordW = $wordInf[2] - $wordInf[0];
770  $x += $wordW + $wordSpacing;
771  }
772  } elseif (isset($conf['breakWidth']) && $conf['breakWidth'] && $this->‪getRenderedTextWidth($conf['text'], $conf) > $conf['breakWidth']) {
773  $maxWidth = 0;
774  $currentWidth = 0;
775  $breakWidth = $conf['breakWidth'];
776  $breakSpace = $this->‪getBreakSpace($conf, $theBBoxInfo);
777  $wordPairs = $this->‪getWordPairsForLineBreak($conf['text']);
778  // Iterate through all word pairs:
779  foreach ($wordPairs as $index => $wordPair) {
780  $wordWidth = $this->‪getRenderedTextWidth($wordPair, $conf);
781  if ($index == 0 || $currentWidth + $wordWidth <= $breakWidth) {
782  $currentWidth += $wordWidth;
783  } else {
784  $maxWidth = max($maxWidth, $currentWidth);
785  $y += $breakSpace;
786  // Restart:
787  $currentWidth = $wordWidth;
788  }
789  }
790  $x = max($maxWidth, $currentWidth) * $sF;
791  }
792  if ($sF > 1) {
793  $x = ceil($x / $sF);
794  $y = ceil($y / $sF);
795  if (is_array($theBBoxInfo)) {
796  foreach ($theBBoxInfo as &$value) {
797  $value = ceil($value / $sF);
798  }
799  unset($value);
800  }
801  }
802  return [$x, $y, $theBBoxInfo];
803  }
804 
814  public function ‪addToMap($cords, $conf)
815  {
816  $this->map .= '<area shape="poly" coords="' . implode(',', $cords) . '"'
817  . ' href="' . htmlspecialchars($conf['url']) . '"'
818  . ($conf['target'] ? ' target="' . htmlspecialchars($conf['target']) . '"' : '')
819  . ((string)$conf['titleText'] !== '' ? ' title="' . htmlspecialchars($conf['titleText']) . '"' : '')
820  . ' alt="' . htmlspecialchars($conf['altText']) . '" />';
821  }
822 
834  public function ‪calcTextCordsForMap($cords, $offset, $conf)
835  {
836  $newCords = [];
837  $pars = ‪GeneralUtility::intExplode(',', $conf['explode'] . ',');
838  $newCords[0] = $cords[0] + $offset[0] - $pars[0];
839  $newCords[1] = $cords[1] + $offset[1] + $pars[1];
840  $newCords[2] = $cords[2] + $offset[0] + $pars[0];
841  $newCords[3] = $cords[3] + $offset[1] + $pars[1];
842  $newCords[4] = $cords[4] + $offset[0] + $pars[0];
843  $newCords[5] = $cords[5] + $offset[1] - $pars[1];
844  $newCords[6] = $cords[6] + $offset[0] - $pars[0];
845  $newCords[7] = $cords[7] + $offset[1] - $pars[1];
846  return $newCords;
847  }
848 
868  public function ‪SpacedImageTTFText(&‪$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF = 1)
869  {
870  $spacing *= $sF;
871  $wordSpacing *= $sF;
872  if (!$spacing && $wordSpacing) {
873  $bits = explode(' ', $text);
874  foreach ($bits as $word) {
875  $word .= ' ';
876  $wordInf = $this->‪ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $word, $splitRenderingConf, $sF);
877  $wordW = $wordInf[2] - $wordInf[0];
878  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $word, $splitRenderingConf, $sF);
879  $x += $wordW + $wordSpacing;
880  }
881  } else {
882  $utf8Chars = $this->csConvObj->utf8_to_numberarray($text);
883  // For each UTF-8 char, do:
884  foreach ($utf8Chars as $char) {
885  $charInf = $this->‪ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $char, $splitRenderingConf, $sF);
886  $charW = $charInf[2] - $charInf[0];
887  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $char, $splitRenderingConf, $sF);
888  $x += $charW + ($char === ' ' ? $wordSpacing : $spacing);
889  }
890  }
891  }
892 
901  public function ‪fontResize($conf)
902  {
903  // You have to use +calc options like [10.h] in 'offset' to get the right position of your text-image, if you use +calc in XY height!!!!
904  $maxWidth = (int)$conf['maxWidth'];
905  [$spacing, $wordSpacing] = $this->‪calcWordSpacing($conf);
906  if ($maxWidth) {
907  // If any kind of spacing applys, we use this function:
908  if ($spacing || $wordSpacing) {
909  return $conf['fontSize'];
910  }
911  do {
912  // Determine bounding box.
913  $bounds = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $conf['text'], $conf['splitRendering.']);
914  if ($conf['angle'] < 0) {
915  $pixelWidth = abs($bounds[4] - $bounds[0]);
916  } elseif ($conf['angle'] > 0) {
917  $pixelWidth = abs($bounds[2] - $bounds[6]);
918  } else {
919  $pixelWidth = abs($bounds[4] - $bounds[6]);
920  }
921  // Size is fine, exit:
922  if ($pixelWidth <= $maxWidth) {
923  break;
924  }
925  $conf['fontSize']--;
926  } while ($conf['fontSize'] > 1);
927  }
928  return $conf['fontSize'];
929  }
930 
942  public function ‪ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF = 1)
943  {
944  // Initialize:
945  $offsetInfo = [];
946  $stringParts = $this->‪splitString($string, $splitRendering, $fontSize, $fontFile);
947  // Traverse string parts:
948  foreach ($stringParts as $strCfg) {
949  $fontFile = GeneralUtility::getFileAbsFileName($strCfg['fontFile']);
950  if (is_readable($fontFile)) {
951  // Calculate Bounding Box for part.
952  $calc = imagettfbbox($this->‪compensateFontSizeiBasedOnFreetypeDpi($sF * $strCfg['fontSize']), $angle, $fontFile, $strCfg['str']);
953  // Calculate offsets:
954  if (empty($offsetInfo)) {
955  // First run, just copy over.
956  $offsetInfo = $calc;
957  } else {
958  $offsetInfo[2] += $calc[2] - $calc[0] + (int)$splitRendering['compX'] + (int)$strCfg['xSpaceBefore'] + (int)$strCfg['xSpaceAfter'];
959  $offsetInfo[3] += $calc[3] - $calc[1] - (int)$splitRendering['compY'] - (int)$strCfg['ySpaceBefore'] - (int)$strCfg['ySpaceAfter'];
960  $offsetInfo[4] += $calc[4] - $calc[6] + (int)$splitRendering['compX'] + (int)$strCfg['xSpaceBefore'] + (int)$strCfg['xSpaceAfter'];
961  $offsetInfo[5] += $calc[5] - $calc[7] - (int)$splitRendering['compY'] - (int)$strCfg['ySpaceBefore'] - (int)$strCfg['ySpaceAfter'];
962  }
963  } else {
964  ‪debug('cannot read file: ' . $fontFile, self::class . '::ImageTTFBBoxWrapper()');
965  }
966  }
967  return $offsetInfo;
968  }
969 
984  public function ‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF = 1)
985  {
986  // Initialize:
987  $stringParts = $this->‪splitString($string, $splitRendering, $fontSize, $fontFile);
988  $x = (int)ceil($sF * $x);
989  $y = (int)ceil($sF * $y);
990  // Traverse string parts:
991  foreach ($stringParts as $i => $strCfg) {
992  // Initialize:
993  $colorIndex = $color;
994  // Set custom color if any (only when niceText is off):
995  if (($strCfg['color'] ?? false) && $sF == 1) {
996  $cols = $this->‪convertColor($strCfg['color']);
997  $colorIndex = imagecolorallocate(‪$im, $cols[0], $cols[1], $cols[2]);
998  $colorIndex = $color >= 0 ? $colorIndex : -$colorIndex;
999  }
1000  // Setting xSpaceBefore
1001  if ($i) {
1002  $x += (int)$strCfg['xSpaceBefore'];
1003  $y -= (int)$strCfg['ySpaceBefore'];
1004  }
1005  $fontFile = GeneralUtility::getFileAbsFileName($strCfg['fontFile']);
1006  if (is_readable($fontFile)) {
1007  // Render part:
1008  imagettftext(‪$im, $this->‪compensateFontSizeiBasedOnFreetypeDpi($sF * $strCfg['fontSize']), $angle, $x, $y, $colorIndex, $fontFile, $strCfg['str']);
1009  // Calculate offset to apply:
1010  $wordInf = imagettfbbox($this->‪compensateFontSizeiBasedOnFreetypeDpi($sF * $strCfg['fontSize']), $angle, GeneralUtility::getFileAbsFileName($strCfg['fontFile']), $strCfg['str']);
1011  $x += $wordInf[2] - $wordInf[0] + (int)($splitRendering['compX'] ?? 0) + (int)($strCfg['xSpaceAfter'] ?? 0);
1012  $y += $wordInf[5] - $wordInf[7] - (int)($splitRendering['compY'] ?? 0) - (int)($strCfg['ySpaceAfter'] ?? 0);
1013  } else {
1014  ‪debug('cannot read file: ' . $fontFile, self::class . '::ImageTTFTextWrapper()');
1015  }
1016  }
1017  }
1018 
1028  public function ‪splitString($string, $splitRendering, $fontSize, $fontFile)
1029  {
1030  // Initialize by setting the whole string and default configuration as the first entry.
1031  $result = [];
1032  $result[] = [
1033  'str' => $string,
1034  'fontSize' => $fontSize,
1035  'fontFile' => $fontFile,
1036  ];
1037  // Traverse the split-rendering configuration:
1038  // Splitting will create more entries in $result with individual configurations.
1039  if (is_array($splitRendering)) {
1040  $sKeyArray = ‪ArrayUtility::filterAndSortByNumericKeys($splitRendering);
1041  // Traverse configured options:
1042  foreach ($sKeyArray as $key) {
1043  $cfg = $splitRendering[$key . '.'];
1044  // Process each type of split rendering keyword:
1045  switch ((string)$splitRendering[$key]) {
1046  case 'highlightWord':
1047  if ((string)$cfg['value'] !== '') {
1048  $newResult = [];
1049  // Traverse the current parts of the result array:
1050  foreach ($result as $part) {
1051  // Explode the string value by the word value to highlight:
1052  $explodedParts = explode($cfg['value'], $part['str']);
1053  foreach ($explodedParts as $c => $expValue) {
1054  if ((string)$expValue !== '') {
1055  $newResult[] = array_merge($part, ['str' => $expValue]);
1056  }
1057  if ($c + 1 < count($explodedParts)) {
1058  $newResult[] = [
1059  'str' => $cfg['value'],
1060  'fontSize' => $cfg['fontSize'] ?: $part['fontSize'],
1061  'fontFile' => $cfg['fontFile'] ?: $part['fontFile'],
1062  'color' => $cfg['color'],
1063  'xSpaceBefore' => $cfg['xSpaceBefore'],
1064  'xSpaceAfter' => $cfg['xSpaceAfter'],
1065  'ySpaceBefore' => $cfg['ySpaceBefore'],
1066  'ySpaceAfter' => $cfg['ySpaceAfter'],
1067  ];
1068  }
1069  }
1070  }
1071  // Set the new result as result array:
1072  if (!empty($newResult)) {
1073  $result = $newResult;
1074  }
1075  }
1076  break;
1077  case 'charRange':
1078  if ((string)$cfg['value'] !== '') {
1079  // Initialize range:
1080  $ranges = ‪GeneralUtility::trimExplode(',', $cfg['value'], true);
1081  foreach ($ranges as $i => $rangeDef) {
1082  $ranges[$i] = ‪GeneralUtility::intExplode('-', (string)$ranges[$i]);
1083  if (!isset($ranges[$i][1])) {
1084  $ranges[$i][1] = $ranges[$i][0];
1085  }
1086  }
1087  $newResult = [];
1088  // Traverse the current parts of the result array:
1089  foreach ($result as $part) {
1090  // Initialize:
1091  $currentState = -1;
1092  $bankAccum = '';
1093  // Explode the string value by the word value to highlight:
1094  $utf8Chars = $this->csConvObj->utf8_to_numberarray($part['str']);
1095  foreach ($utf8Chars as $utfChar) {
1096  // Find number and evaluate position:
1097  $uNumber = (int)$this->csConvObj->utf8CharToUnumber($utfChar);
1098  $inRange = 0;
1099  foreach ($ranges as $rangeDef) {
1100  if ($uNumber >= $rangeDef[0] && (!$rangeDef[1] || $uNumber <= $rangeDef[1])) {
1101  $inRange = 1;
1102  break;
1103  }
1104  }
1105  if ($currentState == -1) {
1106  $currentState = $inRange;
1107  }
1108  // Initialize first char
1109  // Switch bank:
1110  if ($inRange != $currentState && $uNumber !== 9 && $uNumber !== 10 && $uNumber !== 13 && $uNumber !== 32) {
1111  // Set result:
1112  if ($bankAccum !== '') {
1113  $newResult[] = [
1114  'str' => $bankAccum,
1115  'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'],
1116  'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'],
1117  'color' => $currentState ? $cfg['color'] : '',
1118  'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '',
1119  'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '',
1120  'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '',
1121  'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : '',
1122  ];
1123  }
1124  // Initialize new settings:
1125  $currentState = $inRange;
1126  $bankAccum = '';
1127  }
1128  // Add char to bank:
1129  $bankAccum .= $utfChar;
1130  }
1131  // Set result for FINAL part:
1132  if ($bankAccum !== '') {
1133  $newResult[] = [
1134  'str' => $bankAccum,
1135  'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'],
1136  'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'],
1137  'color' => $currentState ? $cfg['color'] : '',
1138  'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '',
1139  'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '',
1140  'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '',
1141  'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : '',
1142  ];
1143  }
1144  }
1145  // Set the new result as result array:
1146  if (!empty($newResult)) {
1147  $result = $newResult;
1148  }
1149  }
1150  break;
1151  }
1152  }
1153  }
1154  return $result;
1155  }
1156 
1166  public function ‪calcWordSpacing($conf, $scaleFactor = 1)
1167  {
1168  $spacing = (int)($conf['spacing'] ?? 0);
1169  $wordSpacing = (int)($conf['wordSpacing'] ?? 0);
1170  $wordSpacing = $wordSpacing ?: $spacing * 2;
1171  $spacing *= $scaleFactor;
1172  $wordSpacing *= $scaleFactor;
1173  return [$spacing, $wordSpacing];
1174  }
1175 
1183  public function ‪getTextScalFactor($conf)
1184  {
1185  if (!($conf['niceText'] ?? false)) {
1186  $sF = 1;
1187  } else {
1188  // NICETEXT::
1189  $sF = ‪MathUtility::forceIntegerInRange(($conf['niceText.']['scaleFactor'] ?? 2), 2, 5);
1190  }
1191  return $sF;
1192  }
1193 
1198  public function ‪setImageFileExt(array ‪$imageFileExt): void
1199  {
1200  $this->imageFileExt = ‪$imageFileExt;
1201  }
1202 
1218  protected function ‪renderTTFText(&‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $conf, $sF = 1)
1219  {
1220  if (isset($conf['breakWidth']) && $conf['breakWidth'] && $this->‪getRenderedTextWidth($string, $conf) > $conf['breakWidth']) {
1221  $phrase = '';
1222  $currentWidth = 0;
1223  $breakWidth = $conf['breakWidth'];
1224  $breakSpace = $this->‪getBreakSpace($conf);
1225  $wordPairs = $this->‪getWordPairsForLineBreak($string);
1226  // Iterate through all word pairs:
1227  foreach ($wordPairs as $index => $wordPair) {
1228  $wordWidth = $this->‪getRenderedTextWidth($wordPair, $conf);
1229  if ($index == 0 || $currentWidth + $wordWidth <= $breakWidth) {
1230  $currentWidth += $wordWidth;
1231  $phrase .= $wordPair;
1232  } else {
1233  // Render the current phrase that is below breakWidth:
1234  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $phrase, $splitRendering, $sF);
1235  // Calculate the news height offset:
1236  $y += $breakSpace;
1237  // Restart the phrase:
1238  $currentWidth = $wordWidth;
1239  $phrase = $wordPair;
1240  }
1241  }
1242  // Render the remaining phrase:
1243  if ($currentWidth) {
1244  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $phrase, $splitRendering, $sF);
1245  }
1246  } else {
1247  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF);
1248  }
1249  }
1250 
1257  protected function ‪getWordPairsForLineBreak($string)
1258  {
1259  $wordPairs = [];
1260  $wordsArray = preg_split('#([- .,!:]+)#', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
1261  $wordsArray = is_array($wordsArray) ? $wordsArray : [];
1262  $wordsCount = count($wordsArray);
1263  for ($index = 0; $index < $wordsCount; $index += 2) {
1264  $wordPairs[] = $wordsArray[$index] . ($wordsArray[$index + 1] ?? '');
1265  }
1266  return $wordPairs;
1267  }
1268 
1276  protected function ‪getRenderedTextWidth($text, $conf)
1277  {
1278  $bounds = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $text, $conf['splitRendering.']);
1279  if ($conf['angle'] < 0) {
1280  $pixelWidth = abs($bounds[4] - $bounds[0]);
1281  } elseif ($conf['angle'] > 0) {
1282  $pixelWidth = abs($bounds[2] - $bounds[6]);
1283  } else {
1284  $pixelWidth = abs($bounds[4] - $bounds[6]);
1285  }
1286  return $pixelWidth;
1287  }
1288 
1296  protected function ‪getBreakSpace($conf, array $boundingBox = null)
1297  {
1298  if (!isset($boundingBox)) {
1299  $boundingBox = $this->‪calcBBox($conf);
1300  $boundingBox = $boundingBox[2];
1301  }
1302  if (isset($conf['breakSpace']) && $conf['breakSpace']) {
1303  $breakSpace = $boundingBox['lineHeight'] * $conf['breakSpace'];
1304  } else {
1305  $breakSpace = $boundingBox['lineHeight'];
1306  }
1307  return $breakSpace;
1308  }
1309 
1310  /*********************************************
1311  *
1312  * Other GIFBUILDER objects related to TEXT
1313  *
1314  *********************************************/
1325  public function ‪makeOutline(&‪$im, $conf, ‪$workArea, $txtConf)
1326  {
1327  $thickness = (int)$conf['thickness'];
1328  if ($thickness) {
1329  $txtConf['fontColor'] = $conf['color'];
1330  $outLineDist = ‪MathUtility::forceIntegerInRange($thickness, 1, 2);
1331  for ($b = 1; $b <= $outLineDist; $b++) {
1332  if ($b == 1) {
1333  $it = 8;
1334  } else {
1335  $it = 16;
1336  }
1337  $outL = $this->‪circleOffset($b, $it);
1338  for ($a = 0; $a < $it; $a++) {
1339  $this->‪makeText(‪$im, $txtConf, $this->‪applyOffset(‪$workArea, $outL[$a]));
1340  }
1341  }
1342  }
1343  }
1344 
1355  public function ‪circleOffset($distance, $iterations)
1356  {
1357  $res = [];
1358  if ($distance && $iterations) {
1359  for ($a = 0; $a < $iterations; $a++) {
1360  $yOff = round(sin(2 * M_PI / $iterations * ($a + 1)) * 100 * $distance);
1361  if ($yOff) {
1362  $yOff = (int)(ceil(abs($yOff / 100)) * ($yOff / abs($yOff)));
1363  }
1364  $xOff = round(cos(2 * M_PI / $iterations * ($a + 1)) * 100 * $distance);
1365  if ($xOff) {
1366  $xOff = (int)(ceil(abs($xOff / 100)) * ($xOff / abs($xOff)));
1367  }
1368  $res[$a] = [$xOff, $yOff];
1369  }
1370  }
1371  return $res;
1372  }
1373 
1384  public function ‪makeEmboss(&‪$im, $conf, ‪$workArea, $txtConf)
1385  {
1386  $conf['color'] = $conf['highColor'];
1387  $this->‪makeShadow(‪$im, $conf, ‪$workArea, $txtConf);
1388  $newOffset = ‪GeneralUtility::intExplode(',', $conf['offset']);
1389  $newOffset[0] *= -1;
1390  $newOffset[1] *= -1;
1391  $conf['offset'] = implode(',', $newOffset);
1392  $conf['color'] = $conf['lowColor'];
1393  $this->‪makeShadow(‪$im, $conf, ‪$workArea, $txtConf);
1394  }
1395 
1408  public function ‪makeShadow(&‪$im, $conf, ‪$workArea, $txtConf)
1409  {
1410  ‪$workArea = $this->‪applyOffset(‪$workArea, ‪GeneralUtility::intExplode(',', $conf['offset']));
1411  $blurRate = ‪MathUtility::forceIntegerInRange((int)$conf['blur'], 0, 99);
1412  // No effects if ImageMagick ver. 5+
1413  if (!$blurRate || !$this->processorEffectsEnabled) {
1414  $txtConf['fontColor'] = $conf['color'];
1415  $this->‪makeText(‪$im, $txtConf, ‪$workArea);
1416  } else {
1417  ‪$w = imagesx(‪$im);
1418  ‪$h = imagesy(‪$im);
1419  // Area around the blur used for cropping something
1420  $blurBorder = 3;
1421  $tmpStr = $this->‪randomName();
1422  $fileMenu = $tmpStr . '_menu.' . ‪$this->gifExtension;
1423  $fileColor = $tmpStr . '_color.' . ‪$this->gifExtension;
1424  $fileMask = $tmpStr . '_mask.' . ‪$this->gifExtension;
1425  // BlurColor Image laves
1426  $blurColImg = imagecreatetruecolor(‪$w, ‪$h);
1427  $bcols = $this->‪convertColor($conf['color']);
1428  $Bcolor = imagecolorallocate($blurColImg, $bcols[0], $bcols[1], $bcols[2]);
1429  imagefilledrectangle($blurColImg, 0, 0, ‪$w, ‪$h, $Bcolor);
1430  $this->‪ImageWrite($blurColImg, $fileColor);
1431  imagedestroy($blurColImg);
1432  // The mask is made: BlurTextImage
1433  $blurTextImg = imagecreatetruecolor(‪$w + $blurBorder * 2, ‪$h + $blurBorder * 2);
1434  // Black background
1435  $Bcolor = imagecolorallocate($blurTextImg, 0, 0, 0);
1436  imagefilledrectangle($blurTextImg, 0, 0, ‪$w + $blurBorder * 2, ‪$h + $blurBorder * 2, $Bcolor);
1437  $txtConf['fontColor'] = 'white';
1438  $blurBordArr = [$blurBorder, $blurBorder];
1439  $this->‪makeText($blurTextImg, $txtConf, $this->‪applyOffset(‪$workArea, $blurBordArr));
1440  // Dump to temporary file
1441  $this->‪ImageWrite($blurTextImg, $fileMask);
1442  // Destroy
1443  imagedestroy($blurTextImg);
1444  $command = $this->‪v5_blur($blurRate + 1);
1445  $this->‪imageMagickExec($fileMask, $fileMask, $command . ' +matte');
1446  // The mask is loaded again
1447  $blurTextImg_tmp = $this->‪imageCreateFromFile($fileMask);
1448  // If nothing went wrong we continue with the blurred mask
1449  if ($blurTextImg_tmp) {
1450  // Cropping the border from the mask
1451  $blurTextImg = imagecreatetruecolor(‪$w, ‪$h);
1452  $this->‪imagecopyresized($blurTextImg, $blurTextImg_tmp, 0, 0, $blurBorder, $blurBorder, ‪$w, ‪$h, ‪$w, ‪$h);
1453  // Destroy the temporary mask
1454  imagedestroy($blurTextImg_tmp);
1455  // Adjust the mask
1456  $intensity = 40;
1457  if ($conf['intensity'] ?? false) {
1458  $intensity = ‪MathUtility::forceIntegerInRange($conf['intensity'], 0, 100);
1459  }
1460  $intensity = (int)ceil(255 - $intensity / 100 * 255);
1461  $this->‪inputLevels($blurTextImg, 0, $intensity);
1462  $opacity = ‪MathUtility::forceIntegerInRange((int)$conf['opacity'], 0, 100);
1463  if ($opacity && $opacity < 100) {
1464  $high = (int)ceil(255 * $opacity / 100);
1465  // Reducing levels as the opacity demands
1466  $this->‪outputLevels($blurTextImg, 0, $high);
1467  }
1468  // Dump the mask again
1469  $this->‪ImageWrite($blurTextImg, $fileMask);
1470  // Destroy the mask
1471  imagedestroy($blurTextImg);
1472  // The pictures are combined
1473  // The main pictures is saved temporarily
1474  $this->‪ImageWrite(‪$im, $fileMenu);
1475  $this->‪combineExec($fileMenu, $fileColor, $fileMask, $fileMenu);
1476  // The main image is loaded again...
1477  $backIm = $this->‪imageCreateFromFile($fileMenu);
1478  // ... and if nothing went wrong we load it onto the old one.
1479  if ($backIm) {
1480  if (!$this->saveAlphaLayer) {
1481  imagecolortransparent($backIm, -1);
1482  }
1483  ‪$im = $backIm;
1484  }
1485  }
1486  // Deleting temporary files;
1487  unlink($fileMenu);
1488  unlink($fileColor);
1489  unlink($fileMask);
1490  }
1491  }
1492 
1493  /****************************
1494  *
1495  * Other GIFBUILDER objects
1496  *
1497  ****************************/
1506  public function ‪makeBox(&‪$im, $conf, ‪$workArea)
1507  {
1508  $cords = ‪GeneralUtility::intExplode(',', $conf['dimensions'] . ',,,');
1509  $conf['offset'] = $cords[0] . ',' . $cords[1];
1510  $cords = $this->‪objPosition($conf, ‪$workArea, [$cords[2], $cords[3]]);
1511  $cols = $this->‪convertColor($conf['color'] ?? '');
1512  $opacity = 0;
1513  if (isset($conf['opacity'])) {
1514  // conversion:
1515  // PHP 0 = opaque, 127 = transparent
1516  // TYPO3 100 = opaque, 0 = transparent
1517  $opacity = ‪MathUtility::forceIntegerInRange((int)$conf['opacity'], 1, 100, 1);
1518  $opacity = (int)abs($opacity - 100);
1519  $opacity = (int)round(127 * $opacity / 100);
1520  }
1521  $tmpColor = imagecolorallocatealpha(‪$im, $cols[0], $cols[1], $cols[2], $opacity);
1522  imagefilledrectangle(‪$im, $cords[0], $cords[1], $cords[0] + $cords[2] - 1, $cords[1] + $cords[3] - 1, $tmpColor);
1523  }
1524 
1545  public function ‪makeEllipse(&‪$im, array $conf, array ‪$workArea)
1546  {
1547  $ellipseConfiguration = ‪GeneralUtility::intExplode(',', $conf['dimensions'] . ',,,');
1548  // Ellipse offset inside workArea (x/y)
1549  $conf['offset'] = $ellipseConfiguration[0] . ',' . $ellipseConfiguration[1];
1550  // @see objPosition
1551  $imageCoordinates = $this->‪objPosition($conf, ‪$workArea, [$ellipseConfiguration[2], $ellipseConfiguration[3]]);
1552  $color = $this->‪convertColor($conf['color'] ?? '');
1553  $fillingColor = imagecolorallocate(‪$im, $color[0], $color[1], $color[2]);
1554  imagefilledellipse(‪$im, $imageCoordinates[0], $imageCoordinates[1], $imageCoordinates[2], $imageCoordinates[3], $fillingColor);
1555  }
1556 
1566  public function ‪makeEffect(&‪$im, $conf)
1567  {
1568  $commands = $this->‪IMparams($conf['value']);
1569  if ($commands) {
1570  $this->‪applyImageMagickToPHPGif(‪$im, $commands);
1571  }
1572  }
1573 
1582  public function ‪IMparams(‪$setup)
1583  {
1584  if (!trim(‪$setup)) {
1585  return '';
1586  }
1587  $effects = explode('|', ‪$setup);
1588  $commands = '';
1589  foreach ($effects as $val) {
1590  $pairs = explode('=', $val, 2);
1591  $value = trim($pairs[1] ?? '');
1592  $effect = strtolower(trim($pairs[0]));
1593  switch ($effect) {
1594  case 'gamma':
1595  $commands .= ' -gamma ' . (float)$value;
1596  break;
1597  case 'blur':
1598  if ($this->processorEffectsEnabled) {
1599  $commands .= $this->‪v5_blur((int)$value);
1600  }
1601  break;
1602  case 'sharpen':
1603  if ($this->processorEffectsEnabled) {
1604  $commands .= $this->‪v5_sharpen((int)$value);
1605  }
1606  break;
1607  case 'rotate':
1608  $commands .= ' -rotate ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 360);
1609  break;
1610  case 'solarize':
1611  $commands .= ' -solarize ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 99);
1612  break;
1613  case 'swirl':
1614  $commands .= ' -swirl ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 1000);
1615  break;
1616  case 'wave':
1617  $params = ‪GeneralUtility::intExplode(',', $value);
1618  $commands .= ' -wave ' . ‪MathUtility::forceIntegerInRange($params[0], 0, 99) . 'x' . ‪MathUtility::forceIntegerInRange($params[1], 0, 99);
1619  break;
1620  case 'charcoal':
1621  $commands .= ' -charcoal ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 100);
1622  break;
1623  case 'gray':
1624  $commands .= ' -colorspace GRAY';
1625  break;
1626  case 'edge':
1627  $commands .= ' -edge ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 99);
1628  break;
1629  case 'emboss':
1630  $commands .= ' -emboss';
1631  break;
1632  case 'flip':
1633  $commands .= ' -flip';
1634  break;
1635  case 'flop':
1636  $commands .= ' -flop';
1637  break;
1638  case 'colors':
1639  $commands .= ' -colors ' . ‪MathUtility::forceIntegerInRange((int)$value, 2, 255);
1640  break;
1641  case 'shear':
1642  $commands .= ' -shear ' . ‪MathUtility::forceIntegerInRange((int)$value, -90, 90);
1643  break;
1644  case 'invert':
1645  $commands .= ' -negate';
1646  break;
1647  }
1648  }
1649  return $commands;
1650  }
1651 
1662  public function ‪adjust(&‪$im, $conf)
1663  {
1664  ‪$setup = $conf['value'];
1665  if (!trim(‪$setup)) {
1666  return;
1667  }
1668  $effects = explode('|', ‪$setup);
1669  foreach ($effects as $val) {
1670  $pairs = explode('=', $val, 2);
1671  $value = trim($pairs[1]);
1672  $effect = strtolower(trim($pairs[0]));
1673  switch ($effect) {
1674  case 'inputlevels':
1675  // low,high
1676  $params = ‪GeneralUtility::intExplode(',', $value);
1677  $this->‪inputLevels(‪$im, $params[0], $params[1]);
1678  break;
1679  case 'outputlevels':
1680  $params = ‪GeneralUtility::intExplode(',', $value);
1681  $this->‪outputLevels(‪$im, $params[0], $params[1]);
1682  break;
1683  case 'autolevels':
1684  $this->‪autolevels(‪$im);
1685  break;
1686  }
1687  }
1688  }
1689 
1697  public function ‪crop(&‪$im, $conf)
1698  {
1699  // Clears workArea to total image
1700  $this->‪setWorkArea('');
1701  $cords = ‪GeneralUtility::intExplode(',', $conf['crop'] . ',,,');
1702  $conf['offset'] = $cords[0] . ',' . $cords[1];
1703  $cords = $this->‪objPosition($conf, $this->workArea, [$cords[2], $cords[3]]);
1704  $newIm = imagecreatetruecolor($cords[2], $cords[3]);
1705  $cols = $this->‪convertColor(!empty($conf['backColor']) ? $conf['backColor'] : $this->setup['backColor']);
1706  $Bcolor = imagecolorallocate($newIm, $cols[0], $cols[1], $cols[2]);
1707  imagefilledrectangle($newIm, 0, 0, $cords[2], $cords[3], $Bcolor);
1708  $newConf = [];
1709  ‪$workArea = [0, 0, $cords[2], $cords[3]];
1710  if ($cords[0] < 0) {
1711  ‪$workArea[0] = abs($cords[0]);
1712  } else {
1713  $newConf['offset'] = -$cords[0];
1714  }
1715  if ($cords[1] < 0) {
1716  ‪$workArea[1] = abs($cords[1]);
1717  } else {
1718  $newConf['offset'] .= ',' . -$cords[1];
1719  }
1720  $this->‪copyGifOntoGif($newIm, ‪$im, $newConf, ‪$workArea);
1721  ‪$im = $newIm;
1722  $this->w = imagesx(‪$im);
1723  $this->h = imagesy(‪$im);
1724  // Clears workArea to total image
1725  $this->‪setWorkArea('');
1726  }
1727 
1735  public function ‪scale(&‪$im, $conf)
1736  {
1737  if ($conf['width'] || $conf['height'] || $conf['params']) {
1738  $tmpStr = $this->‪randomName();
1739  $theFile = $tmpStr . '.' . ‪$this->gifExtension;
1740  $this->‪ImageWrite(‪$im, $theFile);
1741  $theNewFile = $this->‪imageMagickConvert($theFile, $this->gifExtension, $conf['width'] ?? '', $conf['height'] ?? '', $conf['params'] ?? '');
1742  $tmpImg = $this->‪imageCreateFromFile($theNewFile[3]);
1743  if ($tmpImg) {
1744  imagedestroy(‪$im);
1745  ‪$im = $tmpImg;
1746  $this->w = imagesx(‪$im);
1747  $this->h = imagesy(‪$im);
1748  // Clears workArea to total image
1749  $this->‪setWorkArea('');
1750  }
1751  unlink($theFile);
1752  if ($theNewFile[3] && $theNewFile[3] != $theFile) {
1753  unlink($theNewFile[3]);
1754  }
1755  }
1756  }
1757 
1766  public function ‪setWorkArea(‪$workArea)
1767  {
1768  $this->workArea = ‪GeneralUtility::intExplode(',', ‪$workArea);
1769  $this->workArea = $this->‪applyOffset($this->workArea, $this->OFFSET);
1770  if (!($this->workArea[2] ?? false)) {
1771  $this->workArea[2] = ‪$this->w;
1772  }
1773  if (!($this->workArea[3] ?? false)) {
1774  $this->workArea[3] = ‪$this->h;
1775  }
1776  }
1777 
1778  /*************************
1779  *
1780  * Adjustment functions
1781  *
1782  ************************/
1788  public function ‪autolevels(&‪$im)
1789  {
1790  $totalCols = imagecolorstotal(‪$im);
1791  $grayArr = [];
1792  for ($c = 0; $c < $totalCols; $c++) {
1793  $cols = imagecolorsforindex(‪$im, $c);
1794  $grayArr[] = round(($cols['red'] + $cols['green'] + $cols['blue']) / 3);
1795  }
1796  $min = min($grayArr);
1797  $max = max($grayArr);
1798  $delta = $max - $min;
1799  if ($delta) {
1800  for ($c = 0; $c < $totalCols; $c++) {
1801  $cols = imagecolorsforindex(‪$im, $c);
1802  $cols['red'] = floor(($cols['red'] - $min) / $delta * 255);
1803  $cols['green'] = floor(($cols['green'] - $min) / $delta * 255);
1804  $cols['blue'] = floor(($cols['blue'] - $min) / $delta * 255);
1805  imagecolorset(‪$im, $c, $cols['red'], $cols['green'], $cols['blue']);
1806  }
1807  }
1808  }
1809 
1818  public function ‪outputLevels(&‪$im, $low, $high, $swap = false)
1819  {
1820  if ($low < $high) {
1821  $low = ‪MathUtility::forceIntegerInRange($low, 0, 255);
1822  $high = ‪MathUtility::forceIntegerInRange($high, 0, 255);
1823  if ($swap) {
1824  $temp = $low;
1825  $low = 255 - $high;
1826  $high = 255 - $temp;
1827  }
1828  $delta = $high - $low;
1829  $totalCols = imagecolorstotal(‪$im);
1830  for ($c = 0; $c < $totalCols; $c++) {
1831  $cols = imagecolorsforindex(‪$im, $c);
1832  $cols['red'] = $low + floor($cols['red'] / 255 * $delta);
1833  $cols['green'] = $low + floor($cols['green'] / 255 * $delta);
1834  $cols['blue'] = $low + floor($cols['blue'] / 255 * $delta);
1835  imagecolorset(‪$im, $c, $cols['red'], $cols['green'], $cols['blue']);
1836  }
1837  }
1838  }
1839 
1847  public function ‪inputLevels(&‪$im, $low, $high)
1848  {
1849  if ($low < $high) {
1850  $low = ‪MathUtility::forceIntegerInRange($low, 0, 255);
1851  $high = ‪MathUtility::forceIntegerInRange($high, 0, 255);
1852  $delta = $high - $low;
1853  $totalCols = imagecolorstotal(‪$im);
1854  for ($c = 0; $c < $totalCols; $c++) {
1855  $cols = imagecolorsforindex(‪$im, $c);
1856  $cols['red'] = ‪MathUtility::forceIntegerInRange((int)(($cols['red'] - $low) / $delta * 255), 0, 255);
1857  $cols['green'] = ‪MathUtility::forceIntegerInRange((int)(($cols['green'] - $low) / $delta * 255), 0, 255);
1858  $cols['blue'] = ‪MathUtility::forceIntegerInRange((int)(($cols['blue'] - $low) / $delta * 255), 0, 255);
1859  imagecolorset(‪$im, $c, $cols['red'], $cols['green'], $cols['blue']);
1860  }
1861  }
1862  }
1863 
1871  public function ‪IMreduceColors($file, $cols)
1872  {
1873  $fI = GeneralUtility::split_fileref($file);
1874  $ext = strtolower($fI['fileext']);
1875  $result = $this->‪randomName() . '.' . $ext;
1876  $reduce = ‪MathUtility::forceIntegerInRange($cols, 0, $ext === 'gif' ? 256 : $this->truecolorColors, 0);
1877  if ($reduce > 0) {
1878  $params = ' -colors ' . $reduce;
1879  if ($reduce <= 256) {
1880  $params .= ' -type Palette';
1881  }
1882  $prefix = $ext === 'png' && $reduce <= 256 ? 'png8:' : '';
1883  $this->‪imageMagickExec($file, $prefix . $result, $params);
1884  if ($result) {
1885  return $result;
1886  }
1887  }
1888  return '';
1889  }
1890 
1891  /*********************************
1892  *
1893  * GIFBUILDER Helper functions
1894  *
1895  *********************************/
1906  public function ‪v5_sharpen($factor)
1907  {
1908  $factor = ‪MathUtility::forceIntegerInRange((int)ceil($factor / 10), 0, 10);
1909  $sharpenArr = explode(',', ',' . $this->im5fx_sharpenSteps);
1910  $sharpenF = trim($sharpenArr[$factor]);
1911  if ($sharpenF) {
1912  return ' -sharpen ' . $sharpenF;
1913  }
1914  return '';
1915  }
1916 
1927  public function ‪v5_blur($factor)
1928  {
1929  $factor = ‪MathUtility::forceIntegerInRange((int)ceil($factor / 10), 0, 10);
1930  $blurArr = explode(',', ',' . $this->im5fx_blurSteps);
1931  $blurF = trim($blurArr[$factor]);
1932  if ($blurF) {
1933  return ' -blur ' . $blurF;
1934  }
1935  return '';
1936  }
1937 
1944  public function ‪randomName()
1945  {
1947  return ‪Environment::getVarPath() . '/transient/' . md5(‪StringUtility::getUniqueId());
1948  }
1949 
1958  public function ‪applyOffset($cords, ‪$OFFSET)
1959  {
1960  $cords[0] = (int)$cords[0] + (int)‪$OFFSET[0];
1961  $cords[1] = (int)($cords[1] ?? 0) + (int)(‪$OFFSET[1] ?? 0);
1962  return $cords;
1963  }
1964 
1972  public function ‪convertColor($string)
1973  {
1974  $col = [];
1975  $cParts = explode(':', $string, 2);
1976  // Finding the RGB definitions of the color:
1977  $string = $cParts[0];
1978  if (str_contains($string, '#')) {
1979  $string = preg_replace('/[^A-Fa-f0-9]*/', '', $string) ?? '';
1980  $col[] = hexdec(substr($string, 0, 2));
1981  $col[] = hexdec(substr($string, 2, 2));
1982  $col[] = hexdec(substr($string, 4, 2));
1983  } elseif (str_contains($string, ',')) {
1984  $string = preg_replace('/[^,0-9]*/', '', $string) ?? '';
1985  $strArr = explode(',', $string);
1986  $col[] = (int)$strArr[0];
1987  $col[] = (int)$strArr[1];
1988  $col[] = (int)$strArr[2];
1989  } else {
1990  $string = strtolower(trim($string));
1991  if ($this->colMap[$string] ?? false) {
1992  $col = $this->colMap[$string];
1993  } else {
1994  $col = [0, 0, 0];
1995  }
1996  }
1997  // ... and possibly recalculating the value
1998  if (trim($cParts[1] ?? '')) {
1999  $cParts[1] = trim($cParts[1]);
2000  if ($cParts[1][0] === '*') {
2001  $val = (float)substr($cParts[1], 1);
2002  $col[0] = ‪MathUtility::forceIntegerInRange((int)($col[0] * $val), 0, 255);
2003  $col[1] = ‪MathUtility::forceIntegerInRange((int)($col[1] * $val), 0, 255);
2004  $col[2] = ‪MathUtility::forceIntegerInRange((int)($col[2] * $val), 0, 255);
2005  } else {
2006  $val = (int)$cParts[1];
2007  $col[0] = ‪MathUtility::forceIntegerInRange((int)($col[0] + $val), 0, 255);
2008  $col[1] = ‪MathUtility::forceIntegerInRange((int)($col[1] + $val), 0, 255);
2009  $col[2] = ‪MathUtility::forceIntegerInRange((int)($col[2] + $val), 0, 255);
2010  }
2011  }
2012  return $col;
2013  }
2014 
2027  public function ‪objPosition($conf, ‪$workArea, $BB)
2028  {
2029  // offset, align, valign, workarea
2030  $result = [];
2031  $result[2] = $BB[0];
2032  $result[3] = $BB[1];
2033  ‪$w = ‪$workArea[2];
2034  ‪$h = ‪$workArea[3];
2035  $align = explode(',', $conf['align'] ?? ',');
2036  $align[0] = strtolower(substr(trim($align[0]), 0, 1));
2037  $align[1] = strtolower(substr(trim($align[1]), 0, 1));
2038  switch ($align[0]) {
2039  case 'r':
2040  $result[0] = ‪$w - $result[2];
2041  break;
2042  case 'c':
2043  $result[0] = round((‪$w - $result[2]) / 2);
2044  break;
2045  default:
2046  $result[0] = 0;
2047  }
2048  switch ($align[1]) {
2049  case 'b':
2050  // y pos
2051  $result[1] = ‪$h - $result[3];
2052  break;
2053  case 'c':
2054  $result[1] = round((‪$h - $result[3]) / 2);
2055  break;
2056  default:
2057  $result[1] = 0;
2058  }
2059  $result = $this->‪applyOffset($result, ‪GeneralUtility::intExplode(',', $conf['offset'] ?? ''));
2060  $result = $this->‪applyOffset($result, ‪$workArea);
2061  return $result;
2062  }
2063 
2064  /***********************************
2065  *
2066  * Scaling, Dimensions of images
2067  *
2068  ***********************************/
2087  public function ‪imageMagickConvert($imagefile, $newExt = '', ‪$w = '', ‪$h = '', $params = '', $frame = '', $options = [], $mustCreate = false)
2088  {
2089  if (!$this->processorEnabled) {
2090  // Returning file info right away
2091  return $this->‪getImageDimensions($imagefile);
2092  }
2093  $info = $this->‪getImageDimensions($imagefile);
2094  if (!$info) {
2095  return null;
2096  }
2097 
2098  $newExt = strtolower(trim($newExt));
2099  // If no extension is given the original extension is used
2100  if (!$newExt) {
2101  $newExt = $info[2];
2102  }
2103  if ($newExt === 'web') {
2104  if (in_array($info[2], $this->webImageExt, true)) {
2105  $newExt = $info[2];
2106  } else {
2107  $newExt = $this->‪gif_or_jpg($info[2], $info[0], $info[1]);
2108  if (!$params) {
2109  $params = $this->cmds[$newExt];
2110  }
2111  }
2112  }
2113  if (!in_array($newExt, $this->imageFileExt, true)) {
2114  return null;
2115  }
2116 
2117  $data = $this->‪getImageScale($info, ‪$w, ‪$h, $options);
2118  ‪$w = $data['origW'];
2119  ‪$h = $data['origH'];
2120  // If no conversion should be performed
2121  // this flag is TRUE if the width / height does NOT dictate
2122  // the image to be scaled!! (that is if no width / height is
2123  // given or if the destination w/h matches the original image
2124  // dimensions or if the option to not scale the image is set)
2125  $noScale = !‪$w && !‪$h || $data[0] == $info[0] && $data[1] == $info[1] || !empty($options['noScale']);
2126  if ($noScale && !$data['crs'] && !$params && !$frame && $newExt == $info[2] && !$mustCreate) {
2127  // Set the new width and height before returning,
2128  // if the noScale option is set
2129  if (!empty($options['noScale'])) {
2130  $info[0] = $data[0];
2131  $info[1] = $data[1];
2132  }
2133  $info[3] = $imagefile;
2134  return $info;
2135  }
2136  $info[0] = $data[0];
2137  $info[1] = $data[1];
2138  $frame = $this->addFrameSelection ? (int)$frame : 0;
2139  if (!$params) {
2140  $params = $this->cmds[$newExt] ?? '';
2141  }
2142  // Cropscaling:
2143  if ($data['crs']) {
2144  if (!$data['origW']) {
2145  $data['origW'] = $data[0];
2146  }
2147  if (!$data['origH']) {
2148  $data['origH'] = $data[1];
2149  }
2150  $offsetX = (int)(($data[0] - $data['origW']) * ($data['cropH'] + 100) / 200);
2151  $offsetY = (int)(($data[1] - $data['origH']) * ($data['cropV'] + 100) / 200);
2152  $params .= ' -crop ' . $data['origW'] . 'x' . $data['origH'] . '+' . $offsetX . '+' . $offsetY . '! +repage';
2153  }
2154  $command = $this->scalecmd . ' ' . $info[0] . 'x' . $info[1] . '! ' . $params . ' ';
2155  // re-apply colorspace-setting for the resulting image so colors don't appear to dark (sRGB instead of RGB)
2156  $command .= ' -colorspace ' . ‪CommandUtility::escapeShellArgument($this->colorspace);
2157  $cropscale = $data['crs'] ? 'crs-V' . $data['cropV'] . 'H' . $data['cropH'] : '';
2158  if ($this->alternativeOutputKey) {
2159  $theOutputName = md5($command . $cropscale . ‪PathUtility::basename($imagefile) . $this->alternativeOutputKey . '[' . $frame . ']');
2160  } else {
2161  $theOutputName = md5($command . $cropscale . $imagefile . filemtime($imagefile) . '[' . $frame . ']');
2162  }
2163  if ($this->imageMagickConvert_forceFileNameBody) {
2165  $this->imageMagickConvert_forceFileNameBody = '';
2166  }
2167  // Making the temporary filename
2168  ‪GeneralUtility::mkdir_deep(‪Environment::getPublicPath() . '/typo3temp/assets/images/');
2169  ‪$output = ‪Environment::getPublicPath() . '/typo3temp/assets/images/' . $this->filenamePrefix . $theOutputName . '.' . $newExt;
2170  if ($this->dontCheckForExistingTempFile || !file_exists(‪$output)) {
2171  $this->‪imageMagickExec($imagefile, ‪$output, $command, $frame);
2172  }
2173  if (file_exists(‪$output)) {
2174  $info[3] = ‪$output;
2175  $info[2] = $newExt;
2176  // params might change some image data!
2177  if ($params) {
2178  $info = $this->‪getImageDimensions($info[3]);
2179  }
2180  if ($info !== null && $info[2] === $this->gifExtension && !$this->dontCompress) {
2181  ‪self::gifCompress($info[3], '');
2182  }
2183  return $info;
2184  }
2185  return null;
2186  }
2187 
2196  public function ‪getImageDimensions($imageFile)
2197  {
2198  $returnArr = null;
2199  preg_match('/([^\\.]*)$/', $imageFile, $reg);
2200  if (file_exists($imageFile) && in_array(strtolower($reg[0]), $this->imageFileExt, true)) {
2201  $returnArr = $this->‪getCachedImageDimensions($imageFile);
2202  if (!$returnArr) {
2203  $imageInfoObject = GeneralUtility::makeInstance(ImageInfo::class, $imageFile);
2204  if ($imageInfoObject->getWidth()) {
2205  $returnArr = [
2206  $imageInfoObject->getWidth(),
2207  $imageInfoObject->getHeight(),
2208  strtolower($reg[0]),
2209  $imageFile,
2210  ];
2211  $this->‪cacheImageDimensions($returnArr);
2212  } else {
2213  // Size could not be determined, return null instead of boolean
2214  $returnArr = null;
2215  }
2216  }
2217  }
2218  return $returnArr;
2219  }
2228  public function ‪cacheImageDimensions(array $identifyResult)
2229  {
2230  $filePath = $identifyResult[3];
2231  $statusHash = $this->‪generateStatusHashForImageFile($filePath);
2232  $identifier = $this->‪generateCacheKeyForImageFile($filePath);
2233 
2234  $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('imagesizes');
2235  $imageDimensions = [
2236  'hash' => $statusHash,
2237  'imagewidth' => $identifyResult[0],
2238  'imageheight' => $identifyResult[1],
2239  ];
2240  $cache->set($identifier, $imageDimensions);
2241 
2242  return true;
2243  }
2244 
2253  public function ‪getCachedImageDimensions($filePath)
2254  {
2255  $statusHash = $this->‪generateStatusHashForImageFile($filePath);
2256  $identifier = $this->‪generateCacheKeyForImageFile($filePath);
2257  $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('imagesizes');
2258  $cachedImageDimensions = $cache->get($identifier);
2259  if (!isset($cachedImageDimensions['hash'])) {
2260  return false;
2261  }
2262 
2263  if ($cachedImageDimensions['hash'] !== $statusHash) {
2264  // The file has changed. Delete the cache entry.
2265  $cache->remove($identifier);
2266  $result = false;
2267  } else {
2268  preg_match('/([^\\.]*)$/', $filePath, $imageExtension);
2269  $result = [
2270  (int)$cachedImageDimensions['imagewidth'],
2271  (int)$cachedImageDimensions['imageheight'],
2272  strtolower($imageExtension[0]),
2273  $filePath,
2274  ];
2275  }
2276 
2277  return $result;
2278  }
2279 
2289  protected function ‪generateCacheKeyForImageFile($filePath)
2290  {
2291  return sha1($filePath);
2292  }
2293 
2301  protected function ‪generateStatusHashForImageFile($filePath)
2302  {
2303  $fileStatus = stat($filePath);
2304 
2305  return sha1($fileStatus['mtime'] . $fileStatus['size']);
2306  }
2307 
2319  public function ‪getImageScale($info, ‪$w, ‪$h, $options)
2320  {
2321  $out = [];
2322  $max = str_contains(‪$w . ‪$h, 'm') ? 1 : 0;
2323  if (str_contains(‪$w . ‪$h, 'c')) {
2324  $out['cropH'] = (int)substr((string)strstr((string)‪$w, 'c'), 1);
2325  $out['cropV'] = (int)substr((string)strstr((string)‪$h, 'c'), 1);
2326  $crs = true;
2327  } else {
2328  $crs = false;
2329  }
2330  $out['crs'] = $crs;
2331  ‪$w = (int)‪$w;
2332  ‪$h = (int)‪$h;
2333  // If there are max-values...
2334  if (!empty($options['maxW'])) {
2335  // If width is given...
2336  if (‪$w) {
2337  if (‪$w > $options['maxW']) {
2338  ‪$w = $options['maxW'];
2339  // Height should follow
2340  $max = 1;
2341  }
2342  } else {
2343  if ($info[0] > $options['maxW']) {
2344  ‪$w = $options['maxW'];
2345  // Height should follow
2346  $max = 1;
2347  }
2348  }
2349  }
2350  if (!empty($options['maxH'])) {
2351  // If height is given...
2352  if (‪$h) {
2353  if (‪$h > $options['maxH']) {
2354  ‪$h = $options['maxH'];
2355  // Height should follow
2356  $max = 1;
2357  }
2358  } else {
2359  // Changed [0] to [1] 290801
2360  if ($info[1] > $options['maxH']) {
2361  ‪$h = $options['maxH'];
2362  // Height should follow
2363  $max = 1;
2364  }
2365  }
2366  }
2367  $out['origW'] = ‪$w;
2368  $out['origH'] = ‪$h;
2369  $out['max'] = $max;
2370  if (!$this->mayScaleUp) {
2371  if (‪$w > $info[0]) {
2372  ‪$w = $info[0];
2373  }
2374  if (‪$h > $info[1]) {
2375  ‪$h = $info[1];
2376  }
2377  }
2378  // If scaling should be performed. Check that input "info" array will not cause division-by-zero
2379  if ((‪$w || ‪$h) && $info[0] && $info[1]) {
2380  if (‪$w && !‪$h) {
2381  $info[1] = (int)ceil($info[1] * (‪$w / $info[0]));
2382  $info[0] = ‪$w;
2383  }
2384  if (!‪$w && ‪$h) {
2385  $info[0] = (int)ceil($info[0] * (‪$h / $info[1]));
2386  $info[1] = ‪$h;
2387  }
2388  if (‪$w && ‪$h) {
2389  if ($max) {
2390  $ratio = $info[0] / $info[1];
2391  if (‪$h * $ratio > ‪$w) {
2392  ‪$h = (int)round(‪$w / $ratio);
2393  } else {
2394  ‪$w = (int)round(‪$h * $ratio);
2395  }
2396  }
2397  if ($crs) {
2398  $ratio = $info[0] / $info[1];
2399  if (‪$h * $ratio < ‪$w) {
2400  ‪$h = (int)round(‪$w / $ratio);
2401  } else {
2402  ‪$w = (int)round(‪$h * $ratio);
2403  }
2404  }
2405  $info[0] = ‪$w;
2406  $info[1] = ‪$h;
2407  }
2408  }
2409  $out[0] = $info[0];
2410  $out[1] = $info[1];
2411  // Set minimum-measures!
2412  if (isset($options['minW']) && $out[0] < $options['minW']) {
2413  if (($max || $crs) && $out[0]) {
2414  $out[1] = (int)round($out[1] * $options['minW'] / $out[0]);
2415  }
2416  $out[0] = $options['minW'];
2417  }
2418  if (isset($options['minH']) && $out[1] < $options['minH']) {
2419  if (($max || $crs) && $out[1]) {
2420  $out[0] = (int)round($out[0] * $options['minH'] / $out[1]);
2421  }
2422  $out[1] = $options['minH'];
2423  }
2424  return $out;
2425  }
2426 
2427  /***********************************
2428  *
2429  * ImageMagick API functions
2430  *
2431  ***********************************/
2438  public function ‪imageMagickIdentify($imagefile)
2439  {
2440  if (!$this->processorEnabled) {
2441  return null;
2442  }
2443 
2444  $result = $this->‪executeIdentifyCommandForImageFile($imagefile);
2445  if ($result) {
2446  [$width, $height, $fileExtension, $fileType] = explode(' ', $result);
2447  if ((int)$width && (int)$height) {
2448  return [$width, $height, strtolower($fileExtension), $imagefile, strtolower($fileType)];
2449  }
2450  }
2451  return null;
2452  }
2453 
2460  protected function ‪executeIdentifyCommandForImageFile(string $imageFile): ?string
2461  {
2462  $frame = $this->addFrameSelection ? 0 : null;
2464  'identify',
2465  '-format "%w %h %e %m" ' . ‪ImageMagickFile::fromFilePath($imageFile, $frame)
2466  );
2467  $returnVal = [];
2468  ‪CommandUtility::exec($cmd, $returnVal);
2469  $result = array_pop($returnVal);
2470  $this->IM_commands[] = ['identify', $cmd, $result];
2471  return $result;
2472  }
2473 
2484  public function ‪imageMagickExec($input, ‪$output, $params, $frame = 0)
2485  {
2486  if (!$this->processorEnabled) {
2487  return '';
2488  }
2489  // If addFrameSelection is set in the Install Tool, a frame number is added to
2490  // select a specific page of the image (by default this will be the first page)
2491  $frame = $this->addFrameSelection ? (int)$frame : null;
2493  'convert',
2494  $params
2495  . ' ' . ‪ImageMagickFile::fromFilePath($input, $frame)
2497  );
2498  $this->IM_commands[] = [‪$output, $cmd];
2499  $ret = ‪CommandUtility::exec($cmd);
2500  // Change the permissions of the file
2502  return $ret;
2503  }
2504 
2515  public function ‪combineExec($input, $overlay, $mask, ‪$output)
2516  {
2517  if (!$this->processorEnabled) {
2518  return '';
2519  }
2520  $theMask = $this->‪randomName() . '.' . ‪$this->gifExtension;
2521  // +matte = no alpha layer in output
2522  $this->‪imageMagickExec($mask, $theMask, '-colorspace GRAY +matte');
2523 
2524  $parameters = '-compose over'
2525  . ' -quality ' . $this->jpegQuality
2526  . ' +matte '
2528  . ‪ImageMagickFile::fromFilePath($overlay) . ' '
2529  . ‪ImageMagickFile::fromFilePath($theMask) . ' '
2531  $cmd = ‪CommandUtility::imageMagickCommand('combine', $parameters);
2532  $this->IM_commands[] = [‪$output, $cmd];
2533  $ret = ‪CommandUtility::exec($cmd);
2534  // Change the permissions of the file
2536  if (is_file($theMask)) {
2537  @unlink($theMask);
2538  }
2539  return $ret;
2540  }
2541 
2560  public static function ‪gifCompress($theFile, $type)
2561  {
2562  $gfxConf = ‪$GLOBALS['TYPO3_CONF_VARS']['GFX'];
2563  if (!$gfxConf['gif_compress'] || strtolower(substr($theFile, -4, 4)) !== '.gif') {
2564  return '';
2565  }
2566 
2567  if (($type === 'IM' || !$type) && $gfxConf['processor_enabled'] && $gfxConf['processor_path_lzw']) {
2568  // Use temporary file to prevent problems with read and write lock on same file on network file systems
2569  $temporaryName = ‪PathUtility::dirname($theFile) . '/' . md5(‪StringUtility::getUniqueId()) . '.gif';
2570  // Rename could fail, if a simultaneous thread is currently working on the same thing
2571  if (@rename($theFile, $temporaryName)) {
2573  'convert',
2575  $gfxConf['processor_path_lzw']
2576  );
2578  unlink($temporaryName);
2579  }
2580  $returnCode = 'IM';
2581  if (@is_file($theFile)) {
2583  }
2584  } elseif (($type === 'GD' || !$type) && $gfxConf['gdlib'] && !$gfxConf['gdlib_png']) {
2585  $tempImage = imagecreatefromgif($theFile);
2586  imagegif($tempImage, $theFile);
2587  imagedestroy($tempImage);
2588  $returnCode = 'GD';
2589  if (@is_file($theFile)) {
2591  }
2592  } else {
2593  $returnCode = '';
2594  }
2595 
2596  return $returnCode;
2597  }
2598 
2607  public static function ‪readPngGif($theFile, $output_png = false)
2608  {
2609  if (!‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_enabled'] || !@is_file($theFile)) {
2610  return null;
2611  }
2612 
2613  $ext = strtolower(substr($theFile, -4, 4));
2614  if ((string)$ext === '.png' && $output_png || (string)$ext === '.gif' && !$output_png) {
2615  return $theFile;
2616  }
2617 
2618  if (!@is_dir(‪Environment::getPublicPath() . '/typo3temp/assets/images/')) {
2619  ‪GeneralUtility::mkdir_deep(‪Environment::getPublicPath() . '/typo3temp/assets/images/');
2620  }
2621  $newFile = ‪Environment::getPublicPath() . '/typo3temp/assets/images/' . md5($theFile . '|' . filemtime($theFile)) . ($output_png ? '.png' : '.gif');
2623  'convert',
2625  . ' ' . ‪CommandUtility::escapeShellArgument($newFile),
2626  ‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_path']
2627  );
2629  if (@is_file($newFile)) {
2631  return $newFile;
2632  }
2633  return null;
2634  }
2635 
2636  /***********************************
2637  *
2638  * Various IO functions
2639  *
2640  ***********************************/
2641 
2648  public function ‪applyImageMagickToPHPGif(&‪$im, $command)
2649  {
2650  $tmpStr = $this->‪randomName();
2651  $theFile = $tmpStr . '.' . ‪$this->gifExtension;
2652  $this->‪ImageWrite(‪$im, $theFile);
2653  $this->‪imageMagickExec($theFile, $theFile, $command);
2654  $tmpImg = $this->‪imageCreateFromFile($theFile);
2655  if ($tmpImg) {
2656  imagedestroy(‪$im);
2657  ‪$im = $tmpImg;
2658  $this->w = imagesx(‪$im);
2659  $this->h = imagesy(‪$im);
2660  }
2661  unlink($theFile);
2662  }
2663 
2673  public function ‪gif_or_jpg($type, ‪$w, ‪$h)
2674  {
2675  if ($type === 'ai' || ‪$w * $h < $this->pixelLimitGif) {
2676  return ‪$this->gifExtension;
2677  }
2678  return 'jpg';
2679  }
2680 
2690  public function ‪output($file)
2691  {
2692  if ($file) {
2693  $reg = [];
2694  preg_match('/([^\\.]*)$/', $file, $reg);
2695  $ext = strtolower($reg[0]);
2696  switch ($ext) {
2697  case 'gif':
2698  case 'png':
2699  if ($this->‪ImageWrite($this->im, $file)) {
2700  // ImageMagick operations
2701  if ($this->setup['reduceColors'] ?? false) {
2702  $reduced = $this->‪IMreduceColors($file, ‪MathUtility::forceIntegerInRange($this->setup['reduceColors'], 256, $this->truecolorColors, 256));
2703  if ($reduced) {
2704  @copy($reduced, $file);
2705  @unlink($reduced);
2706  }
2707  }
2708  // Compress with IM! (adds extra compression, LZW from ImageMagick)
2709  // (Workaround for the absence of lzw-compression in GD)
2710  ‪self::gifCompress($file, 'IM');
2711  }
2712  break;
2713  case 'jpg':
2714  case 'jpeg':
2715  // Use the default
2716  $quality = 0;
2717  if ($this->setup['quality'] ?? false) {
2718  $quality = ‪MathUtility::forceIntegerInRange($this->setup['quality'], 10, 100);
2719  }
2720  $this->‪ImageWrite($this->im, $file, $quality);
2721  break;
2722  }
2723  }
2724  return $file;
2725  }
2732  public function ‪destroy()
2733  {
2734  imagedestroy($this->im);
2735  }
2736 
2743  public function ‪imgTag($imgInfo)
2744  {
2745  return '<img src="' . $imgInfo[3] . '" width="' . $imgInfo[0] . '" height="' . $imgInfo[1] . '" border="0" alt="" />';
2746  }
2747 
2759  public function ‪ImageWrite($destImg, $theImage, $quality = 0)
2760  {
2761  imageinterlace($destImg, 0);
2762  $ext = strtolower(substr($theImage, (int)strrpos($theImage, '.') + 1));
2763  $result = false;
2764  switch ($ext) {
2765  case 'jpg':
2766  case 'jpeg':
2767  if (function_exists('imagejpeg')) {
2768  if ($quality === 0) {
2769  $quality = ‪$this->jpegQuality;
2770  }
2771  $result = imagejpeg($destImg, $theImage, $quality);
2772  }
2773  break;
2774  case 'gif':
2775  if (function_exists('imagegif')) {
2776  imagetruecolortopalette($destImg, true, 256);
2777  $result = imagegif($destImg, $theImage);
2778  }
2779  break;
2780  case 'png':
2781  if (function_exists('imagepng')) {
2782  $result = imagepng($destImg, $theImage);
2783  }
2784  break;
2785  }
2786  if ($result) {
2788  }
2789  return $result;
2790  }
2791 
2799  public function ‪imageCreateFromFile($sourceImg)
2800  {
2801  $imgInf = pathinfo($sourceImg);
2802  $ext = strtolower($imgInf['extension']);
2803  switch ($ext) {
2804  case 'gif':
2805  if (function_exists('imagecreatefromgif')) {
2806  return imagecreatefromgif($sourceImg);
2807  }
2808  break;
2809  case 'png':
2810  if (function_exists('imagecreatefrompng')) {
2811  $imageHandle = imagecreatefrompng($sourceImg);
2812  if ($this->saveAlphaLayer) {
2813  imagesavealpha($imageHandle, true);
2814  }
2815  return $imageHandle;
2816  }
2817  break;
2818  case 'jpg':
2819  case 'jpeg':
2820  if (function_exists('imagecreatefromjpeg')) {
2821  return imagecreatefromjpeg($sourceImg);
2822  }
2823  break;
2824  }
2825  // If non of the above:
2826  $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $sourceImg);
2827  ‪$im = imagecreatetruecolor($imageInfo->getWidth(), $imageInfo->getHeight());
2828  $Bcolor = imagecolorallocate(‪$im, 128, 128, 128);
2829  imagefilledrectangle(‪$im, 0, 0, $imageInfo->getWidth(), $imageInfo->getHeight(), $Bcolor);
2830  return ‪$im;
2831  }
2832 
2839  public function ‪hexColor($color)
2840  {
2841  $r = dechex($color[0]);
2842  if (strlen($r) < 2) {
2843  $r = '0' . $r;
2844  }
2845  $g = dechex($color[1]);
2846  if (strlen($g) < 2) {
2847  $g = '0' . $g;
2848  }
2849  $b = dechex($color[2]);
2850  if (strlen($b) < 2) {
2851  $b = '0' . $b;
2852  }
2853  return '#' . $r . $g . $b;
2854  }
2855 
2864  public function ‪unifyColors(&$img, $colArr, $closest = false)
2865  {
2866  $retCol = -1;
2867  if (is_array($colArr) && !empty($colArr) && function_exists('imagepng') && function_exists('imagecreatefrompng')) {
2868  $firstCol = array_shift($colArr);
2869  $firstColArr = $this->‪convertColor($firstCol);
2870  $origName = $preName = $this->‪randomName() . '.png';
2871  $postName = $this->‪randomName() . '.png';
2872  $tmpImg = null;
2873  if (count($colArr) > 1) {
2874  $this->‪ImageWrite($img, $preName);
2875  $firstCol = $this->‪hexColor($firstColArr);
2876  foreach ($colArr as $transparentColor) {
2877  $transparentColor = $this->‪convertColor($transparentColor);
2878  $transparentColor = $this->‪hexColor($transparentColor);
2879  $cmd = '-fill "' . $firstCol . '" -opaque "' . $transparentColor . '"';
2880  $this->‪imageMagickExec($preName, $postName, $cmd);
2881  $preName = $postName;
2882  }
2883  $this->‪imageMagickExec($postName, $origName, '');
2884  if (@is_file($origName)) {
2885  $tmpImg = $this->‪imageCreateFromFile($origName);
2886  }
2887  } else {
2888  $tmpImg = $img;
2889  }
2890  if ($tmpImg) {
2891  $img = $tmpImg;
2892  if ($closest) {
2893  $retCol = imagecolorclosest($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]);
2894  } else {
2895  $retCol = imagecolorexact($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]);
2896  }
2897  }
2898  // Unlink files from process
2899  if ($origName) {
2900  @unlink($origName);
2901  }
2902  if ($postName) {
2903  @unlink($postName);
2904  }
2905  }
2906  return $retCol;
2907  }
2908 
2920  public function ‪getTemporaryImageWithText($filename, $textline1, $textline2, $textline3)
2921  {
2922  if (empty(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'])) {
2923  throw new \RuntimeException('TYPO3 Fatal Error: No gdlib. ' . $textline1 . ' ' . $textline2 . ' ' . $textline3, 1270853952);
2924  }
2925  // Creates the basis for the error image
2926  $basePath = ‪ExtensionManagementUtility::extPath('core') . 'Resources/Public/Images/';
2927  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'])) {
2928  ‪$im = imagecreatefrompng($basePath . 'NotFound.png');
2929  } else {
2930  ‪$im = imagecreatefromgif($basePath . 'NotFound.gif');
2931  }
2932  // Sets background color and print color.
2933  $white = imagecolorallocate(‪$im, 255, 255, 255);
2934  $black = imagecolorallocate(‪$im, 0, 0, 0);
2935  // Prints the text strings with the build-in font functions of GD
2936  $x = 0;
2937  $font = 0;
2938  if ($textline1) {
2939  imagefilledrectangle(‪$im, $x, 9, 56, 16, $white);
2940  imagestring(‪$im, $font, $x, 9, $textline1, $black);
2941  }
2942  if ($textline2) {
2943  imagefilledrectangle(‪$im, $x, 19, 56, 26, $white);
2944  imagestring(‪$im, $font, $x, 19, $textline2, $black);
2945  }
2946  if ($textline3) {
2947  imagefilledrectangle(‪$im, $x, 29, 56, 36, $white);
2948  imagestring(‪$im, $font, $x, 29, substr($textline3, -14), $black);
2949  }
2950  // Outputting the image stream and exit
2951  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'])) {
2952  imagepng(‪$im, $filename);
2953  } else {
2954  imagegif(‪$im, $filename);
2955  }
2956  }
2957 
2965  protected function ‪compensateFontSizeiBasedOnFreetypeDpi($fontSize)
2966  {
2967  return $fontSize / 96.0 * 72;
2968  }
2969 }
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$OFFSET
‪array $OFFSET
Definition: GraphicalFunctions.php:264
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getRenderedTextWidth
‪int getRenderedTextWidth($text, $conf)
Definition: GraphicalFunctions.php:1243
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:999
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcTextCordsForMap
‪array calcTextCordsForMap($cords, $offset, $conf)
Definition: GraphicalFunctions.php:801
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$saveAlphaLayer
‪bool $saveAlphaLayer
Definition: GraphicalFunctions.php:184
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\circleOffset
‪array circleOffset($distance, $iterations)
Definition: GraphicalFunctions.php:1322
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\fontResize
‪int fontResize($conf)
Definition: GraphicalFunctions.php:868
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getCachedImageDimensions
‪array bool getCachedImageDimensions($filePath)
Definition: GraphicalFunctions.php:2220
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEffect
‪makeEffect(&$im, $conf)
Definition: GraphicalFunctions.php:1533
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\hexColor
‪string hexColor($color)
Definition: GraphicalFunctions.php:2806
‪TYPO3\CMS\Core\Imaging
Definition: Dimension.php:16
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:25
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$alternativeOutputKey
‪string $alternativeOutputKey
Definition: GraphicalFunctions.php:168
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\convertColor
‪array convertColor($string)
Definition: GraphicalFunctions.php:1939
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$scalecmd
‪string $scalecmd
Definition: GraphicalFunctions.php:190
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\scale
‪scale(&$im, $conf)
Definition: GraphicalFunctions.php:1702
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeShadow
‪makeShadow(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1375
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\setWorkArea
‪setWorkArea($workArea)
Definition: GraphicalFunctions.php:1733
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:206
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeOutline
‪makeOutline(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1292
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeBox
‪makeBox(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:1473
‪TYPO3\CMS\Core\Utility\PathUtility\dirname
‪static string dirname($path)
Definition: PathUtility.php:251
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\output
‪string output($file)
Definition: GraphicalFunctions.php:2657
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getTextScalFactor
‪int getTextScalFactor($conf)
Definition: GraphicalFunctions.php:1150
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$allowedColorSpaceNames
‪array $allowedColorSpaceNames
Definition: GraphicalFunctions.php:66
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$webImageExt
‪array $webImageExt
Definition: GraphicalFunctions.php:112
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\IMparams
‪string IMparams($setup)
Definition: GraphicalFunctions.php:1549
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\__construct
‪__construct()
Definition: GraphicalFunctions.php:274
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$w
‪int $w
Definition: GraphicalFunctions.php:256
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\maskImageOntoImage
‪maskImageOntoImage(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:332
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$workArea
‪array $workArea
Definition: GraphicalFunctions.php:178
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$h
‪int $h
Definition: GraphicalFunctions.php:260
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\IMreduceColors
‪string IMreduceColors($file, $cols)
Definition: GraphicalFunctions.php:1838
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\setImageFileExt
‪setImageFileExt(array $imageFileExt)
Definition: GraphicalFunctions.php:1165
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\renderTTFText
‪renderTTFText(&$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $conf, $sF=1)
Definition: GraphicalFunctions.php:1185
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$dontCheckForExistingTempFile
‪bool $dontCheckForExistingTempFile
Definition: GraphicalFunctions.php:154
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\applyImageMagickToPHPGif
‪applyImageMagickToPHPGif(&$im, $command)
Definition: GraphicalFunctions.php:2615
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getTemporaryImageWithText
‪getTemporaryImageWithText($filename, $textline1, $textline2, $textline3)
Definition: GraphicalFunctions.php:2887
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$IM_commands
‪array $IM_commands
Definition: GraphicalFunctions.php:174
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$imageMagickConvert_forceFileNameBody
‪string $imageMagickConvert_forceFileNameBody
Definition: GraphicalFunctions.php:148
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$mayScaleUp
‪bool $mayScaleUp
Definition: GraphicalFunctions.php:136
‪TYPO3\CMS\Core\Charset\CharsetConverter
Definition: CharsetConverter.php:54
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$processorEnabled
‪bool $processorEnabled
Definition: GraphicalFunctions.php:132
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$map
‪string $map
Definition: GraphicalFunctions.php:245
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$addFrameSelection
‪bool $addFrameSelection
Definition: GraphicalFunctions.php:42
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\ImageWrite
‪bool ImageWrite($destImg, $theImage, $quality=0)
Definition: GraphicalFunctions.php:2726
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$jpegQuality
‪int $jpegQuality
Definition: GraphicalFunctions.php:241
‪TYPO3\CMS\Core\Utility\PathUtility\basename
‪static string basename($path)
Definition: PathUtility.php:226
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getImageDimensions
‪array null getImageDimensions($imageFile)
Definition: GraphicalFunctions.php:2163
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\copyGifOntoGif
‪copyGifOntoGif(&$im, $cpImg, $conf, $workArea)
Definition: GraphicalFunctions.php:439
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$csConvObj
‪CharsetConverter $csConvObj
Definition: GraphicalFunctions.php:237
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:43
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\outputLevels
‪outputLevels(&$im, $low, $high, $swap=false)
Definition: GraphicalFunctions.php:1785
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$processorEffectsEnabled
‪bool $processorEffectsEnabled
Definition: GraphicalFunctions.php:118
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEmboss
‪makeEmboss(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1351
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions
Definition: GraphicalFunctions.php:37
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcBBox
‪array calcBBox($conf)
Definition: GraphicalFunctions.php:699
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$truecolorColors
‪int $truecolorColors
Definition: GraphicalFunctions.php:99
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\adjust
‪adjust(&$im, $conf)
Definition: GraphicalFunctions.php:1629
‪TYPO3\CMS\Core\Utility\GeneralUtility\fixPermissions
‪static mixed fixPermissions($path, $recursive=false)
Definition: GeneralUtility.php:1749
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir_deep
‪static mkdir_deep($directory)
Definition: GeneralUtility.php:1908
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\combineExec
‪string combineExec($input, $overlay, $mask, $output)
Definition: GraphicalFunctions.php:2482
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\autolevels
‪autolevels(&$im)
Definition: GraphicalFunctions.php:1755
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\splitString
‪array splitString($string, $splitRendering, $fontSize, $fontFile)
Definition: GraphicalFunctions.php:995
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\gifCompress
‪static string gifCompress($theFile, $type)
Definition: GraphicalFunctions.php:2527
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\objPosition
‪array objPosition($conf, $workArea, $BB)
Definition: GraphicalFunctions.php:1994
‪TYPO3\CMS\Core\Utility\CommandUtility\exec
‪static string exec($command, &$output=null, &$returnValue=0)
Definition: CommandUtility.php:81
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeText
‪makeText(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:547
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getImageScale
‪array getImageScale($info, $w, $h, $options)
Definition: GraphicalFunctions.php:2286
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\readPngGif
‪static string null readPngGif($theFile, $output_png=false)
Definition: GraphicalFunctions.php:2574
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$colorspace
‪string $colorspace
Definition: GraphicalFunctions.php:60
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\unifyColors
‪int unifyColors(&$img, $colArr, $closest=false)
Definition: GraphicalFunctions.php:2831
‪TYPO3\CMS\Core\Utility\CommandUtility\escapeShellArgument
‪static string escapeShellArgument($input)
Definition: CommandUtility.php:508
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$filenamePrefix
‪string $filenamePrefix
Definition: GraphicalFunctions.php:142
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$pixelLimitGif
‪int $pixelLimitGif
Definition: GraphicalFunctions.php:208
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$colMap
‪array $colMap
Definition: GraphicalFunctions.php:214
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\destroy
‪destroy()
Definition: GraphicalFunctions.php:2699
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\generateStatusHashForImageFile
‪string generateStatusHashForImageFile($filePath)
Definition: GraphicalFunctions.php:2268
‪TYPO3\CMS\Core\Type\File\ImageInfo
Definition: ImageInfo.php:28
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$cmds
‪array $cmds
Definition: GraphicalFunctions.php:122
‪$output
‪$output
Definition: annotationChecker.php:121
‪debug
‪debug($variable='', $title=null, $group=null)
Definition: GlobalDebugFunctions.php:19
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\v5_blur
‪string v5_blur($factor)
Definition: GraphicalFunctions.php:1894
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\compensateFontSizeiBasedOnFreetypeDpi
‪float compensateFontSizeiBasedOnFreetypeDpi($fontSize)
Definition: GraphicalFunctions.php:2932
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageMagickIdentify
‪array null imageMagickIdentify($imagefile)
Definition: GraphicalFunctions.php:2405
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:128
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\SpacedImageTTFText
‪SpacedImageTTFText(&$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF=1)
Definition: GraphicalFunctions.php:835
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageMagickConvert
‪array null imageMagickConvert($imagefile, $newExt='', $w='', $h='', $params='', $frame='', $options=[], $mustCreate=false)
Definition: GraphicalFunctions.php:2054
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$gifExtension
‪string $gifExtension
Definition: GraphicalFunctions.php:48
‪TYPO3\CMS\Core\Imaging\ImageMagickFile\fromFilePath
‪static ImageMagickFile fromFilePath(string $filePath, int $frame=null)
Definition: ImageMagickFile.php:113
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imagecopyresized
‪imagecopyresized(&$dstImg, $srcImg, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight)
Definition: GraphicalFunctions.php:518
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:43
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\txtPosition
‪array txtPosition($conf, $workArea, $BB)
Definition: GraphicalFunctions.php:646
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:927
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$setup
‪array $setup
Definition: GraphicalFunctions.php:252
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$im
‪resource GdImage $im
Definition: GraphicalFunctions.php:268
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\extPath
‪static string extPath($key, $script='')
Definition: ExtensionManagementUtility.php:142
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageCreateFromFile
‪resource imageCreateFromFile($sourceImg)
Definition: GraphicalFunctions.php:2766
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\cacheImageDimensions
‪bool cacheImageDimensions(array $identifyResult)
Definition: GraphicalFunctions.php:2195
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getWordPairsForLineBreak
‪array getWordPairsForLineBreak($string)
Definition: GraphicalFunctions.php:1224
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\ImageTTFTextWrapper
‪ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF=1)
Definition: GraphicalFunctions.php:951
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\v5_sharpen
‪string v5_sharpen($factor)
Definition: GraphicalFunctions.php:1873
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$dontCompress
‪bool $dontCompress
Definition: GraphicalFunctions.php:160
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$gdlibExtensions
‪array $gdlibExtensions
Definition: GraphicalFunctions.php:54
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\randomName
‪string randomName()
Definition: GraphicalFunctions.php:1911
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getBreakSpace
‪int getBreakSpace($conf, array $boundingBox=null)
Definition: GraphicalFunctions.php:1263
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:22
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$im5fx_sharpenSteps
‪string $im5fx_sharpenSteps
Definition: GraphicalFunctions.php:202
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\executeIdentifyCommandForImageFile
‪string null executeIdentifyCommandForImageFile(string $imageFile)
Definition: GraphicalFunctions.php:2427
‪TYPO3\CMS\Core\Utility\CommandUtility
Definition: CommandUtility.php:49
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEllipse
‪makeEllipse(&$im, array $conf, array $workArea)
Definition: GraphicalFunctions.php:1512
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\ImageTTFBBoxWrapper
‪array ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF=1)
Definition: GraphicalFunctions.php:909
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\inputLevels
‪inputLevels(&$im, $low, $high)
Definition: GraphicalFunctions.php:1814
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcWordSpacing
‪array calcWordSpacing($conf, $scaleFactor=1)
Definition: GraphicalFunctions.php:1133
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\gif_or_jpg
‪string gif_or_jpg($type, $w, $h)
Definition: GraphicalFunctions.php:2640
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imgTag
‪string imgTag($imgInfo)
Definition: GraphicalFunctions.php:2710
‪TYPO3\CMS\Core\Utility\CommandUtility\imageMagickCommand
‪static string imageMagickCommand($command, $parameters, $path='')
Definition: CommandUtility.php:94
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageMagickExec
‪string imageMagickExec($input, $output, $params, $frame=0)
Definition: GraphicalFunctions.php:2451
‪TYPO3\CMS\Core\Utility\ArrayUtility\filterAndSortByNumericKeys
‪static array filterAndSortByNumericKeys($setupArr, $acceptAnyKeys=false)
Definition: ArrayUtility.php:852
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\applyOffset
‪array applyOffset($cords, $OFFSET)
Definition: GraphicalFunctions.php:1925
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\generateCacheKeyForImageFile
‪string generateCacheKeyForImageFile($filePath)
Definition: GraphicalFunctions.php:2256
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\copyImageOntoImage
‪copyImageOntoImage(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:417
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\addToMap
‪addToMap($cords, $conf)
Definition: GraphicalFunctions.php:781
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$im5fx_blurSteps
‪string $im5fx_blurSteps
Definition: GraphicalFunctions.php:196
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static string getVarPath()
Definition: Environment.php:218
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\crop
‪crop(&$im, $conf)
Definition: GraphicalFunctions.php:1664
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$imageFileExt
‪array $imageFileExt
Definition: GraphicalFunctions.php:106