‪TYPO3CMS  10.4
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'];
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], 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'] && is_array($conf['imgMap.'])) {
588  $this->‪addToMap($this->‪calcTextCordsForMap($conf['BBOX'][2], $txtPos, $conf['imgMap.']), $conf['imgMap.']);
589  }
590  if (!$conf['hideButCreateMap']) {
591  // Font Color:
592  $cols = $this->‪convertColor($conf['fontColor']);
593  // NiceText is calculated
594  if (!$conf['niceText']) {
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'], $txtPos[0], $txtPos[1], $Fcolor, GeneralUtility::getFileAbsFileName($conf['fontFile']), $theText, $spacing, $wordSpacing, $conf['splitRendering.']);
602  } else {
603  $this->‪renderTTFText(‪$im, $conf['fontSize'], $conf['angle'], $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, 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'], $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'], $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 ($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'] / 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  switch ($conf['align']) {
691  case 'right':
692 
693  case 'center':
694  $factor = abs(cos($angle));
695  $sign = cos($angle) < 0 ? -1 : 1;
696  $len1 = $sign * $factor * $straightBB[0];
697  $len2 = $sign * $BB[0];
698  $result[0] = ‪$w - ceil($len2 * $factor + (1 - $factor) * $len1);
699  $factor = abs(sin($angle));
700  $sign = sin($angle) < 0 ? -1 : 1;
701  $len1 = $sign * $factor * $straightBB[0];
702  $len2 = $sign * $BB[1];
703  $result[1] = ceil($len2 * $factor + (1 - $factor) * $len1);
704  break;
705  }
706  switch ($conf['align']) {
707  case 'right':
708  break;
709  case 'center':
710  $result[0] = round($result[0] / 2);
711  $result[1] = round($result[1] / 2);
712  break;
713  default:
714  $result[0] = 0;
715  $result[1] = 0;
716  }
717  $result = $this->‪applyOffset($result, ‪GeneralUtility::intExplode(',', $conf['offset']));
718  $result = $this->‪applyOffset($result, ‪$workArea);
719  return $result;
720  }
721 
731  public function ‪calcBBox($conf)
732  {
733  $sF = $this->‪getTextScalFactor($conf);
734  [$spacing, $wordSpacing] = $this->‪calcWordSpacing($conf, $sF);
735  $theText = $conf['text'];
736  $charInf = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $theText, $conf['splitRendering.'], $sF);
737  $theBBoxInfo = $charInf;
738  if ($conf['angle']) {
739  $xArr = [$charInf[0], $charInf[2], $charInf[4], $charInf[6]];
740  $yArr = [$charInf[1], $charInf[3], $charInf[5], $charInf[7]];
741  $x = max($xArr) - min($xArr);
742  $y = max($yArr) - min($yArr);
743  } else {
744  $x = $charInf[2] - $charInf[0];
745  $y = $charInf[1] - $charInf[7];
746  }
747  // Set original lineHeight (used by line breaks):
748  $theBBoxInfo['lineHeight'] = $y;
749  if (!empty($conf['lineHeight'])) {
750  $theBBoxInfo['lineHeight'] = (int)$conf['lineHeight'];
751  }
752 
753  // If any kind of spacing applys, we use this function:
754  if ($spacing || $wordSpacing) {
755  $x = 0;
756  if (!$spacing && $wordSpacing) {
757  $bits = explode(' ', $theText);
758  foreach ($bits as $word) {
759  $word .= ' ';
760  $wordInf = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $word, $conf['splitRendering.'], $sF);
761  $wordW = $wordInf[2] - $wordInf[0];
762  $x += $wordW + $wordSpacing;
763  }
764  } else {
765  $utf8Chars = $this->csConvObj->utf8_to_numberarray($theText);
766  // For each UTF-8 char, do:
767  foreach ($utf8Chars as $char) {
768  $charInf = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $char, $conf['splitRendering.'], $sF);
769  $charW = $charInf[2] - $charInf[0];
770  $x += $charW + ($char === ' ' ? $wordSpacing : $spacing);
771  }
772  }
773  } elseif (isset($conf['breakWidth']) && $conf['breakWidth'] && $this->‪getRenderedTextWidth($conf['text'], $conf) > $conf['breakWidth']) {
774  $maxWidth = 0;
775  $currentWidth = 0;
776  $breakWidth = $conf['breakWidth'];
777  $breakSpace = $this->‪getBreakSpace($conf, $theBBoxInfo);
778  $wordPairs = $this->‪getWordPairsForLineBreak($conf['text']);
779  // Iterate through all word pairs:
780  foreach ($wordPairs as $index => $wordPair) {
781  $wordWidth = $this->‪getRenderedTextWidth($wordPair, $conf);
782  if ($index == 0 || $currentWidth + $wordWidth <= $breakWidth) {
783  $currentWidth += $wordWidth;
784  } else {
785  $maxWidth = max($maxWidth, $currentWidth);
786  $y += $breakSpace;
787  // Restart:
788  $currentWidth = $wordWidth;
789  }
790  }
791  $x = max($maxWidth, $currentWidth) * $sF;
792  }
793  if ($sF > 1) {
794  $x = ceil($x / $sF);
795  $y = ceil($y / $sF);
796  if (is_array($theBBoxInfo)) {
797  foreach ($theBBoxInfo as &$value) {
798  $value = ceil($value / $sF);
799  }
800  unset($value);
801  }
802  }
803  return [$x, $y, $theBBoxInfo];
804  }
805 
815  public function ‪addToMap($cords, $conf)
816  {
817  $this->map .= '<area shape="poly" coords="' . implode(',', $cords) . '"'
818  . ' href="' . htmlspecialchars($conf['url']) . '"'
819  . ($conf['target'] ? ' target="' . htmlspecialchars($conf['target']) . '"' : '')
820  . ((string)$conf['titleText'] !== '' ? ' title="' . htmlspecialchars($conf['titleText']) . '"' : '')
821  . ' alt="' . htmlspecialchars($conf['altText']) . '" />';
822  }
823 
835  public function ‪calcTextCordsForMap($cords, $offset, $conf)
836  {
837  $newCords = [];
838  $pars = ‪GeneralUtility::intExplode(',', $conf['explode'] . ',');
839  $newCords[0] = $cords[0] + $offset[0] - $pars[0];
840  $newCords[1] = $cords[1] + $offset[1] + $pars[1];
841  $newCords[2] = $cords[2] + $offset[0] + $pars[0];
842  $newCords[3] = $cords[3] + $offset[1] + $pars[1];
843  $newCords[4] = $cords[4] + $offset[0] + $pars[0];
844  $newCords[5] = $cords[5] + $offset[1] - $pars[1];
845  $newCords[6] = $cords[6] + $offset[0] - $pars[0];
846  $newCords[7] = $cords[7] + $offset[1] - $pars[1];
847  return $newCords;
848  }
849 
869  public function ‪SpacedImageTTFText(&‪$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF = 1)
870  {
871  $spacing *= $sF;
872  $wordSpacing *= $sF;
873  if (!$spacing && $wordSpacing) {
874  $bits = explode(' ', $text);
875  foreach ($bits as $word) {
876  $word .= ' ';
877  $wordInf = $this->‪ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $word, $splitRenderingConf, $sF);
878  $wordW = $wordInf[2] - $wordInf[0];
879  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $word, $splitRenderingConf, $sF);
880  $x += $wordW + $wordSpacing;
881  }
882  } else {
883  $utf8Chars = $this->csConvObj->utf8_to_numberarray($text);
884  // For each UTF-8 char, do:
885  foreach ($utf8Chars as $char) {
886  $charInf = $this->‪ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $char, $splitRenderingConf, $sF);
887  $charW = $charInf[2] - $charInf[0];
888  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $char, $splitRenderingConf, $sF);
889  $x += $charW + ($char === ' ' ? $wordSpacing : $spacing);
890  }
891  }
892  }
893 
902  public function ‪fontResize($conf)
903  {
904  // 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!!!!
905  $maxWidth = (int)$conf['maxWidth'];
906  [$spacing, $wordSpacing] = $this->‪calcWordSpacing($conf);
907  if ($maxWidth) {
908  // If any kind of spacing applys, we use this function:
909  if ($spacing || $wordSpacing) {
910  return $conf['fontSize'];
911  }
912  do {
913  // Determine bounding box.
914  $bounds = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $conf['text'], $conf['splitRendering.']);
915  if ($conf['angle'] < 0) {
916  $pixelWidth = abs($bounds[4] - $bounds[0]);
917  } elseif ($conf['angle'] > 0) {
918  $pixelWidth = abs($bounds[2] - $bounds[6]);
919  } else {
920  $pixelWidth = abs($bounds[4] - $bounds[6]);
921  }
922  // Size is fine, exit:
923  if ($pixelWidth <= $maxWidth) {
924  break;
925  }
926  $conf['fontSize']--;
927  } while ($conf['fontSize'] > 1);
928  }
929  return $conf['fontSize'];
930  }
931 
943  public function ‪ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF = 1)
944  {
945  // Initialize:
946  $offsetInfo = [];
947  $stringParts = $this->‪splitString($string, $splitRendering, $fontSize, $fontFile);
948  // Traverse string parts:
949  foreach ($stringParts as $strCfg) {
950  $fontFile = GeneralUtility::getFileAbsFileName($strCfg['fontFile']);
951  if (is_readable($fontFile)) {
952  // Calculate Bounding Box for part.
953  $calc = imagettfbbox($this->‪compensateFontSizeiBasedOnFreetypeDpi($sF * $strCfg['fontSize']), $angle, $fontFile, $strCfg['str']);
954  // Calculate offsets:
955  if (empty($offsetInfo)) {
956  // First run, just copy over.
957  $offsetInfo = $calc;
958  } else {
959  $offsetInfo[2] += $calc[2] - $calc[0] + (int)$splitRendering['compX'] + (int)$strCfg['xSpaceBefore'] + (int)$strCfg['xSpaceAfter'];
960  $offsetInfo[3] += $calc[3] - $calc[1] - (int)$splitRendering['compY'] - (int)$strCfg['ySpaceBefore'] - (int)$strCfg['ySpaceAfter'];
961  $offsetInfo[4] += $calc[4] - $calc[6] + (int)$splitRendering['compX'] + (int)$strCfg['xSpaceBefore'] + (int)$strCfg['xSpaceAfter'];
962  $offsetInfo[5] += $calc[5] - $calc[7] - (int)$splitRendering['compY'] - (int)$strCfg['ySpaceBefore'] - (int)$strCfg['ySpaceAfter'];
963  }
964  } else {
965  ‪debug('cannot read file: ' . $fontFile, self::class . '::ImageTTFBBoxWrapper()');
966  }
967  }
968  return $offsetInfo;
969  }
970 
985  public function ‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF = 1)
986  {
987  // Initialize:
988  $stringParts = $this->‪splitString($string, $splitRendering, $fontSize, $fontFile);
989  $x = (int)ceil($sF * $x);
990  $y = (int)ceil($sF * $y);
991  // Traverse string parts:
992  foreach ($stringParts as $i => $strCfg) {
993  // Initialize:
994  $colorIndex = $color;
995  // Set custom color if any (only when niceText is off):
996  if ($strCfg['color'] && $sF == 1) {
997  $cols = $this->‪convertColor($strCfg['color']);
998  $colorIndex = imagecolorallocate(‪$im, $cols[0], $cols[1], $cols[2]);
999  $colorIndex = $color >= 0 ? $colorIndex : -$colorIndex;
1000  }
1001  // Setting xSpaceBefore
1002  if ($i) {
1003  $x += (int)$strCfg['xSpaceBefore'];
1004  $y -= (int)$strCfg['ySpaceBefore'];
1005  }
1006  $fontFile = GeneralUtility::getFileAbsFileName($strCfg['fontFile']);
1007  if (is_readable($fontFile)) {
1008  // Render part:
1009  imagettftext(‪$im, $this->‪compensateFontSizeiBasedOnFreetypeDpi($sF * $strCfg['fontSize']), $angle, $x, $y, $colorIndex, $fontFile, $strCfg['str']);
1010  // Calculate offset to apply:
1011  $wordInf = imagettfbbox($this->‪compensateFontSizeiBasedOnFreetypeDpi($sF * $strCfg['fontSize']), $angle, GeneralUtility::getFileAbsFileName($strCfg['fontFile']), $strCfg['str']);
1012  $x += $wordInf[2] - $wordInf[0] + (int)$splitRendering['compX'] + (int)$strCfg['xSpaceAfter'];
1013  $y += $wordInf[5] - $wordInf[7] - (int)$splitRendering['compY'] - (int)$strCfg['ySpaceAfter'];
1014  } else {
1015  ‪debug('cannot read file: ' . $fontFile, self::class . '::ImageTTFTextWrapper()');
1016  }
1017  }
1018  }
1019 
1029  public function ‪splitString($string, $splitRendering, $fontSize, $fontFile)
1030  {
1031  // Initialize by setting the whole string and default configuration as the first entry.
1032  $result = [];
1033  $result[] = [
1034  'str' => $string,
1035  'fontSize' => $fontSize,
1036  'fontFile' => $fontFile
1037  ];
1038  // Traverse the split-rendering configuration:
1039  // Splitting will create more entries in $result with individual configurations.
1040  if (is_array($splitRendering)) {
1041  $sKeyArray = ‪ArrayUtility::filterAndSortByNumericKeys($splitRendering);
1042  // Traverse configured options:
1043  foreach ($sKeyArray as $key) {
1044  $cfg = $splitRendering[$key . '.'];
1045  // Process each type of split rendering keyword:
1046  switch ((string)$splitRendering[$key]) {
1047  case 'highlightWord':
1048  if ((string)$cfg['value'] !== '') {
1049  $newResult = [];
1050  // Traverse the current parts of the result array:
1051  foreach ($result as $part) {
1052  // Explode the string value by the word value to highlight:
1053  $explodedParts = explode($cfg['value'], $part['str']);
1054  foreach ($explodedParts as $c => $expValue) {
1055  if ((string)$expValue !== '') {
1056  $newResult[] = array_merge($part, ['str' => $expValue]);
1057  }
1058  if ($c + 1 < count($explodedParts)) {
1059  $newResult[] = [
1060  'str' => $cfg['value'],
1061  'fontSize' => $cfg['fontSize'] ?: $part['fontSize'],
1062  'fontFile' => $cfg['fontFile'] ?: $part['fontFile'],
1063  'color' => $cfg['color'],
1064  'xSpaceBefore' => $cfg['xSpaceBefore'],
1065  'xSpaceAfter' => $cfg['xSpaceAfter'],
1066  'ySpaceBefore' => $cfg['ySpaceBefore'],
1067  'ySpaceAfter' => $cfg['ySpaceAfter']
1068  ];
1069  }
1070  }
1071  }
1072  // Set the new result as result array:
1073  if (!empty($newResult)) {
1074  $result = $newResult;
1075  }
1076  }
1077  break;
1078  case 'charRange':
1079  if ((string)$cfg['value'] !== '') {
1080  // Initialize range:
1081  $ranges = ‪GeneralUtility::trimExplode(',', $cfg['value'], true);
1082  foreach ($ranges as $i => $rangeDef) {
1083  $ranges[$i] = ‪GeneralUtility::intExplode('-', (string)$ranges[$i]);
1084  if (!isset($ranges[$i][1])) {
1085  $ranges[$i][1] = $ranges[$i][0];
1086  }
1087  }
1088  $newResult = [];
1089  // Traverse the current parts of the result array:
1090  foreach ($result as $part) {
1091  // Initialize:
1092  $currentState = -1;
1093  $bankAccum = '';
1094  // Explode the string value by the word value to highlight:
1095  $utf8Chars = $this->csConvObj->utf8_to_numberarray($part['str']);
1096  foreach ($utf8Chars as $utfChar) {
1097  // Find number and evaluate position:
1098  $uNumber = (int)$this->csConvObj->utf8CharToUnumber($utfChar);
1099  $inRange = 0;
1100  foreach ($ranges as $rangeDef) {
1101  if ($uNumber >= $rangeDef[0] && (!$rangeDef[1] || $uNumber <= $rangeDef[1])) {
1102  $inRange = 1;
1103  break;
1104  }
1105  }
1106  if ($currentState == -1) {
1107  $currentState = $inRange;
1108  }
1109  // Initialize first char
1110  // Switch bank:
1111  if ($inRange != $currentState && $uNumber !== 9 && $uNumber !== 10 && $uNumber !== 13 && $uNumber !== 32) {
1112  // Set result:
1113  if ($bankAccum !== '') {
1114  $newResult[] = [
1115  'str' => $bankAccum,
1116  'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'],
1117  'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'],
1118  'color' => $currentState ? $cfg['color'] : '',
1119  'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '',
1120  'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '',
1121  'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '',
1122  'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : ''
1123  ];
1124  }
1125  // Initialize new settings:
1126  $currentState = $inRange;
1127  $bankAccum = '';
1128  }
1129  // Add char to bank:
1130  $bankAccum .= $utfChar;
1131  }
1132  // Set result for FINAL part:
1133  if ($bankAccum !== '') {
1134  $newResult[] = [
1135  'str' => $bankAccum,
1136  'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'],
1137  'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'],
1138  'color' => $currentState ? $cfg['color'] : '',
1139  'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '',
1140  'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '',
1141  'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '',
1142  'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : ''
1143  ];
1144  }
1145  }
1146  // Set the new result as result array:
1147  if (!empty($newResult)) {
1148  $result = $newResult;
1149  }
1150  }
1151  break;
1152  }
1153  }
1154  }
1155  return $result;
1156  }
1157 
1167  public function ‪calcWordSpacing($conf, $scaleFactor = 1)
1168  {
1169  $spacing = (int)$conf['spacing'];
1170  $wordSpacing = (int)$conf['wordSpacing'];
1171  $wordSpacing = $wordSpacing ?: $spacing * 2;
1172  $spacing *= $scaleFactor;
1173  $wordSpacing *= $scaleFactor;
1174  return [$spacing, $wordSpacing];
1175  }
1176 
1184  public function ‪getTextScalFactor($conf)
1185  {
1186  if (!$conf['niceText']) {
1187  $sF = 1;
1188  } else {
1189  // NICETEXT::
1190  $sF = ‪MathUtility::forceIntegerInRange($conf['niceText.']['scaleFactor'], 2, 5);
1191  }
1192  return $sF;
1193  }
1194 
1199  public function ‪setImageFileExt(array ‪$imageFileExt): void
1200  {
1201  $this->imageFileExt = ‪$imageFileExt;
1202  }
1203 
1219  protected function ‪renderTTFText(&‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $conf, $sF = 1)
1220  {
1221  if (isset($conf['breakWidth']) && $conf['breakWidth'] && $this->‪getRenderedTextWidth($string, $conf) > $conf['breakWidth']) {
1222  $phrase = '';
1223  $currentWidth = 0;
1224  $breakWidth = $conf['breakWidth'];
1225  $breakSpace = $this->‪getBreakSpace($conf);
1226  $wordPairs = $this->‪getWordPairsForLineBreak($string);
1227  // Iterate through all word pairs:
1228  foreach ($wordPairs as $index => $wordPair) {
1229  $wordWidth = $this->‪getRenderedTextWidth($wordPair, $conf);
1230  if ($index == 0 || $currentWidth + $wordWidth <= $breakWidth) {
1231  $currentWidth += $wordWidth;
1232  $phrase .= $wordPair;
1233  } else {
1234  // Render the current phrase that is below breakWidth:
1235  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $phrase, $splitRendering, $sF);
1236  // Calculate the news height offset:
1237  $y += $breakSpace;
1238  // Restart the phrase:
1239  $currentWidth = $wordWidth;
1240  $phrase = $wordPair;
1241  }
1242  }
1243  // Render the remaining phrase:
1244  if ($currentWidth) {
1245  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $phrase, $splitRendering, $sF);
1246  }
1247  } else {
1248  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF);
1249  }
1250  }
1251 
1258  protected function ‪getWordPairsForLineBreak($string)
1259  {
1260  $wordPairs = [];
1261  $wordsArray = preg_split('#([- .,!:]+)#', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
1262  $wordsArray = is_array($wordsArray) ? $wordsArray : [];
1263  $wordsCount = count($wordsArray);
1264  for ($index = 0; $index < $wordsCount; $index += 2) {
1265  $wordPairs[] = $wordsArray[$index] . $wordsArray[$index + 1];
1266  }
1267  return $wordPairs;
1268  }
1269 
1277  protected function ‪getRenderedTextWidth($text, $conf)
1278  {
1279  $bounds = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $text, $conf['splitRendering.']);
1280  if ($conf['angle'] < 0) {
1281  $pixelWidth = abs($bounds[4] - $bounds[0]);
1282  } elseif ($conf['angle'] > 0) {
1283  $pixelWidth = abs($bounds[2] - $bounds[6]);
1284  } else {
1285  $pixelWidth = abs($bounds[4] - $bounds[6]);
1286  }
1287  return $pixelWidth;
1288  }
1289 
1297  protected function ‪getBreakSpace($conf, array $boundingBox = null)
1298  {
1299  if (!isset($boundingBox)) {
1300  $boundingBox = $this->‪calcBBox($conf);
1301  $boundingBox = $boundingBox[2];
1302  }
1303  if (isset($conf['breakSpace']) && $conf['breakSpace']) {
1304  $breakSpace = $boundingBox['lineHeight'] * $conf['breakSpace'];
1305  } else {
1306  $breakSpace = $boundingBox['lineHeight'];
1307  }
1308  return $breakSpace;
1309  }
1310 
1311  /*********************************************
1312  *
1313  * Other GIFBUILDER objects related to TEXT
1314  *
1315  *********************************************/
1326  public function ‪makeOutline(&‪$im, $conf, ‪$workArea, $txtConf)
1327  {
1328  $thickness = (int)$conf['thickness'];
1329  if ($thickness) {
1330  $txtConf['fontColor'] = $conf['color'];
1331  $outLineDist = ‪MathUtility::forceIntegerInRange($thickness, 1, 2);
1332  for ($b = 1; $b <= $outLineDist; $b++) {
1333  if ($b == 1) {
1334  $it = 8;
1335  } else {
1336  $it = 16;
1337  }
1338  $outL = $this->‪circleOffset($b, $it);
1339  for ($a = 0; $a < $it; $a++) {
1340  $this->‪makeText(‪$im, $txtConf, $this->‪applyOffset(‪$workArea, $outL[$a]));
1341  }
1342  }
1343  }
1344  }
1345 
1356  public function ‪circleOffset($distance, $iterations)
1357  {
1358  $res = [];
1359  if ($distance && $iterations) {
1360  for ($a = 0; $a < $iterations; $a++) {
1361  $yOff = round(sin(2 * M_PI / $iterations * ($a + 1)) * 100 * $distance);
1362  if ($yOff) {
1363  $yOff = (int)(ceil(abs($yOff / 100)) * ($yOff / abs($yOff)));
1364  }
1365  $xOff = round(cos(2 * M_PI / $iterations * ($a + 1)) * 100 * $distance);
1366  if ($xOff) {
1367  $xOff = (int)(ceil(abs($xOff / 100)) * ($xOff / abs($xOff)));
1368  }
1369  $res[$a] = [$xOff, $yOff];
1370  }
1371  }
1372  return $res;
1373  }
1374 
1385  public function ‪makeEmboss(&‪$im, $conf, ‪$workArea, $txtConf)
1386  {
1387  $conf['color'] = $conf['highColor'];
1388  $this->‪makeShadow(‪$im, $conf, ‪$workArea, $txtConf);
1389  $newOffset = ‪GeneralUtility::intExplode(',', $conf['offset']);
1390  $newOffset[0] *= -1;
1391  $newOffset[1] *= -1;
1392  $conf['offset'] = implode(',', $newOffset);
1393  $conf['color'] = $conf['lowColor'];
1394  $this->‪makeShadow(‪$im, $conf, ‪$workArea, $txtConf);
1395  }
1396 
1409  public function ‪makeShadow(&‪$im, $conf, ‪$workArea, $txtConf)
1410  {
1411  ‪$workArea = $this->‪applyOffset(‪$workArea, ‪GeneralUtility::intExplode(',', $conf['offset']));
1412  $blurRate = ‪MathUtility::forceIntegerInRange((int)$conf['blur'], 0, 99);
1413  // No effects if ImageMagick ver. 5+
1414  if (!$blurRate || !$this->processorEffectsEnabled) {
1415  $txtConf['fontColor'] = $conf['color'];
1416  $this->‪makeText(‪$im, $txtConf, ‪$workArea);
1417  } else {
1418  ‪$w = imagesx(‪$im);
1419  ‪$h = imagesy(‪$im);
1420  // Area around the blur used for cropping something
1421  $blurBorder = 3;
1422  $tmpStr = $this->‪randomName();
1423  $fileMenu = $tmpStr . '_menu.' . ‪$this->gifExtension;
1424  $fileColor = $tmpStr . '_color.' . ‪$this->gifExtension;
1425  $fileMask = $tmpStr . '_mask.' . ‪$this->gifExtension;
1426  // BlurColor Image laves
1427  $blurColImg = imagecreatetruecolor(‪$w, ‪$h);
1428  $bcols = $this->‪convertColor($conf['color']);
1429  $Bcolor = imagecolorallocate($blurColImg, $bcols[0], $bcols[1], $bcols[2]);
1430  imagefilledrectangle($blurColImg, 0, 0, ‪$w, ‪$h, $Bcolor);
1431  $this->‪ImageWrite($blurColImg, $fileColor);
1432  imagedestroy($blurColImg);
1433  // The mask is made: BlurTextImage
1434  $blurTextImg = imagecreatetruecolor(‪$w + $blurBorder * 2, ‪$h + $blurBorder * 2);
1435  // Black background
1436  $Bcolor = imagecolorallocate($blurTextImg, 0, 0, 0);
1437  imagefilledrectangle($blurTextImg, 0, 0, ‪$w + $blurBorder * 2, ‪$h + $blurBorder * 2, $Bcolor);
1438  $txtConf['fontColor'] = 'white';
1439  $blurBordArr = [$blurBorder, $blurBorder];
1440  $this->‪makeText($blurTextImg, $txtConf, $this->‪applyOffset(‪$workArea, $blurBordArr));
1441  // Dump to temporary file
1442  $this->‪ImageWrite($blurTextImg, $fileMask);
1443  // Destroy
1444  imagedestroy($blurTextImg);
1445  $command = $this->‪v5_blur($blurRate + 1);
1446  $this->‪imageMagickExec($fileMask, $fileMask, $command . ' +matte');
1447  // The mask is loaded again
1448  $blurTextImg_tmp = $this->‪imageCreateFromFile($fileMask);
1449  // If nothing went wrong we continue with the blurred mask
1450  if ($blurTextImg_tmp) {
1451  // Cropping the border from the mask
1452  $blurTextImg = imagecreatetruecolor(‪$w, ‪$h);
1453  $this->‪imagecopyresized($blurTextImg, $blurTextImg_tmp, 0, 0, $blurBorder, $blurBorder, ‪$w, ‪$h, ‪$w, ‪$h);
1454  // Destroy the temporary mask
1455  imagedestroy($blurTextImg_tmp);
1456  // Adjust the mask
1457  $intensity = 40;
1458  if ($conf['intensity']) {
1459  $intensity = ‪MathUtility::forceIntegerInRange($conf['intensity'], 0, 100);
1460  }
1461  $intensity = (int)ceil(255 - $intensity / 100 * 255);
1462  $this->‪inputLevels($blurTextImg, 0, $intensity);
1463  $opacity = ‪MathUtility::forceIntegerInRange((int)$conf['opacity'], 0, 100);
1464  if ($opacity && $opacity < 100) {
1465  $high = (int)ceil(255 * $opacity / 100);
1466  // Reducing levels as the opacity demands
1467  $this->‪outputLevels($blurTextImg, 0, $high);
1468  }
1469  // Dump the mask again
1470  $this->‪ImageWrite($blurTextImg, $fileMask);
1471  // Destroy the mask
1472  imagedestroy($blurTextImg);
1473  // The pictures are combined
1474  // The main pictures is saved temporarily
1475  $this->‪ImageWrite(‪$im, $fileMenu);
1476  $this->‪combineExec($fileMenu, $fileColor, $fileMask, $fileMenu);
1477  // The main image is loaded again...
1478  $backIm = $this->‪imageCreateFromFile($fileMenu);
1479  // ... and if nothing went wrong we load it onto the old one.
1480  if ($backIm) {
1481  if (!$this->saveAlphaLayer) {
1482  imagecolortransparent($backIm, -1);
1483  }
1484  ‪$im = $backIm;
1485  }
1486  }
1487  // Deleting temporary files;
1488  unlink($fileMenu);
1489  unlink($fileColor);
1490  unlink($fileMask);
1491  }
1492  }
1493 
1494  /****************************
1495  *
1496  * Other GIFBUILDER objects
1497  *
1498  ****************************/
1507  public function ‪makeBox(&‪$im, $conf, ‪$workArea)
1508  {
1509  $cords = ‪GeneralUtility::intExplode(',', $conf['dimensions'] . ',,,');
1510  $conf['offset'] = $cords[0] . ',' . $cords[1];
1511  $cords = $this->‪objPosition($conf, ‪$workArea, [$cords[2], $cords[3]]);
1512  $cols = $this->‪convertColor($conf['color']);
1513  $opacity = 0;
1514  if (isset($conf['opacity'])) {
1515  // conversion:
1516  // PHP 0 = opaque, 127 = transparent
1517  // TYPO3 100 = opaque, 0 = transparent
1518  $opacity = ‪MathUtility::forceIntegerInRange((int)$conf['opacity'], 1, 100, 1);
1519  $opacity = (int)abs($opacity - 100);
1520  $opacity = (int)round(127 * $opacity / 100);
1521  }
1522  $tmpColor = imagecolorallocatealpha(‪$im, $cols[0], $cols[1], $cols[2], $opacity);
1523  imagefilledrectangle(‪$im, $cords[0], $cords[1], $cords[0] + $cords[2] - 1, $cords[1] + $cords[3] - 1, $tmpColor);
1524  }
1525 
1546  public function ‪makeEllipse(&‪$im, array $conf, array ‪$workArea)
1547  {
1548  $ellipseConfiguration = ‪GeneralUtility::intExplode(',', $conf['dimensions'] . ',,,');
1549  // Ellipse offset inside workArea (x/y)
1550  $conf['offset'] = $ellipseConfiguration[0] . ',' . $ellipseConfiguration[1];
1551  // @see objPosition
1552  $imageCoordinates = $this->‪objPosition($conf, ‪$workArea, [$ellipseConfiguration[2], $ellipseConfiguration[3]]);
1553  $color = $this->‪convertColor($conf['color']);
1554  $fillingColor = imagecolorallocate(‪$im, $color[0], $color[1], $color[2]);
1555  imagefilledellipse(‪$im, $imageCoordinates[0], $imageCoordinates[1], $imageCoordinates[2], $imageCoordinates[3], $fillingColor);
1556  }
1557 
1567  public function ‪makeEffect(&‪$im, $conf)
1568  {
1569  $commands = $this->‪IMparams($conf['value']);
1570  if ($commands) {
1571  $this->‪applyImageMagickToPHPGif(‪$im, $commands);
1572  }
1573  }
1574 
1583  public function ‪IMparams(‪$setup)
1584  {
1585  if (!trim(‪$setup)) {
1586  return '';
1587  }
1588  $effects = explode('|', ‪$setup);
1589  $commands = '';
1590  foreach ($effects as $val) {
1591  $pairs = explode('=', $val, 2);
1592  $value = trim($pairs[1]);
1593  $effect = strtolower(trim($pairs[0]));
1594  switch ($effect) {
1595  case 'gamma':
1596  $commands .= ' -gamma ' . (float)$value;
1597  break;
1598  case 'blur':
1599  if ($this->processorEffectsEnabled) {
1600  $commands .= $this->‪v5_blur((int)$value);
1601  }
1602  break;
1603  case 'sharpen':
1604  if ($this->processorEffectsEnabled) {
1605  $commands .= $this->‪v5_sharpen((int)$value);
1606  }
1607  break;
1608  case 'rotate':
1609  $commands .= ' -rotate ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 360);
1610  break;
1611  case 'solarize':
1612  $commands .= ' -solarize ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 99);
1613  break;
1614  case 'swirl':
1615  $commands .= ' -swirl ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 1000);
1616  break;
1617  case 'wave':
1618  $params = ‪GeneralUtility::intExplode(',', $value);
1619  $commands .= ' -wave ' . ‪MathUtility::forceIntegerInRange($params[0], 0, 99) . 'x' . ‪MathUtility::forceIntegerInRange($params[1], 0, 99);
1620  break;
1621  case 'charcoal':
1622  $commands .= ' -charcoal ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 100);
1623  break;
1624  case 'gray':
1625  $commands .= ' -colorspace GRAY';
1626  break;
1627  case 'edge':
1628  $commands .= ' -edge ' . ‪MathUtility::forceIntegerInRange((int)$value, 0, 99);
1629  break;
1630  case 'emboss':
1631  $commands .= ' -emboss';
1632  break;
1633  case 'flip':
1634  $commands .= ' -flip';
1635  break;
1636  case 'flop':
1637  $commands .= ' -flop';
1638  break;
1639  case 'colors':
1640  $commands .= ' -colors ' . ‪MathUtility::forceIntegerInRange((int)$value, 2, 255);
1641  break;
1642  case 'shear':
1643  $commands .= ' -shear ' . ‪MathUtility::forceIntegerInRange((int)$value, -90, 90);
1644  break;
1645  case 'invert':
1646  $commands .= ' -negate';
1647  break;
1648  }
1649  }
1650  return $commands;
1651  }
1652 
1663  public function ‪adjust(&‪$im, $conf)
1664  {
1665  ‪$setup = $conf['value'];
1666  if (!trim(‪$setup)) {
1667  return;
1668  }
1669  $effects = explode('|', ‪$setup);
1670  foreach ($effects as $val) {
1671  $pairs = explode('=', $val, 2);
1672  $value = trim($pairs[1]);
1673  $effect = strtolower(trim($pairs[0]));
1674  switch ($effect) {
1675  case 'inputlevels':
1676  // low,high
1677  $params = ‪GeneralUtility::intExplode(',', $value);
1678  $this->‪inputLevels(‪$im, $params[0], $params[1]);
1679  break;
1680  case 'outputlevels':
1681  $params = ‪GeneralUtility::intExplode(',', $value);
1682  $this->‪outputLevels(‪$im, $params[0], $params[1]);
1683  break;
1684  case 'autolevels':
1685  $this->‪autolevels(‪$im);
1686  break;
1687  }
1688  }
1689  }
1690 
1698  public function ‪crop(&‪$im, $conf)
1699  {
1700  // Clears workArea to total image
1701  $this->‪setWorkArea('');
1702  $cords = ‪GeneralUtility::intExplode(',', $conf['crop'] . ',,,');
1703  $conf['offset'] = $cords[0] . ',' . $cords[1];
1704  $cords = $this->‪objPosition($conf, $this->workArea, [$cords[2], $cords[3]]);
1705  $newIm = imagecreatetruecolor($cords[2], $cords[3]);
1706  $cols = $this->‪convertColor($conf['backColor'] ?: $this->setup['backColor']);
1707  $Bcolor = imagecolorallocate($newIm, $cols[0], $cols[1], $cols[2]);
1708  imagefilledrectangle($newIm, 0, 0, $cords[2], $cords[3], $Bcolor);
1709  $newConf = [];
1710  ‪$workArea = [0, 0, $cords[2], $cords[3]];
1711  if ($cords[0] < 0) {
1712  ‪$workArea[0] = abs($cords[0]);
1713  } else {
1714  $newConf['offset'] = -$cords[0];
1715  }
1716  if ($cords[1] < 0) {
1717  ‪$workArea[1] = abs($cords[1]);
1718  } else {
1719  $newConf['offset'] .= ',' . -$cords[1];
1720  }
1721  $this->‪copyGifOntoGif($newIm, ‪$im, $newConf, ‪$workArea);
1722  ‪$im = $newIm;
1723  $this->w = imagesx(‪$im);
1724  $this->h = imagesy(‪$im);
1725  // Clears workArea to total image
1726  $this->‪setWorkArea('');
1727  }
1728 
1736  public function ‪scale(&‪$im, $conf)
1737  {
1738  if ($conf['width'] || $conf['height'] || $conf['params']) {
1739  $tmpStr = $this->‪randomName();
1740  $theFile = $tmpStr . '.' . ‪$this->gifExtension;
1741  $this->‪ImageWrite(‪$im, $theFile);
1742  $theNewFile = $this->‪imageMagickConvert($theFile, $this->gifExtension, $conf['width'], $conf['height'], $conf['params']);
1743  $tmpImg = $this->‪imageCreateFromFile($theNewFile[3]);
1744  if ($tmpImg) {
1745  imagedestroy(‪$im);
1746  ‪$im = $tmpImg;
1747  $this->w = imagesx(‪$im);
1748  $this->h = imagesy(‪$im);
1749  // Clears workArea to total image
1750  $this->‪setWorkArea('');
1751  }
1752  unlink($theFile);
1753  if ($theNewFile[3] && $theNewFile[3] != $theFile) {
1754  unlink($theNewFile[3]);
1755  }
1756  }
1757  }
1758 
1767  public function ‪setWorkArea(‪$workArea)
1768  {
1769  $this->workArea = ‪GeneralUtility::intExplode(',', ‪$workArea);
1770  $this->workArea = $this->‪applyOffset($this->workArea, $this->OFFSET);
1771  if (!$this->workArea[2]) {
1772  $this->workArea[2] = ‪$this->w;
1773  }
1774  if (!$this->workArea[3]) {
1775  $this->workArea[3] = ‪$this->h;
1776  }
1777  }
1778 
1779  /*************************
1780  *
1781  * Adjustment functions
1782  *
1783  ************************/
1789  public function ‪autolevels(&‪$im)
1790  {
1791  $totalCols = imagecolorstotal(‪$im);
1792  $grayArr = [];
1793  for ($c = 0; $c < $totalCols; $c++) {
1794  $cols = imagecolorsforindex(‪$im, $c);
1795  $grayArr[] = round(($cols['red'] + $cols['green'] + $cols['blue']) / 3);
1796  }
1797  $min = min($grayArr);
1798  $max = max($grayArr);
1799  $delta = $max - $min;
1800  if ($delta) {
1801  for ($c = 0; $c < $totalCols; $c++) {
1802  $cols = imagecolorsforindex(‪$im, $c);
1803  $cols['red'] = floor(($cols['red'] - $min) / $delta * 255);
1804  $cols['green'] = floor(($cols['green'] - $min) / $delta * 255);
1805  $cols['blue'] = floor(($cols['blue'] - $min) / $delta * 255);
1806  imagecolorset(‪$im, $c, $cols['red'], $cols['green'], $cols['blue']);
1807  }
1808  }
1809  }
1810 
1819  public function ‪outputLevels(&‪$im, $low, $high, $swap = false)
1820  {
1821  if ($low < $high) {
1822  $low = ‪MathUtility::forceIntegerInRange($low, 0, 255);
1823  $high = ‪MathUtility::forceIntegerInRange($high, 0, 255);
1824  if ($swap) {
1825  $temp = $low;
1826  $low = 255 - $high;
1827  $high = 255 - $temp;
1828  }
1829  $delta = $high - $low;
1830  $totalCols = imagecolorstotal(‪$im);
1831  for ($c = 0; $c < $totalCols; $c++) {
1832  $cols = imagecolorsforindex(‪$im, $c);
1833  $cols['red'] = $low + floor($cols['red'] / 255 * $delta);
1834  $cols['green'] = $low + floor($cols['green'] / 255 * $delta);
1835  $cols['blue'] = $low + floor($cols['blue'] / 255 * $delta);
1836  imagecolorset(‪$im, $c, $cols['red'], $cols['green'], $cols['blue']);
1837  }
1838  }
1839  }
1840 
1848  public function ‪inputLevels(&‪$im, $low, $high)
1849  {
1850  if ($low < $high) {
1851  $low = ‪MathUtility::forceIntegerInRange($low, 0, 255);
1852  $high = ‪MathUtility::forceIntegerInRange($high, 0, 255);
1853  $delta = $high - $low;
1854  $totalCols = imagecolorstotal(‪$im);
1855  for ($c = 0; $c < $totalCols; $c++) {
1856  $cols = imagecolorsforindex(‪$im, $c);
1857  $cols['red'] = ‪MathUtility::forceIntegerInRange((int)(($cols['red'] - $low) / $delta * 255), 0, 255);
1858  $cols['green'] = ‪MathUtility::forceIntegerInRange((int)(($cols['green'] - $low) / $delta * 255), 0, 255);
1859  $cols['blue'] = ‪MathUtility::forceIntegerInRange((int)(($cols['blue'] - $low) / $delta * 255), 0, 255);
1860  imagecolorset(‪$im, $c, $cols['red'], $cols['green'], $cols['blue']);
1861  }
1862  }
1863  }
1864 
1872  public function ‪IMreduceColors($file, $cols)
1873  {
1874  $fI = GeneralUtility::split_fileref($file);
1875  $ext = strtolower($fI['fileext']);
1876  $result = $this->‪randomName() . '.' . $ext;
1877  $reduce = ‪MathUtility::forceIntegerInRange($cols, 0, $ext === 'gif' ? 256 : $this->truecolorColors, 0);
1878  if ($reduce > 0) {
1879  $params = ' -colors ' . $reduce;
1880  if ($reduce <= 256) {
1881  $params .= ' -type Palette';
1882  }
1883  $prefix = $ext === 'png' && $reduce <= 256 ? 'png8:' : '';
1884  $this->‪imageMagickExec($file, $prefix . $result, $params);
1885  if ($result) {
1886  return $result;
1887  }
1888  }
1889  return '';
1890  }
1891 
1892  /*********************************
1893  *
1894  * GIFBUILDER Helper functions
1895  *
1896  *********************************/
1907  public function ‪v5_sharpen($factor)
1908  {
1909  $factor = ‪MathUtility::forceIntegerInRange((int)ceil($factor / 10), 0, 10);
1910  $sharpenArr = explode(',', ',' . $this->im5fx_sharpenSteps);
1911  $sharpenF = trim($sharpenArr[$factor]);
1912  if ($sharpenF) {
1913  return ' -sharpen ' . $sharpenF;
1914  }
1915  return '';
1916  }
1917 
1928  public function ‪v5_blur($factor)
1929  {
1930  $factor = ‪MathUtility::forceIntegerInRange((int)ceil($factor / 10), 0, 10);
1931  $blurArr = explode(',', ',' . $this->im5fx_blurSteps);
1932  $blurF = trim($blurArr[$factor]);
1933  if ($blurF) {
1934  return ' -blur ' . $blurF;
1935  }
1936  return '';
1937  }
1938 
1945  public function ‪randomName()
1946  {
1948  return ‪Environment::getVarPath() . '/transient/' . md5(‪StringUtility::getUniqueId());
1949  }
1950 
1959  public function ‪applyOffset($cords, ‪$OFFSET)
1960  {
1961  $cords[0] = (int)$cords[0] + (int)‪$OFFSET[0];
1962  $cords[1] = (int)$cords[1] + (int)‪$OFFSET[1];
1963  return $cords;
1964  }
1965 
1973  public function ‪convertColor($string)
1974  {
1975  $col = [];
1976  $cParts = explode(':', $string, 2);
1977  // Finding the RGB definitions of the color:
1978  $string = $cParts[0];
1979  if (strpos($string, '#') !== false) {
1980  $string = preg_replace('/[^A-Fa-f0-9]*/', '', $string) ?? '';
1981  $col[] = hexdec(substr($string, 0, 2));
1982  $col[] = hexdec(substr($string, 2, 2));
1983  $col[] = hexdec(substr($string, 4, 2));
1984  } elseif (strpos($string, ',') !== false) {
1985  $string = preg_replace('/[^,0-9]*/', '', $string) ?? '';
1986  $strArr = explode(',', $string);
1987  $col[] = (int)$strArr[0];
1988  $col[] = (int)$strArr[1];
1989  $col[] = (int)$strArr[2];
1990  } else {
1991  $string = strtolower(trim($string));
1992  if ($this->colMap[$string]) {
1993  $col = $this->colMap[$string];
1994  } else {
1995  $col = [0, 0, 0];
1996  }
1997  }
1998  // ... and possibly recalculating the value
1999  if (trim($cParts[1])) {
2000  $cParts[1] = trim($cParts[1]);
2001  if ($cParts[1][0] === '*') {
2002  $val = (float)substr($cParts[1], 1);
2003  $col[0] = ‪MathUtility::forceIntegerInRange((int)($col[0] * $val), 0, 255);
2004  $col[1] = ‪MathUtility::forceIntegerInRange((int)($col[1] * $val), 0, 255);
2005  $col[2] = ‪MathUtility::forceIntegerInRange((int)($col[2] * $val), 0, 255);
2006  } else {
2007  $val = (int)$cParts[1];
2008  $col[0] = ‪MathUtility::forceIntegerInRange((int)($col[0] + $val), 0, 255);
2009  $col[1] = ‪MathUtility::forceIntegerInRange((int)($col[1] + $val), 0, 255);
2010  $col[2] = ‪MathUtility::forceIntegerInRange((int)($col[2] + $val), 0, 255);
2011  }
2012  }
2013  return $col;
2014  }
2015 
2028  public function ‪objPosition($conf, ‪$workArea, $BB)
2029  {
2030  // offset, align, valign, workarea
2031  $result = [];
2032  $result[2] = $BB[0];
2033  $result[3] = $BB[1];
2034  ‪$w = ‪$workArea[2];
2035  ‪$h = ‪$workArea[3];
2036  $align = explode(',', $conf['align']);
2037  $align[0] = strtolower(substr(trim($align[0]), 0, 1));
2038  $align[1] = strtolower(substr(trim($align[1]), 0, 1));
2039  switch ($align[0]) {
2040  case 'r':
2041  $result[0] = ‪$w - $result[2];
2042  break;
2043  case 'c':
2044  $result[0] = round((‪$w - $result[2]) / 2);
2045  break;
2046  default:
2047  $result[0] = 0;
2048  }
2049  switch ($align[1]) {
2050  case 'b':
2051  // y pos
2052  $result[1] = ‪$h - $result[3];
2053  break;
2054  case 'c':
2055  $result[1] = round((‪$h - $result[3]) / 2);
2056  break;
2057  default:
2058  $result[1] = 0;
2059  }
2060  $result = $this->‪applyOffset($result, ‪GeneralUtility::intExplode(',', $conf['offset']));
2061  $result = $this->‪applyOffset($result, ‪$workArea);
2062  return $result;
2063  }
2064 
2065  /***********************************
2066  *
2067  * Scaling, Dimensions of images
2068  *
2069  ***********************************/
2088  public function ‪imageMagickConvert($imagefile, $newExt = '', ‪$w = '', ‪$h = '', $params = '', $frame = '', $options = [], $mustCreate = false)
2089  {
2090  if (!$this->processorEnabled) {
2091  // Returning file info right away
2092  return $this->‪getImageDimensions($imagefile);
2093  }
2094  $info = $this->‪getImageDimensions($imagefile);
2095  if (!$info) {
2096  return null;
2097  }
2098 
2099  $newExt = strtolower(trim($newExt));
2100  // If no extension is given the original extension is used
2101  if (!$newExt) {
2102  $newExt = $info[2];
2103  }
2104  if ($newExt === 'web') {
2105  if (in_array($info[2], $this->webImageExt, true)) {
2106  $newExt = $info[2];
2107  } else {
2108  $newExt = $this->‪gif_or_jpg($info[2], $info[0], $info[1]);
2109  if (!$params) {
2110  $params = $this->cmds[$newExt];
2111  }
2112  }
2113  }
2114  if (!in_array($newExt, $this->imageFileExt, true)) {
2115  return null;
2116  }
2117 
2118  $data = $this->‪getImageScale($info, ‪$w, ‪$h, $options);
2119  ‪$w = $data['origW'];
2120  ‪$h = $data['origH'];
2121  // If no conversion should be performed
2122  // this flag is TRUE if the width / height does NOT dictate
2123  // the image to be scaled!! (that is if no width / height is
2124  // given or if the destination w/h matches the original image
2125  // dimensions or if the option to not scale the image is set)
2126  $noScale = !‪$w && !‪$h || $data[0] == $info[0] && $data[1] == $info[1] || !empty($options['noScale']);
2127  if ($noScale && !$data['crs'] && !$params && !$frame && $newExt == $info[2] && !$mustCreate) {
2128  // Set the new width and height before returning,
2129  // if the noScale option is set
2130  if (!empty($options['noScale'])) {
2131  $info[0] = $data[0];
2132  $info[1] = $data[1];
2133  }
2134  $info[3] = $imagefile;
2135  return $info;
2136  }
2137  $info[0] = $data[0];
2138  $info[1] = $data[1];
2139  $frame = $this->addFrameSelection ? (int)$frame : 0;
2140  if (!$params) {
2141  $params = $this->cmds[$newExt];
2142  }
2143  // Cropscaling:
2144  if ($data['crs']) {
2145  if (!$data['origW']) {
2146  $data['origW'] = $data[0];
2147  }
2148  if (!$data['origH']) {
2149  $data['origH'] = $data[1];
2150  }
2151  $offsetX = (int)(($data[0] - $data['origW']) * ($data['cropH'] + 100) / 200);
2152  $offsetY = (int)(($data[1] - $data['origH']) * ($data['cropV'] + 100) / 200);
2153  $params .= ' -crop ' . $data['origW'] . 'x' . $data['origH'] . '+' . $offsetX . '+' . $offsetY . '! +repage';
2154  }
2155  $command = $this->scalecmd . ' ' . $info[0] . 'x' . $info[1] . '! ' . $params . ' ';
2156  // re-apply colorspace-setting for the resulting image so colors don't appear to dark (sRGB instead of RGB)
2157  $command .= ' -colorspace ' . ‪$this->colorspace;
2158  $cropscale = $data['crs'] ? 'crs-V' . $data['cropV'] . 'H' . $data['cropH'] : '';
2159  if ($this->alternativeOutputKey) {
2160  $theOutputName = GeneralUtility::shortMD5($command . $cropscale . ‪PathUtility::basename($imagefile) . $this->alternativeOutputKey . '[' . $frame . ']');
2161  } else {
2162  $theOutputName = GeneralUtility::shortMD5($command . $cropscale . $imagefile . filemtime($imagefile) . '[' . $frame . ']');
2163  }
2164  if ($this->imageMagickConvert_forceFileNameBody) {
2166  $this->imageMagickConvert_forceFileNameBody = '';
2167  }
2168  // Making the temporary filename
2169  ‪GeneralUtility::mkdir_deep(‪Environment::getPublicPath() . '/typo3temp/assets/images/');
2170  ‪$output = ‪Environment::getPublicPath() . '/typo3temp/assets/images/' . $this->filenamePrefix . $theOutputName . '.' . $newExt;
2171  if ($this->dontCheckForExistingTempFile || !file_exists(‪$output)) {
2172  $this->‪imageMagickExec($imagefile, ‪$output, $command, $frame);
2173  }
2174  if (file_exists(‪$output)) {
2175  $info[3] = ‪$output;
2176  $info[2] = $newExt;
2177  // params might change some image data!
2178  if ($params) {
2179  $info = $this->‪getImageDimensions($info[3]);
2180  }
2181  if ($info[2] == $this->gifExtension && !$this->dontCompress) {
2182  // Compress with IM (lzw) or GD (rle) (Workaround for the absence of lzw-compression in GD)
2183  ‪self::gifCompress($info[3], '');
2184  }
2185  return $info;
2186  }
2187  return null;
2188  }
2189 
2198  public function ‪getImageDimensions($imageFile)
2199  {
2200  $returnArr = null;
2201  preg_match('/([^\\.]*)$/', $imageFile, $reg);
2202  if (file_exists($imageFile) && in_array(strtolower($reg[0]), $this->imageFileExt, true)) {
2203  $returnArr = $this->‪getCachedImageDimensions($imageFile);
2204  if (!$returnArr) {
2205  $imageInfoObject = GeneralUtility::makeInstance(ImageInfo::class, $imageFile);
2206  if ($imageInfoObject->getWidth()) {
2207  $returnArr = [
2208  $imageInfoObject->getWidth(),
2209  $imageInfoObject->getHeight(),
2210  strtolower($reg[0]),
2211  $imageFile
2212  ];
2213  $this->‪cacheImageDimensions($returnArr);
2214  }
2215  }
2216  }
2217  return $returnArr;
2218  }
2219 
2227  public function ‪cacheImageDimensions(array $identifyResult)
2228  {
2229  $filePath = $identifyResult[3];
2230  $statusHash = $this->‪generateStatusHashForImageFile($filePath);
2231  $identifier = $this->‪generateCacheKeyForImageFile($filePath);
2232 
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);
2258  $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('imagesizes');
2259  $cachedImageDimensions = $cache->get($identifier);
2260  if (!isset($cachedImageDimensions['hash'])) {
2261  return false;
2262  }
2263 
2264  if ($cachedImageDimensions['hash'] !== $statusHash) {
2265  // The file has changed. Delete the cache entry.
2266  $cache->remove($identifier);
2267  $result = false;
2268  } else {
2269  preg_match('/([^\\.]*)$/', $filePath, $imageExtension);
2270  $result = [
2271  (int)$cachedImageDimensions['imagewidth'],
2272  (int)$cachedImageDimensions['imageheight'],
2273  strtolower($imageExtension[0]),
2274  $filePath
2275  ];
2276  }
2277 
2278  return $result;
2279  }
2280 
2290  protected function ‪generateCacheKeyForImageFile($filePath)
2291  {
2292  return sha1($filePath);
2293  }
2294 
2302  protected function ‪generateStatusHashForImageFile($filePath)
2303  {
2304  $fileStatus = stat($filePath);
2305 
2306  return sha1($fileStatus['mtime'] . $fileStatus['size']);
2307  }
2308 
2320  public function ‪getImageScale($info, ‪$w, ‪$h, $options)
2321  {
2322  $out = [];
2323  $max = strpos(‪$w . ‪$h, 'm') !== false ? 1 : 0;
2324  if (strpos(‪$w . ‪$h, 'c') !== false) {
2325  $out['cropH'] = (int)substr((string)strstr(‪$w, 'c'), 1);
2326  $out['cropV'] = (int)substr((string)strstr(‪$h, 'c'), 1);
2327  $crs = true;
2328  } else {
2329  $crs = false;
2330  }
2331  $out['crs'] = $crs;
2332  ‪$w = (int)‪$w;
2333  ‪$h = (int)‪$h;
2334  // If there are max-values...
2335  if (!empty($options['maxW'])) {
2336  // If width is given...
2337  if (‪$w) {
2338  if (‪$w > $options['maxW']) {
2339  ‪$w = $options['maxW'];
2340  // Height should follow
2341  $max = 1;
2342  }
2343  } else {
2344  if ($info[0] > $options['maxW']) {
2345  ‪$w = $options['maxW'];
2346  // Height should follow
2347  $max = 1;
2348  }
2349  }
2350  }
2351  if (!empty($options['maxH'])) {
2352  // If height is given...
2353  if (‪$h) {
2354  if (‪$h > $options['maxH']) {
2355  ‪$h = $options['maxH'];
2356  // Height should follow
2357  $max = 1;
2358  }
2359  } else {
2360  // Changed [0] to [1] 290801
2361  if ($info[1] > $options['maxH']) {
2362  ‪$h = $options['maxH'];
2363  // Height should follow
2364  $max = 1;
2365  }
2366  }
2367  }
2368  $out['origW'] = ‪$w;
2369  $out['origH'] = ‪$h;
2370  $out['max'] = $max;
2371  if (!$this->mayScaleUp) {
2372  if (‪$w > $info[0]) {
2373  ‪$w = $info[0];
2374  }
2375  if (‪$h > $info[1]) {
2376  ‪$h = $info[1];
2377  }
2378  }
2379  // If scaling should be performed. Check that input "info" array will not cause division-by-zero
2380  if ((‪$w || ‪$h) && $info[0] && $info[1]) {
2381  if (‪$w && !‪$h) {
2382  $info[1] = ceil($info[1] * (‪$w / $info[0]));
2383  $info[0] = ‪$w;
2384  }
2385  if (!‪$w && ‪$h) {
2386  $info[0] = ceil($info[0] * (‪$h / $info[1]));
2387  $info[1] = ‪$h;
2388  }
2389  if (‪$w && ‪$h) {
2390  if ($max) {
2391  $ratio = $info[0] / $info[1];
2392  if (‪$h * $ratio > ‪$w) {
2393  ‪$h = round(‪$w / $ratio);
2394  } else {
2395  ‪$w = round(‪$h * $ratio);
2396  }
2397  }
2398  if ($crs) {
2399  $ratio = $info[0] / $info[1];
2400  if (‪$h * $ratio < ‪$w) {
2401  ‪$h = round(‪$w / $ratio);
2402  } else {
2403  ‪$w = round(‪$h * $ratio);
2404  }
2405  }
2406  $info[0] = ‪$w;
2407  $info[1] = ‪$h;
2408  }
2409  }
2410  $out[0] = $info[0];
2411  $out[1] = $info[1];
2412  // Set minimum-measures!
2413  if (isset($options['minW']) && $out[0] < $options['minW']) {
2414  if (($max || $crs) && $out[0]) {
2415  $out[1] = round($out[1] * $options['minW'] / $out[0]);
2416  }
2417  $out[0] = $options['minW'];
2418  }
2419  if (isset($options['minH']) && $out[1] < $options['minH']) {
2420  if (($max || $crs) && $out[1]) {
2421  $out[0] = round($out[0] * $options['minH'] / $out[1]);
2422  }
2423  $out[1] = $options['minH'];
2424  }
2425  return $out;
2426  }
2427 
2428  /***********************************
2429  *
2430  * ImageMagick API functions
2431  *
2432  ***********************************/
2439  public function ‪imageMagickIdentify($imagefile)
2440  {
2441  if (!$this->processorEnabled) {
2442  return null;
2443  }
2444 
2445  $result = $this->‪executeIdentifyCommandForImageFile($imagefile);
2446  if ($result) {
2447  [$width, $height, $fileExtension, $fileType] = explode(' ', $result);
2448  if ((int)$width && (int)$height) {
2449  return [$width, $height, strtolower($fileExtension), $imagefile, strtolower($fileType)];
2450  }
2451  }
2452  return null;
2453  }
2454 
2461  protected function ‪executeIdentifyCommandForImageFile(string $imageFile): ?string
2462  {
2463  $frame = $this->addFrameSelection ? 0 : null;
2465  'identify',
2466  '-format "%w %h %e %m" ' . ‪ImageMagickFile::fromFilePath($imageFile, $frame)
2467  );
2468  $returnVal = [];
2469  ‪CommandUtility::exec($cmd, $returnVal);
2470  $result = array_pop($returnVal);
2471  $this->IM_commands[] = ['identify', $cmd, $result];
2472  return $result;
2473  }
2474 
2485  public function ‪imageMagickExec($input, ‪$output, $params, $frame = 0)
2486  {
2487  if (!$this->processorEnabled) {
2488  return '';
2489  }
2490  // If addFrameSelection is set in the Install Tool, a frame number is added to
2491  // select a specific page of the image (by default this will be the first page)
2492  $frame = $this->addFrameSelection ? (int)$frame : null;
2494  'convert',
2495  $params
2496  . ' ' . ‪ImageMagickFile::fromFilePath($input, $frame)
2498  );
2499  $this->IM_commands[] = [‪$output, $cmd];
2500  $ret = ‪CommandUtility::exec($cmd);
2501  // Change the permissions of the file
2503  return $ret;
2504  }
2505 
2516  public function ‪combineExec($input, $overlay, $mask, ‪$output)
2517  {
2518  if (!$this->processorEnabled) {
2519  return '';
2520  }
2521  $theMask = $this->‪randomName() . '.' . ‪$this->gifExtension;
2522  // +matte = no alpha layer in output
2523  $this->‪imageMagickExec($mask, $theMask, '-colorspace GRAY +matte');
2524 
2525  $parameters = '-compose over'
2526  . ' -quality ' . $this->jpegQuality
2527  . ' +matte '
2529  . ‪ImageMagickFile::fromFilePath($overlay) . ' '
2530  . ‪ImageMagickFile::fromFilePath($theMask) . ' '
2532  $cmd = ‪CommandUtility::imageMagickCommand('combine', $parameters);
2533  $this->IM_commands[] = [‪$output, $cmd];
2534  $ret = ‪CommandUtility::exec($cmd);
2535  // Change the permissions of the file
2537  if (is_file($theMask)) {
2538  @unlink($theMask);
2539  }
2540  return $ret;
2541  }
2542 
2561  public static function ‪gifCompress($theFile, $type)
2562  {
2563  $gfxConf = ‪$GLOBALS['TYPO3_CONF_VARS']['GFX'];
2564  if (!$gfxConf['gif_compress'] || strtolower(substr($theFile, -4, 4)) !== '.gif') {
2565  return '';
2566  }
2567 
2568  if (($type === 'IM' || !$type) && $gfxConf['processor_enabled'] && $gfxConf['processor_path_lzw']) {
2569  // Use temporary file to prevent problems with read and write lock on same file on network file systems
2570  $temporaryName = ‪PathUtility::dirname($theFile) . '/' . md5(‪StringUtility::getUniqueId()) . '.gif';
2571  // Rename could fail, if a simultaneous thread is currently working on the same thing
2572  if (@rename($theFile, $temporaryName)) {
2574  'convert',
2576  $gfxConf['processor_path_lzw']
2577  );
2579  unlink($temporaryName);
2580  }
2581  $returnCode = 'IM';
2582  if (@is_file($theFile)) {
2584  }
2585  } elseif (($type === 'GD' || !$type) && $gfxConf['gdlib'] && !$gfxConf['gdlib_png']) {
2586  $tempImage = imagecreatefromgif($theFile);
2587  imagegif($tempImage, $theFile);
2588  imagedestroy($tempImage);
2589  $returnCode = 'GD';
2590  if (@is_file($theFile)) {
2592  }
2593  } else {
2594  $returnCode = '';
2595  }
2596 
2597  return $returnCode;
2598  }
2599 
2608  public static function ‪readPngGif($theFile, $output_png = false)
2609  {
2610  if (!‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_enabled'] || !@is_file($theFile)) {
2611  return null;
2612  }
2613 
2614  $ext = strtolower(substr($theFile, -4, 4));
2615  if ((string)$ext === '.png' && $output_png || (string)$ext === '.gif' && !$output_png) {
2616  return $theFile;
2617  }
2618 
2619  if (!@is_dir(‪Environment::getPublicPath() . '/typo3temp/assets/images/')) {
2620  ‪GeneralUtility::mkdir_deep(‪Environment::getPublicPath() . '/typo3temp/assets/images/');
2621  }
2622  $newFile = ‪Environment::getPublicPath() . '/typo3temp/assets/images/' . md5($theFile . '|' . filemtime($theFile)) . ($output_png ? '.png' : '.gif');
2624  'convert',
2626  . ' ' . ‪CommandUtility::escapeShellArgument($newFile),
2627  ‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_path']
2628  );
2630  if (@is_file($newFile)) {
2632  return $newFile;
2633  }
2634  return null;
2635  }
2636 
2637  /***********************************
2638  *
2639  * Various IO functions
2640  *
2641  ***********************************/
2642 
2649  public function ‪applyImageMagickToPHPGif(&‪$im, $command)
2650  {
2651  $tmpStr = $this->‪randomName();
2652  $theFile = $tmpStr . '.' . ‪$this->gifExtension;
2653  $this->‪ImageWrite(‪$im, $theFile);
2654  $this->‪imageMagickExec($theFile, $theFile, $command);
2655  $tmpImg = $this->‪imageCreateFromFile($theFile);
2656  if ($tmpImg) {
2657  imagedestroy(‪$im);
2658  ‪$im = $tmpImg;
2659  $this->w = imagesx(‪$im);
2660  $this->h = imagesy(‪$im);
2661  }
2662  unlink($theFile);
2663  }
2664 
2674  public function ‪gif_or_jpg($type, ‪$w, ‪$h)
2675  {
2676  if ($type === 'ai' || ‪$w * $h < $this->pixelLimitGif) {
2677  return ‪$this->gifExtension;
2678  }
2679  return 'jpg';
2680  }
2681 
2691  public function ‪output($file)
2692  {
2693  if ($file) {
2694  $reg = [];
2695  preg_match('/([^\\.]*)$/', $file, $reg);
2696  $ext = strtolower($reg[0]);
2697  switch ($ext) {
2698  case 'gif':
2699  case 'png':
2700  if ($this->‪ImageWrite($this->im, $file)) {
2701  // ImageMagick operations
2702  if ($this->setup['reduceColors']) {
2703  $reduced = $this->‪IMreduceColors($file, ‪MathUtility::forceIntegerInRange($this->setup['reduceColors'], 256, $this->truecolorColors, 256));
2704  if ($reduced) {
2705  @copy($reduced, $file);
2706  @unlink($reduced);
2707  }
2708  }
2709  // Compress with IM! (adds extra compression, LZW from ImageMagick)
2710  // (Workaround for the absence of lzw-compression in GD)
2711  ‪self::gifCompress($file, 'IM');
2712  }
2713  break;
2714  case 'jpg':
2715  case 'jpeg':
2716  // Use the default
2717  $quality = 0;
2718  if ($this->setup['quality']) {
2719  $quality = ‪MathUtility::forceIntegerInRange($this->setup['quality'], 10, 100);
2720  }
2721  $this->‪ImageWrite($this->im, $file, $quality);
2722  break;
2723  }
2724  }
2725  return $file;
2726  }
2733  public function ‪destroy()
2734  {
2735  imagedestroy($this->im);
2736  }
2737 
2744  public function ‪imgTag($imgInfo)
2745  {
2746  return '<img src="' . $imgInfo[3] . '" width="' . $imgInfo[0] . '" height="' . $imgInfo[1] . '" border="0" alt="" />';
2747  }
2748 
2760  public function ‪ImageWrite($destImg, $theImage, $quality = 0)
2761  {
2762  imageinterlace($destImg, 0);
2763  $ext = strtolower(substr($theImage, (int)strrpos($theImage, '.') + 1));
2764  $result = false;
2765  switch ($ext) {
2766  case 'jpg':
2767  case 'jpeg':
2768  if (function_exists('imagejpeg')) {
2769  if ($quality === 0) {
2770  $quality = ‪$this->jpegQuality;
2771  }
2772  $result = imagejpeg($destImg, $theImage, $quality);
2773  }
2774  break;
2775  case 'gif':
2776  if (function_exists('imagegif')) {
2777  imagetruecolortopalette($destImg, true, 256);
2778  $result = imagegif($destImg, $theImage);
2779  }
2780  break;
2781  case 'png':
2782  if (function_exists('imagepng')) {
2783  $result = imagepng($destImg, $theImage);
2784  }
2785  break;
2786  }
2787  if ($result) {
2789  }
2790  return $result;
2791  }
2792 
2800  public function ‪imageCreateFromFile($sourceImg)
2801  {
2802  $imgInf = pathinfo($sourceImg);
2803  $ext = strtolower($imgInf['extension']);
2804  switch ($ext) {
2805  case 'gif':
2806  if (function_exists('imagecreatefromgif')) {
2807  return imagecreatefromgif($sourceImg);
2808  }
2809  break;
2810  case 'png':
2811  if (function_exists('imagecreatefrompng')) {
2812  $imageHandle = imagecreatefrompng($sourceImg);
2813  if ($this->saveAlphaLayer) {
2814  imagesavealpha($imageHandle, true);
2815  }
2816  return $imageHandle;
2817  }
2818  break;
2819  case 'jpg':
2820  case 'jpeg':
2821  if (function_exists('imagecreatefromjpeg')) {
2822  return imagecreatefromjpeg($sourceImg);
2823  }
2824  break;
2825  }
2826  // If non of the above:
2827  $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $sourceImg);
2828  ‪$im = imagecreatetruecolor($imageInfo->getWidth(), $imageInfo->getHeight());
2829  $Bcolor = imagecolorallocate(‪$im, 128, 128, 128);
2830  imagefilledrectangle(‪$im, 0, 0, $imageInfo->getWidth(), $imageInfo->getHeight(), $Bcolor);
2831  return ‪$im;
2832  }
2833 
2840  public function ‪hexColor($color)
2841  {
2842  $r = dechex($color[0]);
2843  if (strlen($r) < 2) {
2844  $r = '0' . $r;
2845  }
2846  $g = dechex($color[1]);
2847  if (strlen($g) < 2) {
2848  $g = '0' . $g;
2849  }
2850  $b = dechex($color[2]);
2851  if (strlen($b) < 2) {
2852  $b = '0' . $b;
2853  }
2854  return '#' . $r . $g . $b;
2855  }
2856 
2865  public function ‪unifyColors(&$img, $colArr, $closest = false)
2866  {
2867  $retCol = -1;
2868  if (is_array($colArr) && !empty($colArr) && function_exists('imagepng') && function_exists('imagecreatefrompng')) {
2869  $firstCol = array_shift($colArr);
2870  $firstColArr = $this->‪convertColor($firstCol);
2871  $origName = $preName = $this->‪randomName() . '.png';
2872  $postName = $this->‪randomName() . '.png';
2873  $tmpImg = null;
2874  if (count($colArr) > 1) {
2875  $this->‪ImageWrite($img, $preName);
2876  $firstCol = $this->‪hexColor($firstColArr);
2877  foreach ($colArr as $transparentColor) {
2878  $transparentColor = $this->‪convertColor($transparentColor);
2879  $transparentColor = $this->‪hexColor($transparentColor);
2880  $cmd = '-fill "' . $firstCol . '" -opaque "' . $transparentColor . '"';
2881  $this->‪imageMagickExec($preName, $postName, $cmd);
2882  $preName = $postName;
2883  }
2884  $this->‪imageMagickExec($postName, $origName, '');
2885  if (@is_file($origName)) {
2886  $tmpImg = $this->‪imageCreateFromFile($origName);
2887  }
2888  } else {
2889  $tmpImg = $img;
2890  }
2891  if ($tmpImg) {
2892  $img = $tmpImg;
2893  if ($closest) {
2894  $retCol = imagecolorclosest($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]);
2895  } else {
2896  $retCol = imagecolorexact($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]);
2897  }
2898  }
2899  // Unlink files from process
2900  if ($origName) {
2901  @unlink($origName);
2902  }
2903  if ($postName) {
2904  @unlink($postName);
2905  }
2906  }
2907  return $retCol;
2908  }
2909 
2921  public function ‪getTemporaryImageWithText($filename, $textline1, $textline2, $textline3)
2922  {
2923  if (empty(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'])) {
2924  throw new \RuntimeException('TYPO3 Fatal Error: No gdlib. ' . $textline1 . ' ' . $textline2 . ' ' . $textline3, 1270853952);
2925  }
2926  // Creates the basis for the error image
2927  $basePath = ‪ExtensionManagementUtility::extPath('core') . 'Resources/Public/Images/';
2928  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'])) {
2929  ‪$im = imagecreatefrompng($basePath . 'NotFound.png');
2930  } else {
2931  ‪$im = imagecreatefromgif($basePath . 'NotFound.gif');
2932  }
2933  // Sets background color and print color.
2934  $white = imagecolorallocate(‪$im, 255, 255, 255);
2935  $black = imagecolorallocate(‪$im, 0, 0, 0);
2936  // Prints the text strings with the build-in font functions of GD
2937  $x = 0;
2938  $font = 0;
2939  if ($textline1) {
2940  imagefilledrectangle(‪$im, $x, 9, 56, 16, $white);
2941  imagestring(‪$im, $font, $x, 9, $textline1, $black);
2942  }
2943  if ($textline2) {
2944  imagefilledrectangle(‪$im, $x, 19, 56, 26, $white);
2945  imagestring(‪$im, $font, $x, 19, $textline2, $black);
2946  }
2947  if ($textline3) {
2948  imagefilledrectangle(‪$im, $x, 29, 56, 36, $white);
2949  imagestring(‪$im, $font, $x, 29, substr($textline3, -14), $black);
2950  }
2951  // Outputting the image stream and exit
2952  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'])) {
2953  imagepng(‪$im, $filename);
2954  } else {
2955  imagegif(‪$im, $filename);
2956  }
2957  }
2958 
2966  protected function ‪compensateFontSizeiBasedOnFreetypeDpi($fontSize)
2967  {
2968  return $fontSize / 96.0 * 72;
2969  }
2970 }
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$OFFSET
‪array $OFFSET
Definition: GraphicalFunctions.php:264
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$im
‪resource $im
Definition: GraphicalFunctions.php:268
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getRenderedTextWidth
‪int getRenderedTextWidth($text, $conf)
Definition: GraphicalFunctions.php:1244
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcTextCordsForMap
‪array calcTextCordsForMap($cords, $offset, $conf)
Definition: GraphicalFunctions.php:802
‪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:1323
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\fontResize
‪int fontResize($conf)
Definition: GraphicalFunctions.php:869
‪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:1534
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\hexColor
‪string hexColor($color)
Definition: GraphicalFunctions.php:2807
‪TYPO3\CMS\Core\Imaging
Definition: Dimension.php:16
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:24
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$alternativeOutputKey
‪string $alternativeOutputKey
Definition: GraphicalFunctions.php:168
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\convertColor
‪array convertColor($string)
Definition: GraphicalFunctions.php:1940
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$scalecmd
‪string $scalecmd
Definition: GraphicalFunctions.php:190
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\scale
‪scale(&$im, $conf)
Definition: GraphicalFunctions.php:1703
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeShadow
‪makeShadow(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1376
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\setWorkArea
‪setWorkArea($workArea)
Definition: GraphicalFunctions.php:1734
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:180
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeOutline
‪makeOutline(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1293
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeBox
‪makeBox(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:1474
‪TYPO3\CMS\Core\Utility\PathUtility\dirname
‪static string dirname($path)
Definition: PathUtility.php:186
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\output
‪string output($file)
Definition: GraphicalFunctions.php:2658
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getTextScalFactor
‪int getTextScalFactor($conf)
Definition: GraphicalFunctions.php:1151
‪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:1550
‪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:1839
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\setImageFileExt
‪setImageFileExt(array $imageFileExt)
Definition: GraphicalFunctions.php:1166
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\renderTTFText
‪renderTTFText(&$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $conf, $sF=1)
Definition: GraphicalFunctions.php:1186
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$dontCheckForExistingTempFile
‪bool $dontCheckForExistingTempFile
Definition: GraphicalFunctions.php:154
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\applyImageMagickToPHPGif
‪applyImageMagickToPHPGif(&$im, $command)
Definition: GraphicalFunctions.php:2616
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getTemporaryImageWithText
‪getTemporaryImageWithText($filename, $textline1, $textline2, $textline3)
Definition: GraphicalFunctions.php:2888
‪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:2727
‪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:165
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getImageDimensions
‪array null getImageDimensions($imageFile)
Definition: GraphicalFunctions.php:2165
‪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:1786
‪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:1352
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions
Definition: GraphicalFunctions.php:37
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcBBox
‪array calcBBox($conf)
Definition: GraphicalFunctions.php:698
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$truecolorColors
‪int $truecolorColors
Definition: GraphicalFunctions.php:99
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\adjust
‪adjust(&$im, $conf)
Definition: GraphicalFunctions.php:1630
‪TYPO3\CMS\Core\Utility\GeneralUtility\fixPermissions
‪static mixed fixPermissions($path, $recursive=false)
Definition: GeneralUtility.php:1863
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir_deep
‪static mkdir_deep($directory)
Definition: GeneralUtility.php:2022
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\combineExec
‪string combineExec($input, $overlay, $mask, $output)
Definition: GraphicalFunctions.php:2483
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\autolevels
‪autolevels(&$im)
Definition: GraphicalFunctions.php:1756
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\splitString
‪array splitString($string, $splitRendering, $fontSize, $fontFile)
Definition: GraphicalFunctions.php:996
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\gifCompress
‪static string gifCompress($theFile, $type)
Definition: GraphicalFunctions.php:2528
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\objPosition
‪array objPosition($conf, $workArea, $BB)
Definition: GraphicalFunctions.php:1995
‪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:2287
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:35
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\readPngGif
‪static string null readPngGif($theFile, $output_png=false)
Definition: GraphicalFunctions.php:2575
‪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:2832
‪TYPO3\CMS\Core\Utility\CommandUtility\escapeShellArgument
‪static string escapeShellArgument($input)
Definition: CommandUtility.php:504
‪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:2700
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\generateStatusHashForImageFile
‪string generateStatusHashForImageFile($filePath)
Definition: GraphicalFunctions.php:2269
‪TYPO3\CMS\Core\Type\File\ImageInfo
Definition: ImageInfo.php:27
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$cmds
‪array $cmds
Definition: GraphicalFunctions.php:122
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪$output
‪$output
Definition: annotationChecker.php:119
‪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:1895
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\compensateFontSizeiBasedOnFreetypeDpi
‪float compensateFontSizeiBasedOnFreetypeDpi($fontSize)
Definition: GraphicalFunctions.php:2933
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageMagickIdentify
‪array null imageMagickIdentify($imagefile)
Definition: GraphicalFunctions.php:2406
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:92
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\SpacedImageTTFText
‪SpacedImageTTFText(&$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF=1)
Definition: GraphicalFunctions.php:836
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageMagickConvert
‪array null imageMagickConvert($imagefile, $newExt='', $w='', $h='', $params='', $frame='', $options=[], $mustCreate=false)
Definition: GraphicalFunctions.php:2055
‪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:5
‪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:40
‪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:988
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$setup
‪array $setup
Definition: GraphicalFunctions.php:252
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\extPath
‪static string extPath($key, $script='')
Definition: ExtensionManagementUtility.php:127
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageCreateFromFile
‪resource imageCreateFromFile($sourceImg)
Definition: GraphicalFunctions.php:2767
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\cacheImageDimensions
‪bool cacheImageDimensions(array $identifyResult)
Definition: GraphicalFunctions.php:2194
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getWordPairsForLineBreak
‪array getWordPairsForLineBreak($string)
Definition: GraphicalFunctions.php:1225
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\ImageTTFTextWrapper
‪ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF=1)
Definition: GraphicalFunctions.php:952
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\v5_sharpen
‪string v5_sharpen($factor)
Definition: GraphicalFunctions.php:1874
‪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:46
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\randomName
‪string randomName()
Definition: GraphicalFunctions.php:1912
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getBreakSpace
‪int getBreakSpace($conf, array $boundingBox=null)
Definition: GraphicalFunctions.php:1264
‪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:2428
‪TYPO3\CMS\Core\Utility\CommandUtility
Definition: CommandUtility.php:49
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEllipse
‪makeEllipse(&$im, array $conf, array $workArea)
Definition: GraphicalFunctions.php:1513
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\ImageTTFBBoxWrapper
‪array ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF=1)
Definition: GraphicalFunctions.php:910
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\inputLevels
‪inputLevels(&$im, $low, $high)
Definition: GraphicalFunctions.php:1815
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcWordSpacing
‪array calcWordSpacing($conf, $scaleFactor=1)
Definition: GraphicalFunctions.php:1134
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\gif_or_jpg
‪string gif_or_jpg($type, $w, $h)
Definition: GraphicalFunctions.php:2641
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imgTag
‪string imgTag($imgInfo)
Definition: GraphicalFunctions.php:2711
‪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:2452
‪TYPO3\CMS\Core\Utility\ArrayUtility\filterAndSortByNumericKeys
‪static array filterAndSortByNumericKeys($setupArr, $acceptAnyKeys=false)
Definition: ArrayUtility.php:844
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\applyOffset
‪array applyOffset($cords, $OFFSET)
Definition: GraphicalFunctions.php:1926
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\generateCacheKeyForImageFile
‪string generateCacheKeyForImageFile($filePath)
Definition: GraphicalFunctions.php:2257
‪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:782
‪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:192
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\crop
‪crop(&$im, $conf)
Definition: GraphicalFunctions.php:1665
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$imageFileExt
‪array $imageFileExt
Definition: GraphicalFunctions.php:106