‪TYPO3CMS  9.5
GraphicalFunctions.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
27 
35 {
41  public ‪$addFrameSelection = true;
42 
48  public ‪$gifExtension = 'gif';
49 
55  protected ‪$gdlibExtensions = [];
56 
62  protected ‪$colorspace = 'RGB';
63 
69  protected ‪$allowedColorSpaceNames = [
70  'CMY',
71  'CMYK',
72  'Gray',
73  'HCL',
74  'HSB',
75  'HSL',
76  'HWB',
77  'Lab',
78  'LCH',
79  'LMS',
80  'Log',
81  'Luv',
82  'OHTA',
83  'Rec601Luma',
84  'Rec601YCbCr',
85  'Rec709Luma',
86  'Rec709YCbCr',
87  'RGB',
88  'sRGB',
89  'Transparent',
90  'XYZ',
91  'YCbCr',
92  'YCC',
93  'YIQ',
94  'YCbCr',
95  'YUV'
96  ];
97 
103  public ‪$truecolorColors = 16777215;
104 
111  protected ‪$imageFileExt = ['gif', 'jpg', 'jpeg', 'png', 'tif', 'bmp', 'tga', 'pcx', 'ai', 'pdf'];
112 
118  protected ‪$webImageExt = ['gif', 'jpg', 'jpeg', 'png'];
119 
125  protected ‪$processorEffectsEnabled = false;
126 
130  public ‪$cmds = [
131  'jpg' => '',
132  'jpeg' => '',
133  'gif' => '',
134  'png' => ''
135  ];
136 
141  protected ‪$processorEnabled;
142 
146  protected ‪$mayScaleUp = true;
147 
153  public ‪$filenamePrefix = '';
154 
161 
167  public ‪$dontCheckForExistingTempFile = false;
168 
174  public ‪$dontCompress = false;
175 
183  public ‪$alternativeOutputKey = '';
184 
190  public ‪$IM_commands = [];
191 
195  public ‪$workArea = [];
196 
202  protected ‪$saveAlphaLayer = false;
203 
209  public ‪$scalecmd = '-auto-orient -geometry';
210 
216  protected ‪$im5fx_blurSteps = '1x2,2x2,3x2,4x3,5x3,5x4,6x4,7x5,8x5,9x5';
217 
223  protected ‪$im5fx_sharpenSteps = '1x2,2x2,3x2,2x3,3x3,4x3,3x4,4x4,4x5,5x5';
224 
230  protected ‪$pixelLimitGif = 10000;
231 
237  protected ‪$colMap = [
238  'aqua' => [0, 255, 255],
239  'black' => [0, 0, 0],
240  'blue' => [0, 0, 255],
241  'fuchsia' => [255, 0, 255],
242  'gray' => [128, 128, 128],
243  'green' => [0, 128, 0],
244  'lime' => [0, 255, 0],
245  'maroon' => [128, 0, 0],
246  'navy' => [0, 0, 128],
247  'olive' => [128, 128, 0],
248  'purple' => [128, 0, 128],
249  'red' => [255, 0, 0],
250  'silver' => [192, 192, 192],
251  'teal' => [0, 128, 128],
252  'yellow' => [255, 255, 0],
253  'white' => [255, 255, 255]
254  ];
255 
261  protected ‪$csConvObj;
262 
266  protected ‪$jpegQuality = 85;
267 
271  public ‪$map = '';
272 
279  public ‪$setup = [];
280 
284  public ‪$w = 0;
285 
289  public ‪$h = 0;
290 
294  protected ‪$OFFSET;
295 
299  protected ‪$im;
300 
305  public function ‪__construct()
306  {
307  $gfxConf = ‪$GLOBALS['TYPO3_CONF_VARS']['GFX'];
308  if (function_exists('imagecreatefromjpeg') && function_exists('imagejpeg')) {
309  $this->gdlibExtensions[] = 'jpg';
310  $this->gdlibExtensions[] = 'jpeg';
311  }
312  if (function_exists('imagecreatefrompng') && function_exists('imagepng')) {
313  $this->gdlibExtensions[] = 'png';
314  }
315  if (function_exists('imagecreatefromgif') && function_exists('imagegif')) {
316  $this->gdlibExtensions[] = 'gif';
317  }
318 
319  if ($gfxConf['processor_colorspace'] && in_array($gfxConf['processor_colorspace'], $this->allowedColorSpaceNames, true)) {
320  $this->colorspace = $gfxConf['processor_colorspace'];
321  }
322 
323  $this->processorEnabled = (bool)$gfxConf['processor_enabled'];
324  // Setting default JPG parameters:
325  $this->jpegQuality = ‪MathUtility::forceIntegerInRange($gfxConf['jpg_quality'], 10, 100, 85);
326  $this->addFrameSelection = (bool)$gfxConf['processor_allowFrameSelection'];
327  if ($gfxConf['gdlib_png']) {
328  $this->gifExtension = 'png';
329  }
330  $this->imageFileExt = GeneralUtility::trimExplode(',', $gfxConf['imagefile_ext']);
331 
332  // Boolean. This is necessary if using ImageMagick 5+.
333  // Effects in Imagemagick 5+ tends to render very slowly!!
334  // - therefore must be disabled in order not to perform sharpen, blurring and such.
335  $this->cmds['jpg'] = $this->cmds['jpeg'] = '-colorspace ' . $this->colorspace . ' -quality ' . ‪$this->jpegQuality;
336 
337  // ... but if 'processor_effects' is set, enable effects
338  if ($gfxConf['processor_effects']) {
339  $this->processorEffectsEnabled = true;
340  $this->cmds['jpg'] .= $this->‪v5_sharpen(10);
341  $this->cmds['jpeg'] .= $this->‪v5_sharpen(10);
342  }
343  // Secures that images are not scaled up.
344  $this->mayScaleUp = (bool)$gfxConf['processor_allowUpscaling'];
345  $this->csConvObj = GeneralUtility::makeInstance(CharsetConverter::class);
346  }
347 
351  public function ‪init()
352  {
353  trigger_error('GraphicalFunctions->init() will be removed in TYPO3 v10.0. Simply remove the call to the method, since this is now evaluted in the constructor.', E_USER_DEPRECATED);
354  $gfxConf = ‪$GLOBALS['TYPO3_CONF_VARS']['GFX'];
355  if (function_exists('imagecreatefromjpeg') && function_exists('imagejpeg')) {
356  $this->gdlibExtensions[] = 'jpg';
357  $this->gdlibExtensions[] = 'jpeg';
358  }
359  if (function_exists('imagecreatefrompng') && function_exists('imagepng')) {
360  $this->gdlibExtensions[] = 'png';
361  }
362  if (function_exists('imagecreatefromgif') && function_exists('imagegif')) {
363  $this->gdlibExtensions[] = 'gif';
364  }
365 
366  if ($gfxConf['processor_colorspace'] && in_array($gfxConf['processor_colorspace'], $this->allowedColorSpaceNames, true)) {
367  $this->colorspace = $gfxConf['processor_colorspace'];
368  }
369 
370  $this->processorEnabled = (bool)$gfxConf['processor_enabled'];
371  // Setting default JPG parameters:
372  $this->jpegQuality = ‪MathUtility::forceIntegerInRange($gfxConf['jpg_quality'], 10, 100, 85);
373  $this->addFrameSelection = (bool)$gfxConf['processor_allowFrameSelection'];
374  if ($gfxConf['gdlib_png']) {
375  $this->gifExtension = 'png';
376  }
377  $this->imageFileExt = GeneralUtility::trimExplode(',', $gfxConf['imagefile_ext']);
378 
379  // Boolean. This is necessary if using ImageMagick 5+.
380  // Effects in Imagemagick 5+ tends to render very slowly!!
381  // - therefore must be disabled in order not to perform sharpen, blurring and such.
382  $this->cmds['jpg'] = $this->cmds['jpeg'] = '-colorspace ' . $this->colorspace . ' -quality ' . ‪$this->jpegQuality;
383 
384  // ... but if 'processor_effects' is set, enable effects
385  if ($gfxConf['processor_effects']) {
386  $this->processorEffectsEnabled = true;
387  $this->cmds['jpg'] .= $this->‪v5_sharpen(10);
388  $this->cmds['jpeg'] .= $this->‪v5_sharpen(10);
389  }
390  // Secures that images are not scaled up.
391  $this->mayScaleUp = (bool)$gfxConf['processor_allowUpscaling'];
392  $this->csConvObj = GeneralUtility::makeInstance(CharsetConverter::class);
393  }
394 
395  /*************************************************
396  *
397  * Layering images / "IMAGE" GIFBUILDER object
398  *
399  *************************************************/
410  public function ‪maskImageOntoImage(&‪$im, $conf, ‪$workArea)
411  {
412  if ($conf['file'] && $conf['mask']) {
413  $imgInf = pathinfo($conf['file']);
414  $imgExt = strtolower($imgInf['extension']);
415  if (!in_array($imgExt, $this->gdlibExtensions, true)) {
416  $BBimage = $this->‪imageMagickConvert($conf['file'], $this->gifExtension);
417  } else {
418  $BBimage = $this->‪getImageDimensions($conf['file']);
419  }
420  $maskInf = pathinfo($conf['mask']);
421  $maskExt = strtolower($maskInf['extension']);
422  if (!in_array($maskExt, $this->gdlibExtensions, true)) {
423  $BBmask = $this->‪imageMagickConvert($conf['mask'], $this->gifExtension);
424  } else {
425  $BBmask = $this->‪getImageDimensions($conf['mask']);
426  }
427  if ($BBimage && $BBmask) {
428  ‪$w = imagesx(‪$im);
429  ‪$h = imagesy(‪$im);
430  $tmpStr = $this->‪randomName();
431  $theImage = $tmpStr . '_img.' . ‪$this->gifExtension;
432  $theDest = $tmpStr . '_dest.' . ‪$this->gifExtension;
433  $theMask = $tmpStr . '_mask.' . ‪$this->gifExtension;
434  // Prepare overlay image
435  $cpImg = $this->‪imageCreateFromFile($BBimage[3]);
436  $destImg = imagecreatetruecolor(‪$w, ‪$h);
437  // Preserve alpha transparency
438  if ($this->saveAlphaLayer) {
439  imagesavealpha($destImg, true);
440  $Bcolor = imagecolorallocatealpha($destImg, 0, 0, 0, 127);
441  imagefill($destImg, 0, 0, $Bcolor);
442  } else {
443  $Bcolor = imagecolorallocate($destImg, 0, 0, 0);
444  imagefilledrectangle($destImg, 0, 0, ‪$w, ‪$h, $Bcolor);
445  }
446  $this->‪copyGifOntoGif($destImg, $cpImg, $conf, ‪$workArea);
447  $this->‪ImageWrite($destImg, $theImage);
448  imagedestroy($cpImg);
449  imagedestroy($destImg);
450  // Prepare mask image
451  $cpImg = $this->‪imageCreateFromFile($BBmask[3]);
452  $destImg = imagecreatetruecolor(‪$w, ‪$h);
453  if ($this->saveAlphaLayer) {
454  imagesavealpha($destImg, true);
455  $Bcolor = imagecolorallocatealpha($destImg, 0, 0, 0, 127);
456  imagefill($destImg, 0, 0, $Bcolor);
457  } else {
458  $Bcolor = imagecolorallocate($destImg, 0, 0, 0);
459  imagefilledrectangle($destImg, 0, 0, ‪$w, ‪$h, $Bcolor);
460  }
461  $this->‪copyGifOntoGif($destImg, $cpImg, $conf, ‪$workArea);
462  $this->‪ImageWrite($destImg, $theMask);
463  imagedestroy($cpImg);
464  imagedestroy($destImg);
465  // Mask the images
466  $this->‪ImageWrite(‪$im, $theDest);
467  // Let combineExec handle maskNegation
468  $this->‪combineExec($theDest, $theImage, $theMask, $theDest);
469  // The main image is loaded again...
470  $backIm = $this->‪imageCreateFromFile($theDest);
471  // ... and if nothing went wrong we load it onto the old one.
472  if ($backIm) {
473  if (!$this->saveAlphaLayer) {
474  imagecolortransparent($backIm, -1);
475  }
476  ‪$im = $backIm;
477  }
478  // Unlink files from process
479  unlink($theDest);
480  unlink($theImage);
481  unlink($theMask);
482  }
483  }
484  }
485 
494  public function ‪copyImageOntoImage(&‪$im, $conf, ‪$workArea)
495  {
496  if ($conf['file']) {
497  if (!in_array($conf['BBOX'][2], $this->gdlibExtensions, true)) {
498  $conf['BBOX'] = $this->‪imageMagickConvert($conf['BBOX'][3], $this->gifExtension);
499  $conf['file'] = $conf['BBOX'][3];
500  }
501  $cpImg = $this->‪imageCreateFromFile($conf['file']);
502  $this->‪copyGifOntoGif(‪$im, $cpImg, $conf, ‪$workArea);
503  imagedestroy($cpImg);
504  }
505  }
506 
516  public function ‪copyGifOntoGif(&‪$im, $cpImg, $conf, ‪$workArea)
517  {
518  $cpW = imagesx($cpImg);
519  $cpH = imagesy($cpImg);
520  $tile = GeneralUtility::intExplode(',', $conf['tile']);
521  $tile[0] = ‪MathUtility::forceIntegerInRange($tile[0], 1, 20);
522  $tile[1] = ‪MathUtility::forceIntegerInRange($tile[1], 1, 20);
523  $cpOff = $this->‪objPosition($conf, ‪$workArea, [$cpW * $tile[0], $cpH * $tile[1]]);
524  for ($xt = 0; $xt < $tile[0]; $xt++) {
525  $Xstart = $cpOff[0] + $cpW * $xt;
526  // If this image is inside of the workArea, then go on
527  if ($Xstart + $cpW > ‪$workArea[0]) {
528  // X:
529  if ($Xstart < ‪$workArea[0]) {
530  $cpImgCutX = ‪$workArea[0] - $Xstart;
531  $Xstart = ‪$workArea[0];
532  } else {
533  $cpImgCutX = 0;
534  }
535  ‪$w = $cpW - $cpImgCutX;
536  if ($Xstart > ‪$workArea[0] + ‪$workArea[2] - ‪$w) {
537  ‪$w = ‪$workArea[0] + ‪$workArea[2] - $Xstart;
538  }
539  // If this image is inside of the workArea, then go on
540  if ($Xstart < ‪$workArea[0] + ‪$workArea[2]) {
541  // Y:
542  for ($yt = 0; $yt < $tile[1]; $yt++) {
543  $Ystart = $cpOff[1] + $cpH * $yt;
544  // If this image is inside of the workArea, then go on
545  if ($Ystart + $cpH > ‪$workArea[1]) {
546  if ($Ystart < ‪$workArea[1]) {
547  $cpImgCutY = ‪$workArea[1] - $Ystart;
548  $Ystart = ‪$workArea[1];
549  } else {
550  $cpImgCutY = 0;
551  }
552  ‪$h = $cpH - $cpImgCutY;
553  if ($Ystart > ‪$workArea[1] + ‪$workArea[3] - ‪$h) {
554  ‪$h = ‪$workArea[1] + ‪$workArea[3] - $Ystart;
555  }
556  // If this image is inside of the workArea, then go on
557  if ($Ystart < ‪$workArea[1] + ‪$workArea[3]) {
558  $this->‪imagecopyresized(‪$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, ‪$w, ‪$h, ‪$w, ‪$h);
559  }
560  }
561  }
562  }
563  }
564  }
565  }
566 
595  public function ‪imagecopyresized(&$dstImg, $srcImg, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight)
596  {
597  if (!$this->saveAlphaLayer) {
598  // Make true color image
599  $tmpImg = imagecreatetruecolor(imagesx($dstImg), imagesy($dstImg));
600  // Copy the source image onto that
601  ‪imagecopyresized($tmpImg, $dstImg, 0, 0, 0, 0, imagesx($dstImg), imagesy($dstImg), imagesx($dstImg), imagesy($dstImg));
602  // Then copy the source image onto that (the actual operation!)
603  ‪imagecopyresized($tmpImg, $srcImg, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
604  // Set the destination image
605  $dstImg = $tmpImg;
606  } else {
607  ‪imagecopyresized($dstImg, $srcImg, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
608  }
609  }
610 
611  /********************************
612  *
613  * Text / "TEXT" GIFBUILDER object
614  *
615  ********************************/
624  public function ‪makeText(&‪$im, $conf, ‪$workArea)
625  {
626  // Spacing
627  list($spacing, $wordSpacing) = $this->‪calcWordSpacing($conf);
628  // Position
629  $txtPos = $this->‪txtPosition($conf, ‪$workArea, $conf['BBOX']);
630  $theText = $conf['text'];
631  if ($conf['imgMap'] && is_array($conf['imgMap.'])) {
632  $this->‪addToMap($this->‪calcTextCordsForMap($conf['BBOX'][2], $txtPos, $conf['imgMap.']), $conf['imgMap.']);
633  }
634  if (!$conf['hideButCreateMap']) {
635  // Font Color:
636  $cols = $this->‪convertColor($conf['fontColor']);
637  // NiceText is calculated
638  if (!$conf['niceText']) {
639  $Fcolor = imagecolorallocate(‪$im, $cols[0], $cols[1], $cols[2]);
640  // antiAliasing is setup:
641  $Fcolor = $conf['antiAlias'] ? $Fcolor : -$Fcolor;
642  for ($a = 0; $a < $conf['iterations']; $a++) {
643  // If any kind of spacing applys, we use this function:
644  if ($spacing || $wordSpacing) {
645  $this->‪SpacedImageTTFText(‪$im, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, GeneralUtility::getFileAbsFileName($conf['fontFile']), $theText, $spacing, $wordSpacing, $conf['splitRendering.']);
646  } else {
647  $this->‪renderTTFText(‪$im, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, $conf['fontFile'], $theText, $conf['splitRendering.'], $conf);
648  }
649  }
650  } else {
651  // NICETEXT::
652  // options anti_aliased and iterations is NOT available when doing this!!
653  ‪$w = imagesx(‪$im);
654  ‪$h = imagesy(‪$im);
655  $tmpStr = $this->‪randomName();
656  $fileMenu = $tmpStr . '_menuNT.' . ‪$this->gifExtension;
657  $fileColor = $tmpStr . '_colorNT.' . ‪$this->gifExtension;
658  $fileMask = $tmpStr . '_maskNT.' . ‪$this->gifExtension;
659  // Scalefactor
660  $sF = ‪MathUtility::forceIntegerInRange($conf['niceText.']['scaleFactor'], 2, 5);
661  $newW = ceil($sF * imagesx(‪$im));
662  $newH = ceil($sF * imagesy(‪$im));
663  // Make mask
664  $maskImg = imagecreatetruecolor($newW, $newH);
665  $Bcolor = imagecolorallocate($maskImg, 255, 255, 255);
666  imagefilledrectangle($maskImg, 0, 0, $newW, $newH, $Bcolor);
667  $Fcolor = imagecolorallocate($maskImg, 0, 0, 0);
668  // If any kind of spacing applies, we use this function:
669  if ($spacing || $wordSpacing) {
670  $this->‪SpacedImageTTFText($maskImg, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, GeneralUtility::getFileAbsFileName($conf['fontFile']), $theText, $spacing, $wordSpacing, $conf['splitRendering.'], $sF);
671  } else {
672  $this->‪renderTTFText($maskImg, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, $conf['fontFile'], $theText, $conf['splitRendering.'], $conf, $sF);
673  }
674  $this->‪ImageWrite($maskImg, $fileMask);
675  imagedestroy($maskImg);
676  // Downscales the mask
677  if (!$this->processorEffectsEnabled) {
678  $command = trim($this->scalecmd . ' ' . ‪$w . 'x' . ‪$h . '! -negate');
679  } else {
680  $command = trim($conf['niceText.']['before'] . ' ' . $this->scalecmd . ' ' . ‪$w . 'x' . ‪$h . '! ' . $conf['niceText.']['after'] . ' -negate');
681  if ($conf['niceText.']['sharpen']) {
682  $command .= $this->‪v5_sharpen($conf['niceText.']['sharpen']);
683  }
684  }
685  $this->‪imageMagickExec($fileMask, $fileMask, $command);
686  // Make the color-file
687  $colorImg = imagecreatetruecolor(‪$w, ‪$h);
688  $Ccolor = imagecolorallocate($colorImg, $cols[0], $cols[1], $cols[2]);
689  imagefilledrectangle($colorImg, 0, 0, ‪$w, ‪$h, $Ccolor);
690  $this->‪ImageWrite($colorImg, $fileColor);
691  imagedestroy($colorImg);
692  // The mask is applied
693  // The main pictures is saved temporarily
694  $this->‪ImageWrite(‪$im, $fileMenu);
695  $this->‪combineExec($fileMenu, $fileColor, $fileMask, $fileMenu);
696  // The main image is loaded again...
697  $backIm = $this->‪imageCreateFromFile($fileMenu);
698  // ... and if nothing went wrong we load it onto the old one.
699  if ($backIm) {
700  if (!$this->saveAlphaLayer) {
701  imagecolortransparent($backIm, -1);
702  }
703  ‪$im = $backIm;
704  }
705  // Deleting temporary files;
706  unlink($fileMenu);
707  unlink($fileColor);
708  unlink($fileMask);
709  }
710  }
711  }
712 
723  public function ‪txtPosition($conf, ‪$workArea, $BB)
724  {
725  $angle = (int)$conf['angle'] / 180 * M_PI;
726  $conf['angle'] = 0;
727  $straightBB = $this->‪calcBBox($conf);
728  // offset, align, valign, workarea
729  // [0]=x, [1]=y, [2]=w, [3]=h
730  $result = [];
731  $result[2] = $BB[0];
732  $result[3] = $BB[1];
733  ‪$w = ‪$workArea[2];
734  switch ($conf['align']) {
735  case 'right':
736 
737  case 'center':
738  $factor = abs(cos($angle));
739  $sign = cos($angle) < 0 ? -1 : 1;
740  $len1 = $sign * $factor * $straightBB[0];
741  $len2 = $sign * $BB[0];
742  $result[0] = ‪$w - ceil($len2 * $factor + (1 - $factor) * $len1);
743  $factor = abs(sin($angle));
744  $sign = sin($angle) < 0 ? -1 : 1;
745  $len1 = $sign * $factor * $straightBB[0];
746  $len2 = $sign * $BB[1];
747  $result[1] = ceil($len2 * $factor + (1 - $factor) * $len1);
748  break;
749  }
750  switch ($conf['align']) {
751  case 'right':
752  break;
753  case 'center':
754  $result[0] = round($result[0] / 2);
755  $result[1] = round($result[1] / 2);
756  break;
757  default:
758  $result[0] = 0;
759  $result[1] = 0;
760  }
761  $result = $this->‪applyOffset($result, GeneralUtility::intExplode(',', $conf['offset']));
762  $result = $this->‪applyOffset($result, ‪$workArea);
763  return $result;
764  }
765 
774  public function ‪calcBBox($conf)
775  {
776  $sF = $this->‪getTextScalFactor($conf);
777  list($spacing, $wordSpacing) = $this->‪calcWordSpacing($conf, $sF);
778  $theText = $conf['text'];
779  $charInf = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $theText, $conf['splitRendering.'], $sF);
780  $theBBoxInfo = $charInf;
781  if ($conf['angle']) {
782  $xArr = [$charInf[0], $charInf[2], $charInf[4], $charInf[6]];
783  $yArr = [$charInf[1], $charInf[3], $charInf[5], $charInf[7]];
784  $x = max($xArr) - min($xArr);
785  $y = max($yArr) - min($yArr);
786  } else {
787  $x = $charInf[2] - $charInf[0];
788  $y = $charInf[1] - $charInf[7];
789  }
790  // Set original lineHeight (used by line breaks):
791  $theBBoxInfo['lineHeight'] = $y;
792  if (!empty($conf['lineHeight'])) {
793  $theBBoxInfo['lineHeight'] = (int)$conf['lineHeight'];
794  }
795 
796  // If any kind of spacing applys, we use this function:
797  if ($spacing || $wordSpacing) {
798  $x = 0;
799  if (!$spacing && $wordSpacing) {
800  $bits = explode(' ', $theText);
801  foreach ($bits as $word) {
802  $word .= ' ';
803  $wordInf = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $word, $conf['splitRendering.'], $sF);
804  $wordW = $wordInf[2] - $wordInf[0];
805  $x += $wordW + $wordSpacing;
806  }
807  } else {
808  $utf8Chars = $this->csConvObj->utf8_to_numberarray($theText);
809  // For each UTF-8 char, do:
810  foreach ($utf8Chars as $char) {
811  $charInf = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $char, $conf['splitRendering.'], $sF);
812  $charW = $charInf[2] - $charInf[0];
813  $x += $charW + ($char === ' ' ? $wordSpacing : $spacing);
814  }
815  }
816  } elseif (isset($conf['breakWidth']) && $conf['breakWidth'] && $this->‪getRenderedTextWidth($conf['text'], $conf) > $conf['breakWidth']) {
817  $maxWidth = 0;
818  $currentWidth = 0;
819  $breakWidth = $conf['breakWidth'];
820  $breakSpace = $this->‪getBreakSpace($conf, $theBBoxInfo);
821  $wordPairs = $this->‪getWordPairsForLineBreak($conf['text']);
822  // Iterate through all word pairs:
823  foreach ($wordPairs as $index => $wordPair) {
824  $wordWidth = $this->‪getRenderedTextWidth($wordPair, $conf);
825  if ($index == 0 || $currentWidth + $wordWidth <= $breakWidth) {
826  $currentWidth += $wordWidth;
827  } else {
828  $maxWidth = max($maxWidth, $currentWidth);
829  $y += $breakSpace;
830  // Restart:
831  $currentWidth = $wordWidth;
832  }
833  }
834  $x = max($maxWidth, $currentWidth) * $sF;
835  }
836  if ($sF > 1) {
837  $x = ceil($x / $sF);
838  $y = ceil($y / $sF);
839  if (is_array($theBBoxInfo)) {
840  foreach ($theBBoxInfo as &$value) {
841  $value = ceil($value / $sF);
842  }
843  unset($value);
844  }
845  }
846  return [$x, $y, $theBBoxInfo];
847  }
848 
857  public function ‪addToMap($cords, $conf)
858  {
859  $this->map .= '<area' . ' shape="poly"' . ' coords="' . implode(',', $cords) . '"'
860  . ' href="' . htmlspecialchars($conf['url']) . '"'
861  . ($conf['target'] ? ' target="' . htmlspecialchars($conf['target']) . '"' : '')
862  . ((string)$conf['titleText'] !== '' ? ' title="' . htmlspecialchars($conf['titleText']) . '"' : '')
863  . ' alt="' . htmlspecialchars($conf['altText']) . '" />';
864  }
865 
876  public function ‪calcTextCordsForMap($cords, $offset, $conf)
877  {
878  $pars = GeneralUtility::intExplode(',', $conf['explode'] . ',');
879  $newCords[0] = $cords[0] + $offset[0] - $pars[0];
880  $newCords[1] = $cords[1] + $offset[1] + $pars[1];
881  $newCords[2] = $cords[2] + $offset[0] + $pars[0];
882  $newCords[3] = $cords[3] + $offset[1] + $pars[1];
883  $newCords[4] = $cords[4] + $offset[0] + $pars[0];
884  $newCords[5] = $cords[5] + $offset[1] - $pars[1];
885  $newCords[6] = $cords[6] + $offset[0] - $pars[0];
886  $newCords[7] = $cords[7] + $offset[1] - $pars[1];
887  return $newCords;
888  }
889 
909  public function ‪SpacedImageTTFText(&‪$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF = 1)
910  {
911  $spacing *= $sF;
912  $wordSpacing *= $sF;
913  if (!$spacing && $wordSpacing) {
914  $bits = explode(' ', $text);
915  foreach ($bits as $word) {
916  $word .= ' ';
917  $wordInf = $this->‪ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $word, $splitRenderingConf, $sF);
918  $wordW = $wordInf[2] - $wordInf[0];
919  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $word, $splitRenderingConf, $sF);
920  $x += $wordW + $wordSpacing;
921  }
922  } else {
923  $utf8Chars = $this->csConvObj->utf8_to_numberarray($text);
924  // For each UTF-8 char, do:
925  foreach ($utf8Chars as $char) {
926  $charInf = $this->‪ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $char, $splitRenderingConf, $sF);
927  $charW = $charInf[2] - $charInf[0];
928  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $char, $splitRenderingConf, $sF);
929  $x += $charW + ($char === ' ' ? $wordSpacing : $spacing);
930  }
931  }
932  }
933 
942  public function ‪fontResize($conf)
943  {
944  // 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!!!!
945  $maxWidth = (int)$conf['maxWidth'];
946  list($spacing, $wordSpacing) = $this->‪calcWordSpacing($conf);
947  if ($maxWidth) {
948  // If any kind of spacing applys, we use this function:
949  if ($spacing || $wordSpacing) {
950  return $conf['fontSize'];
951  }
952  do {
953  // Determine bounding box.
954  $bounds = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $conf['text'], $conf['splitRendering.']);
955  if ($conf['angle'] < 0) {
956  $pixelWidth = abs($bounds[4] - $bounds[0]);
957  } elseif ($conf['angle'] > 0) {
958  $pixelWidth = abs($bounds[2] - $bounds[6]);
959  } else {
960  $pixelWidth = abs($bounds[4] - $bounds[6]);
961  }
962  // Size is fine, exit:
963  if ($pixelWidth <= $maxWidth) {
964  break;
965  }
966  $conf['fontSize']--;
967  } while ($conf['fontSize'] > 1);
968  }
969  return $conf['fontSize'];
970  }
971 
983  public function ‪ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF = 1)
984  {
985  // Initialize:
986  $offsetInfo = [];
987  $stringParts = $this->‪splitString($string, $splitRendering, $fontSize, $fontFile);
988  // Traverse string parts:
989  foreach ($stringParts as $strCfg) {
990  $fontFile = GeneralUtility::getFileAbsFileName($strCfg['fontFile']);
991  if (is_readable($fontFile)) {
992  // Calculate Bounding Box for part.
993  $calc = imagettfbbox($this->‪compensateFontSizeiBasedOnFreetypeDpi($sF * $strCfg['fontSize']), $angle, $fontFile, $strCfg['str']);
994  // Calculate offsets:
995  if (empty($offsetInfo)) {
996  // First run, just copy over.
997  $offsetInfo = $calc;
998  } else {
999  $offsetInfo[2] += $calc[2] - $calc[0] + (int)$splitRendering['compX'] + (int)$strCfg['xSpaceBefore'] + (int)$strCfg['xSpaceAfter'];
1000  $offsetInfo[3] += $calc[3] - $calc[1] - (int)$splitRendering['compY'] - (int)$strCfg['ySpaceBefore'] - (int)$strCfg['ySpaceAfter'];
1001  $offsetInfo[4] += $calc[4] - $calc[6] + (int)$splitRendering['compX'] + (int)$strCfg['xSpaceBefore'] + (int)$strCfg['xSpaceAfter'];
1002  $offsetInfo[5] += $calc[5] - $calc[7] - (int)$splitRendering['compY'] - (int)$strCfg['ySpaceBefore'] - (int)$strCfg['ySpaceAfter'];
1003  }
1004  } else {
1005  ‪debug('cannot read file: ' . $fontFile, self::class . '::ImageTTFBBoxWrapper()');
1006  }
1007  }
1008  return $offsetInfo;
1009  }
1010 
1025  public function ‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF = 1)
1026  {
1027  // Initialize:
1028  $stringParts = $this->‪splitString($string, $splitRendering, $fontSize, $fontFile);
1029  $x = ceil($sF * $x);
1030  $y = ceil($sF * $y);
1031  // Traverse string parts:
1032  foreach ($stringParts as $i => $strCfg) {
1033  // Initialize:
1034  $colorIndex = $color;
1035  // Set custom color if any (only when niceText is off):
1036  if ($strCfg['color'] && $sF == 1) {
1037  $cols = $this->‪convertColor($strCfg['color']);
1038  $colorIndex = imagecolorallocate(‪$im, $cols[0], $cols[1], $cols[2]);
1039  $colorIndex = $color >= 0 ? $colorIndex : -$colorIndex;
1040  }
1041  // Setting xSpaceBefore
1042  if ($i) {
1043  $x += (int)$strCfg['xSpaceBefore'];
1044  $y -= (int)$strCfg['ySpaceBefore'];
1045  }
1046  $fontFile = GeneralUtility::getFileAbsFileName($strCfg['fontFile']);
1047  if (is_readable($fontFile)) {
1048  // Render part:
1049  imagettftext(‪$im, $this->‪compensateFontSizeiBasedOnFreetypeDpi($sF * $strCfg['fontSize']), $angle, $x, $y, $colorIndex, $fontFile, $strCfg['str']);
1050  // Calculate offset to apply:
1051  $wordInf = imagettfbbox($this->‪compensateFontSizeiBasedOnFreetypeDpi($sF * $strCfg['fontSize']), $angle, GeneralUtility::getFileAbsFileName($strCfg['fontFile']), $strCfg['str']);
1052  $x += $wordInf[2] - $wordInf[0] + (int)$splitRendering['compX'] + (int)$strCfg['xSpaceAfter'];
1053  $y += $wordInf[5] - $wordInf[7] - (int)$splitRendering['compY'] - (int)$strCfg['ySpaceAfter'];
1054  } else {
1055  ‪debug('cannot read file: ' . $fontFile, self::class . '::ImageTTFTextWrapper()');
1056  }
1057  }
1058  }
1059 
1069  public function ‪splitString($string, $splitRendering, $fontSize, $fontFile)
1070  {
1071  // Initialize by setting the whole string and default configuration as the first entry.
1072  $result = [];
1073  $result[] = [
1074  'str' => $string,
1075  'fontSize' => $fontSize,
1076  'fontFile' => $fontFile
1077  ];
1078  // Traverse the split-rendering configuration:
1079  // Splitting will create more entries in $result with individual configurations.
1080  if (is_array($splitRendering)) {
1081  $sKeyArray = ‪ArrayUtility::filterAndSortByNumericKeys($splitRendering);
1082  // Traverse configured options:
1083  foreach ($sKeyArray as $key) {
1084  $cfg = $splitRendering[$key . '.'];
1085  // Process each type of split rendering keyword:
1086  switch ((string)$splitRendering[$key]) {
1087  case 'highlightWord':
1088  if ((string)$cfg['value'] !== '') {
1089  $newResult = [];
1090  // Traverse the current parts of the result array:
1091  foreach ($result as $part) {
1092  // Explode the string value by the word value to highlight:
1093  $explodedParts = explode($cfg['value'], $part['str']);
1094  foreach ($explodedParts as $c => $expValue) {
1095  if ((string)$expValue !== '') {
1096  $newResult[] = array_merge($part, ['str' => $expValue]);
1097  }
1098  if ($c + 1 < count($explodedParts)) {
1099  $newResult[] = [
1100  'str' => $cfg['value'],
1101  'fontSize' => $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'],
1102  'fontFile' => $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'],
1103  'color' => $cfg['color'],
1104  'xSpaceBefore' => $cfg['xSpaceBefore'],
1105  'xSpaceAfter' => $cfg['xSpaceAfter'],
1106  'ySpaceBefore' => $cfg['ySpaceBefore'],
1107  'ySpaceAfter' => $cfg['ySpaceAfter']
1108  ];
1109  }
1110  }
1111  }
1112  // Set the new result as result array:
1113  if (!empty($newResult)) {
1114  $result = $newResult;
1115  }
1116  }
1117  break;
1118  case 'charRange':
1119  if ((string)$cfg['value'] !== '') {
1120  // Initialize range:
1121  $ranges = GeneralUtility::trimExplode(',', $cfg['value'], true);
1122  foreach ($ranges as $i => $rangeDef) {
1123  $ranges[$i] = GeneralUtility::intExplode('-', $ranges[$i]);
1124  if (!isset($ranges[$i][1])) {
1125  $ranges[$i][1] = $ranges[$i][0];
1126  }
1127  }
1128  $newResult = [];
1129  // Traverse the current parts of the result array:
1130  foreach ($result as $part) {
1131  // Initialize:
1132  $currentState = -1;
1133  $bankAccum = '';
1134  // Explode the string value by the word value to highlight:
1135  $utf8Chars = $this->csConvObj->utf8_to_numberarray($part['str']);
1136  foreach ($utf8Chars as $utfChar) {
1137  // Find number and evaluate position:
1138  $uNumber = (int)$this->csConvObj->utf8CharToUnumber($utfChar);
1139  $inRange = 0;
1140  foreach ($ranges as $rangeDef) {
1141  if ($uNumber >= $rangeDef[0] && (!$rangeDef[1] || $uNumber <= $rangeDef[1])) {
1142  $inRange = 1;
1143  break;
1144  }
1145  }
1146  if ($currentState == -1) {
1147  $currentState = $inRange;
1148  }
1149  // Initialize first char
1150  // Switch bank:
1151  if ($inRange != $currentState && $uNumber !== 9 && $uNumber !== 10 && $uNumber !== 13 && $uNumber !== 32) {
1152  // Set result:
1153  if ($bankAccum !== '') {
1154  $newResult[] = [
1155  'str' => $bankAccum,
1156  'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'],
1157  'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'],
1158  'color' => $currentState ? $cfg['color'] : '',
1159  'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '',
1160  'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '',
1161  'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '',
1162  'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : ''
1163  ];
1164  }
1165  // Initialize new settings:
1166  $currentState = $inRange;
1167  $bankAccum = '';
1168  }
1169  // Add char to bank:
1170  $bankAccum .= $utfChar;
1171  }
1172  // Set result for FINAL part:
1173  if ($bankAccum !== '') {
1174  $newResult[] = [
1175  'str' => $bankAccum,
1176  'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'],
1177  'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'],
1178  'color' => $currentState ? $cfg['color'] : '',
1179  'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '',
1180  'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '',
1181  'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '',
1182  'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : ''
1183  ];
1184  }
1185  }
1186  // Set the new result as result array:
1187  if (!empty($newResult)) {
1188  $result = $newResult;
1189  }
1190  }
1191  break;
1192  }
1193  }
1194  }
1195  return $result;
1196  }
1197 
1207  public function ‪calcWordSpacing($conf, $scaleFactor = 1)
1208  {
1209  $spacing = (int)$conf['spacing'];
1210  $wordSpacing = (int)$conf['wordSpacing'];
1211  $wordSpacing = $wordSpacing ?: $spacing * 2;
1212  $spacing *= $scaleFactor;
1213  $wordSpacing *= $scaleFactor;
1214  return [$spacing, $wordSpacing];
1215  }
1216 
1224  public function ‪getTextScalFactor($conf)
1225  {
1226  if (!$conf['niceText']) {
1227  $sF = 1;
1228  } else {
1229  // NICETEXT::
1230  $sF = ‪MathUtility::forceIntegerInRange($conf['niceText.']['scaleFactor'], 2, 5);
1231  }
1232  return $sF;
1233  }
1234 
1250  protected function ‪renderTTFText(&‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $conf, $sF = 1)
1251  {
1252  if (isset($conf['breakWidth']) && $conf['breakWidth'] && $this->‪getRenderedTextWidth($string, $conf) > $conf['breakWidth']) {
1253  $phrase = '';
1254  $currentWidth = 0;
1255  $breakWidth = $conf['breakWidth'];
1256  $breakSpace = $this->‪getBreakSpace($conf);
1257  $wordPairs = $this->‪getWordPairsForLineBreak($string);
1258  // Iterate through all word pairs:
1259  foreach ($wordPairs as $index => $wordPair) {
1260  $wordWidth = $this->‪getRenderedTextWidth($wordPair, $conf);
1261  if ($index == 0 || $currentWidth + $wordWidth <= $breakWidth) {
1262  $currentWidth += $wordWidth;
1263  $phrase .= $wordPair;
1264  } else {
1265  // Render the current phrase that is below breakWidth:
1266  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $phrase, $splitRendering, $sF);
1267  // Calculate the news height offset:
1268  $y += $breakSpace;
1269  // Restart the phrase:
1270  $currentWidth = $wordWidth;
1271  $phrase = $wordPair;
1272  }
1273  }
1274  // Render the remaining phrase:
1275  if ($currentWidth) {
1276  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $phrase, $splitRendering, $sF);
1277  }
1278  } else {
1279  $this->‪ImageTTFTextWrapper(‪$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF);
1280  }
1281  }
1282 
1289  protected function ‪getWordPairsForLineBreak($string)
1290  {
1291  $wordPairs = [];
1292  $wordsArray = preg_split('#([- .,!:]+)#', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
1293  $wordsCount = count($wordsArray);
1294  for ($index = 0; $index < $wordsCount; $index += 2) {
1295  $wordPairs[] = $wordsArray[$index] . $wordsArray[$index + 1];
1296  }
1297  return $wordPairs;
1298  }
1299 
1307  protected function ‪getRenderedTextWidth($text, $conf)
1308  {
1309  $bounds = $this->‪ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $text, $conf['splitRendering.']);
1310  if ($conf['angle'] < 0) {
1311  $pixelWidth = abs($bounds[4] - $bounds[0]);
1312  } elseif ($conf['angle'] > 0) {
1313  $pixelWidth = abs($bounds[2] - $bounds[6]);
1314  } else {
1315  $pixelWidth = abs($bounds[4] - $bounds[6]);
1316  }
1317  return $pixelWidth;
1318  }
1319 
1327  protected function ‪getBreakSpace($conf, array $boundingBox = null)
1328  {
1329  if (!isset($boundingBox)) {
1330  $boundingBox = $this->‪calcBBox($conf);
1331  $boundingBox = $boundingBox[2];
1332  }
1333  if (isset($conf['breakSpace']) && $conf['breakSpace']) {
1334  $breakSpace = $boundingBox['lineHeight'] * $conf['breakSpace'];
1335  } else {
1336  $breakSpace = $boundingBox['lineHeight'];
1337  }
1338  return $breakSpace;
1339  }
1340 
1341  /*********************************************
1342  *
1343  * Other GIFBUILDER objects related to TEXT
1344  *
1345  *********************************************/
1355  public function ‪makeOutline(&‪$im, $conf, ‪$workArea, $txtConf)
1356  {
1357  $thickness = (int)$conf['thickness'];
1358  if ($thickness) {
1359  $txtConf['fontColor'] = $conf['color'];
1360  $outLineDist = ‪MathUtility::forceIntegerInRange($thickness, 1, 2);
1361  for ($b = 1; $b <= $outLineDist; $b++) {
1362  if ($b == 1) {
1363  $it = 8;
1364  } else {
1365  $it = 16;
1366  }
1367  $outL = $this->‪circleOffset($b, $it);
1368  for ($a = 0; $a < $it; $a++) {
1369  $this->‪makeText(‪$im, $txtConf, $this->‪applyOffset(‪$workArea, $outL[$a]));
1370  }
1371  }
1372  }
1373  }
1374 
1385  public function ‪circleOffset($distance, $iterations)
1386  {
1387  $res = [];
1388  if ($distance && $iterations) {
1389  for ($a = 0; $a < $iterations; $a++) {
1390  $yOff = round(sin(2 * M_PI / $iterations * ($a + 1)) * 100 * $distance);
1391  if ($yOff) {
1392  $yOff = (int)(ceil(abs($yOff / 100)) * ($yOff / abs($yOff)));
1393  }
1394  $xOff = round(cos(2 * M_PI / $iterations * ($a + 1)) * 100 * $distance);
1395  if ($xOff) {
1396  $xOff = (int)(ceil(abs($xOff / 100)) * ($xOff / abs($xOff)));
1397  }
1398  $res[$a] = [$xOff, $yOff];
1399  }
1400  }
1401  return $res;
1402  }
1403 
1413  public function ‪makeEmboss(&‪$im, $conf, ‪$workArea, $txtConf)
1414  {
1415  $conf['color'] = $conf['highColor'];
1416  $this->‪makeShadow(‪$im, $conf, ‪$workArea, $txtConf);
1417  $newOffset = GeneralUtility::intExplode(',', $conf['offset']);
1418  $newOffset[0] *= -1;
1419  $newOffset[1] *= -1;
1420  $conf['offset'] = implode(',', $newOffset);
1421  $conf['color'] = $conf['lowColor'];
1422  $this->‪makeShadow(‪$im, $conf, ‪$workArea, $txtConf);
1423  }
1424 
1435  public function ‪makeShadow(&‪$im, $conf, ‪$workArea, $txtConf)
1436  {
1437  ‪$workArea = $this->‪applyOffset(‪$workArea, GeneralUtility::intExplode(',', $conf['offset']));
1438  $blurRate = ‪MathUtility::forceIntegerInRange((int)$conf['blur'], 0, 99);
1439  // No effects if ImageMagick ver. 5+
1440  if (!$blurRate || !$this->processorEffectsEnabled) {
1441  $txtConf['fontColor'] = $conf['color'];
1442  $this->‪makeText(‪$im, $txtConf, ‪$workArea);
1443  } else {
1444  ‪$w = imagesx(‪$im);
1445  ‪$h = imagesy(‪$im);
1446  // Area around the blur used for cropping something
1447  $blurBorder = 3;
1448  $tmpStr = $this->‪randomName();
1449  $fileMenu = $tmpStr . '_menu.' . ‪$this->gifExtension;
1450  $fileColor = $tmpStr . '_color.' . ‪$this->gifExtension;
1451  $fileMask = $tmpStr . '_mask.' . ‪$this->gifExtension;
1452  // BlurColor Image laves
1453  $blurColImg = imagecreatetruecolor(‪$w, ‪$h);
1454  $bcols = $this->‪convertColor($conf['color']);
1455  $Bcolor = imagecolorallocate($blurColImg, $bcols[0], $bcols[1], $bcols[2]);
1456  imagefilledrectangle($blurColImg, 0, 0, ‪$w, ‪$h, $Bcolor);
1457  $this->‪ImageWrite($blurColImg, $fileColor);
1458  imagedestroy($blurColImg);
1459  // The mask is made: BlurTextImage
1460  $blurTextImg = imagecreatetruecolor(‪$w + $blurBorder * 2, ‪$h + $blurBorder * 2);
1461  // Black background
1462  $Bcolor = imagecolorallocate($blurTextImg, 0, 0, 0);
1463  imagefilledrectangle($blurTextImg, 0, 0, ‪$w + $blurBorder * 2, ‪$h + $blurBorder * 2, $Bcolor);
1464  $txtConf['fontColor'] = 'white';
1465  $blurBordArr = [$blurBorder, $blurBorder];
1466  $this->‪makeText($blurTextImg, $txtConf, $this->‪applyOffset(‪$workArea, $blurBordArr));
1467  // Dump to temporary file
1468  $this->‪ImageWrite($blurTextImg, $fileMask);
1469  // Destroy
1470  imagedestroy($blurTextImg);
1471  $command = $this->‪v5_blur($blurRate + 1);
1472  $this->‪imageMagickExec($fileMask, $fileMask, $command . ' +matte');
1473  // The mask is loaded again
1474  $blurTextImg_tmp = $this->‪imageCreateFromFile($fileMask);
1475  // If nothing went wrong we continue with the blurred mask
1476  if ($blurTextImg_tmp) {
1477  // Cropping the border from the mask
1478  $blurTextImg = imagecreatetruecolor(‪$w, ‪$h);
1479  $this->‪imagecopyresized($blurTextImg, $blurTextImg_tmp, 0, 0, $blurBorder, $blurBorder, ‪$w, ‪$h, ‪$w, ‪$h);
1480  // Destroy the temporary mask
1481  imagedestroy($blurTextImg_tmp);
1482  // Adjust the mask
1483  $intensity = 40;
1484  if ($conf['intensity']) {
1485  $intensity = ‪MathUtility::forceIntegerInRange($conf['intensity'], 0, 100);
1486  }
1487  $intensity = ceil(255 - $intensity / 100 * 255);
1488  $this->‪inputLevels($blurTextImg, 0, $intensity);
1489  $opacity = ‪MathUtility::forceIntegerInRange((int)$conf['opacity'], 0, 100);
1490  if ($opacity && $opacity < 100) {
1491  $high = ceil(255 * $opacity / 100);
1492  // Reducing levels as the opacity demands
1493  $this->‪outputLevels($blurTextImg, 0, $high);
1494  }
1495  // Dump the mask again
1496  $this->‪ImageWrite($blurTextImg, $fileMask);
1497  // Destroy the mask
1498  imagedestroy($blurTextImg);
1499  // The pictures are combined
1500  // The main pictures is saved temporarily
1501  $this->‪ImageWrite(‪$im, $fileMenu);
1502  $this->‪combineExec($fileMenu, $fileColor, $fileMask, $fileMenu);
1503  // The main image is loaded again...
1504  $backIm = $this->‪imageCreateFromFile($fileMenu);
1505  // ... and if nothing went wrong we load it onto the old one.
1506  if ($backIm) {
1507  if (!$this->saveAlphaLayer) {
1508  imagecolortransparent($backIm, -1);
1509  }
1510  ‪$im = $backIm;
1511  }
1512  }
1513  // Deleting temporary files;
1514  unlink($fileMenu);
1515  unlink($fileColor);
1516  unlink($fileMask);
1517  }
1518  }
1519 
1520  /****************************
1521  *
1522  * Other GIFBUILDER objects
1523  *
1524  ****************************/
1533  public function ‪makeBox(&‪$im, $conf, ‪$workArea)
1534  {
1535  $cords = GeneralUtility::intExplode(',', $conf['dimensions'] . ',,,');
1536  $conf['offset'] = $cords[0] . ',' . $cords[1];
1537  $cords = $this->‪objPosition($conf, ‪$workArea, [$cords[2], $cords[3]]);
1538  $cols = $this->‪convertColor($conf['color']);
1539  $opacity = 0;
1540  if (isset($conf['opacity'])) {
1541  // conversion:
1542  // PHP 0 = opaque, 127 = transparent
1543  // TYPO3 100 = opaque, 0 = transparent
1544  $opacity = ‪MathUtility::forceIntegerInRange((int)$conf['opacity'], 1, 100, 1);
1545  $opacity = abs($opacity - 100);
1546  $opacity = round(127 * $opacity / 100);
1547  }
1548  $tmpColor = imagecolorallocatealpha(‪$im, $cols[0], $cols[1], $cols[2], $opacity);
1549  imagefilledrectangle(‪$im, $cords[0], $cords[1], $cords[0] + $cords[2] - 1, $cords[1] + $cords[3] - 1, $tmpColor);
1550  }
1551 
1572  public function ‪makeEllipse(&‪$im, array $conf, array ‪$workArea)
1573  {
1574  $ellipseConfiguration = GeneralUtility::intExplode(',', $conf['dimensions'] . ',,,');
1575  // Ellipse offset inside workArea (x/y)
1576  $conf['offset'] = $ellipseConfiguration[0] . ',' . $ellipseConfiguration[1];
1577  // @see objPosition
1578  $imageCoordinates = $this->‪objPosition($conf, ‪$workArea, [$ellipseConfiguration[2], $ellipseConfiguration[3]]);
1579  $color = $this->‪convertColor($conf['color']);
1580  $fillingColor = imagecolorallocate(‪$im, $color[0], $color[1], $color[2]);
1581  imagefilledellipse(‪$im, $imageCoordinates[0], $imageCoordinates[1], $imageCoordinates[2], $imageCoordinates[3], $fillingColor);
1582  }
1583 
1592  public function ‪makeEffect(&‪$im, $conf)
1593  {
1594  $commands = $this->‪IMparams($conf['value']);
1595  if ($commands) {
1596  $this->‪applyImageMagickToPHPGif(‪$im, $commands);
1597  }
1598  }
1599 
1608  public function ‪IMparams(‪$setup)
1609  {
1610  if (!trim(‪$setup)) {
1611  return '';
1612  }
1613  $effects = explode('|', ‪$setup);
1614  $commands = '';
1615  foreach ($effects as $val) {
1616  $pairs = explode('=', $val, 2);
1617  $value = trim($pairs[1]);
1618  $effect = strtolower(trim($pairs[0]));
1619  switch ($effect) {
1620  case 'gamma':
1621  $commands .= ' -gamma ' . (float)$value;
1622  break;
1623  case 'blur':
1624  if ($this->processorEffectsEnabled) {
1625  $commands .= $this->‪v5_blur($value);
1626  }
1627  break;
1628  case 'sharpen':
1629  if ($this->processorEffectsEnabled) {
1630  $commands .= $this->‪v5_sharpen($value);
1631  }
1632  break;
1633  case 'rotate':
1634  $commands .= ' -rotate ' . ‪MathUtility::forceIntegerInRange($value, 0, 360);
1635  break;
1636  case 'solarize':
1637  $commands .= ' -solarize ' . ‪MathUtility::forceIntegerInRange($value, 0, 99);
1638  break;
1639  case 'swirl':
1640  $commands .= ' -swirl ' . ‪MathUtility::forceIntegerInRange($value, 0, 1000);
1641  break;
1642  case 'wave':
1643  $params = GeneralUtility::intExplode(',', $value);
1644  $commands .= ' -wave ' . ‪MathUtility::forceIntegerInRange($params[0], 0, 99) . 'x' . ‪MathUtility::forceIntegerInRange($params[1], 0, 99);
1645  break;
1646  case 'charcoal':
1647  $commands .= ' -charcoal ' . ‪MathUtility::forceIntegerInRange($value, 0, 100);
1648  break;
1649  case 'gray':
1650  $commands .= ' -colorspace GRAY';
1651  break;
1652  case 'edge':
1653  $commands .= ' -edge ' . ‪MathUtility::forceIntegerInRange($value, 0, 99);
1654  break;
1655  case 'emboss':
1656  $commands .= ' -emboss';
1657  break;
1658  case 'flip':
1659  $commands .= ' -flip';
1660  break;
1661  case 'flop':
1662  $commands .= ' -flop';
1663  break;
1664  case 'colors':
1665  $commands .= ' -colors ' . ‪MathUtility::forceIntegerInRange($value, 2, 255);
1666  break;
1667  case 'shear':
1668  $commands .= ' -shear ' . ‪MathUtility::forceIntegerInRange($value, -90, 90);
1669  break;
1670  case 'invert':
1671  $commands .= ' -negate';
1672  break;
1673  }
1674  }
1675  return $commands;
1676  }
1677 
1685  public function ‪adjust(&‪$im, $conf)
1686  {
1687  ‪$setup = $conf['value'];
1688  if (!trim(‪$setup)) {
1689  return;
1690  }
1691  $effects = explode('|', ‪$setup);
1692  foreach ($effects as $val) {
1693  $pairs = explode('=', $val, 2);
1694  $value = trim($pairs[1]);
1695  $effect = strtolower(trim($pairs[0]));
1696  switch ($effect) {
1697  case 'inputlevels':
1698  // low,high
1699  $params = GeneralUtility::intExplode(',', $value);
1700  $this->‪inputLevels(‪$im, $params[0], $params[1]);
1701  break;
1702  case 'outputlevels':
1703  $params = GeneralUtility::intExplode(',', $value);
1704  $this->‪outputLevels(‪$im, $params[0], $params[1]);
1705  break;
1706  case 'autolevels':
1707  $this->‪autolevels(‪$im);
1708  break;
1709  }
1710  }
1711  }
1712 
1720  public function ‪crop(&‪$im, $conf)
1721  {
1722  // Clears workArea to total image
1723  $this->‪setWorkArea('');
1724  $cords = GeneralUtility::intExplode(',', $conf['crop'] . ',,,');
1725  $conf['offset'] = $cords[0] . ',' . $cords[1];
1726  $cords = $this->‪objPosition($conf, $this->workArea, [$cords[2], $cords[3]]);
1727  $newIm = imagecreatetruecolor($cords[2], $cords[3]);
1728  $cols = $this->‪convertColor($conf['backColor'] ?: $this->setup['backColor']);
1729  $Bcolor = imagecolorallocate($newIm, $cols[0], $cols[1], $cols[2]);
1730  imagefilledrectangle($newIm, 0, 0, $cords[2], $cords[3], $Bcolor);
1731  $newConf = [];
1732  ‪$workArea = [0, 0, $cords[2], $cords[3]];
1733  if ($cords[0] < 0) {
1734  ‪$workArea[0] = abs($cords[0]);
1735  } else {
1736  $newConf['offset'] = -$cords[0];
1737  }
1738  if ($cords[1] < 0) {
1739  ‪$workArea[1] = abs($cords[1]);
1740  } else {
1741  $newConf['offset'] .= ',' . -$cords[1];
1742  }
1743  $this->‪copyGifOntoGif($newIm, ‪$im, $newConf, ‪$workArea);
1744  ‪$im = $newIm;
1745  $this->w = imagesx(‪$im);
1746  $this->h = imagesy(‪$im);
1747  // Clears workArea to total image
1748  $this->‪setWorkArea('');
1749  }
1750 
1758  public function ‪scale(&‪$im, $conf)
1759  {
1760  if ($conf['width'] || $conf['height'] || $conf['params']) {
1761  $tmpStr = $this->‪randomName();
1762  $theFile = $tmpStr . '.' . ‪$this->gifExtension;
1763  $this->‪ImageWrite(‪$im, $theFile);
1764  $theNewFile = $this->‪imageMagickConvert($theFile, $this->gifExtension, $conf['width'], $conf['height'], $conf['params']);
1765  $tmpImg = $this->‪imageCreateFromFile($theNewFile[3]);
1766  if ($tmpImg) {
1767  imagedestroy(‪$im);
1768  ‪$im = $tmpImg;
1769  $this->w = imagesx(‪$im);
1770  $this->h = imagesy(‪$im);
1771  // Clears workArea to total image
1772  $this->‪setWorkArea('');
1773  }
1774  unlink($theFile);
1775  if ($theNewFile[3] && $theNewFile[3] != $theFile) {
1776  unlink($theNewFile[3]);
1777  }
1778  }
1779  }
1780 
1789  public function ‪setWorkArea(‪$workArea)
1790  {
1791  $this->workArea = GeneralUtility::intExplode(',', ‪$workArea);
1792  $this->workArea = $this->‪applyOffset($this->workArea, $this->OFFSET);
1793  if (!$this->workArea[2]) {
1794  $this->workArea[2] = ‪$this->w;
1795  }
1796  if (!$this->workArea[3]) {
1797  $this->workArea[3] = ‪$this->h;
1798  }
1799  }
1800 
1801  /*************************
1802  *
1803  * Adjustment functions
1804  *
1805  ************************/
1811  public function ‪autolevels(&‪$im)
1812  {
1813  $totalCols = imagecolorstotal(‪$im);
1814  $grayArr = [];
1815  for ($c = 0; $c < $totalCols; $c++) {
1816  $cols = imagecolorsforindex(‪$im, $c);
1817  $grayArr[] = round(($cols['red'] + $cols['green'] + $cols['blue']) / 3);
1818  }
1819  $min = min($grayArr);
1820  $max = max($grayArr);
1821  $delta = $max - $min;
1822  if ($delta) {
1823  for ($c = 0; $c < $totalCols; $c++) {
1824  $cols = imagecolorsforindex(‪$im, $c);
1825  $cols['red'] = floor(($cols['red'] - $min) / $delta * 255);
1826  $cols['green'] = floor(($cols['green'] - $min) / $delta * 255);
1827  $cols['blue'] = floor(($cols['blue'] - $min) / $delta * 255);
1828  imagecolorset(‪$im, $c, $cols['red'], $cols['green'], $cols['blue']);
1829  }
1830  }
1831  }
1832 
1841  public function ‪outputLevels(&‪$im, $low, $high, $swap = false)
1842  {
1843  if ($low < $high) {
1844  $low = ‪MathUtility::forceIntegerInRange($low, 0, 255);
1845  $high = ‪MathUtility::forceIntegerInRange($high, 0, 255);
1846  if ($swap) {
1847  $temp = $low;
1848  $low = 255 - $high;
1849  $high = 255 - $temp;
1850  }
1851  $delta = $high - $low;
1852  $totalCols = imagecolorstotal(‪$im);
1853  for ($c = 0; $c < $totalCols; $c++) {
1854  $cols = imagecolorsforindex(‪$im, $c);
1855  $cols['red'] = $low + floor($cols['red'] / 255 * $delta);
1856  $cols['green'] = $low + floor($cols['green'] / 255 * $delta);
1857  $cols['blue'] = $low + floor($cols['blue'] / 255 * $delta);
1858  imagecolorset(‪$im, $c, $cols['red'], $cols['green'], $cols['blue']);
1859  }
1860  }
1861  }
1862 
1870  public function ‪inputLevels(&‪$im, $low, $high)
1871  {
1872  if ($low < $high) {
1873  $low = ‪MathUtility::forceIntegerInRange($low, 0, 255);
1874  $high = ‪MathUtility::forceIntegerInRange($high, 0, 255);
1875  $delta = $high - $low;
1876  $totalCols = imagecolorstotal(‪$im);
1877  for ($c = 0; $c < $totalCols; $c++) {
1878  $cols = imagecolorsforindex(‪$im, $c);
1879  $cols['red'] = ‪MathUtility::forceIntegerInRange(($cols['red'] - $low) / $delta * 255, 0, 255);
1880  $cols['green'] = ‪MathUtility::forceIntegerInRange(($cols['green'] - $low) / $delta * 255, 0, 255);
1881  $cols['blue'] = ‪MathUtility::forceIntegerInRange(($cols['blue'] - $low) / $delta * 255, 0, 255);
1882  imagecolorset(‪$im, $c, $cols['red'], $cols['green'], $cols['blue']);
1883  }
1884  }
1885  }
1886 
1894  public function ‪IMreduceColors($file, $cols)
1895  {
1896  $fI = GeneralUtility::split_fileref($file);
1897  $ext = strtolower($fI['fileext']);
1898  $result = $this->‪randomName() . '.' . $ext;
1899  $reduce = ‪MathUtility::forceIntegerInRange($cols, 0, $ext === 'gif' ? 256 : $this->truecolorColors, 0);
1900  if ($reduce > 0) {
1901  $params = ' -colors ' . $reduce;
1902  if ($reduce <= 256) {
1903  $params .= ' -type Palette';
1904  }
1905  $prefix = $ext === 'png' && $reduce <= 256 ? 'png8:' : '';
1906  $this->‪imageMagickExec($file, $prefix . $result, $params);
1907  if ($result) {
1908  return $result;
1909  }
1910  }
1911  return '';
1912  }
1914  /*********************************
1915  *
1916  * GIFBUILDER Helper functions
1917  *
1918  *********************************/
1927  public function ‪v5_sharpen($factor)
1928  {
1929  $factor = ‪MathUtility::forceIntegerInRange(ceil($factor / 10), 0, 10);
1930  $sharpenArr = explode(',', ',' . $this->im5fx_sharpenSteps);
1931  $sharpenF = trim($sharpenArr[$factor]);
1932  if ($sharpenF) {
1933  return ' -sharpen ' . $sharpenF;
1934  }
1935  return '';
1936  }
1937 
1946  public function ‪v5_blur($factor)
1947  {
1948  $factor = ‪MathUtility::forceIntegerInRange(ceil($factor / 10), 0, 10);
1949  $blurArr = explode(',', ',' . $this->im5fx_blurSteps);
1950  $blurF = trim($blurArr[$factor]);
1951  if ($blurF) {
1952  return ' -blur ' . $blurF;
1953  }
1954  return '';
1955  }
1956 
1963  public function ‪randomName()
1964  {
1965  GeneralUtility::mkdir_deep(‪Environment::getVarPath() . '/transient/');
1966  return ‪Environment::getVarPath() . '/transient/' . md5(uniqid('', true));
1967  }
1968 
1977  public function ‪applyOffset($cords, ‪$OFFSET)
1978  {
1979  $cords[0] = (int)$cords[0] + (int)‪$OFFSET[0];
1980  $cords[1] = (int)$cords[1] + (int)‪$OFFSET[1];
1981  return $cords;
1982  }
1983 
1991  public function ‪convertColor($string)
1992  {
1993  $col = [];
1994  $cParts = explode(':', $string, 2);
1995  // Finding the RGB definitions of the color:
1996  $string = $cParts[0];
1997  if (strstr($string, '#')) {
1998  $string = preg_replace('/[^A-Fa-f0-9]*/', '', $string);
1999  $col[] = hexdec(substr($string, 0, 2));
2000  $col[] = hexdec(substr($string, 2, 2));
2001  $col[] = hexdec(substr($string, 4, 2));
2002  } elseif (strstr($string, ',')) {
2003  $string = preg_replace('/[^,0-9]*/', '', $string);
2004  $strArr = explode(',', $string);
2005  $col[] = (int)$strArr[0];
2006  $col[] = (int)$strArr[1];
2007  $col[] = (int)$strArr[2];
2008  } else {
2009  $string = strtolower(trim($string));
2010  if ($this->colMap[$string]) {
2011  $col = $this->colMap[$string];
2012  } else {
2013  $col = [0, 0, 0];
2014  }
2015  }
2016  // ... and possibly recalculating the value
2017  if (trim($cParts[1])) {
2018  $cParts[1] = trim($cParts[1]);
2019  if ($cParts[1][0] === '*') {
2020  $val = (float)substr($cParts[1], 1);
2021  $col[0] = ‪MathUtility::forceIntegerInRange($col[0] * $val, 0, 255);
2022  $col[1] = ‪MathUtility::forceIntegerInRange($col[1] * $val, 0, 255);
2023  $col[2] = ‪MathUtility::forceIntegerInRange($col[2] * $val, 0, 255);
2024  } else {
2025  $val = (int)$cParts[1];
2026  $col[0] = ‪MathUtility::forceIntegerInRange($col[0] + $val, 0, 255);
2027  $col[1] = ‪MathUtility::forceIntegerInRange($col[1] + $val, 0, 255);
2028  $col[2] = ‪MathUtility::forceIntegerInRange($col[2] + $val, 0, 255);
2029  }
2030  }
2031  return $col;
2032  }
2033 
2044  public function ‪objPosition($conf, ‪$workArea, $BB)
2045  {
2046  // offset, align, valign, workarea
2047  $result = [];
2048  $result[2] = $BB[0];
2049  $result[3] = $BB[1];
2050  ‪$w = ‪$workArea[2];
2051  ‪$h = ‪$workArea[3];
2052  $align = explode(',', $conf['align']);
2053  $align[0] = strtolower(substr(trim($align[0]), 0, 1));
2054  $align[1] = strtolower(substr(trim($align[1]), 0, 1));
2055  switch ($align[0]) {
2056  case 'r':
2057  $result[0] = ‪$w - $result[2];
2058  break;
2059  case 'c':
2060  $result[0] = round((‪$w - $result[2]) / 2);
2061  break;
2062  default:
2063  $result[0] = 0;
2064  }
2065  switch ($align[1]) {
2066  case 'b':
2067  // y pos
2068  $result[1] = ‪$h - $result[3];
2069  break;
2070  case 'c':
2071  $result[1] = round((‪$h - $result[3]) / 2);
2072  break;
2073  default:
2074  $result[1] = 0;
2075  }
2076  $result = $this->‪applyOffset($result, GeneralUtility::intExplode(',', $conf['offset']));
2077  $result = $this->‪applyOffset($result, ‪$workArea);
2078  return $result;
2079  }
2080 
2081  /***********************************
2082  *
2083  * Scaling, Dimensions of images
2084  *
2085  ***********************************/
2100  public function ‪imageMagickConvert($imagefile, $newExt = '', ‪$w = '', ‪$h = '', $params = '', $frame = '', $options = [], $mustCreate = false)
2101  {
2102  if (!$this->processorEnabled) {
2103  // Returning file info right away
2104  return $this->‪getImageDimensions($imagefile);
2105  }
2106  $info = $this->‪getImageDimensions($imagefile);
2107  if (!$info) {
2108  return null;
2109  }
2110 
2111  $newExt = strtolower(trim($newExt));
2112  // If no extension is given the original extension is used
2113  if (!$newExt) {
2114  $newExt = $info[2];
2115  }
2116  if ($newExt === 'web') {
2117  if (in_array($info[2], $this->webImageExt, true)) {
2118  $newExt = $info[2];
2119  } else {
2120  $newExt = $this->‪gif_or_jpg($info[2], $info[0], $info[1]);
2121  if (!$params) {
2122  $params = $this->cmds[$newExt];
2123  }
2124  }
2125  }
2126  if (!in_array($newExt, $this->imageFileExt, true)) {
2127  return null;
2128  }
2129 
2130  $data = $this->‪getImageScale($info, ‪$w, ‪$h, $options);
2131  ‪$w = $data['origW'];
2132  ‪$h = $data['origH'];
2133  // If no conversion should be performed
2134  // this flag is TRUE if the width / height does NOT dictate
2135  // the image to be scaled!! (that is if no width / height is
2136  // given or if the destination w/h matches the original image
2137  // dimensions or if the option to not scale the image is set)
2138  $noScale = !‪$w && !‪$h || $data[0] == $info[0] && $data[1] == $info[1] || !empty($options['noScale']);
2139  if ($noScale && !$data['crs'] && !$params && !$frame && $newExt == $info[2] && !$mustCreate) {
2140  // Set the new width and height before returning,
2141  // if the noScale option is set
2142  if (!empty($options['noScale'])) {
2143  $info[0] = $data[0];
2144  $info[1] = $data[1];
2145  }
2146  $info[3] = $imagefile;
2147  return $info;
2148  }
2149  $info[0] = $data[0];
2150  $info[1] = $data[1];
2151  $frame = $this->addFrameSelection ? (int)$frame : '';
2152  if (!$params) {
2153  $params = $this->cmds[$newExt];
2154  }
2155  // Cropscaling:
2156  if ($data['crs']) {
2157  if (!$data['origW']) {
2158  $data['origW'] = $data[0];
2159  }
2160  if (!$data['origH']) {
2161  $data['origH'] = $data[1];
2162  }
2163  $offsetX = (int)(($data[0] - $data['origW']) * ($data['cropH'] + 100) / 200);
2164  $offsetY = (int)(($data[1] - $data['origH']) * ($data['cropV'] + 100) / 200);
2165  $params .= ' -crop ' . $data['origW'] . 'x' . $data['origH'] . '+' . $offsetX . '+' . $offsetY . '! +repage';
2166  }
2167  $command = $this->scalecmd . ' ' . $info[0] . 'x' . $info[1] . '! ' . $params . ' ';
2168  // re-apply colorspace-setting for the resulting image so colors don't appear to dark (sRGB instead of RGB)
2169  $command .= ' -colorspace ' . ‪$this->colorspace;
2170  $cropscale = $data['crs'] ? 'crs-V' . $data['cropV'] . 'H' . $data['cropH'] : '';
2171  if ($this->alternativeOutputKey) {
2172  $theOutputName = GeneralUtility::shortMD5($command . $cropscale . ‪PathUtility::basename($imagefile) . $this->alternativeOutputKey . '[' . $frame . ']');
2173  } else {
2174  $theOutputName = GeneralUtility::shortMD5($command . $cropscale . $imagefile . filemtime($imagefile) . '[' . $frame . ']');
2175  }
2176  if ($this->imageMagickConvert_forceFileNameBody) {
2178  $this->imageMagickConvert_forceFileNameBody = '';
2179  }
2180  // Making the temporary filename
2181  GeneralUtility::mkdir_deep(‪Environment::getPublicPath() . '/typo3temp/assets/images/');
2182  ‪$output = ‪Environment::getPublicPath() . '/typo3temp/assets/images/' . $this->filenamePrefix . $theOutputName . '.' . $newExt;
2183  if ($this->dontCheckForExistingTempFile || !file_exists(‪$output)) {
2184  $this->‪imageMagickExec($imagefile, ‪$output, $command, $frame);
2185  }
2186  if (file_exists(‪$output)) {
2187  $info[3] = ‪$output;
2188  $info[2] = $newExt;
2189  // params might change some image data!
2190  if ($params) {
2191  $info = $this->‪getImageDimensions($info[3]);
2192  }
2193  if ($info[2] == $this->gifExtension && !$this->dontCompress) {
2194  // Compress with IM (lzw) or GD (rle) (Workaround for the absence of lzw-compression in GD)
2195  ‪self::gifCompress($info[3], '');
2196  }
2197  return $info;
2198  }
2199  return null;
2200  }
2201 
2209  public function ‪getImageDimensions($imageFile)
2210  {
2211  $returnArr = null;
2212  preg_match('/([^\\.]*)$/', $imageFile, $reg);
2213  if (file_exists($imageFile) && in_array(strtolower($reg[0]), $this->imageFileExt, true)) {
2214  $returnArr = $this->‪getCachedImageDimensions($imageFile);
2215  if (!$returnArr) {
2216  $imageInfoObject = GeneralUtility::makeInstance(ImageInfo::class, $imageFile);
2217  if ($imageInfoObject->getWidth()) {
2218  $returnArr = [
2219  $imageInfoObject->getWidth(),
2220  $imageInfoObject->getHeight(),
2221  strtolower($reg[0]),
2222  $imageFile
2223  ];
2224  $this->‪cacheImageDimensions($returnArr);
2225  }
2226  }
2227  }
2228  return $returnArr;
2229  }
2230 
2238  public function ‪cacheImageDimensions(array $identifyResult)
2239  {
2240  $filePath = $identifyResult[3];
2241  $statusHash = $this->‪generateStatusHashForImageFile($filePath);
2242  $identifier = $this->‪generateCacheKeyForImageFile($filePath);
2243 
2245  $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_imagesizes');
2246  $imageDimensions = [
2247  'hash' => $statusHash,
2248  'imagewidth' => $identifyResult[0],
2249  'imageheight' => $identifyResult[1],
2250  ];
2251  $cache->set($identifier, $imageDimensions);
2252 
2253  return true;
2254  }
2255 
2264  public function ‪getCachedImageDimensions($filePath)
2265  {
2266  $statusHash = $this->‪generateStatusHashForImageFile($filePath);
2267  $identifier = $this->‪generateCacheKeyForImageFile($filePath);
2269  $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_imagesizes');
2270  $cachedImageDimensions = $cache->get($identifier);
2271  if (!isset($cachedImageDimensions['hash'])) {
2272  return false;
2273  }
2274 
2275  if ($cachedImageDimensions['hash'] !== $statusHash) {
2276  // The file has changed. Delete the cache entry.
2277  $cache->remove($identifier);
2278  $result = false;
2279  } else {
2280  preg_match('/([^\\.]*)$/', $filePath, $imageExtension);
2281  $result = [
2282  (int)$cachedImageDimensions['imagewidth'],
2283  (int)$cachedImageDimensions['imageheight'],
2284  strtolower($imageExtension[0]),
2285  $filePath
2286  ];
2287  }
2288 
2289  return $result;
2290  }
2291 
2301  protected function ‪generateCacheKeyForImageFile($filePath)
2302  {
2303  return sha1($filePath);
2304  }
2305 
2313  protected function ‪generateStatusHashForImageFile($filePath)
2314  {
2315  $fileStatus = stat($filePath);
2316 
2317  return sha1($fileStatus['mtime'] . $fileStatus['size']);
2318  }
2319 
2331  public function ‪getImageScale($info, ‪$w, ‪$h, $options)
2332  {
2333  if (strstr(‪$w . ‪$h, 'm')) {
2334  $max = 1;
2335  } else {
2336  $max = 0;
2337  }
2338  if (strstr(‪$w . ‪$h, 'c')) {
2339  $out['cropH'] = (int)substr(strstr(‪$w, 'c'), 1);
2340  $out['cropV'] = (int)substr(strstr(‪$h, 'c'), 1);
2341  $crs = true;
2342  } else {
2343  $crs = false;
2344  }
2345  $out['crs'] = $crs;
2346  ‪$w = (int)‪$w;
2347  ‪$h = (int)‪$h;
2348  // If there are max-values...
2349  if (!empty($options['maxW'])) {
2350  // If width is given...
2351  if (‪$w) {
2352  if (‪$w > $options['maxW']) {
2353  ‪$w = $options['maxW'];
2354  // Height should follow
2355  $max = 1;
2356  }
2357  } else {
2358  if ($info[0] > $options['maxW']) {
2359  ‪$w = $options['maxW'];
2360  // Height should follow
2361  $max = 1;
2362  }
2363  }
2364  }
2365  if (!empty($options['maxH'])) {
2366  // If height is given...
2367  if (‪$h) {
2368  if (‪$h > $options['maxH']) {
2369  ‪$h = $options['maxH'];
2370  // Height should follow
2371  $max = 1;
2372  }
2373  } else {
2374  // Changed [0] to [1] 290801
2375  if ($info[1] > $options['maxH']) {
2376  ‪$h = $options['maxH'];
2377  // Height should follow
2378  $max = 1;
2379  }
2380  }
2381  }
2382  $out['origW'] = ‪$w;
2383  $out['origH'] = ‪$h;
2384  $out['max'] = $max;
2385  if (!$this->mayScaleUp) {
2386  if (‪$w > $info[0]) {
2387  ‪$w = $info[0];
2388  }
2389  if (‪$h > $info[1]) {
2390  ‪$h = $info[1];
2391  }
2392  }
2393  // If scaling should be performed. Check that input "info" array will not cause division-by-zero
2394  if ((‪$w || ‪$h) && $info[0] && $info[1]) {
2395  if (‪$w && !‪$h) {
2396  $info[1] = ceil($info[1] * (‪$w / $info[0]));
2397  $info[0] = ‪$w;
2398  }
2399  if (!‪$w && ‪$h) {
2400  $info[0] = ceil($info[0] * (‪$h / $info[1]));
2401  $info[1] = ‪$h;
2402  }
2403  if (‪$w && ‪$h) {
2404  if ($max) {
2405  $ratio = $info[0] / $info[1];
2406  if (‪$h * $ratio > ‪$w) {
2407  ‪$h = round(‪$w / $ratio);
2408  } else {
2409  ‪$w = round(‪$h * $ratio);
2410  }
2411  }
2412  if ($crs) {
2413  $ratio = $info[0] / $info[1];
2414  if (‪$h * $ratio < ‪$w) {
2415  ‪$h = round(‪$w / $ratio);
2416  } else {
2417  ‪$w = round(‪$h * $ratio);
2418  }
2419  }
2420  $info[0] = ‪$w;
2421  $info[1] = ‪$h;
2422  }
2423  }
2424  $out[0] = $info[0];
2425  $out[1] = $info[1];
2426  // Set minimum-measures!
2427  if (isset($options['minW']) && $out[0] < $options['minW']) {
2428  if (($max || $crs) && $out[0]) {
2429  $out[1] = round($out[1] * $options['minW'] / $out[0]);
2430  }
2431  $out[0] = $options['minW'];
2432  }
2433  if (isset($options['minH']) && $out[1] < $options['minH']) {
2434  if (($max || $crs) && $out[1]) {
2435  $out[0] = round($out[0] * $options['minH'] / $out[1]);
2436  }
2437  $out[1] = $options['minH'];
2438  }
2439  return $out;
2440  }
2441 
2442  /***********************************
2443  *
2444  * ImageMagick API functions
2445  *
2446  ***********************************/
2453  public function ‪imageMagickIdentify($imagefile)
2454  {
2455  if (!$this->processorEnabled) {
2456  return null;
2457  }
2458 
2459  $result = $this->‪executeIdentifyCommandForImageFile($imagefile);
2460  if ($result) {
2461  [$width, $height, $fileExtension, $fileType] = explode(' ', $result);
2462  if ((int)$width && (int)$height) {
2463  return [$width, $height, strtolower($fileExtension), $imagefile, strtolower($fileType)];
2464  }
2465  }
2466  return null;
2467  }
2468 
2475  protected function ‪executeIdentifyCommandForImageFile(string $imageFile): ?string
2476  {
2477  $frame = $this->addFrameSelection ? 0 : null;
2479  'identify',
2480  '-format "%w %h %e %m" ' . ‪ImageMagickFile::fromFilePath($imageFile, $frame)
2481  );
2482  $returnVal = [];
2483  ‪CommandUtility::exec($cmd, $returnVal);
2484  $result = array_pop($returnVal);
2485  $this->IM_commands[] = ['identify', $cmd, $result];
2486  return $result;
2487  }
2488 
2499  public function ‪imageMagickExec($input, ‪$output, $params, $frame = 0)
2500  {
2501  if (!$this->processorEnabled) {
2502  return '';
2503  }
2504  // If addFrameSelection is set in the Install Tool, a frame number is added to
2505  // select a specific page of the image (by default this will be the first page)
2506  $frame = $this->addFrameSelection ? (int)$frame : null;
2508  'convert',
2509  $params
2510  . ' ' . ‪ImageMagickFile::fromFilePath($input, $frame)
2512  );
2513  $this->IM_commands[] = [‪$output, $cmd];
2514  $ret = ‪CommandUtility::exec($cmd);
2515  // Change the permissions of the file
2516  GeneralUtility::fixPermissions(‪$output);
2517  return $ret;
2518  }
2519 
2530  public function ‪combineExec($input, $overlay, $mask, ‪$output)
2531  {
2532  if (!$this->processorEnabled) {
2533  return '';
2534  }
2535  $theMask = $this->‪randomName() . '.' . ‪$this->gifExtension;
2536  // +matte = no alpha layer in output
2537  $this->‪imageMagickExec($mask, $theMask, '-colorspace GRAY +matte');
2538 
2539  $parameters = '-compose over'
2540  . ' -quality ' . $this->jpegQuality
2541  . ' +matte '
2543  . ‪ImageMagickFile::fromFilePath($overlay) . ' '
2544  . ‪ImageMagickFile::fromFilePath($theMask) . ' '
2546  $cmd = ‪CommandUtility::imageMagickCommand('combine', $parameters);
2547  $this->IM_commands[] = [‪$output, $cmd];
2548  $ret = ‪CommandUtility::exec($cmd);
2549  // Change the permissions of the file
2550  GeneralUtility::fixPermissions(‪$output);
2551  if (is_file($theMask)) {
2552  @unlink($theMask);
2553  }
2554  return $ret;
2555  }
2556 
2575  public static function ‪gifCompress($theFile, $type)
2576  {
2577  $gfxConf = ‪$GLOBALS['TYPO3_CONF_VARS']['GFX'];
2578  if (!$gfxConf['gif_compress'] || strtolower(substr($theFile, -4, 4)) !== '.gif') {
2579  return '';
2580  }
2581 
2582  if (($type === 'IM' || !$type) && $gfxConf['processor_enabled'] && $gfxConf['processor_path_lzw']) {
2583  // Use temporary file to prevent problems with read and write lock on same file on network file systems
2584  $temporaryName = ‪PathUtility::dirname($theFile) . '/' . md5(uniqid('', true)) . '.gif';
2585  // Rename could fail, if a simultaneous thread is currently working on the same thing
2586  if (@rename($theFile, $temporaryName)) {
2588  'convert',
2590  $gfxConf['processor_path_lzw']
2591  );
2593  unlink($temporaryName);
2594  }
2595  $returnCode = 'IM';
2596  if (@is_file($theFile)) {
2597  GeneralUtility::fixPermissions($theFile);
2598  }
2599  } elseif (($type === 'GD' || !$type) && $gfxConf['gdlib'] && !$gfxConf['gdlib_png']) {
2600  $tempImage = imagecreatefromgif($theFile);
2601  imagegif($tempImage, $theFile);
2602  imagedestroy($tempImage);
2603  $returnCode = 'GD';
2604  if (@is_file($theFile)) {
2605  GeneralUtility::fixPermissions($theFile);
2606  }
2607  } else {
2608  $returnCode = '';
2609  }
2610 
2611  return $returnCode;
2612  }
2613 
2622  public static function ‪readPngGif($theFile, $output_png = false)
2623  {
2624  if (!‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_enabled'] || !@is_file($theFile)) {
2625  return null;
2626  }
2627 
2628  $ext = strtolower(substr($theFile, -4, 4));
2629  if ((string)$ext === '.png' && $output_png || (string)$ext === '.gif' && !$output_png) {
2630  return $theFile;
2631  }
2632 
2633  if (!@is_dir(‪Environment::getPublicPath() . '/typo3temp/assets/images/')) {
2634  GeneralUtility::mkdir_deep(‪Environment::getPublicPath() . '/typo3temp/assets/images/');
2635  }
2636  $newFile = ‪Environment::getPublicPath() . '/typo3temp/assets/images/' . md5($theFile . '|' . filemtime($theFile)) . ($output_png ? '.png' : '.gif');
2638  'convert',
2640  ‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_path']
2641  );
2643  if (@is_file($newFile)) {
2644  GeneralUtility::fixPermissions($newFile);
2645  return $newFile;
2646  }
2647  return null;
2648  }
2649 
2650  /***********************************
2651  *
2652  * Various IO functions
2653  *
2654  ***********************************/
2655 
2662  public function ‪applyImageMagickToPHPGif(&‪$im, $command)
2663  {
2664  $tmpStr = $this->‪randomName();
2665  $theFile = $tmpStr . '.' . ‪$this->gifExtension;
2666  $this->‪ImageWrite(‪$im, $theFile);
2667  $this->‪imageMagickExec($theFile, $theFile, $command);
2668  $tmpImg = $this->‪imageCreateFromFile($theFile);
2669  if ($tmpImg) {
2670  imagedestroy(‪$im);
2671  ‪$im = $tmpImg;
2672  $this->w = imagesx(‪$im);
2673  $this->h = imagesy(‪$im);
2674  }
2675  unlink($theFile);
2676  }
2677 
2687  public function ‪gif_or_jpg($type, ‪$w, ‪$h)
2688  {
2689  if ($type === 'ai' || ‪$w * $h < $this->pixelLimitGif) {
2690  return ‪$this->gifExtension;
2691  }
2692  return 'jpg';
2693  }
2694 
2704  public function ‪output($file)
2705  {
2706  if ($file) {
2707  $reg = [];
2708  preg_match('/([^\\.]*)$/', $file, $reg);
2709  $ext = strtolower($reg[0]);
2710  switch ($ext) {
2711  case 'gif':
2712  case 'png':
2713  if ($this->‪ImageWrite($this->im, $file)) {
2714  // ImageMagick operations
2715  if ($this->setup['reduceColors']) {
2716  $reduced = $this->‪IMreduceColors($file, ‪MathUtility::forceIntegerInRange($this->setup['reduceColors'], 256, $this->truecolorColors, 256));
2717  if ($reduced) {
2718  @copy($reduced, $file);
2719  @unlink($reduced);
2720  }
2721  }
2722  // Compress with IM! (adds extra compression, LZW from ImageMagick)
2723  // (Workaround for the absence of lzw-compression in GD)
2724  ‪self::gifCompress($file, 'IM');
2725  }
2726  break;
2727  case 'jpg':
2728  case 'jpeg':
2729  // Use the default
2730  $quality = 0;
2731  if ($this->setup['quality']) {
2732  $quality = ‪MathUtility::forceIntegerInRange($this->setup['quality'], 10, 100);
2733  }
2734  $this->‪ImageWrite($this->im, $file, $quality);
2735  break;
2736  }
2737  }
2738  return $file;
2739  }
2740 
2746  public function ‪destroy()
2747  {
2748  imagedestroy($this->im);
2749  }
2750 
2757  public function ‪imgTag($imgInfo)
2758  {
2759  return '<img src="' . $imgInfo[3] . '" width="' . $imgInfo[0] . '" height="' . $imgInfo[1] . '" border="0" alt="" />';
2760  }
2761 
2771  public function ‪ImageWrite($destImg, $theImage, $quality = 0)
2772  {
2773  imageinterlace($destImg, 0);
2774  $ext = strtolower(substr($theImage, strrpos($theImage, '.') + 1));
2775  $result = false;
2776  switch ($ext) {
2777  case 'jpg':
2778  case 'jpeg':
2779  if (function_exists('imagejpeg')) {
2780  if ($quality === 0) {
2781  $quality = ‪$this->jpegQuality;
2782  }
2783  $result = imagejpeg($destImg, $theImage, $quality);
2784  }
2785  break;
2786  case 'gif':
2787  if (function_exists('imagegif')) {
2788  imagetruecolortopalette($destImg, true, 256);
2789  $result = imagegif($destImg, $theImage);
2790  }
2791  break;
2792  case 'png':
2793  if (function_exists('imagepng')) {
2794  $result = imagepng($destImg, $theImage);
2795  }
2796  break;
2797  }
2798  if ($result) {
2799  GeneralUtility::fixPermissions($theImage);
2800  }
2801  return $result;
2802  }
2803 
2811  public function ‪imageCreateFromFile($sourceImg)
2812  {
2813  $imgInf = pathinfo($sourceImg);
2814  $ext = strtolower($imgInf['extension']);
2815  switch ($ext) {
2816  case 'gif':
2817  if (function_exists('imagecreatefromgif')) {
2818  return imagecreatefromgif($sourceImg);
2819  }
2820  break;
2821  case 'png':
2822  if (function_exists('imagecreatefrompng')) {
2823  $imageHandle = imagecreatefrompng($sourceImg);
2824  if ($this->saveAlphaLayer) {
2825  imagesavealpha($imageHandle, true);
2826  }
2827  return $imageHandle;
2828  }
2829  break;
2830  case 'jpg':
2831  case 'jpeg':
2832  if (function_exists('imagecreatefromjpeg')) {
2833  return imagecreatefromjpeg($sourceImg);
2834  }
2835  break;
2836  }
2837  // If non of the above:
2838  $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $sourceImg);
2839  ‪$im = imagecreatetruecolor($imageInfo->getWidth(), $imageInfo->getHeight());
2840  $Bcolor = imagecolorallocate(‪$im, 128, 128, 128);
2841  imagefilledrectangle(‪$im, 0, 0, $imageInfo->getWidth(), $imageInfo->getHeight(), $Bcolor);
2842  return ‪$im;
2843  }
2844 
2851  public function ‪hexColor($color)
2852  {
2853  $r = dechex($color[0]);
2854  if (strlen($r) < 2) {
2855  $r = '0' . $r;
2856  }
2857  $g = dechex($color[1]);
2858  if (strlen($g) < 2) {
2859  $g = '0' . $g;
2860  }
2861  $b = dechex($color[2]);
2862  if (strlen($b) < 2) {
2863  $b = '0' . $b;
2864  }
2865  return '#' . $r . $g . $b;
2866  }
2867 
2876  public function ‪unifyColors(&$img, $colArr, $closest = false)
2877  {
2878  $retCol = -1;
2879  if (is_array($colArr) && !empty($colArr) && function_exists('imagepng') && function_exists('imagecreatefrompng')) {
2880  $firstCol = array_shift($colArr);
2881  $firstColArr = $this->‪convertColor($firstCol);
2882  $origName = $preName = $this->‪randomName() . '.png';
2883  $postName = $this->‪randomName() . '.png';
2884  $tmpImg = null;
2885  if (count($colArr) > 1) {
2886  $this->‪ImageWrite($img, $preName);
2887  $firstCol = $this->‪hexColor($firstColArr);
2888  foreach ($colArr as $transparentColor) {
2889  $transparentColor = $this->‪convertColor($transparentColor);
2890  $transparentColor = $this->‪hexColor($transparentColor);
2891  $cmd = '-fill "' . $firstCol . '" -opaque "' . $transparentColor . '"';
2892  $this->‪imageMagickExec($preName, $postName, $cmd);
2893  $preName = $postName;
2894  }
2895  $this->‪imageMagickExec($postName, $origName, '');
2896  if (@is_file($origName)) {
2897  $tmpImg = $this->‪imageCreateFromFile($origName);
2898  }
2899  } else {
2900  $tmpImg = $img;
2901  }
2902  if ($tmpImg) {
2903  $img = $tmpImg;
2904  if ($closest) {
2905  $retCol = imagecolorclosest($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]);
2906  } else {
2907  $retCol = imagecolorexact($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]);
2908  }
2909  }
2910  // Unlink files from process
2911  if ($origName) {
2912  @unlink($origName);
2913  }
2914  if ($postName) {
2915  @unlink($postName);
2916  }
2917  }
2918  return $retCol;
2919  }
2920 
2932  public function ‪getTemporaryImageWithText($filename, $textline1, $textline2, $textline3)
2933  {
2934  if (empty(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'])) {
2935  throw new \RuntimeException('TYPO3 Fatal Error: No gdlib. ' . $textline1 . ' ' . $textline2 . ' ' . $textline3, 1270853952);
2936  }
2937  // Creates the basis for the error image
2938  $basePath = ‪ExtensionManagementUtility::extPath('core') . 'Resources/Public/Images/';
2939  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'])) {
2940  ‪$im = imagecreatefrompng($basePath . 'NotFound.png');
2941  } else {
2942  ‪$im = imagecreatefromgif($basePath . 'NotFound.gif');
2943  }
2944  // Sets background color and print color.
2945  $white = imagecolorallocate(‪$im, 255, 255, 255);
2946  $black = imagecolorallocate(‪$im, 0, 0, 0);
2947  // Prints the text strings with the build-in font functions of GD
2948  $x = 0;
2949  $font = 0;
2950  if ($textline1) {
2951  imagefilledrectangle(‪$im, $x, 9, 56, 16, $white);
2952  imagestring(‪$im, $font, $x, 9, $textline1, $black);
2953  }
2954  if ($textline2) {
2955  imagefilledrectangle(‪$im, $x, 19, 56, 26, $white);
2956  imagestring(‪$im, $font, $x, 19, $textline2, $black);
2957  }
2958  if ($textline3) {
2959  imagefilledrectangle(‪$im, $x, 29, 56, 36, $white);
2960  imagestring(‪$im, $font, $x, 29, substr($textline3, -14), $black);
2961  }
2962  // Outputting the image stream and exit
2963  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'])) {
2964  imagepng(‪$im, $filename);
2965  } else {
2966  imagegif(‪$im, $filename);
2967  }
2968  }
2969 
2977  protected function ‪compensateFontSizeiBasedOnFreetypeDpi($fontSize)
2978  {
2979  return $fontSize / 96.0 * 72;
2980  }
2981 }
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$OFFSET
‪array $OFFSET
Definition: GraphicalFunctions.php:262
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$im
‪resource $im
Definition: GraphicalFunctions.php:266
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getRenderedTextWidth
‪int getRenderedTextWidth($text, $conf)
Definition: GraphicalFunctions.php:1274
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcTextCordsForMap
‪array calcTextCordsForMap($cords, $offset, $conf)
Definition: GraphicalFunctions.php:843
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$saveAlphaLayer
‪bool $saveAlphaLayer
Definition: GraphicalFunctions.php:182
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\circleOffset
‪array circleOffset($distance, $iterations)
Definition: GraphicalFunctions.php:1352
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\fontResize
‪int fontResize($conf)
Definition: GraphicalFunctions.php:909
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getCachedImageDimensions
‪array bool getCachedImageDimensions($filePath)
Definition: GraphicalFunctions.php:2231
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEffect
‪makeEffect(&$im, $conf)
Definition: GraphicalFunctions.php:1559
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\hexColor
‪string hexColor($color)
Definition: GraphicalFunctions.php:2818
‪TYPO3\CMS\Core\Imaging
Definition: Dimension.php:2
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:23
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$alternativeOutputKey
‪string $alternativeOutputKey
Definition: GraphicalFunctions.php:166
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\convertColor
‪array convertColor($string)
Definition: GraphicalFunctions.php:1958
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$scalecmd
‪string $scalecmd
Definition: GraphicalFunctions.php:188
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\scale
‪scale(&$im, $conf)
Definition: GraphicalFunctions.php:1725
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeShadow
‪makeShadow(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1402
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\setWorkArea
‪setWorkArea($workArea)
Definition: GraphicalFunctions.php:1756
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:153
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeOutline
‪makeOutline(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1322
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeBox
‪makeBox(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:1500
‪TYPO3\CMS\Core\Utility\PathUtility\dirname
‪static string dirname($path)
Definition: PathUtility.php:185
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\output
‪string output($file)
Definition: GraphicalFunctions.php:2671
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getTextScalFactor
‪int getTextScalFactor($conf)
Definition: GraphicalFunctions.php:1191
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$allowedColorSpaceNames
‪array $allowedColorSpaceNames
Definition: GraphicalFunctions.php:64
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$webImageExt
‪array $webImageExt
Definition: GraphicalFunctions.php:110
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\IMparams
‪string IMparams($setup)
Definition: GraphicalFunctions.php:1575
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\__construct
‪__construct()
Definition: GraphicalFunctions.php:272
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$w
‪int $w
Definition: GraphicalFunctions.php:254
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\maskImageOntoImage
‪maskImageOntoImage(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:377
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$workArea
‪array $workArea
Definition: GraphicalFunctions.php:176
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$h
‪int $h
Definition: GraphicalFunctions.php:258
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\IMreduceColors
‪string IMreduceColors($file, $cols)
Definition: GraphicalFunctions.php:1861
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\renderTTFText
‪renderTTFText(&$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $conf, $sF=1)
Definition: GraphicalFunctions.php:1217
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$dontCheckForExistingTempFile
‪bool $dontCheckForExistingTempFile
Definition: GraphicalFunctions.php:152
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\applyImageMagickToPHPGif
‪applyImageMagickToPHPGif(&$im, $command)
Definition: GraphicalFunctions.php:2629
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getTemporaryImageWithText
‪getTemporaryImageWithText($filename, $textline1, $textline2, $textline3)
Definition: GraphicalFunctions.php:2899
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$IM_commands
‪array $IM_commands
Definition: GraphicalFunctions.php:172
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$imageMagickConvert_forceFileNameBody
‪string $imageMagickConvert_forceFileNameBody
Definition: GraphicalFunctions.php:146
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$mayScaleUp
‪bool $mayScaleUp
Definition: GraphicalFunctions.php:134
‪TYPO3\CMS\Core\Charset\CharsetConverter
Definition: CharsetConverter.php:54
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$processorEnabled
‪bool $processorEnabled
Definition: GraphicalFunctions.php:130
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$map
‪string $map
Definition: GraphicalFunctions.php:243
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$addFrameSelection
‪bool $addFrameSelection
Definition: GraphicalFunctions.php:40
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\ImageWrite
‪bool ImageWrite($destImg, $theImage, $quality=0)
Definition: GraphicalFunctions.php:2738
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$jpegQuality
‪int $jpegQuality
Definition: GraphicalFunctions.php:239
‪TYPO3\CMS\Core\Utility\PathUtility\basename
‪static string basename($path)
Definition: PathUtility.php:164
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getImageDimensions
‪array null getImageDimensions($imageFile)
Definition: GraphicalFunctions.php:2176
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\copyGifOntoGif
‪copyGifOntoGif(&$im, $cpImg, $conf, $workArea)
Definition: GraphicalFunctions.php:483
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$csConvObj
‪CharsetConverter $csConvObj
Definition: GraphicalFunctions.php:235
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:36
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\outputLevels
‪outputLevels(&$im, $low, $high, $swap=false)
Definition: GraphicalFunctions.php:1808
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$processorEffectsEnabled
‪bool $processorEffectsEnabled
Definition: GraphicalFunctions.php:116
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEmboss
‪makeEmboss(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1380
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions
Definition: GraphicalFunctions.php:35
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcBBox
‪array calcBBox($conf)
Definition: GraphicalFunctions.php:741
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$truecolorColors
‪int $truecolorColors
Definition: GraphicalFunctions.php:97
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\adjust
‪adjust(&$im, $conf)
Definition: GraphicalFunctions.php:1652
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\combineExec
‪string combineExec($input, $overlay, $mask, $output)
Definition: GraphicalFunctions.php:2497
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\autolevels
‪autolevels(&$im)
Definition: GraphicalFunctions.php:1778
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\splitString
‪array splitString($string, $splitRendering, $fontSize, $fontFile)
Definition: GraphicalFunctions.php:1036
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\gifCompress
‪static string gifCompress($theFile, $type)
Definition: GraphicalFunctions.php:2542
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\objPosition
‪array objPosition($conf, $workArea, $BB)
Definition: GraphicalFunctions.php:2011
‪TYPO3\CMS\Core\Utility\CommandUtility\exec
‪static string exec($command, &$output=null, &$returnValue=0)
Definition: CommandUtility.php:80
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeText
‪makeText(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:591
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getImageScale
‪array getImageScale($info, $w, $h, $options)
Definition: GraphicalFunctions.php:2298
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:34
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\init
‪init()
Definition: GraphicalFunctions.php:318
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\readPngGif
‪static string null readPngGif($theFile, $output_png=false)
Definition: GraphicalFunctions.php:2589
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$colorspace
‪string $colorspace
Definition: GraphicalFunctions.php:58
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\unifyColors
‪int unifyColors(&$img, $colArr, $closest=false)
Definition: GraphicalFunctions.php:2843
‪TYPO3\CMS\Core\Utility\CommandUtility\escapeShellArgument
‪static string escapeShellArgument($input)
Definition: CommandUtility.php:503
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$filenamePrefix
‪string $filenamePrefix
Definition: GraphicalFunctions.php:140
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$pixelLimitGif
‪int $pixelLimitGif
Definition: GraphicalFunctions.php:206
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$colMap
‪array $colMap
Definition: GraphicalFunctions.php:212
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\destroy
‪destroy()
Definition: GraphicalFunctions.php:2713
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\generateStatusHashForImageFile
‪string generateStatusHashForImageFile($filePath)
Definition: GraphicalFunctions.php:2280
‪TYPO3\CMS\Core\Type\File\ImageInfo
Definition: ImageInfo.php:25
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$cmds
‪array $cmds
Definition: GraphicalFunctions.php:120
‪$output
‪$output
Definition: annotationChecker.php:113
‪debug
‪debug($variable='', $title=null, $group=null)
Definition: GlobalDebugFunctions.php:5
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\v5_blur
‪string v5_blur($factor)
Definition: GraphicalFunctions.php:1913
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\compensateFontSizeiBasedOnFreetypeDpi
‪float compensateFontSizeiBasedOnFreetypeDpi($fontSize)
Definition: GraphicalFunctions.php:2944
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageMagickIdentify
‪array null imageMagickIdentify($imagefile)
Definition: GraphicalFunctions.php:2420
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\SpacedImageTTFText
‪SpacedImageTTFText(&$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF=1)
Definition: GraphicalFunctions.php:876
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageMagickConvert
‪array null imageMagickConvert($imagefile, $newExt='', $w='', $h='', $params='', $frame='', $options=[], $mustCreate=false)
Definition: GraphicalFunctions.php:2067
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$gifExtension
‪string $gifExtension
Definition: GraphicalFunctions.php:46
‪TYPO3\CMS\Core\Imaging\ImageMagickFile\fromFilePath
‪static ImageMagickFile fromFilePath(string $filePath, int $frame=null)
Definition: ImageMagickFile.php:111
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:23
‪$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:562
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:39
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\txtPosition
‪array txtPosition($conf, $workArea, $BB)
Definition: GraphicalFunctions.php:690
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$setup
‪array $setup
Definition: GraphicalFunctions.php:250
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\extPath
‪static string extPath($key, $script='')
Definition: ExtensionManagementUtility.php:149
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageCreateFromFile
‪resource imageCreateFromFile($sourceImg)
Definition: GraphicalFunctions.php:2778
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\cacheImageDimensions
‪bool cacheImageDimensions(array $identifyResult)
Definition: GraphicalFunctions.php:2205
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getWordPairsForLineBreak
‪array getWordPairsForLineBreak($string)
Definition: GraphicalFunctions.php:1256
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\ImageTTFTextWrapper
‪ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF=1)
Definition: GraphicalFunctions.php:992
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\v5_sharpen
‪string v5_sharpen($factor)
Definition: GraphicalFunctions.php:1894
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$dontCompress
‪bool $dontCompress
Definition: GraphicalFunctions.php:158
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$gdlibExtensions
‪array $gdlibExtensions
Definition: GraphicalFunctions.php:52
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\randomName
‪string randomName()
Definition: GraphicalFunctions.php:1930
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\getBreakSpace
‪int getBreakSpace($conf, array $boundingBox=null)
Definition: GraphicalFunctions.php:1294
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$im5fx_sharpenSteps
‪string $im5fx_sharpenSteps
Definition: GraphicalFunctions.php:200
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\executeIdentifyCommandForImageFile
‪string null executeIdentifyCommandForImageFile(string $imageFile)
Definition: GraphicalFunctions.php:2442
‪TYPO3\CMS\Core\Utility\CommandUtility
Definition: CommandUtility.php:48
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEllipse
‪makeEllipse(&$im, array $conf, array $workArea)
Definition: GraphicalFunctions.php:1539
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\ImageTTFBBoxWrapper
‪array ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF=1)
Definition: GraphicalFunctions.php:950
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\inputLevels
‪inputLevels(&$im, $low, $high)
Definition: GraphicalFunctions.php:1837
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcWordSpacing
‪array calcWordSpacing($conf, $scaleFactor=1)
Definition: GraphicalFunctions.php:1174
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\gif_or_jpg
‪string gif_or_jpg($type, $w, $h)
Definition: GraphicalFunctions.php:2654
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imgTag
‪string imgTag($imgInfo)
Definition: GraphicalFunctions.php:2724
‪TYPO3\CMS\Core\Utility\CommandUtility\imageMagickCommand
‪static string imageMagickCommand($command, $parameters, $path='')
Definition: CommandUtility.php:93
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\imageMagickExec
‪string imageMagickExec($input, $output, $params, $frame=0)
Definition: GraphicalFunctions.php:2466
‪TYPO3\CMS\Core\Utility\ArrayUtility\filterAndSortByNumericKeys
‪static array filterAndSortByNumericKeys($setupArr, $acceptAnyKeys=false)
Definition: ArrayUtility.php:772
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\applyOffset
‪array applyOffset($cords, $OFFSET)
Definition: GraphicalFunctions.php:1944
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\generateCacheKeyForImageFile
‪string generateCacheKeyForImageFile($filePath)
Definition: GraphicalFunctions.php:2268
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\copyImageOntoImage
‪copyImageOntoImage(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:461
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\addToMap
‪addToMap($cords, $conf)
Definition: GraphicalFunctions.php:824
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$im5fx_blurSteps
‪string $im5fx_blurSteps
Definition: GraphicalFunctions.php:194
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static string getVarPath()
Definition: Environment.php:165
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\crop
‪crop(&$im, $conf)
Definition: GraphicalFunctions.php:1687
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$imageFileExt
‪array $imageFileExt
Definition: GraphicalFunctions.php:104