imageLib::resolveMeteringMode()   B
last analyzed

Complexity

Conditions 9
Paths 9

Size

Total Lines 33
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 28
nc 9
nop 1
dl 0
loc 33
rs 8.0555
c 0
b 0
f 0
1
<?php
2
   # ========================================================================#
3
   #
4
   #  This work is licensed under the Creative Commons Attribution 3.0 Unported
5
   #  License. To view a copy of this license,
6
   #  visit http://creativecommons.org/licenses/by/3.0/ or send a letter to
7
   #  Creative Commons, 444 Castro Street, Suite 900, Mountain View, California,
8
   #  94041, USA.
9
   #
10
   #  All rights reserved.
11
   #
12
   #  Author:    Jarrod Oberto
13
   #  Version:   1.5.1
14
   #  Date:      10-05-11
15
   #  Purpose:   Provide tools for image manipulation using GD
16
   #  Param In:  See functions.
17
   #  Param Out: Produces a resized image
18
   #  Requires : Requires PHP GD library.
19
   #  Usage Example:
20
   #                     include("lib/php_image_magician.php");
21
   #                     $magicianObj = new resize('images/car.jpg');
22
   #                     $magicianObj -> resizeImage(150, 100, 0);
23
   #                     $magicianObj -> saveImage('images/car_small.jpg', 100);
24
   #
25
   #        - See end of doc for more examples -
26
   #
27
   #  Supported file types include: jpg, png, gif, bmp, psd (read)
28
   #
29
   #
30
   #
31
   #  The following functions are taken from phpThumb() [available from
32
   #    http://phpthumb.sourceforge.net], and are used with written permission
33
   #  from James Heinrich.
34
   #    - GD2BMPstring
35
   #      - GetPixelColor
36
   #      - LittleEndian2String
37
   #
38
   #  The following functions are from Marc Hibbins and are used with written
39
   #  permission (are also under the Attribution-ShareAlike
40
   #  [http://creativecommons.org/licenses/by-sa/3.0/] license.
41
   #    -
42
   #
43
   #  PhpPsdReader is used with written permission from Tim de Koning.
44
   #  [http://www.kingsquare.nl/phppsdreader]
45
   #
46
   #
47
   #
48
   #  Modificatoin history
49
   #  Date      Initials  Ver Description
50
   #  10-05-11  J.C.O   0.0 Initial build
51
   #  01-06-11  J.C.O   0.1.1   * Added reflections
52
   #              * Added Rounded corners
53
   #              * You can now use PNG interlacing
54
   #              * Added shadow
55
   #              * Added caption box
56
   #              * Added vintage filter
57
   #              * Added dynamic image resizing (resize on the fly)
58
   #              * minor bug fixes
59
   #  05-06-11  J.C.O   0.1.1.1 * Fixed undefined variables
60
   #  17-06-11  J.C.O   0.1.2   * Added image_batch_class.php class
61
   #              * Minor bug fixes
62
   #  26-07-11  J.C.O   0.1.4 * Added support for external images
63
   #              * Can now set the crop poisition
64
   #  03-08-11  J.C.O   0.1.5 * Added reset() method to reset resource to
65
   #                original input file.
66
   #              * Added method addTextToCaptionBox() to
67
   #                simplify adding text to a caption box.
68
   #              * Added experimental writeIPTC. (not finished)
69
   #              * Added experimental readIPTC. (not finished)
70
   #  11-08-11  J.C.O     * Added initial border presets.
71
   #  30-08-11  J.C.O     * Added 'auto' crop option to crop portrait
72
   #                images near the top.
73
   #  08-09-11  J.C.O     * Added cropImage() method to allow standalone
74
   #                cropping.
75
   #  17-09-11  J.C.O     * Added setCropFromTop() set method - set the
76
   #                percentage to crop from the top when using
77
   #                crop 'auto' option.
78
   #              * Added setTransparency() set method - allows you
79
   #                to turn transparency off (like when saving
80
   #                as a jpg).
81
   #              * Added setFillColor() set method - set the
82
   #                background color to use instead of transparency.
83
   #  05-11-11  J.C.O   0.1.5.1 * Fixed interlacing option
84
   #  0-07-12  J.C.O   1.0
85
   #
86
   #  Known issues & Limitations:
87
   # -------------------------------
88
   #  Not so much an issue, the image is destroyed on the deconstruct rather than
89
   #  when we have finished with it. The reason for this is that we don't know
90
   #  when we're finished with it as you can both save the image and display
91
   #  it directly to the screen (imagedestroy($this->imageResized))
92
   #
93
   #  Opening BMP files is slow. A test with 884 bmp files processed in a loop
94
   #  takes forever - over 5 min. This test inlcuded opening the file, then
95
   #  getting and displaying its width and height.
96
   #
97
   #  $forceStretch:
98
   # -------------------------------
99
   #  On by default.
100
   #  $forceStretch can be disabled by calling method setForceStretch with false
101
   #  parameter. If disabled, if an images original size is smaller than the size
102
   #  specified by the user, the original size will be used. This is useful when
103
   #  dealing with small images.
104
   #
105
   #  If enabled, images smaller than the size specified will be stretched to
106
   #  that size.
107
   #
108
   #  Tips:
109
   # -------------------------------
110
   #  * If you're resizing a transparent png and saving it as a jpg, set
111
   #  $keepTransparency to false with: $magicianObj->setTransparency(false);
112
   #
113
   #  FEATURES:
114
   #    * EASY TO USE
115
   #    * BMP SUPPORT (read & write)
116
   #    * PSD (photoshop) support (read)
117
   #    * RESIZE IMAGES
118
   #      - Preserve transparency (png, gif)
119
   #      - Apply sharpening (jpg) (requires PHP >= 5.1.0)
120
   #      - Set image quality (jpg, png)
121
   #      - Resize modes:
122
   #        - exact size
123
   #        - resize by width (auto height)
124
   #        - resize by height (auto width)
125
   #        - auto (automatically determine the best of the above modes to use)
126
   #        - crop - resize as best as it can then crop the rest
127
   #      - Force stretching of smaller images (upscale)
128
   #    * APPLY FILTERS
129
   #      - Convert to grey scale
130
   #      - Convert to black and white
131
   #      - Convert to sepia
132
   #      - Convert to negative
133
   #    * ROTATE IMAGES
134
   #      - Rotate using predefined "left", "right", or "180"; or any custom degree amount
135
   #    * EXTRACT EXIF DATA (requires exif module)
136
   #      - make
137
   #      - model
138
   #      - date
139
   #      - exposure
140
   #      - aperture
141
   #      - f-stop
142
   #      - iso
143
   #      - focal length
144
   #      - exposure program
145
   #      - metering mode
146
   #      - flash status
147
   #      - creator
148
   #      - copyright
149
   #    * ADD WATERMARK
150
   #      - Specify exact x, y placement
151
   #      - Or, specify using one of the 9 pre-defined placements such as "tl"
152
   #        (for top left), "m" (for middle), "br" (for bottom right)
153
   #        - also specify padding from edge amount (optional).
154
   #      - Set opacity of watermark (png).
155
   #    * ADD BORDER
156
   #    * USE HEX WHEN SPECIFYING COLORS (eg: #ffffff)
157
   #    * SAVE IMAGE OR OUTPUT TO SCREEN
158
   #
159
   #
160
   # ========================================================================#
161
162
163
class imageLib
164
{
165
166
    private $fileName;
167
    private $image;
168
    protected $imageResized;
169
    private $widthOriginal;     # Always be the original width
170
    private $heightOriginal;
171
    private $width;         # Current width (width after resize)
172
    private $height;
173
    private $imageSize;
174
  private $fileExtension;
175
176
  private $debug = true;
177
  private $errorArray = array();
178
179
  private $forceStretch = true;
180
  private $aggresiveSharpening = false;
181
182
  private $transparentArray = array('.png', '.gif');
183
  private $keepTransparency = true;
184
  private $fillColorArray = array('r'=>255, 'g'=>255, 'b'=>255);
185
186
  private $sharpenArray = array('jpg');
187
188
  private $psdReaderPath;
189
  private $filterOverlayPath;
190
191
  private $isInterlace;
192
193
  private $captionBoxPositionArray = array();
194
195
  private $fontDir = 'fonts';
196
197
  private $cropFromTopPercent = 10;
198
199
200
## --------------------------------------------------------
201
202
    function __construct($fileName)
203
    # Author:     Jarrod Oberto
204
  # Date:     27-02-08
205
    # Purpose:    Constructor
206
    # Param in:   $fileName: File name and path.
207
    # Param out:  n/a
208
    # Reference:
209
    # Notes:
210
    #
211
    {
212
    if (!$this->testGDInstalled()) { if ($this->debug) { throw new Exception('The GD Library is not installed.'); }else{ throw new Exception(); }};
213
214
    $this->initialise();
215
216
        // *** Save the image file name. Only store this incase you want to display it
217
        $this->fileName = $fileName;
218
    $this->fileExtension = fix_strtolower(strrchr($fileName, '.'));
219
220
        // *** Open up the file
221
        $this->image = $this->openImage($fileName);
222
223
224
    // *** Assign here so we don't modify the original
225
    $this->imageResized = $this->image;
226
227
        // *** If file is an image
228
        if ($this->testIsImage($this->image))
229
        {
230
            // *** Get width and height
231
            $this->width  = imagesx($this->image);
232
            $this->widthOriginal = imagesx($this->image);
233
            $this->height = imagesy($this->image);
234
            $this->heightOriginal = imagesy($this->image);
235
236
237
        /*  Added 15-09-08
238
         *  Get the filesize using this build in method.
239
         *  Stores an array of size
240
         *
241
         *  $this->imageSize[1] = width
242
         *  $this->imageSize[2] = height
243
         *  $this->imageSize[3] = width x height
244
         *
245
         */
246
            $this->imageSize = getimagesize($this->fileName);
247
248
        } else {
249
      $this->errorArray[] = 'File is not an image';
250
    }
251
    }
252
253
## --------------------------------------------------------
254
255
  private function initialise () {
256
257
    $this->psdReaderPath = __DIR__ . '/classPhpPsdReader.php';
258
    $this->filterOverlayPath = __DIR__ . '/filters';
259
260
    // *** Set if image should be interlaced or not.
261
    $this->isInterlace = false;
262
  }
263
264
265
266
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
267
  Resize
268
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
269
270
271
    public function resizeImage($newWidth, $newHeight, $option = 0, $sharpen = false, $autoRotate = false)
272
    # Author:     Jarrod Oberto
273
    # Date:       27-02-08
274
    # Purpose:    Resizes the image
275
    # Param in:   $newWidth:
276
    #             $newHeight:
277
    #             $option:     0 / exact = defined size;
278
    #                          1 / portrait = keep aspect set height;
279
    #                          2 / landscape = keep aspect set width;
280
    #                          3 / auto = auto;
281
  #                          4 / crop= resize and crop;
282
  #
283
  #         $option can also be an array containing options for
284
  #         cropping. E.G., array('crop', 'r')
285
  #
286
  #         This array only applies to 'crop' and the 'r' refers to
287
  #         "crop right". Other value include; tl, t, tr, l, m (default),
288
  #         r, bl, b, br, or you can specify your own co-ords (which
289
  #         isn't recommended.
290
  #
291
  #       $sharpen:    true: sharpen (jpg only);
292
  #                false: don't sharpen
293
    # Param out:  n/a
294
    # Reference:
295
    # Notes:      To clarify the $option input:
296
    #               0 = The exact height and width dimensions you set.
297
    #               1 = Whatever height is passed in will be the height that
298
    #                   is set. The width will be calculated and set automatically
299
    #                   to a the value that keeps the original aspect ratio.
300
    #               2 = The same but based on the width. We try make the image the
301
  #                  biggest size we can while stil fitting inside the box size
302
    #               3 = Depending whether the image is landscape or portrait, this
303
    #                   will automatically determine whether to resize via
304
    #                   dimension 1,2 or 0
305
  #               4 = Will resize and then crop the image for best fit
306
  #
307
  #       forceStretch can be applied to options 1,2,3 and 4
308
    #
309
    {
310
311
    // *** We can pass in an array of options to change the crop position
312
    $cropPos = 'm';
313
    if (is_array($option) && fix_strtolower($option[0]) === 'crop') {
314
      $cropPos = $option[1];         # get the crop option
315
    } else if (strpos($option, '-') !== false) {
316
      // *** Or pass in a hyphen seperated option
317
      $optionPiecesArray = explode('-', $option);
318
      $cropPos = end($optionPiecesArray);
319
    }
320
321
    // *** Check the option is valid
322
    $option = $this->prepOption($option);
323
324
    // *** Make sure the file passed in is valid
325
    if (!$this->image) { if ($this->debug) { throw new Exception('file ' . $this->getFileName() .' is missing or invalid'); }else{ throw new Exception(); }};
326
327
    // *** Get optimal width and height - based on $option
328
    $dimensionsArray = $this->getDimensions($newWidth, $newHeight, $option);
329
330
    $optimalWidth  = $dimensionsArray['optimalWidth'];
331
    $optimalHeight = $dimensionsArray['optimalHeight'];
332
333
    // *** Resample - create image canvas of x, y size
334
    $this->imageResized = imagecreatetruecolor($optimalWidth, $optimalHeight);
335
    $this->keepTransparancy($optimalWidth, $optimalHeight, $this->imageResized);
336
    imagecopyresampled($this->imageResized, $this->image, 0, 0, 0, 0, $optimalWidth, $optimalHeight, $this->width, $this->height);
337
338
339
    // *** If '4', then crop too
340
    if ($option == 4 || $option === 'crop') {
341
342
      if (($optimalWidth >= $newWidth && $optimalHeight >= $newHeight)) {
343
        $this->crop($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos);
344
      }
345
    }
346
347
    // *** If Rotate.
348
    if ($autoRotate) {
349
350
      $exifData = $this->getExif(false);
351
      if (count($exifData) > 0) {
352
353
        switch($exifData['orientation']) {
354
            case 8:
355
                $this->imageResized = imagerotate($this->imageResized,90,0);
356
                break;
357
            case 3:
358
                $this->imageResized = imagerotate($this->imageResized,180,0);
359
                break;
360
            case 6:
361
                $this->imageResized = imagerotate($this->imageResized,-90,0);
362
                break;
363
        }
364
      }
365
    }
366
367
    // *** Sharpen image (if jpg and the user wishes to do so)
368
    if ($sharpen && in_array($this->fileExtension, $this->sharpenArray)) {
369
370
      // *** Sharpen
371
      $this->sharpen();
372
    }
373
    }
374
375
## --------------------------------------------------------
376
377
  public function cropImage($newWidth, $newHeight, $cropPos = 'm')
378
    # Author:     Jarrod Oberto
379
    # Date:       08-09-11
380
    # Purpose:    Crops the image
381
    # Param in:   $newWidth: crop with
382
    #             $newHeight: crop height
383
  #       $cropPos: Can be any of the following:
384
  #             tl, t, tr, l, m, r, bl, b, br, auto
385
  #           Or:
386
  #             a custom position such as '30x50'
387
    # Param out:  n/a
388
    # Reference:
389
    # Notes:
390
    #
391
  {
392
393
    // *** Make sure the file passed in is valid
394
    if (!$this->image) { if ($this->debug) { throw new Exception('file ' . $this->getFileName() .' is missing or invalid'); }else{ throw new Exception(); }};
395
396
    $this->imageResized = $this->image;
397
    $this->crop($this->width, $this->height, $newWidth, $newHeight, $cropPos);
398
399
  }
400
401
## --------------------------------------------------------
402
403
  private function keepTransparancy($width, $height, $im)
404
    # Author:     Jarrod Oberto
405
    # Date:       08-04-11
406
    # Purpose:    Keep transparency for png and gif image
407
    # Param in:
408
    # Param out:  n/a
409
    # Reference:
410
    # Notes:
411
    #
412
  {
413
    // *** If PNG, perform some transparency retention actions (gif untested)
414
    if (in_array($this->fileExtension, $this->transparentArray) && $this->keepTransparency) {
415
      imagealphablending($im, false);
416
      imagesavealpha($im, true);
417
      $transparent = imagecolorallocatealpha($im, 255, 255, 255, 127);
418
      imagefilledrectangle($im, 0, 0, $width, $height, $transparent);
419
    } else {
420
      $color = imagecolorallocate($im, $this->fillColorArray['r'], $this->fillColorArray['g'], $this->fillColorArray['b']);
421
      imagefilledrectangle($im, 0, 0, $width, $height, $color);
422
    }
423
  }
424
425
## --------------------------------------------------------
426
427
    private function crop($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos)
428
    # Author:     Jarrod Oberto
429
    # Date:       15-09-08
430
    # Purpose:    Crops the image
431
    # Param in:   $newWidth:
432
    #             $newHeight:
433
    # Param out:  n/a
434
    # Reference:
435
    # Notes:
436
    #
437
    {
438
439
    // *** Get cropping co-ordinates
440
    $cropArray = $this->getCropPlacing($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos);
441
    $cropStartX = $cropArray['x'];
442
    $cropStartY = $cropArray['y'];
443
444
    // *** Crop this bad boy
445
    $crop = imagecreatetruecolor($newWidth , $newHeight);
446
    $this->keepTransparancy($optimalWidth, $optimalHeight, $crop);
447
    imagecopyresampled($crop, $this->imageResized, 0, 0, $cropStartX, $cropStartY, $newWidth, $newHeight , $newWidth, $newHeight);
0 ignored issues
show
Bug introduced by
It seems like $cropStartY can also be of type string; however, parameter $src_y of imagecopyresampled() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

447
    imagecopyresampled($crop, $this->imageResized, 0, 0, $cropStartX, /** @scrutinizer ignore-type */ $cropStartY, $newWidth, $newHeight , $newWidth, $newHeight);
Loading history...
Bug introduced by
It seems like $cropStartX can also be of type string; however, parameter $src_x of imagecopyresampled() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

447
    imagecopyresampled($crop, $this->imageResized, 0, 0, /** @scrutinizer ignore-type */ $cropStartX, $cropStartY, $newWidth, $newHeight , $newWidth, $newHeight);
Loading history...
448
449
    $this->imageResized = $crop;
450
451
    // *** Set new width and height to our variables
452
    $this->width = $newWidth;
453
    $this->height = $newHeight;
454
455
    }
456
457
## --------------------------------------------------------
458
459
  private function getCropPlacing($optimalWidth, $optimalHeight, $newWidth, $newHeight, $pos='m')
460
  #
461
  # Author:   Jarrod Oberto
462
  # Date:   July 11
463
  # Purpose:  Set the cropping area.
464
  # Params in:
465
  # Params out: (array) the crop x and y co-ordinates.
466
  # Notes:    When specifying the exact pixel crop position (eg 10x15), be
467
  #       very careful as it's easy to crop out of the image leaving
468
  #       black borders.
469
  #
470
  {
471
    $pos = fix_strtolower($pos);
472
473
    // *** If co-ords have been entered
474
    if (strstr($pos, 'x')) {
475
      $pos = str_replace(' ', '', $pos);
476
477
      $xyArray = explode('x', $pos);
478
      list($cropStartX, $cropStartY) = $xyArray;
479
480
    } else {
481
482
      switch ($pos) {
483
        case 'tl':
484
          $cropStartX = 0;
485
          $cropStartY = 0;
486
          break;
487
488
        case 't':
489
          $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
490
          $cropStartY = 0;
491
          break;
492
493
        case 'tr':
494
          $cropStartX = $optimalWidth - $newWidth;
495
          $cropStartY = 0;
496
          break;
497
498
        case 'l':
499
          $cropStartX = 0;
500
          $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
501
          break;
502
503
        case 'm':
504
          $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
505
          $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
506
          break;
507
508
        case 'r':
509
          $cropStartX = $optimalWidth - $newWidth;
510
          $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
511
          break;
512
513
        case 'bl':
514
          $cropStartX = 0;
515
          $cropStartY = $optimalHeight - $newHeight;
516
          break;
517
518
        case 'b':
519
          $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
520
          $cropStartY = $optimalHeight - $newHeight;
521
          break;
522
523
        case 'br':
524
          $cropStartX = $optimalWidth - $newWidth;
525
          $cropStartY = $optimalHeight - $newHeight;
526
          break;
527
528
        case 'auto':
529
          // *** If image is a portrait crop from top, not center. v1.5
530
          if ($optimalHeight > $optimalWidth) {
531
            $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
532
            $cropStartY = ($this->cropFromTopPercent /100) * $optimalHeight;
533
          } else {
534
535
            // *** Else crop from the center
536
            $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
537
            $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
538
          }
539
          break;
540
541
        default:
542
          // *** Default to center
543
          $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );
544
          $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );
545
          break;
546
      }
547
    }
548
549
    return array('x' => $cropStartX, 'y' => $cropStartY);
550
  }
551
552
## --------------------------------------------------------
553
554
  private function getDimensions($newWidth, $newHeight, $option)
555
    # Author:     Jarrod Oberto
556
    # Date:       17-11-09
557
    # Purpose:    Get new image dimensions based on user specificaions
558
    # Param in:   $newWidth:
559
    #             $newHeight:
560
    # Param out:  Array of new width and height values
561
    # Reference:
562
    # Notes:    If $option = 3 then this function is call recursivly
563
  #
564
  #       To clarify the $option input:
565
    #               0 = The exact height and width dimensions you set.
566
    #               1 = Whatever height is passed in will be the height that
567
    #                   is set. The width will be calculated and set automatically
568
    #                   to a the value that keeps the original aspect ratio.
569
    #               2 = The same but based on the width.
570
    #               3 = Depending whether the image is landscape or portrait, this
571
    #                   will automatically determine whether to resize via
572
    #                   dimension 1,2 or 0.
573
  #               4 = Resize the image as much as possible, then crop the
574
  #         remainder.
575
  {
576
577
        switch ((string)($option))
578
        {
579
            case '0':
580
      case 'exact':
581
                $optimalWidth = $newWidth;
582
                $optimalHeight= $newHeight;
583
                break;
584
            case '1':
585
      case 'portrait':
586
                $dimensionsArray = $this->getSizeByFixedHeight($newWidth, $newHeight);
587
        $optimalWidth = $dimensionsArray['optimalWidth'];
588
        $optimalHeight = $dimensionsArray['optimalHeight'];
589
                break;
590
            case '2':
591
      case 'landscape':
592
                $dimensionsArray = $this->getSizeByFixedWidth($newWidth, $newHeight);
593
        $optimalWidth = $dimensionsArray['optimalWidth'];
594
        $optimalHeight = $dimensionsArray['optimalHeight'];
595
                break;
596
            case '3':
597
      case 'auto':
598
                $dimensionsArray = $this->getSizeByAuto($newWidth, $newHeight);
599
        $optimalWidth = $dimensionsArray['optimalWidth'];
600
        $optimalHeight = $dimensionsArray['optimalHeight'];
601
                break;
602
      case '4':
603
      case 'crop':
604
                $dimensionsArray = $this->getOptimalCrop($newWidth, $newHeight);
605
        $optimalWidth = $dimensionsArray['optimalWidth'];
606
        $optimalHeight = $dimensionsArray['optimalHeight'];
607
                break;
608
        }
609
610
    return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $optimalHeight does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $optimalWidth does not seem to be defined for all execution paths leading up to this point.
Loading history...
611
  }
612
613
## --------------------------------------------------------
614
615
    private function getSizeByFixedHeight($newWidth, $newHeight)
0 ignored issues
show
Unused Code introduced by
The parameter $newWidth is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

615
    private function getSizeByFixedHeight(/** @scrutinizer ignore-unused */ $newWidth, $newHeight)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
616
    {
617
    // *** If forcing is off...
618
    if (!$this->forceStretch) {
619
620
      // *** ...check if actual height is less than target height
621
      if ($this->height < $newHeight) {
622
        return array('optimalWidth' => $this->width, 'optimalHeight' => $this->height);
623
      }
624
    }
625
626
        $ratio = $this->width / $this->height;
627
628
        $newWidth = $newHeight * $ratio;
629
630
        //return $newWidth;
631
    return array('optimalWidth' => $newWidth, 'optimalHeight' => $newHeight);
632
    }
633
634
## --------------------------------------------------------
635
636
    private function getSizeByFixedWidth($newWidth, $newHeight)
0 ignored issues
show
Unused Code introduced by
The parameter $newHeight is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

636
    private function getSizeByFixedWidth($newWidth, /** @scrutinizer ignore-unused */ $newHeight)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
637
    {
638
    // *** If forcing is off...
639
    if (!$this->forceStretch) {
640
641
      // *** ...check if actual width is less than target width
642
      if ($this->width < $newWidth) {
643
        return array('optimalWidth' => $this->width, 'optimalHeight' => $this->height);
644
      }
645
    }
646
647
    $ratio = $this->height / $this->width;
648
649
        $newHeight = $newWidth * $ratio;
650
651
        //return $newHeight;
652
    return array('optimalWidth' => $newWidth, 'optimalHeight' => $newHeight);
653
    }
654
655
## --------------------------------------------------------
656
657
    private function getSizeByAuto($newWidth, $newHeight)
658
    # Author:     Jarrod Oberto
659
    # Date:       19-08-08
660
    # Purpose:    Depending on the height, choose to resize by 0, 1, or 2
661
    # Param in:   The new height and new width
662
    # Notes:
663
    #
664
    {
665
    // *** If forcing is off...
666
    if (!$this->forceStretch) {
667
668
      // *** ...check if actual size is less than target size
669
      if ($this->width < $newWidth && $this->height < $newHeight) {
670
        return array('optimalWidth' => $this->width, 'optimalHeight' => $this->height);
671
      }
672
    }
673
674
        if ($this->height < $this->width)
675
        // *** Image to be resized is wider (landscape)
676
        {
677
            //$optimalWidth = $newWidth;
678
            //$optimalHeight= $this->getSizeByFixedWidth($newWidth);
679
680
            $dimensionsArray = $this->getSizeByFixedWidth($newWidth, $newHeight);
681
      $optimalWidth = $dimensionsArray['optimalWidth'];
682
      $optimalHeight = $dimensionsArray['optimalHeight'];
683
        }
684
        elseif ($this->height > $this->width)
685
        // *** Image to be resized is taller (portrait)
686
        {
687
            //$optimalWidth = $this->getSizeByFixedHeight($newHeight);
688
            //$optimalHeight= $newHeight;
689
690
            $dimensionsArray = $this->getSizeByFixedHeight($newWidth, $newHeight);
691
      $optimalWidth = $dimensionsArray['optimalWidth'];
692
      $optimalHeight = $dimensionsArray['optimalHeight'];
693
        }
694
    else
695
        // *** Image to be resizerd is a square
696
        {
697
698
      if ($newHeight < $newWidth) {
699
          //$optimalWidth = $newWidth;
700
        //$optimalHeight= $this->getSizeByFixedWidth($newWidth);
701
                $dimensionsArray = $this->getSizeByFixedWidth($newWidth, $newHeight);
702
        $optimalWidth = $dimensionsArray['optimalWidth'];
703
        $optimalHeight = $dimensionsArray['optimalHeight'];
704
      } else if ($newHeight > $newWidth) {
705
          //$optimalWidth = $this->getSizeByFixedHeight($newHeight);
706
            //$optimalHeight= $newHeight;
707
                $dimensionsArray = $this->getSizeByFixedHeight($newWidth, $newHeight);
708
        $optimalWidth = $dimensionsArray['optimalWidth'];
709
        $optimalHeight = $dimensionsArray['optimalHeight'];
710
      } else {
711
        // *** Sqaure being resized to a square
712
        $optimalWidth = $newWidth;
713
        $optimalHeight= $newHeight;
714
      }
715
        }
716
717
    return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight);
718
    }
719
720
## --------------------------------------------------------
721
722
    private function getOptimalCrop($newWidth, $newHeight)
723
  # Author:     Jarrod Oberto
724
    # Date:       17-11-09
725
    # Purpose:    Get optimal crop dimensions
726
    # Param in:   width and height as requested by user (fig 3)
727
    # Param out:  Array of optimal width and height (fig 2)
728
    # Reference:
729
    # Notes:      The optimal width and height return are not the same as the
730
  #       same as the width and height passed in. For example:
731
  #
732
  #
733
  #   |-----------------|     |------------|       |-------|
734
  #   |             |   =>  |**|      |**|   =>  |       |
735
  #   |             |     |**|      |**|       |       |
736
    #   |           |       |------------|       |-------|
737
  #   |-----------------|
738
  #        original                optimal             crop
739
  #              size                   size               size
740
  #  Fig          1                      2                  3
741
  #
742
  #       300 x 250           150 x 125          150 x 100
743
  #
744
  #    The optimal size is the smallest size (that is closest to the crop size)
745
  #    while retaining proportion/ratio.
746
  #
747
  #  The crop size is the optimal size that has been cropped on one axis to
748
  #  make the image the exact size specified by the user.
749
  #
750
  #               * represent cropped area
751
  #
752
  {
753
754
    // *** If forcing is off...
755
    if (!$this->forceStretch) {
756
757
      // *** ...check if actual size is less than target size
758
      if ($this->width < $newWidth && $this->height < $newHeight) {
759
        return array('optimalWidth' => $this->width, 'optimalHeight' => $this->height);
760
      }
761
    }
762
763
    $heightRatio = $this->height / $newHeight;
764
    $widthRatio  = $this->width /  $newWidth;
765
766
    if ($heightRatio < $widthRatio) {
767
      $optimalRatio = $heightRatio;
768
    } else {
769
      $optimalRatio = $widthRatio;
770
    }
771
772
    $optimalHeight = round( $this->height / $optimalRatio );
773
    $optimalWidth  = round( $this->width  / $optimalRatio );
774
775
    return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight);
776
  }
777
778
## --------------------------------------------------------
779
780
  private function sharpen()
781
    # Author:     Jarrod Oberto
782
    # Date:       08 04 2011
783
    # Purpose:    Sharpen image
784
    # Param in:   n/a
785
    # Param out:  n/a
786
    # Reference:
787
    # Notes:
788
    # Credit:   Incorporates Joe Lencioni (August 6, 2008) code
789
  {
790
791
    if (version_compare(PHP_VERSION, '5.1.0') >= 0) {
792
793
      // ***
794
      if ($this->aggresiveSharpening) { # A more aggressive sharpening solution
795
796
        $sharpenMatrix = array( array( -1, -1, -1 ),
797
                         array( -1, 16, -1 ),
798
                         array( -1, -1, -1 ) );
799
        $divisor = 8;
800
        $offset = 0;
801
802
        imageconvolution($this->imageResized, $sharpenMatrix, $divisor, $offset);
803
      }
804
      else # More subtle and personally more desirable
805
      {
806
        $sharpness  = $this->findSharp($this->widthOriginal, $this->width);
807
808
        $sharpenMatrix  = array(
809
          array(-1, -2, -1),
810
          array(-2, $sharpness + 12, -2), //Lessen the effect of a filter by increasing the value in the center cell
811
          array(-1, -2, -1)
812
        );
813
        $divisor    = $sharpness; // adjusts brightness
814
        $offset     = 0;
815
        imageconvolution($this->imageResized, $sharpenMatrix, $divisor, $offset);
816
      }
817
    }
818
    else
819
    {
820
      if ($this->debug) { throw new Exception('Sharpening required PHP 5.1.0 or greater.'); }
821
    }
822
  }
823
824
  ## --------------------------------------------------------
825
826
  private function sharpen2($level)
0 ignored issues
show
Unused Code introduced by
The method sharpen2() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
827
  {
828
      $sharpenMatrix  = array(
0 ignored issues
show
Unused Code introduced by
The assignment to $sharpenMatrix is dead and can be removed.
Loading history...
829
        array($level, $level, $level),
830
        array($level, (8*$level)+1, $level), //Lessen the effect of a filter by increasing the value in the center cell
831
        array($level, $level, $level)
832
      );
833
834
  }
835
836
## --------------------------------------------------------
837
838
  private function findSharp($orig, $final)
839
    # Author:     Ryan Rud (http://adryrun.com)
840
    # Purpose:    Find optimal sharpness
841
    # Param in:   n/a
842
    # Param out:  n/a
843
    # Reference:
844
    # Notes:
845
    #
846
  {
847
    $final  = $final * (750.0 / $orig);
848
    $a    = 52;
849
    $b    = -0.27810650887573124;
850
    $c    = .00047337278106508946;
851
852
    $result = $a + $b * $final + $c * $final * $final;
853
854
    return max(round($result), 0);
855
  }
856
857
## --------------------------------------------------------
858
859
  private function prepOption($option)
860
    # Author:     Jarrod Oberto
861
    # Purpose:    Prep option like change the passed in option to lowercase
862
    # Param in:   (str/int) $option: eg. 'exact', 'crop'. 0, 4
863
    # Param out:  lowercase string
864
    # Reference:
865
    # Notes:
866
    #
867
  {
868
    if (is_array($option)) {
869
      if (fix_strtolower($option[0]) === 'crop' && count($option) == 2) {
870
        return 'crop';
871
      } else {
872
        throw new Exception('Crop resize option array is badly formatted.');
873
      }
874
    } else if (strpos($option, 'crop') !== false) {
875
      return 'crop';
876
    }
877
878
    if (is_string($option)) {
879
      return fix_strtolower($option);
880
    }
881
882
    return $option;
883
  }
884
885
886
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
887
  Presets
888
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
889
890
#
891
# Preset are pre-defined templates you can apply to your image.
892
#
893
# These are inteded to be applied to thumbnail images.
894
#
895
896
897
  public function borderPreset($preset)
898
  {
899
    switch ($preset)
900
    {
901
902
      case 'simple':
903
        $this->addBorder(7, '#fff');
904
        $this->addBorder(6, '#f2f1f0');
905
        $this->addBorder(2, '#fff');
906
        $this->addBorder(1, '#ccc');
907
        break;
908
      default:
909
        break;
910
    }
911
912
  }
913
914
915
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
916
  Draw border
917
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
918
919
  public function addBorder($thickness = 1, $rgbArray = array(255, 255, 255))
920
    # Author:     Jarrod Oberto
921
    # Date:       05-05-11
922
    # Purpose:    Add a border to the image
923
    # Param in:
924
    # Param out:
925
    # Reference:
926
    # Notes:    This border is added to the INSIDE of the image
927
    #
928
  {
929
    if ($this->imageResized) {
930
931
      $rgbArray = $this->formatColor($rgbArray);
932
      $r = $rgbArray['r'];
933
      $g = $rgbArray['g'];
934
      $b = $rgbArray['b'];
935
936
937
      $x1 = 0;
938
      $y1 = 0;
939
      $x2 = imagesx($this->imageResized) - 1;
940
      $y2 = imagesy($this->imageResized) - 1;
941
942
      $rgbArray = imagecolorallocate($this->imageResized, $r, $g, $b);
943
944
945
      for($i = 0; $i < $thickness; $i++) {
946
          imagerectangle($this->imageResized, $x1++, $y1++, $x2--, $y2--, $rgbArray);
947
      }
948
    }
949
  }
950
951
952
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
953
  Gray Scale
954
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
955
956
  public function greyScale()
957
    # Author:     Jarrod Oberto
958
    # Date:       07-05-2011
959
    # Purpose:    Make image greyscale
960
    # Param in:   n/a
961
    # Param out:
962
    # Reference:
963
    # Notes:
964
    #
965
  {
966
    if ($this->imageResized) {
967
      imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
968
    }
969
970
  }
971
972
  ## --------------------------------------------------------
973
974
  public function greyScaleEnhanced()
975
    # Author:     Jarrod Oberto
976
    # Date:       07-05-2011
977
    # Purpose:    Make image greyscale
978
    # Param in:   n/a
979
    # Param out:
980
    # Reference:
981
    # Notes:
982
    #
983
  {
984
    if ($this->imageResized) {
985
      imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
986
      imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -15);
987
      imagefilter($this->imageResized, IMG_FILTER_BRIGHTNESS, 2);
988
      $this->sharpen($this->width);
0 ignored issues
show
Unused Code introduced by
The call to imageLib::sharpen() has too many arguments starting with $this->width. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

988
      $this->/** @scrutinizer ignore-call */ 
989
             sharpen($this->width);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
989
    }
990
  }
991
992
  ## --------------------------------------------------------
993
994
  public function greyScaleDramatic()
995
  # Alias of gd_filter_monopin
996
  {
997
    $this->gd_filter_monopin();
998
  }
999
1000
1001
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1002
  Black 'n White
1003
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1004
1005
  public function blackAndWhite()
1006
    # Author:     Jarrod Oberto
1007
    # Date:       07-05-2011
1008
    # Purpose:    Make image black and white
1009
    # Param in:   n/a
1010
    # Param out:
1011
    # Reference:
1012
    # Notes:
1013
    #
1014
  {
1015
    if ($this->imageResized) {
1016
1017
      imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
1018
      imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -1000);
1019
    }
1020
1021
  }
1022
1023
1024
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1025
  Negative
1026
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1027
1028
  public function negative()
1029
    # Author:     Jarrod Oberto
1030
    # Date:       07-05-2011
1031
    # Purpose:    Make image negative
1032
    # Param in:   n/a
1033
    # Param out:
1034
    # Reference:
1035
    # Notes:
1036
    #
1037
  {
1038
    if ($this->imageResized) {
1039
1040
      imagefilter($this->imageResized, IMG_FILTER_NEGATE);
1041
    }
1042
1043
  }
1044
1045
1046
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1047
  Sepia
1048
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1049
1050
  public function sepia()
1051
    # Author:     Jarrod Oberto
1052
    # Date:       07-05-2011
1053
    # Purpose:    Make image sepia
1054
    # Param in:   n/a
1055
    # Param out:
1056
    # Reference:
1057
    # Notes:
1058
    #
1059
  {
1060
    if ($this->imageResized) {
1061
      imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
1062
      imagefilter($this->imageResized, IMG_FILTER_BRIGHTNESS, -10);
1063
      imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -20);
1064
      imagefilter($this->imageResized, IMG_FILTER_COLORIZE, 60, 30, -15);
1065
    }
1066
  }
1067
1068
  ## --------------------------------------------------------
1069
1070
  public function sepia2()
1071
1072
  {
1073
    if ($this->imageResized) {
1074
1075
      $total = imagecolorstotal( $this->imageResized );
1076
      for ( $i = 0; $i < $total; $i++ ) {
1077
        $index = imagecolorsforindex( $this->imageResized, $i );
1078
        $red = ( $index["red"] * 0.393 + $index["green"] * 0.769 + $index["blue"] * 0.189 ) / 1.351;
1079
        $green = ( $index["red"] * 0.349 + $index["green"] * 0.686 + $index["blue"] * 0.168 ) / 1.203;
1080
        $blue = ( $index["red"] * 0.272 + $index["green"] * 0.534 + $index["blue"] * 0.131 ) / 2.140;
1081
        imagecolorset( $this->imageResized, $i, $red, $green, $blue );
0 ignored issues
show
Bug introduced by
$blue of type double is incompatible with the type integer expected by parameter $blue of imagecolorset(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1081
        imagecolorset( $this->imageResized, $i, $red, $green, /** @scrutinizer ignore-type */ $blue );
Loading history...
Bug introduced by
$green of type double is incompatible with the type integer expected by parameter $green of imagecolorset(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1081
        imagecolorset( $this->imageResized, $i, $red, /** @scrutinizer ignore-type */ $green, $blue );
Loading history...
Bug introduced by
$red of type double is incompatible with the type integer expected by parameter $red of imagecolorset(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1081
        imagecolorset( $this->imageResized, $i, /** @scrutinizer ignore-type */ $red, $green, $blue );
Loading history...
1082
      }
1083
1084
1085
    }
1086
  }
1087
1088
1089
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1090
  Vintage
1091
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1092
1093
  public function vintage()
1094
  # Alias of gd_filter_monopin
1095
  {
1096
    $this->gd_filter_vintage();
1097
  }
1098
1099
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1100
  Presets By Marc Hibbins
1101
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1102
1103
1104
  /** Apply 'Monopin' preset */
1105
  public function gd_filter_monopin()
1106
  {
1107
1108
    if ($this->imageResized) {
1109
      imagefilter($this->imageResized, IMG_FILTER_GRAYSCALE);
1110
      imagefilter($this->imageResized, IMG_FILTER_BRIGHTNESS, -15);
1111
      imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -15);
1112
      $this->imageResized = $this->gd_apply_overlay($this->imageResized, 'vignette', 100);
1113
    }
1114
  }
1115
1116
  ## --------------------------------------------------------
1117
1118
  public function gd_filter_vintage()
1119
  {
1120
    if ($this->imageResized) {
1121
      $this->imageResized = $this->gd_apply_overlay($this->imageResized, 'vignette', 45);
1122
      imagefilter($this->imageResized, IMG_FILTER_BRIGHTNESS, 20);
1123
      imagefilter($this->imageResized, IMG_FILTER_CONTRAST, -35);
1124
      imagefilter($this->imageResized, IMG_FILTER_COLORIZE, 60, -10, 35);
1125
      imagefilter($this->imageResized, IMG_FILTER_SMOOTH, 7);
1126
      $this->imageResized = $this->gd_apply_overlay($this->imageResized, 'scratch', 10);
1127
    }
1128
  }
1129
1130
  ## --------------------------------------------------------
1131
1132
  /** Apply a PNG overlay */
1133
  private function gd_apply_overlay($im, $type, $amount)
1134
  #
1135
  # Original Author:    Marc Hibbins
1136
  # License:  Attribution-ShareAlike 3.0
1137
  # Purpose:
1138
  # Params in:
1139
  # Params out:
1140
  # Notes:
1141
  #
1142
  {
1143
    $width = imagesx($im);
1144
    $height = imagesy($im);
1145
    $filter = imagecreatetruecolor($width, $height);
1146
1147
    imagealphablending($filter, false);
1148
    imagesavealpha($filter, true);
1149
1150
    $transparent = imagecolorallocatealpha($filter, 255, 255, 255, 127);
1151
    imagefilledrectangle($filter, 0, 0, $width, $height, $transparent);
1152
1153
    // *** Resize overlay
1154
    $overlay = $this->filterOverlayPath . '/' . $type . '.png';
1155
    $png = imagecreatefrompng($overlay);
1156
    imagecopyresampled($filter, $png, 0, 0, 0, 0, $width, $height, imagesx($png), imagesy($png));
1157
1158
    $comp = imagecreatetruecolor($width, $height);
1159
    imagecopy($comp, $im, 0, 0, 0, 0, $width, $height);
1160
    imagecopy($comp, $filter, 0, 0, 0, 0, $width, $height);
1161
    imagecopymerge($im, $comp, 0, 0, 0, 0, $width, $height, $amount);
1162
1163
    imagedestroy($comp);
1164
    return $im;
1165
  }
1166
1167
1168
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1169
  Colorise
1170
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1171
1172
  public function image_colorize($rgb) {
1173
      imagetruecolortopalette($this->imageResized,true,256);
1174
    $numColors = imagecolorstotal($this->imageResized);
1175
1176
    for ($x = 0; $x < $numColors; $x++) {
1177
    list($r,$g,$b) = array_values(imagecolorsforindex($this->imageResized,$x));
1178
1179
    // calculate grayscale in percent
1180
    $grayscale = ($r + $g + $b) / 3 / 0xff;
1181
1182
      imagecolorset($this->imageResized,$x,
1183
      $grayscale * $rgb[0],
1184
      $grayscale * $rgb[1],
1185
      $grayscale * $rgb[2]
1186
    );
1187
1188
    }
1189
1190
    return true;
1191
  }
1192
1193
1194
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1195
  Reflection
1196
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1197
1198
  public function addReflection($reflectionHeight = 50, $startingTransparency = 30, $inside = false, $bgColor = '#fff', $stretch=false, $divider = 0)
1199
  {
1200
1201
    // *** Convert color
1202
    $rgbArray = $this->formatColor($bgColor);
1203
    $r = $rgbArray['r'];
1204
    $g = $rgbArray['g'];
1205
    $b = $rgbArray['b'];
1206
1207
    $im = $this->imageResized;
1208
    $li = imagecreatetruecolor($this->width, 1);
1209
1210
    $bgc = imagecolorallocate($li, $r, $g, $b);
1211
    imagefilledrectangle($li, 0, 0, $this->width, 1, $bgc);
1212
1213
    $bg = imagecreatetruecolor($this->width, $reflectionHeight);
1214
    $wh = imagecolorallocate($im, 255, 255, 255);
1215
1216
    $im = imagerotate($im, -180, $wh);
1217
    imagecopyresampled($bg, $im, 0, 0, 0, 0, $this->width, $this->height, $this->width, $this->height);
1218
1219
    $im = $bg;
1220
1221
    $bg = imagecreatetruecolor($this->width, $reflectionHeight);
1222
1223
    for ($x = 0; $x < $this->width; $x++) {
1224
      imagecopy($bg, $im, $x, 0, $this->width-$x -1, 0, 1, $reflectionHeight);
1225
    }
1226
    $im = $bg;
1227
1228
    $transaprencyAmount = $this->invertTransparency($startingTransparency, 100);
0 ignored issues
show
Unused Code introduced by
The assignment to $transaprencyAmount is dead and can be removed.
Loading history...
1229
1230
1231
    // *** Fade
1232
    if ($stretch) {
1233
      $step = 100/($reflectionHeight + $startingTransparency);
1234
    } else{
1235
      $step = 100/$reflectionHeight;
1236
    }
1237
    for($i=0; $i<=$reflectionHeight; $i++){
1238
1239
      if($startingTransparency>100) $startingTransparency = 100;
1240
      if($startingTransparency< 1) $startingTransparency = 1;
1241
      imagecopymerge($bg, $li, 0, $i, 0, 0, $this->width, 1, $startingTransparency);
1242
      $startingTransparency+=$step;
1243
    }
1244
1245
    // *** Apply fade
1246
    imagecopymerge($im, $li, 0, 0, 0, 0, $this->width, $divider, 100); // Divider
1247
1248
1249
    // *** width, height of reflection.
1250
    $x = imagesx($im);
1251
    $y = imagesy($im);
1252
1253
1254
    // *** Determines if the reflection should be displayed inside or outside the image
1255
    if ($inside) {
1256
1257
      // Create new blank image with sizes.
1258
      $final = imagecreatetruecolor($this->width, $this->height);
1259
1260
      imagecopymerge ($final, $this->imageResized, 0, 0, 0, $reflectionHeight, $this->width, $this->height - $reflectionHeight, 100);
1261
      imagecopymerge ($final, $im, 0, $this->height - $reflectionHeight, 0, 0, $x, $y, 100);
1262
1263
    } else {
1264
1265
      // Create new blank image with sizes.
1266
      $final = imagecreatetruecolor($this->width, $this->height + $y);
1267
1268
      imagecopymerge ($final, $this->imageResized, 0, 0, 0, 0, $this->width, $this->height, 100);
1269
      imagecopymerge ($final, $im, 0, $this->height, 0, 0, $x, $y, 100);
1270
    }
1271
1272
    $this->imageResized = $final;
1273
1274
    imagedestroy($li);
1275
    imagedestroy($im);
1276
  }
1277
1278
1279
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1280
  Rotate
1281
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1282
1283
  public function rotate($value = 90, $bgColor = 'transparent')
1284
    # Author:     Jarrod Oberto
1285
    # Date:       07-05-2011
1286
    # Purpose:    Rotate image
1287
    # Param in:   (mixed) $degrees: (int) number of degress to rotate image
1288
  #               (str) param "left": rotate left
1289
  #               (str) param "right": rotate right
1290
  #               (str) param "upside": upside-down image
1291
    # Param out:
1292
    # Reference:
1293
    # Notes:    The default direction of imageRotate() is counter clockwise.
1294
    #
1295
  {
1296
    if ($this->imageResized) {
1297
1298
      if (is_integer($value)) {
1299
        $degrees = $value;
1300
      }
1301
1302
      // *** Convert color
1303
      $rgbArray = $this->formatColor($bgColor);
1304
      $r = $rgbArray['r'];
1305
      $g = $rgbArray['g'];
1306
      $b = $rgbArray['b'];
1307
      if (isset($rgbArray['a'])) {$a = $rgbArray['a']; }
1308
1309
      if (is_string($value)) {
1310
1311
        $value = fix_strtolower($value);
1312
1313
        switch ($value) {
1314
          case 'left':
1315
            $degrees = 90;
1316
            break;
1317
          case 'right':
1318
            $degrees = 270;
1319
            break;
1320
          case 'upside':
1321
            $degrees = 180;
1322
            break;
1323
          default:
1324
            break;
1325
        }
1326
1327
      }
1328
1329
      // *** The default direction of imageRotate() is counter clockwise
1330
      //   * This makes it clockwise
1331
      $degrees = 360 - $degrees;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $degrees does not seem to be defined for all execution paths leading up to this point.
Loading history...
1332
1333
      // *** Create background color
1334
      $bg = imagecolorallocatealpha($this->imageResized, $r, $g, $b, $a);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $a does not seem to be defined for all execution paths leading up to this point.
Loading history...
1335
1336
      // *** Fill with background
1337
        imagefill($this->imageResized, 0, 0 , $bg);
1338
1339
      // *** Rotate
1340
      $this->imageResized = imagerotate($this->imageResized, $degrees, $bg); // Rotate 45 degrees and allocated the transparent colour as the one to make transparent (obviously)
1341
1342
      // Ensure alpha transparency
1343
        imagesavealpha($this->imageResized,true);
1344
1345
    }
1346
  }
1347
1348
1349
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1350
  Round corners
1351
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1352
1353
  public function roundCorners($radius = 5,  $bgColor = 'transparent')
1354
    # Author:     Jarrod Oberto
1355
    # Date:       19-05-2011
1356
    # Purpose:    Create rounded corners on your image
1357
    # Param in:   (int) radius = the amount of curvature
1358
  #       (mixed) $bgColor = the corner background color
1359
    # Param out:  n/a
1360
    # Reference:
1361
    # Notes:
1362
    #
1363
  {
1364
1365
    // *** Check if the user wants transparency
1366
    $isTransparent = false;
1367
    if (!is_array($bgColor)) {
1368
      if (fix_strtolower($bgColor) === 'transparent') {
1369
        $isTransparent = true;
1370
      }
1371
    }
1372
1373
1374
    // *** If we use transparency, we need to color our curved mask with a unique color
1375
    if ($isTransparent) {
1376
      $bgColor = $this->findUnusedGreen();
1377
    }
1378
1379
    // *** Convert color
1380
    $rgbArray = $this->formatColor($bgColor);
1381
    $r = $rgbArray['r'];
1382
    $g = $rgbArray['g'];
1383
    $b = $rgbArray['b'];
1384
    if (isset($rgbArray['a'])) {$a = $rgbArray['a']; }
0 ignored issues
show
Unused Code introduced by
The assignment to $a is dead and can be removed.
Loading history...
1385
1386
1387
1388
    // *** Create top-left corner mask (square)
1389
    $cornerImg = imagecreatetruecolor($radius, $radius);
1390
    //$cornerImg = imagecreate($radius, $radius);
1391
1392
      //imagealphablending($cornerImg, true);
1393
      //imagesavealpha($cornerImg, true);
1394
1395
      //imagealphablending($this->imageResized, false);
1396
      //imagesavealpha($this->imageResized, true);
1397
1398
    // *** Give it a color
1399
    $maskColor = imagecolorallocate($cornerImg, 0, 0, 0);
1400
1401
1402
1403
    // *** Replace the mask color (black) to transparent
1404
    imagecolortransparent($cornerImg, $maskColor);
1405
1406
1407
1408
    // *** Create the image background color
1409
    $imagebgColor = imagecolorallocate($cornerImg, $r, $g, $b);
1410
1411
1412
1413
    // *** Fill the corner area to the user defined color
1414
    imagefill($cornerImg, 0, 0, $imagebgColor);
1415
1416
1417
    imagefilledellipse($cornerImg, $radius, $radius, $radius * 2, $radius * 2, $maskColor );
1418
1419
1420
    // *** Map to top left corner
1421
    imagecopymerge($this->imageResized, $cornerImg, 0, 0, 0, 0, $radius, $radius, 100); #tl
1422
1423
    // *** Map rounded corner to other corners by rotating and applying the mask
1424
    $cornerImg = imagerotate($cornerImg, 90, 0);
1425
    imagecopymerge($this->imageResized, $cornerImg, 0, $this->height - $radius, 0, 0, $radius, $radius, 100); #bl
1426
1427
    $cornerImg = imagerotate($cornerImg, 90, 0);
1428
    imagecopymerge($this->imageResized, $cornerImg, $this->width - $radius, $this->height - $radius, 0, 0, $radius, $radius, 100); #br
1429
1430
    $cornerImg = imagerotate($cornerImg, 90, 0);
1431
    imagecopymerge($this->imageResized, $cornerImg, $this->width - $radius, 0, 0, 0, $radius, $radius, 100); #tr
1432
1433
1434
    // *** If corners are to be transparent, we fill our chromakey color as transparent.
1435
    if ($isTransparent) {
1436
      //imagecolortransparent($this->imageResized, $imagebgColor);
1437
      $this->imageResized = $this->transparentImage($this->imageResized);
1438
      imagesavealpha($this->imageResized, true);
1439
    }
1440
1441
  }
1442
1443
1444
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1445
  Shadow
1446
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1447
1448
  public function addShadow($shadowAngle=45, $blur=15, $bgColor='transparent')
1449
  #
1450
  # Author:   Jarrod Oberto (Adapted from Pascal Naidon)
1451
  # Ref:    http://www.les-stooges.org/pascal/webdesign/vignettes/index.php?la=en
1452
  # Purpose:  Add a drop shadow to your image
1453
  # Params in:  (int) $angle: the angle of the shadow
1454
  #       (int) $blur: the blur distance
1455
  #       (mixed) $bgColor: the color of the background
1456
  # Params out:
1457
  # Notes:
1458
  #
1459
  {
1460
    // *** A higher number results in a smoother shadow
1461
    define('STEPS', $blur*2);
1462
1463
    // *** Set the shadow distance
1464
    $shadowDistance = $blur*0.25;
1465
1466
    // *** Set blur width and height
1467
    $blurWidth = $blurHeight = $blur;
1468
1469
1470
    if ($shadowAngle == 0) {
1471
      $distWidth = 0;
1472
      $distHeight = 0;
1473
    } else {
1474
      $distWidth = $shadowDistance * cos(deg2rad($shadowAngle));
1475
      $distHeight = $shadowDistance * sin(deg2rad($shadowAngle));
1476
    }
1477
1478
1479
    // *** Convert color
1480
    if (fix_strtolower($bgColor) !== 'transparent') {
1481
      $rgbArray = $this->formatColor($bgColor);
1482
      $r0 = $rgbArray['r'];
1483
      $g0 = $rgbArray['g'];
1484
      $b0 = $rgbArray['b'];
1485
    }
1486
1487
1488
    $image = $this->imageResized;
1489
    $width = $this->width;
1490
    $height = $this->height;
1491
1492
1493
      $newImage = imagecreatetruecolor($width, $height);
1494
    imagecopyresampled($newImage, $image, 0, 0, 0, 0, $width, $height, $width, $height);
1495
1496
1497
    // *** RGB
1498
    $rgb = imagecreatetruecolor($width+$blurWidth,$height+$blurHeight);
1499
    $colour = imagecolorallocate($rgb, 0, 0, 0);
1500
    imagefilledrectangle($rgb, 0, 0, $width+$blurWidth, $height+$blurHeight, $colour);
1501
    $colour = imagecolorallocate($rgb, 255, 255, 255);
1502
    //imagefilledrectangle($rgb, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-$distWidth, $height+$blurWidth*0.5-$distHeight, $colour);
1503
    imagefilledrectangle($rgb, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-$distWidth, $height+$blurWidth*0.5-$distHeight, $colour);
0 ignored issues
show
Bug introduced by
$blurWidth * 0.5 - $distWidth of type double is incompatible with the type integer expected by parameter $x1 of imagefilledrectangle(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1503
    imagefilledrectangle($rgb, /** @scrutinizer ignore-type */ $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-$distWidth, $height+$blurWidth*0.5-$distHeight, $colour);
Loading history...
Bug introduced by
$width + $blurWidth * 0.5 - $distWidth of type double is incompatible with the type integer expected by parameter $x2 of imagefilledrectangle(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1503
    imagefilledrectangle($rgb, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, /** @scrutinizer ignore-type */ $width+$blurWidth*0.5-$distWidth, $height+$blurWidth*0.5-$distHeight, $colour);
Loading history...
Bug introduced by
$blurHeight * 0.5 - $distHeight of type double is incompatible with the type integer expected by parameter $y1 of imagefilledrectangle(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1503
    imagefilledrectangle($rgb, $blurWidth*0.5-$distWidth, /** @scrutinizer ignore-type */ $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-$distWidth, $height+$blurWidth*0.5-$distHeight, $colour);
Loading history...
Bug introduced by
$height + $blurWidth * 0.5 - $distHeight of type double is incompatible with the type integer expected by parameter $y2 of imagefilledrectangle(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1503
    imagefilledrectangle($rgb, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-$distWidth, /** @scrutinizer ignore-type */ $height+$blurWidth*0.5-$distHeight, $colour);
Loading history...
1504
    //imagecopymerge($rgb, $newImage, 1+$blurWidth*0.5-$distWidth, 1+$blurHeight*0.5-$distHeight, 0,0, $width, $height, 100);
1505
    imagecopymerge($rgb, $newImage, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, 0,0, $width+$blurWidth, $height+$blurHeight, 100);
0 ignored issues
show
Bug introduced by
$blurHeight * 0.5 - $distHeight of type double is incompatible with the type integer expected by parameter $dst_y of imagecopymerge(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1505
    imagecopymerge($rgb, $newImage, $blurWidth*0.5-$distWidth, /** @scrutinizer ignore-type */ $blurHeight*0.5-$distHeight, 0,0, $width+$blurWidth, $height+$blurHeight, 100);
Loading history...
Bug introduced by
$blurWidth * 0.5 - $distWidth of type double is incompatible with the type integer expected by parameter $dst_x of imagecopymerge(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1505
    imagecopymerge($rgb, $newImage, /** @scrutinizer ignore-type */ $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, 0,0, $width+$blurWidth, $height+$blurHeight, 100);
Loading history...
1506
1507
1508
    // *** Shadow (alpha)
1509
    $shadow = imagecreatetruecolor($width+$blurWidth,$height+$blurHeight);
1510
      imagealphablending($shadow, false);
1511
    $colour = imagecolorallocate($shadow, 0, 0, 0);
1512
    imagefilledrectangle($shadow, 0, 0, $width+$blurWidth, $height+$blurHeight, $colour);
1513
1514
1515
    for($i=0;$i<=STEPS;$i++) {
1516
1517
      $t = ((1.0*$i)/STEPS);
1518
      $intensity = 255*$t*$t;
1519
1520
      $colour = imagecolorallocate($shadow, $intensity, $intensity, $intensity);
1521
      $points = array(
1522
        $blurWidth*$t,        $blurHeight,     // Point 1 (x, y)
1523
        $blurWidth,         $blurHeight*$t,  // Point 2 (x, y)
1524
        $width,           $blurHeight*$t,  // Point 3 (x, y)
1525
        $width+$blurWidth*(1-$t), $blurHeight,     // Point 4 (x, y)
1526
        $width+$blurWidth*(1-$t), $height,     // Point 5 (x, y)
1527
        $width,           $height+$blurHeight*(1-$t),  // Point 6 (x, y)
1528
        $blurWidth,         $height+$blurHeight*(1-$t),  // Point 7 (x, y)
1529
        $blurWidth*$t,        $height      // Point 8 (x, y)
1530
      );
1531
      imagepolygon($shadow, $points, 8, $colour);
1532
    }
1533
1534
    for($i=0;$i<=STEPS;$i++) {
1535
1536
      $t = ((1.0*$i)/STEPS);
1537
        $intensity = 255*$t*$t;
1538
1539
      $colour = imagecolorallocate($shadow, $intensity, $intensity, $intensity);
1540
      imagefilledarc($shadow, $blurWidth-1, $blurHeight-1, 2*(1-$t)*$blurWidth, 2*(1-$t)*$blurHeight, 180, 268, $colour, IMG_ARC_PIE);
1541
      imagefilledarc($shadow, $width, $blurHeight-1, 2*(1-$t)*$blurWidth, 2*(1-$t)*$blurHeight, 270, 358, $colour, IMG_ARC_PIE);
1542
      imagefilledarc($shadow, $width, $height, 2*(1-$t)*$blurWidth, 2*(1-$t)*$blurHeight, 0, 90, $colour, IMG_ARC_PIE);
1543
      imagefilledarc($shadow, $blurWidth-1, $height, 2*(1-$t)*$blurWidth, 2*(1-$t)*$blurHeight, 90, 180, $colour, IMG_ARC_PIE);
1544
    }
1545
1546
1547
    $colour = imagecolorallocate($shadow, 255, 255, 255);
1548
    imagefilledrectangle($shadow, $blurWidth, $blurHeight, $width, $height, $colour);
1549
    imagefilledrectangle($shadow, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-1-$distWidth, $height+$blurHeight*0.5-1-$distHeight, $colour);
1550
1551
1552
    // *** The magic
1553
        imagealphablending($rgb, false);
1554
1555
        for ($theX=0;$theX<imagesx($rgb);$theX++){
1556
      for ($theY=0;$theY<imagesy($rgb);$theY++){
1557
1558
        // *** Get the RGB values for every pixel of the RGB image
1559
        $colArray = imagecolorat($rgb,$theX,$theY);
1560
        $r = ($colArray >> 16) & 0xFF;
1561
        $g = ($colArray >> 8) & 0xFF;
1562
        $b = $colArray & 0xFF;
1563
1564
        // *** Get the alpha value for every pixel of the shadow image
1565
        $colArray = imagecolorat($shadow,$theX,$theY);
1566
        $a = $colArray & 0xFF;
1567
        $a = 127-floor($a/2);
1568
        $t = $a/128.0;
1569
1570
        // *** Create color
1571
        if(fix_strtolower($bgColor) === 'transparent') {
1572
          $myColour = imagecolorallocatealpha($rgb,$r,$g,$b,$a);
0 ignored issues
show
Bug introduced by
$a of type double is incompatible with the type integer expected by parameter $alpha of imagecolorallocatealpha(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1572
          $myColour = imagecolorallocatealpha($rgb,$r,$g,$b,/** @scrutinizer ignore-type */ $a);
Loading history...
1573
        } else {
1574
          $myColour = imagecolorallocate($rgb,$r*(1.0-$t)+$r0*$t,$g*(1.0-$t)+$g0*$t,$b*(1.0-$t)+$b0*$t);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $r0 does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug introduced by
$r * 1.0 - $t + $r0 * $t of type double is incompatible with the type integer expected by parameter $red of imagecolorallocate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1574
          $myColour = imagecolorallocate($rgb,/** @scrutinizer ignore-type */ $r*(1.0-$t)+$r0*$t,$g*(1.0-$t)+$g0*$t,$b*(1.0-$t)+$b0*$t);
Loading history...
Comprehensibility Best Practice introduced by
The variable $g0 does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug introduced by
$b * 1.0 - $t + $b0 * $t of type double is incompatible with the type integer expected by parameter $blue of imagecolorallocate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1574
          $myColour = imagecolorallocate($rgb,$r*(1.0-$t)+$r0*$t,$g*(1.0-$t)+$g0*$t,/** @scrutinizer ignore-type */ $b*(1.0-$t)+$b0*$t);
Loading history...
Bug introduced by
$g * 1.0 - $t + $g0 * $t of type double is incompatible with the type integer expected by parameter $green of imagecolorallocate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1574
          $myColour = imagecolorallocate($rgb,$r*(1.0-$t)+$r0*$t,/** @scrutinizer ignore-type */ $g*(1.0-$t)+$g0*$t,$b*(1.0-$t)+$b0*$t);
Loading history...
Comprehensibility Best Practice introduced by
The variable $b0 does not seem to be defined for all execution paths leading up to this point.
Loading history...
1575
        }
1576
1577
        // *** Add color to new rgb image
1578
        imagesetpixel($rgb, $theX, $theY, $myColour);
1579
      }
1580
    }
1581
1582
    imagealphablending($rgb, true);
1583
    imagesavealpha($rgb, true);
1584
1585
    $this->imageResized = $rgb;
1586
1587
    imagedestroy($image);
1588
    imagedestroy($newImage);
1589
    imagedestroy($shadow);
1590
  }
1591
1592
1593
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1594
  Add Caption Box
1595
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1596
1597
  public function addCaptionBox($side='b', $thickness=50, $padding=0, $bgColor='#000', $transaprencyAmount=30)
1598
  #
1599
  # Author:   Jarrod Oberto
1600
  # Date:   26 May 2011
1601
  # Purpose:  Add a caption box
1602
  # Params in:  (str) $side: the side to add the caption box (t, r, b, or l).
1603
  #       (int) $thickness: how thick you want the caption box to be.
1604
  #       (mixed) $bgColor: The color of the caption box.
1605
  #       (int) $transaprencyAmount: The amount of transparency to be
1606
  #       applied.
1607
  # Params out: n/a
1608
  # Notes:
1609
  #
1610
  {
1611
      $side = fix_strtolower($side);
1612
1613
      // *** Convert color
1614
      $rgbArray = $this->formatColor($bgColor);
1615
      $r = $rgbArray['r'];
1616
      $g = $rgbArray['g'];
1617
      $b = $rgbArray['b'];
1618
1619
      $positionArray = $this->calculateCaptionBoxPosition($side, $thickness, $padding);
1620
1621
      // *** Store incase we want to use method addTextToCaptionBox()
1622
      $this->captionBoxPositionArray = $positionArray;
1623
1624
1625
      $transaprencyAmount = $this->invertTransparency($transaprencyAmount, 127, false);
1626
      $transparent = imagecolorallocatealpha($this->imageResized, $r, $g, $b, $transaprencyAmount);
1627
      imagefilledrectangle($this->imageResized, $positionArray['x1'], $positionArray['y1'], $positionArray['x2'], $positionArray['y2'], $transparent);
1628
  }
1629
1630
  ## --------------------------------------------------------
1631
1632
  public function addTextToCaptionBox($text, $fontColor='#fff', $fontSize = 12, $angle = 0, $font = null)
1633
  #
1634
  # Author:   Jarrod Oberto
1635
  # Date:   03 Aug 11
1636
  # Purpose:  Simplify adding text to a caption box by automatically
1637
  #       locating the center of the caption box
1638
  # Params in:  The usually text paams (less a couple)
1639
  # Params out: n/a
1640
  # Notes:
1641
  #
1642
  {
1643
1644
    // *** Get the caption box measurements
1645
    if (count($this->captionBoxPositionArray) == 4) {
1646
      $x1 = $this->captionBoxPositionArray['x1'];
1647
      $x2 = $this->captionBoxPositionArray['x2'];
1648
      $y1 = $this->captionBoxPositionArray['y1'];
1649
      $y2 = $this->captionBoxPositionArray['y2'];
1650
    } else {
1651
      if ($this->debug) { throw new Exception('No caption box found.'); }else{ return false; }
1652
    }
1653
1654
1655
    // *** Get text font
1656
    $font = $this->getTextFont($font);
1657
1658
    // *** Get text size
1659
    $textSizeArray = $this->getTextSize($fontSize, $angle, $font, $text);
1660
    $textWidth = $textSizeArray['width'];
1661
    $textHeight = $textSizeArray['height'];
1662
1663
    // *** Find the width/height middle points
1664
    $boxXMiddle = (($x2 - $x1) / 2);
1665
    $boxYMiddle = (($y2 - $y1) / 2);
1666
1667
    // *** Box middle - half the text width/height
1668
    $xPos = ($x1 + $boxXMiddle) - ($textWidth/2);
1669
    $yPos = ($y1 + $boxYMiddle) - ($textHeight/2);
1670
1671
    $pos = $xPos . 'x' . $yPos;
1672
1673
    $this->addText($text, $pos, $padding = 0, $fontColor, $fontSize, $angle, $font);
1674
1675
  }
1676
1677
  ## --------------------------------------------------------
1678
1679
  private function calculateCaptionBoxPosition($side, $thickness, $padding)
1680
  {
1681
    $positionArray = array();
1682
1683
    switch ($side) {
1684
      case 't':
1685
        $positionArray['x1'] = 0;
1686
        $positionArray['y1'] = $padding;
1687
        $positionArray['x2'] = $this->width;
1688
        $positionArray['y2'] = $thickness + $padding;
1689
        break;
1690
      case 'r':
1691
        $positionArray['x1'] = $this->width - $thickness - $padding;
1692
        $positionArray['y1'] = 0;
1693
        $positionArray['x2'] = $this->width - $padding;
1694
        $positionArray['y2'] = $this->height;
1695
        break;
1696
      case 'b':
1697
        $positionArray['x1'] = 0;
1698
        $positionArray['y1'] = $this->height - $thickness - $padding;
1699
        $positionArray['x2'] = $this->width;
1700
        $positionArray['y2'] = $this->height - $padding;
1701
        break;
1702
      case 'l':
1703
        $positionArray['x1'] = $padding;
1704
        $positionArray['y1'] = 0;
1705
        $positionArray['x2'] = $thickness + $padding;
1706
        $positionArray['y2'] = $this->height;
1707
        break;
1708
1709
      default:
1710
        break;
1711
    }
1712
1713
    return $positionArray;
1714
1715
  }
1716
1717
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
1718
  Get EXIF Data
1719
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
1720
1721
  public function getExif($debug=false)
1722
    # Author:     Jarrod Oberto
1723
    # Date:       07-05-2011
1724
    # Purpose:    Get image EXIF data
1725
    # Param in:   n/a
1726
    # Param out:  An associate array of EXIF data
1727
    # Reference:
1728
    # Notes:
1729
    # 23 May 13 : added orientation flag -jco
1730
    #
1731
  {
1732
1733
    if (!$this->debug || !$debug) { $debug = false; }
1734
1735
    // *** Check all is good - check the EXIF library exists and the file exists, too.
1736
    if (!$this->testEXIFInstalled()) { if ($debug) { throw new Exception('The EXIF Library is not installed.'); }else{ return array(); }};
1737
    if (!file_exists($this->fileName)) { if ($debug) { throw new Exception('Image not found.'); }else{ return array(); }};
1738
    if ($this->fileExtension !== '.jpg') { if ($debug) { throw new Exception('Metadata not supported for this image type.'); }else{ return array(); }};
1739
    $exifData = exif_read_data($this->fileName, 'IFD0');
1740
1741
    // *** Format the apperture value
1742
    $ev = $exifData['ApertureValue'];
1743
    $apPeicesArray = explode('/', $ev);
1744
    if (count($apPeicesArray) == 2) {
1745
      $apertureValue = round($apPeicesArray[0] / $apPeicesArray[1], 2, PHP_ROUND_HALF_DOWN) . ' EV';
1746
    } else { $apertureValue = '';}
1747
1748
    // *** Format the focal length
1749
    $focalLength = $exifData['FocalLength'];
1750
    $flPeicesArray = explode('/', $focalLength);
1751
    if (count($flPeicesArray) == 2) {
1752
      $focalLength = $flPeicesArray[0] / $flPeicesArray[1] . '.0 mm';
1753
    } else { $focalLength = '';}
1754
1755
    // *** Format fNumber
1756
    $fNumber = $exifData['FNumber'];
1757
    $fnPeicesArray = explode('/', $fNumber);
1758
    if (count($fnPeicesArray) == 2) {
1759
      $fNumber = $fnPeicesArray[0] / $fnPeicesArray[1];
1760
    } else { $fNumber = '';}
1761
1762
    // *** Resolve ExposureProgram
1763
    if (isset($exifData['ExposureProgram'])) { $ep =  $exifData['ExposureProgram']; }
1764
    if (isset($ep)) { $ep = $this->resolveExposureProgram($ep); }
1765
1766
1767
    // *** Resolve MeteringMode
1768
    $mm = $exifData['MeteringMode'];
1769
    $mm = $this->resolveMeteringMode($mm);
1770
1771
    // *** Resolve Flash
1772
    $flash = $exifData['Flash'];
1773
    $flash = $this->resolveFlash($flash);
1774
1775
1776
    if (isset($exifData['Make'])) {
1777
      $exifDataArray['make'] = $exifData['Make'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$exifDataArray was never initialized. Although not strictly required by PHP, it is generally a good practice to add $exifDataArray = array(); before regardless.
Loading history...
1778
    } else { $exifDataArray['make'] = ''; }
1779
1780
    if (isset($exifData['Model'])) {
1781
      $exifDataArray['model'] = $exifData['Model'];
1782
    } else { $exifDataArray['model'] = ''; }
1783
1784
    if (isset($exifData['DateTime'])) {
1785
      $exifDataArray['date'] = $exifData['DateTime'];
1786
    } else { $exifDataArray['date'] = ''; }
1787
1788
    if (isset($exifData['ExposureTime'])) {
1789
      $exifDataArray['exposure time'] = $exifData['ExposureTime'] . ' sec.';
1790
    } else { $exifDataArray['exposure time'] = ''; }
1791
1792
    if ($apertureValue != '') {
1793
      $exifDataArray['aperture value'] = $apertureValue;
1794
    } else { $exifDataArray['aperture value'] = ''; }
1795
1796
    if (isset($exifData['COMPUTED']['ApertureFNumber'])) {
1797
      $exifDataArray['f-stop'] = $exifData['COMPUTED']['ApertureFNumber'];
1798
    } else { $exifDataArray['f-stop'] = ''; }
1799
1800
    if (isset($exifData['FNumber'])) {
1801
      $exifDataArray['fnumber'] = $exifData['FNumber'];
1802
    } else { $exifDataArray['fnumber'] = ''; }
1803
1804
    if ($fNumber != '') {
1805
      $exifDataArray['fnumber value'] = $fNumber;
1806
    } else { $exifDataArray['fnumber value'] = ''; }
1807
1808
    if (isset($exifData['ISOSpeedRatings'])) {
1809
      $exifDataArray['iso'] = $exifData['ISOSpeedRatings'];
1810
    } else { $exifDataArray['iso'] = ''; }
1811
1812
    if ($focalLength != '') {
1813
      $exifDataArray['focal length'] = $focalLength;
1814
    } else { $exifDataArray['focal length'] = ''; }
1815
1816
    if (isset($ep)) {
1817
      $exifDataArray['exposure program'] = $ep;
1818
    } else { $exifDataArray['exposure program'] = ''; }
1819
1820
    if ($mm != '') {
1821
      $exifDataArray['metering mode'] = $mm;
1822
    } else { $exifDataArray['metering mode'] = ''; }
1823
1824
    if ($flash != '') {
1825
      $exifDataArray['flash status'] = $flash;
1826
    } else { $exifDataArray['flash status'] = ''; }
1827
1828
    if (isset($exifData['Artist'])) {
1829
      $exifDataArray['creator'] = $exifData['Artist'] ;
1830
    } else { $exifDataArray['creator'] = ''; }
1831
1832
    if (isset($exifData['Copyright'])) {
1833
      $exifDataArray['copyright'] = $exifData['Copyright'];
1834
    } else { $exifDataArray['copyright'] = ''; }
1835
1836
    // *** Orientation
1837
    if (isset($exifData['Orientation'])) {
1838
        $exifDataArray['orientation'] = $exifData['Orientation'];
1839
    } else { $exifDataArray['orientation'] = ''; }
1840
1841
    return $exifDataArray;
1842
  }
1843
1844
  ## --------------------------------------------------------
1845
1846
  private function resolveExposureProgram($ep)
1847
  {
1848
    switch ($ep) {
1849
      case 0:
1850
        $ep = '';
1851
        break;
1852
      case 1:
1853
        $ep = 'manual';
1854
        break;
1855
      case 2:
1856
        $ep = 'normal program';
1857
        break;
1858
      case 3:
1859
        $ep = 'aperture priority';
1860
        break;
1861
      case 4:
1862
        $ep = 'shutter priority';
1863
        break;
1864
      case 5:
1865
        $ep = 'creative program';
1866
        break;
1867
      case 6:
1868
        $ep = 'action program';
1869
        break;
1870
      case 7:
1871
        $ep = 'portrait mode';
1872
        break;
1873
      case 8:
1874
        $ep = 'landscape mode';
1875
        break;
1876
1877
      default:
1878
        break;
1879
    }
1880
1881
    return $ep;
1882
  }
1883
1884
  ## --------------------------------------------------------
1885
1886
  private function resolveMeteringMode($mm)
1887
  {
1888
    switch ($mm) {
1889
      case 0:
1890
        $mm = 'unknown';
1891
        break;
1892
      case 1:
1893
        $mm = 'average';
1894
        break;
1895
      case 2:
1896
        $mm = 'center weighted average';
1897
        break;
1898
      case 3:
1899
        $mm = 'spot';
1900
        break;
1901
      case 4:
1902
        $mm = 'multi spot';
1903
        break;
1904
      case 5:
1905
        $mm = 'pattern';
1906
        break;
1907
      case 6:
1908
        $mm = 'partial';
1909
        break;
1910
      case 255:
1911
        $mm = 'other';
1912
        break;
1913
1914
      default:
1915
        break;
1916
    }
1917
1918
    return $mm;
1919
  }
1920
1921
  ## --------------------------------------------------------
1922
1923
  private function resolveFlash($flash)
1924
  {
1925
    switch ($flash) {
1926
      case 0:
1927
        $flash = 'flash did not fire';
1928
        break;
1929
      case 1:
1930
        $flash = 'flash fired';
1931
        break;
1932
      case 5:
1933
        $flash = 'strobe return light not detected';
1934
        break;
1935
      case 7:
1936
        $flash = 'strobe return light detected';
1937
        break;
1938
      case 9:
1939
        $flash = 'flash fired, compulsory flash mode';
1940
        break;
1941
      case 13:
1942
        $flash = 'flash fired, compulsory flash mode, return light not detected';
1943
        break;
1944
      case 15:
1945
        $flash = 'flash fired, compulsory flash mode, return light detected';
1946
        break;
1947
      case 16:
1948
        $flash = 'flash did not fire, compulsory flash mode';
1949
        break;
1950
      case 24:
1951
        $flash = 'flash did not fire, auto mode';
1952
        break;
1953
      case 25:
1954
        $flash = 'flash fired, auto mode';
1955
        break;
1956
      case 29:
1957
        $flash = 'flash fired, auto mode, return light not detected';
1958
        break;
1959
      case 31:
1960
        $flash = 'flash fired, auto mode, return light detected';
1961
        break;
1962
      case 32:
1963
        $flash = 'no flash function';
1964
        break;
1965
      case 65:
1966
        $flash = 'flash fired, red-eye reduction mode';
1967
        break;
1968
      case 69:
1969
        $flash = 'flash fired, red-eye reduction mode, return light not detected';
1970
        break;
1971
      case 71:
1972
        $flash = 'flash fired, red-eye reduction mode, return light detected';
1973
        break;
1974
      case 73:
1975
        $flash = 'flash fired, compulsory flash mode, red-eye reduction mode';
1976
        break;
1977
      case 77:
1978
        $flash = 'flash fired, compulsory flash mode, red-eye reduction mode, return light not detected';
1979
        break;
1980
      case 79:
1981
        $flash = 'flash fired, compulsory flash mode, red-eye reduction mode, return light detected';
1982
        break;
1983
      case 89:
1984
        $flash = 'flash fired, auto mode, red-eye reduction mode';
1985
        break;
1986
      case 93:
1987
        $flash = 'flash fired, auto mode, return light not detected, red-eye reduction mode';
1988
        break;
1989
      case 95:
1990
        $flash = 'flash fired, auto mode, return light detected, red-eye reduction mode';
1991
        break;
1992
1993
      default:
1994
        break;
1995
    }
1996
1997
    return $flash;
1998
1999
  }
2000
2001
2002
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
2003
  Get IPTC Data
2004
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
2005
2006
2007
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
2008
  Write IPTC Data
2009
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
2010
2011
  public function writeIPTCcaption($value)
2012
  # Caption
2013
  {
2014
    $this->writeIPTC(120, $value);
2015
  }
2016
2017
  ## --------------------------------------------------------
2018
2019
  public function writeIPTCwriter($value)
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2019
  public function writeIPTCwriter(/** @scrutinizer ignore-unused */ $value)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2020
  {
2021
    //$this->writeIPTC(65, $value);
2022
  }
2023
2024
  ## --------------------------------------------------------
2025
2026
  private function writeIPTC($dat, $value)
2027
  {
2028
2029
    # LIMIT TO JPG
2030
2031
    $caption_block = $this->iptc_maketag(2, $dat, $value);
2032
    $image_string = iptcembed($caption_block, $this->fileName);
2033
    file_put_contents('iptc.jpg', $image_string);
2034
  }
2035
2036
## --------------------------------------------------------
2037
2038
  private function iptc_maketag($rec,$dat,$val)
2039
  # Author:   Thies C. Arntzen
2040
  # Purpose:    Function to format the new IPTC text
2041
  # Param in:   $rec: Application record. (We’re working with #2)
2042
  #       $dat: Index. (120 for caption, 118 for contact. See the IPTC IIM
2043
  #         specification:
2044
  #         http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf
2045
  #       $val: Value/data/text. Make sure this is within the length
2046
  #         constraints of the IPTC IIM specification
2047
  # Ref:      http://blog.peterhaza.no/working-with-image-meta-data-in-exif-and-iptc-headers-from-php/
2048
  #       http://php.net/manual/en/function.iptcembed.php
2049
  #
2050
  {
2051
    $len = strlen($val);
2052
    if ($len < 0x8000)
2053
      return chr(0x1c).chr($rec).chr($dat).
2054
      chr($len >> 8).
2055
      chr($len & 0xff).
2056
      $val;
2057
    else
2058
      return chr(0x1c).chr($rec).chr($dat).
2059
      chr(0x80).chr(0x04).
2060
      chr(($len >> 24) & 0xff).
2061
      chr(($len >> 16) & 0xff).
2062
      chr(($len >> 8 ) & 0xff).
2063
      chr(($len ) & 0xff).
2064
      $val;
2065
  }
2066
2067
2068
2069
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
2070
  Write XMP Data
2071
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
2072
2073
  //http://xmpphptoolkit.sourceforge.net/
2074
2075
2076
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
2077
  Add Text
2078
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
2079
2080
  public function addText($text, $pos = '20x20', $padding = 0, $fontColor='#fff', $fontSize = 12, $angle = 0, $font = null)
2081
    # Author:     Jarrod Oberto
2082
  # Date:       18-11-09
2083
    # Purpose:    Add text to an image
2084
    # Param in:
2085
    # Param out:
2086
    # Reference:  http://php.net/manual/en/function.imagettftext.php
2087
    # Notes:      Make sure you supply the font.
2088
    #
2089
  {
2090
2091
    // *** Convert color
2092
    $rgbArray = $this->formatColor($fontColor);
2093
    $r = $rgbArray['r'];
2094
    $g = $rgbArray['g'];
2095
    $b = $rgbArray['b'];
2096
2097
    // *** Get text font
2098
    $font = $this->getTextFont($font);
2099
2100
    // *** Get text size
2101
    $textSizeArray = $this->getTextSize($fontSize, $angle, $font, $text);
2102
    $textWidth = $textSizeArray['width'];
2103
    $textHeight = $textSizeArray['height'];
2104
2105
    // *** Find co-ords to place text
2106
    $posArray = $this->calculatePosition($pos, $padding, $textWidth, $textHeight, false);
2107
    $x = $posArray['width'];
2108
    $y = $posArray['height'];
2109
2110
    $fontColor = imagecolorallocate($this->imageResized, $r, $g, $b);
2111
2112
    // *** Add text
2113
    imagettftext($this->imageResized, $fontSize, $angle, $x, $y, $fontColor, $font, $text);
0 ignored issues
show
Bug introduced by
$y of type double is incompatible with the type integer expected by parameter $y of imagettftext(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2113
    imagettftext($this->imageResized, $fontSize, $angle, $x, /** @scrutinizer ignore-type */ $y, $fontColor, $font, $text);
Loading history...
Bug introduced by
It seems like $x can also be of type double and string; however, parameter $x of imagettftext() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2113
    imagettftext($this->imageResized, $fontSize, $angle, /** @scrutinizer ignore-type */ $x, $y, $fontColor, $font, $text);
Loading history...
Bug introduced by
It seems like $font can also be of type false; however, parameter $fontfile of imagettftext() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2113
    imagettftext($this->imageResized, $fontSize, $angle, $x, $y, $fontColor, /** @scrutinizer ignore-type */ $font, $text);
Loading history...
2114
  }
2115
2116
  ## --------------------------------------------------------
2117
2118
  private function getTextFont($font)
2119
  {
2120
    // *** Font path (shou
2121
    $fontPath =  __DIR__ . '/' . $this->fontDir;
2122
2123
2124
    // *** The below is/may be needed depending on your version (see ref)
2125
    putenv('GDFONTPATH=' . realpath('.'));
2126
2127
    // *** Check if the passed in font exsits...
2128
    if ($font == null || !file_exists($font)) {
2129
2130
      // *** ...If not, default to this font.
2131
      $font = $fontPath . '/arimo.ttf';
2132
2133
      // *** Check our default font exists...
2134
      if (!file_exists($font)) {
2135
2136
        // *** If not, return false
2137
        if ($this->debug) { throw new Exception('Font not found'); }else{ return false; }
2138
      }
2139
    }
2140
2141
    return $font;
2142
2143
  }
2144
2145
  ## --------------------------------------------------------
2146
2147
  private function getTextSize($fontSize, $angle, $font, $text)
2148
  {
2149
2150
    // *** Define box (so we can get the width)
2151
    $box = @imagettfbbox($fontSize, $angle, $font, $text);
2152
2153
    // ***  Get width of text from dimensions
2154
    $textWidth = abs($box[4] - $box[0]);
2155
2156
    // ***  Get height of text from dimensions (should also be same as $fontSize)
2157
    $textHeight = abs($box[5] - $box[1]);
2158
2159
    return array('height' => $textHeight, 'width' => $textWidth);
2160
  }
2161
2162
2163
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
2164
  Add Watermark
2165
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
2166
2167
  public function addWatermark($watermarkImage, $pos, $padding = 0, $opacity = 0)
2168
    # Author:     Jarrod Oberto
2169
    # Date:       18-11-09
2170
    # Purpose:    Add watermark image
2171
    # Param in:   (str) $watermark: The watermark image
2172
  #       (str) $pos: Could be a pre-determined position such as:
2173
  #           tl = top left,
2174
  #           t  = top (middle),
2175
  #           tr = top right,
2176
  #           l  = left,
2177
  #           m  = middle,
2178
  #           r  = right,
2179
  #           bl = bottom left,
2180
  #           b  = bottom (middle),
2181
  #           br = bottom right
2182
  #         Or, it could be a co-ordinate position such as: 50x100
2183
  #
2184
  #       (int) $padding: If using a pre-determined position you can
2185
  #         adjust the padding from the edges by passing an amount
2186
  #         in pixels. If using co-ordinates, this value is ignored.
2187
    # Param out:
2188
    # Reference:  http://www.php.net/manual/en/image.examples-watermark.php
2189
    # Notes:      Based on example in reference.
2190
  #
2191
    #
2192
  {
2193
2194
    // Load the stamp and the photo to apply the watermark to
2195
    $stamp = $this->openImage ($watermarkImage);    # stamp
2196
    $im = $this->imageResized;            # photo
2197
2198
    // *** Get stamps width and height
2199
    $sx = imagesx($stamp);
2200
    $sy = imagesy($stamp);
2201
2202
    // *** Find co-ords to place image
2203
    $posArray = $this->calculatePosition($pos, $padding, $sx, $sy);
2204
    $x = $posArray['width'];
2205
    $y = $posArray['height'];
2206
2207
    // *** Set watermark opacity
2208
    if (fix_strtolower(strrchr($watermarkImage, '.')) === '.png') {
2209
2210
      $opacity = $this->invertTransparency($opacity, 100);
2211
      $this->filterOpacity($stamp, $opacity);
2212
    }
2213
2214
    // Copy the watermark image onto our photo
2215
    imagecopy($im, $stamp, $x, $y, 0, 0, imagesx($stamp), imagesy($stamp));
0 ignored issues
show
Bug introduced by
It seems like $y can also be of type string; however, parameter $dst_y of imagecopy() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2215
    imagecopy($im, $stamp, $x, /** @scrutinizer ignore-type */ $y, 0, 0, imagesx($stamp), imagesy($stamp));
Loading history...
Bug introduced by
It seems like $x can also be of type string; however, parameter $dst_x of imagecopy() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2215
    imagecopy($im, $stamp, /** @scrutinizer ignore-type */ $x, $y, 0, 0, imagesx($stamp), imagesy($stamp));
Loading history...
2216
2217
  }
2218
2219
  ## --------------------------------------------------------
2220
2221
  private function calculatePosition($pos, $padding, $assetWidth, $assetHeight, $upperLeft = true)
2222
  #
2223
  # Author:   Jarrod Oberto
2224
  # Date:   08-05-11
2225
  # Purpose:  Calculate the x, y pixel cordinates of the asset to place
2226
  # Params in:  (str) $pos: Either something like: "tl", "l", "br" or an
2227
  #         exact position like: "100x50"
2228
  #       (int) $padding: The amount of padding from the edge. Only
2229
  #         used for the predefined $pos.
2230
  #       (int) $assetWidth: The width of the asset to add to the image
2231
  #       (int) $assetHeight: The height of the asset to add to the image
2232
  #       (bol) $upperLeft: if true, the asset will be positioned based
2233
  #         on the upper left x, y coords. If false, it means you're
2234
  #         using the lower left as the basepoint and this will
2235
  #         convert it to the upper left position
2236
  # Params out:
2237
  # NOTE: this is done from the UPPER left corner!! But will convert lower
2238
  #   left basepoints to upper left if $upperleft is set to false
2239
  #
2240
  #
2241
  {
2242
    $pos = fix_strtolower($pos);
2243
2244
    // *** If co-ords have been entered
2245
    if (strstr($pos, 'x')) {
2246
      $pos = str_replace(' ', '', $pos);
2247
2248
      $xyArray = explode('x', $pos);
2249
      list($width, $height) = $xyArray;
2250
2251
    } else {
2252
2253
      switch ($pos) {
2254
        case 'tl':
2255
          $width = 0 + $padding;
2256
          $height = 0 + $padding;
2257
          break;
2258
2259
        case 't':
2260
          $width = ($this->width / 2) - ($assetWidth / 2);
2261
          $height = 0 + $padding;
2262
          break;
2263
2264
        case 'tr':
2265
          $width = $this->width - $assetWidth - $padding;
2266
          $height = 0 + $padding;;
2267
          break;
2268
2269
        case 'l':
2270
          $width = 0 + $padding;
2271
          $height = ($this->height / 2) - ($assetHeight / 2);
2272
          break;
2273
2274
        case 'm':
2275
          $width = ($this->width / 2) - ($assetWidth / 2);
2276
          $height = ($this->height / 2) - ($assetHeight / 2);
2277
          break;
2278
2279
        case 'r':
2280
          $width = $this->width - $assetWidth - $padding;
2281
          $height = ($this->height / 2) - ($assetHeight / 2);
2282
          break;
2283
2284
        case 'bl':
2285
          $width = 0 + $padding;
2286
          $height = $this->height - $assetHeight - $padding;
2287
          break;
2288
2289
        case 'b':
2290
          $width = ($this->width / 2) - ($assetWidth / 2);
2291
          $height = $this->height - $assetHeight - $padding;
2292
          break;
2293
2294
        case 'br':
2295
          $width = $this->width - $assetWidth - $padding;
2296
          $height = $this->height - $assetHeight - $padding;
2297
          break;
2298
2299
        default:
2300
          $width = 0;
2301
          $height = 0;
2302
          break;
2303
      }
2304
    }
2305
2306
    if (!$upperLeft) {
2307
      $height = $height + $assetHeight;
2308
    }
2309
2310
    return array('width' => $width, 'height' => $height);
2311
  }
2312
2313
2314
  ## --------------------------------------------------------
2315
2316
  private function filterOpacity(&$img, $opacity = 75)
2317
  #
2318
  # Author:     aiden dot mail at freemail dot hu
2319
  # Author date:  29-03-08 08:16
2320
  # Date added:   08-05-11
2321
  # Purpose:    Change opacity of image
2322
  # Params in:    $img: Image resource id
2323
  #         (int) $opacity: the opacity amount: 0-100, 100 being not opaque.
2324
  # Params out:   (bool) true on success, else false
2325
  # Ref:      http://www.php.net/manual/en/function.imagefilter.php#82162
2326
  # Notes:      png only
2327
  #
2328
  {
2329
2330
    if (!isset($opacity)) {
2331
      return false;
2332
    }
2333
2334
    if ($opacity == 100) {
2335
      return true;
2336
    }
2337
2338
    $opacity /= 100;
2339
2340
    //get image width and height
2341
    $w = imagesx($img);
2342
    $h = imagesy($img);
2343
2344
    //turn alpha blending off
2345
    imagealphablending($img, false);
2346
2347
    //find the most opaque pixel in the image (the one with the smallest alpha value)
2348
    $minalpha = 127;
2349
    for ($x = 0; $x < $w; $x++)
2350
      for ($y = 0; $y < $h; $y++) {
2351
        $alpha = ( imagecolorat($img, $x, $y) >> 24 ) & 0xFF;
2352
        if ($alpha < $minalpha) {
2353
          $minalpha = $alpha;
2354
        }
2355
      }
2356
2357
    //loop through image pixels and modify alpha for each
2358
    for ($x = 0; $x < $w; $x++) {
2359
      for ($y = 0; $y < $h; $y++) {
2360
        //get current alpha value (represents the TANSPARENCY!)
2361
        $colorxy = imagecolorat($img, $x, $y);
2362
        $alpha = ( $colorxy >> 24 ) & 0xFF;
2363
        //calculate new alpha
2364
        if ($minalpha !== 127) {
2365
          $alpha = 127 + 127 * $opacity * ( $alpha - 127 ) / ( 127 - $minalpha );
2366
        } else {
2367
          $alpha += 127 * $opacity;
2368
        }
2369
        //get the color index with new alpha
2370
        $alphacolorxy = imagecolorallocatealpha($img, ( $colorxy >> 16 ) & 0xFF, ( $colorxy >> 8 ) & 0xFF, $colorxy & 0xFF, $alpha);
2371
        //set pixel with the new color + opacity
2372
        if (!imagesetpixel($img, $x, $y, $alphacolorxy)) {
2373
2374
          return false;
2375
        }
2376
      }
2377
    }
2378
2379
    return true;
2380
  }
2381
2382
## --------------------------------------------------------
2383
2384
    private function openImage($file)
2385
    # Author:     Jarrod Oberto
2386
    # Date:       27-02-08
2387
    # Purpose:
2388
    # Param in:
2389
    # Param out:  n/a
2390
    # Reference:
2391
    # Notes:
2392
    #
2393
    {
2394
2395
    if (!file_exists($file) && !$this->checkStringStartsWith('http://', $file)) { if ($this->debug) { throw new Exception('Image not found.'); }else{ throw new Exception(); }};
2396
2397
        // *** Get extension
2398
        $extension = strrchr($file, '.');
2399
        $extension = fix_strtolower($extension);
2400
        switch($extension)
2401
        {
2402
            case '.jpg':
2403
            case '.jpeg':
2404
                $img = @imagecreatefromjpeg($file);
2405
                break;
2406
            case '.gif':
2407
                $img = @imagecreatefromgif($file);
2408
                break;
2409
            case '.png':
2410
                $img = @imagecreatefrompng($file);
2411
                break;
2412
            case '.bmp':
2413
                $img = @$this->imagecreatefrombmp($file);
2414
                break;
2415
            case '.psd':
2416
                $img = @$this->imagecreatefrompsd($file);
2417
                break;
2418
2419
2420
            // ... etc
2421
2422
            default:
2423
                $img = false;
2424
                break;
2425
        }
2426
2427
        return $img;
2428
    }
2429
2430
## --------------------------------------------------------
2431
2432
  public function reset()
2433
  #
2434
  # Author:   Jarrod Oberto
2435
  # Date:   30-08-11
2436
  # Purpose:  Reset the resource (allow further editing)
2437
  # Params in:
2438
  # Params out:
2439
  # Notes:
2440
  #
2441
  {
2442
    $this->__construct($this->fileName);
2443
  }
2444
2445
## --------------------------------------------------------
2446
2447
    public function saveImage($savePath, $imageQuality="100")
2448
    # Author:     Jarrod Oberto
2449
    # Date:       27-02-08
2450
    # Purpose:    Saves the image
2451
    # Param in:   $savePath: Where to save the image including filename:
2452
    #             $imageQuality: image quality you want the image saved at 0-100
2453
    # Param out:  n/a
2454
    # Reference:
2455
    # Notes:    * gif doesn't have a quality parameter
2456
  #       * jpg has a quality setting 0-100 (100 being the best)
2457
    #       * png has a quality setting 0-9 (0 being the best)
2458
  #
2459
  #             * bmp files have no native support for bmp files. We use a
2460
  #       third party class to save as bmp.
2461
    {
2462
2463
    // *** Perform a check or two.
2464
    if (!is_resource($this->imageResized)) { if ($this->debug) { throw new Exception('saveImage: This is not a resource.'); }else{ throw new Exception(); }}
2465
    $fileInfoArray = pathinfo($savePath);
2466
    clearstatcache();
2467
    if (!is_writable($fileInfoArray['dirname'])) {  if ($this->debug) { throw new Exception('The path is not writable. Please check your permissions.'); }else{ throw new Exception(); }}
2468
2469
    // *** Get extension
2470
        $extension = strrchr($savePath, '.');
2471
        $extension = fix_strtolower($extension);
2472
2473
    $error = '';
2474
2475
        switch($extension)
2476
        {
2477
            case '.jpg':
2478
            case '.jpeg':
2479
        $this->checkInterlaceImage($this->isInterlace);
2480
        if (imagetypes() & IMG_JPG) {
2481
          imagejpeg($this->imageResized, $savePath, $imageQuality);
2482
        } else { $error = 'jpg'; }
2483
                break;
2484
2485
            case '.gif':
2486
        $this->checkInterlaceImage($this->isInterlace);
2487
        if (imagetypes() & IMG_GIF) {
2488
          imagegif($this->imageResized, $savePath);
2489
        } else { $error = 'gif'; }
2490
                break;
2491
2492
            case '.png':
2493
        // *** Scale quality from 0-100 to 0-9
2494
        $scaleQuality = round(($imageQuality/100) * 9);
2495
2496
        // *** Invert qualit setting as 0 is best, not 9
2497
        $invertScaleQuality = 9 - $scaleQuality;
2498
2499
        $this->checkInterlaceImage($this->isInterlace);
2500
        if (imagetypes() & IMG_PNG) {
2501
           imagepng($this->imageResized, $savePath, $invertScaleQuality);
0 ignored issues
show
Bug introduced by
$invertScaleQuality of type double is incompatible with the type integer expected by parameter $quality of imagepng(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2501
           imagepng($this->imageResized, $savePath, /** @scrutinizer ignore-type */ $invertScaleQuality);
Loading history...
2502
        } else { $error = 'png'; }
2503
                break;
2504
2505
            case '.bmp':
2506
        file_put_contents($savePath, $this->GD2BMPstring($this->imageResized));
2507
          break;
2508
2509
2510
            // ... etc
2511
2512
            default:
2513
        // *** No extension - No save.
2514
        $this->errorArray[] = 'This file type (' . $extension . ') is not supported. File not saved.';
2515
                break;
2516
        }
2517
2518
    //imagedestroy($this->imageResized);
2519
2520
    // *** Display error if a file type is not supported.
2521
    if ($error != '') {
2522
      $this->errorArray[] = $error . ' support is NOT enabled. File not saved.';
2523
    }
2524
    }
2525
2526
## --------------------------------------------------------
2527
2528
  public function displayImage($fileType = 'jpg', $imageQuality="100")
2529
    # Author:     Jarrod Oberto
2530
    # Date:       18-11-09
2531
    # Purpose:    Display images directly to the browser
2532
    # Param in:   The image type you want to display
2533
    # Param out:
2534
    # Reference:
2535
    # Notes:
2536
    #
2537
  {
2538
2539
    if (!is_resource($this->imageResized)) { if ($this->debug) { throw new Exception('saveImage: This is not a resource.'); }else{ throw new Exception(); }}
2540
2541
        switch($fileType)
2542
        {
2543
            case 'jpg':
2544
            case 'jpeg':
2545
        header('Content-type: image/jpeg');
2546
        imagejpeg($this->imageResized, '', $imageQuality);
2547
                break;
2548
            case 'gif':
2549
        header('Content-type: image/gif');
2550
        imagegif($this->imageResized);
2551
                break;
2552
            case 'png':
2553
        header('Content-type: image/png');
2554
2555
        // *** Scale quality from 0-100 to 0-9
2556
        $scaleQuality = round(($imageQuality/100) * 9);
2557
2558
        // *** Invert qualit setting as 0 is best, not 9
2559
        $invertScaleQuality = 9 - $scaleQuality;
2560
2561
        imagepng($this->imageResized, '', $invertScaleQuality);
0 ignored issues
show
Bug introduced by
$invertScaleQuality of type double is incompatible with the type integer expected by parameter $quality of imagepng(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2561
        imagepng($this->imageResized, '', /** @scrutinizer ignore-type */ $invertScaleQuality);
Loading history...
2562
        break;
2563
      case 'bmp':
2564
        echo 'bmp file format is not supported.';
2565
        break;
2566
2567
            // ... etc
2568
2569
            default:
2570
        // *** No extension - No save.
2571
                break;
2572
        }
2573
2574
2575
    //imagedestroy($this->imageResized);
2576
  }
2577
2578
## --------------------------------------------------------
2579
2580
  public function setTransparency($bool)
2581
  # Sep 2011
2582
  {
2583
    $this->keepTransparency = $bool;
2584
  }
2585
2586
## --------------------------------------------------------
2587
2588
  public function setFillColor($value)
2589
  # Sep 2011
2590
    # Param in:   (mixed) $value: (array) Could be an array of RGB
2591
  #               (str) Could be hex #ffffff or #fff, fff, ffffff
2592
  #
2593
  # If the keepTransparency is set to false, then no transparency is to be used.
2594
  # This is ideal when you want to save as jpg.
2595
  #
2596
  # this method allows you to set the background color to use instead of
2597
  # transparency.
2598
  #
2599
  {
2600
    $colorArray = $this->formatColor($value);
2601
    $this->fillColorArray = $colorArray;
2602
  }
2603
2604
## --------------------------------------------------------
2605
2606
  public function setCropFromTop($value)
2607
  # Sep 2011
2608
  {
2609
    $this->cropFromTopPercent = $value;
2610
  }
2611
2612
## --------------------------------------------------------
2613
2614
    public function testGDInstalled()
2615
    # Author:     Jarrod Oberto
2616
    # Date:       27-02-08
2617
    # Purpose:    Test to see if GD is installed
2618
    # Param in:   n/a
2619
    # Param out:  (bool) True is gd extension loaded otherwise false
2620
    # Reference:
2621
    # Notes:
2622
    #
2623
    {
2624
        if(extension_loaded('gd') && function_exists('gd_info'))
2625
        {
2626
            $gdInstalled = true;
2627
        }
2628
        else
2629
        {
2630
            $gdInstalled = false;
2631
        }
2632
2633
        return $gdInstalled;
2634
    }
2635
2636
## --------------------------------------------------------
2637
2638
    public function testEXIFInstalled()
2639
    # Author:     Jarrod Oberto
2640
    # Date:       08-05-11
2641
    # Purpose:    Test to see if EXIF is installed
2642
    # Param in:   n/a
2643
    # Param out:  (bool) True is exif extension loaded otherwise false
2644
    # Reference:
2645
    # Notes:
2646
    #
2647
    {
2648
        if(extension_loaded('exif'))
2649
        {
2650
            $exifInstalled = true;
2651
        }
2652
        else
2653
        {
2654
            $exifInstalled = false;
2655
        }
2656
2657
        return $exifInstalled;
2658
    }
2659
2660
## --------------------------------------------------------
2661
2662
    public function testIsImage($image)
2663
    # Author:     Jarrod Oberto
2664
    # Date:       27-02-08
2665
    # Purpose:    Test if file is an image
2666
    # Param in:   n/a
2667
    # Param out:  n/a
2668
    # Reference:
2669
    # Notes:
2670
    #
2671
    {
2672
        if ($image)
2673
        {
2674
            $fileIsImage = true;
2675
        }
2676
        else
2677
        {
2678
            $fileIsImage = false;
2679
        }
2680
2681
        return $fileIsImage;
2682
    }
2683
2684
## --------------------------------------------------------
2685
2686
    public function testFunct()
2687
    # Author:     Jarrod Oberto
2688
    # Date:       27-02-08
2689
    # Purpose:    Test Function
2690
    # Param in:   n/a
2691
    # Param out:  n/a
2692
    # Reference:
2693
    # Notes:
2694
    #
2695
    {
2696
        echo $this->height;
2697
    }
2698
2699
## --------------------------------------------------------
2700
2701
    public function setForceStretch($value)
2702
    # Author:     Jarrod Oberto
2703
    # Date:       23-12-10
2704
    # Purpose:
2705
    # Param in:   (bool) $value
2706
    # Param out:  n/a
2707
    # Reference:
2708
    # Notes:
2709
    #
2710
    {
2711
        $this->forceStretch = $value;
2712
    }
2713
2714
## --------------------------------------------------------
2715
2716
    public function setFile($fileName)
2717
    # Author:     Jarrod Oberto
2718
    # Date:       28-02-08
2719
    # Purpose:
2720
    # Param in:   n/a
2721
    # Param out:  n/a
2722
    # Reference:
2723
    # Notes:
2724
    #
2725
    {
2726
        self::__construct($fileName);
0 ignored issues
show
Bug Best Practice introduced by
The method imageLib::__construct() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2726
        self::/** @scrutinizer ignore-call */ 
2727
              __construct($fileName);
Loading history...
2727
    }
2728
2729
## --------------------------------------------------------
2730
2731
  public function getFileName()
2732
    # Author:     Jarrod Oberto
2733
    # Date:       10-09-08
2734
    # Purpose:
2735
    # Param in:   n/a
2736
    # Param out:  n/a
2737
    # Reference:
2738
    # Notes:
2739
    #
2740
    {
2741
      return $this->fileName;
2742
    }
2743
2744
## --------------------------------------------------------
2745
2746
  public function getHeight()
2747
    {
2748
      return $this->height;
2749
    }
2750
2751
## --------------------------------------------------------
2752
2753
  public function getWidth()
2754
    {
2755
      return $this->width;
2756
    }
2757
2758
## --------------------------------------------------------
2759
2760
  public function getOriginalHeight()
2761
    {
2762
      return $this->heightOriginal;
2763
    }
2764
2765
## --------------------------------------------------------
2766
2767
  public function getOriginalWidth()
2768
    {
2769
      return $this->widthOriginal;
2770
    }
2771
2772
## --------------------------------------------------------
2773
2774
  public function getErrors()
2775
    # Author:     Jarrod Oberto
2776
    # Date:       19-11-09
2777
    # Purpose:    Returns the error array
2778
    # Param in:   n/a
2779
    # Param out:  Array of errors
2780
    # Reference:
2781
    # Notes:
2782
    #
2783
  {
2784
    return $this->errorArray;
2785
  }
2786
2787
## --------------------------------------------------------
2788
2789
  private function checkInterlaceImage($isEnabled)
2790
  # jpg will use progressive (they don't use interace)
2791
  {
2792
    if ($isEnabled) {
2793
      imageinterlace($this->imageResized, $isEnabled);
2794
    }
2795
  }
2796
2797
## --------------------------------------------------------
2798
2799
  protected function formatColor($value)
2800
    # Author:     Jarrod Oberto
2801
    # Date:       09-05-11
2802
    # Purpose:    Determine color method passed in and return color as RGB
2803
    # Param in:   (mixed) $value: (array) Could be an array of RGB
2804
  #               (str) Could be hex #ffffff or #fff, fff, ffffff
2805
    # Param out:
2806
    # Reference:
2807
    # Notes:
2808
    #
2809
  {
2810
    $rgbArray = array();
2811
2812
    // *** If it's an array it should be R, G, B
2813
    if (is_array($value)) {
2814
2815
      if (key($value) == 0 && count($value) == 3) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing key($value) of type integer|null|string to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
2816
2817
        $rgbArray['r'] = $value[0];
2818
        $rgbArray['g'] = $value[1];
2819
        $rgbArray['b'] = $value[2];
2820
2821
      } else {
2822
        $rgbArray = $value;
2823
      }
2824
    } else if (fix_strtolower($value) === 'transparent') {
2825
2826
      $rgbArray = array(
2827
        'r' => 255,
2828
        'g' => 255,
2829
        'b' => 255,
2830
        'a' => 127
2831
      );
2832
2833
    } else {
2834
2835
      // *** ...Else it should be hex. Let's make it RGB
2836
      $rgbArray = $this -> hex2dec($value);
2837
    }
2838
2839
    return $rgbArray;
2840
  }
2841
2842
  ## --------------------------------------------------------
2843
2844
  function hex2dec($hex)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2845
  # Purpose:  Convert #hex color to RGB
2846
  {
2847
    $color = str_replace('#', '', $hex);
2848
2849
    if (strlen($color) == 3) {
2850
      $color = $color . $color;
2851
    }
2852
2853
    $rgb = array(
2854
      'r' => hexdec(substr($color, 0, 2)),
2855
      'g' => hexdec(substr($color, 2, 2)),
2856
      'b' => hexdec(substr($color, 4, 2)),
2857
      'a' => 0
2858
    );
2859
    return $rgb;
2860
  }
2861
2862
  ## --------------------------------------------------------
2863
2864
  private function createImageColor ($colorArray)
0 ignored issues
show
Unused Code introduced by
The method createImageColor() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
2865
  {
2866
    $r = $colorArray['r'];
2867
    $g = $colorArray['g'];
2868
    $b = $colorArray['b'];
2869
2870
    return imagecolorallocate($this->imageResized, $r, $g, $b);
2871
  }
2872
2873
  ## --------------------------------------------------------
2874
2875
  private function testColorExists($colorArray)
2876
  {
2877
    $r = $colorArray['r'];
2878
    $g = $colorArray['g'];
2879
    $b = $colorArray['b'];
2880
2881
    if (imagecolorexact($this->imageResized, $r, $g, $b) == -1) {
2882
      return false;
2883
    } else {
2884
      return true;
2885
    }
2886
  }
2887
2888
  ## --------------------------------------------------------
2889
2890
  private function findUnusedGreen()
2891
  # Purpose:  We find a green color suitable to use like green-screen effect.
2892
  #     Therefore, the color must not exist in the image.
2893
  {
2894
    $green = 255;
2895
2896
    do {
2897
2898
      $greenChroma = array(0, $green, 0);
2899
      $colorArray = $this->formatColor($greenChroma);
2900
      $match = $this->testColorExists($colorArray);
2901
      $green--;
2902
2903
    } while ($match == false && $green > 0);
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2904
2905
    // *** If no match, just bite the bullet and use green value of 255
2906
    if (!$match) {
2907
      $greenChroma = array(0, $green, 0);
2908
    }
2909
2910
    return $greenChroma;
2911
  }
2912
2913
  ## --------------------------------------------------------
2914
2915
  private function findUnusedBlue()
0 ignored issues
show
Unused Code introduced by
The method findUnusedBlue() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
2916
  # Purpose:  We find a green color suitable to use like green-screen effect.
2917
  #     Therefore, the color must not exist in the image.
2918
  {
2919
    $blue = 255;
2920
2921
    do {
2922
2923
      $blueChroma = array(0, 0, $blue);
2924
      $colorArray = $this->formatColor($blueChroma);
2925
      $match = $this->testColorExists($colorArray);
2926
      $blue--;
2927
2928
    } while ($match == false && $blue > 0);
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2929
2930
    // *** If no match, just bite the bullet and use blue value of 255
2931
    if (!$match) {
2932
      $blueChroma = array(0, 0, $blue);
2933
    }
2934
2935
    return $blueChroma;
2936
  }
2937
2938
  ## --------------------------------------------------------
2939
2940
  private function invertTransparency($value, $originalMax, $invert=true)
2941
  # Purpose:  This does two things:
2942
  #       1) Convert the range from 0-127 to 0-100
2943
  #       2) Inverts value to 100 is not transparent while 0 is fully
2944
  #          transparent (like Photoshop)
2945
  {
2946
    // *** Test max range
2947
    if ($value > $originalMax) {
2948
      $value = $originalMax;
2949
    }
2950
2951
    // *** Test min range
2952
    if ($value < 0) {
2953
      $value = 0;
2954
    }
2955
2956
    if ($invert) {
2957
      return $originalMax - (($value/100) * $originalMax);
2958
    } else {
2959
      return ($value/100) * $originalMax;
2960
    }
2961
  }
2962
2963
  ## --------------------------------------------------------
2964
2965
  private function transparentImage($src)
2966
  {
2967
    // *** making images with white bg transparent
2968
    $r1 = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $r1 is dead and can be removed.
Loading history...
2969
    $g1 = 255;
0 ignored issues
show
Unused Code introduced by
The assignment to $g1 is dead and can be removed.
Loading history...
2970
    $b1 = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $b1 is dead and can be removed.
Loading history...
2971
    for ($x = 0; $x < imagesx($src); ++$x) {
2972
      for ($y = 0; $y < imagesy($src); ++$y) {
2973
        $color = imagecolorat($src, $x, $y);
2974
        $r = ($color >> 16) & 0xFF;
2975
        $g = ($color >> 8) & 0xFF;
2976
        $b = $color & 0xFF;
2977
        for ($i = 0; $i < 270; $i++) {
2978
          //if ($r . $g . $b == ($r1 + $i) . ($g1 + $i) . ($b1 + $i)) {
2979
          if ($r == 0 && $g == 255 && $b == 0) {
2980
          //if ($g == 255) {
2981
            $trans_colour = imagecolorallocatealpha($src, 0, 0, 0, 127);
2982
            imagefill($src, $x, $y, $trans_colour);
2983
          }
2984
        }
2985
      }
2986
    }
2987
2988
    return $src;
2989
  }
2990
2991
  ## --------------------------------------------------------
2992
2993
  function checkStringStartsWith($needle, $haystack)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2994
  # Check if a string starts with a specific pattern
2995
  {
2996
    return (substr($haystack, 0, strlen($needle))==$needle);
2997
  }
2998
2999
3000
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
3001
  BMP SUPPORT (SAVING) - James Heinrich
3002
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
3003
3004
  private function GD2BMPstring(&$gd_image)
3005
    # Author:     James Heinrich
3006
    # Purpose:    Save file as type bmp
3007
    # Param in:   The image canvas (passed as ref)
3008
    # Param out:
3009
    # Reference:
3010
    # Notes:    This code was stripped out of two external files
3011
  #       (phpthumb.bmp.php,phpthumb.functions.php) and added below to
3012
  #       avoid dependancies.
3013
    #
3014
  {
3015
    $imageX = imagesx($gd_image);
3016
    $imageY = imagesy($gd_image);
3017
3018
    $BMP = '';
3019
    for ($y = ($imageY - 1); $y >= 0; $y--) {
3020
      $thisline = '';
3021
      for ($x = 0; $x < $imageX; $x++) {
3022
        $argb = $this->GetPixelColor($gd_image, $x, $y);
3023
        $thisline .= chr($argb['blue']).chr($argb['green']).chr($argb['red']);
3024
      }
3025
      while (strlen($thisline) % 4) {
3026
        $thisline .= "\x00";
3027
      }
3028
      $BMP .= $thisline;
3029
    }
3030
3031
    $bmpSize = strlen($BMP) + 14 + 40;
3032
    // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
3033
    $BITMAPFILEHEADER  = 'BM';                                    // WORD    bfType;
3034
    $BITMAPFILEHEADER .= $this->LittleEndian2String($bmpSize, 4); // DWORD   bfSize;
3035
    $BITMAPFILEHEADER .= $this->LittleEndian2String(       0, 2); // WORD    bfReserved1;
3036
    $BITMAPFILEHEADER .= $this->LittleEndian2String(       0, 2); // WORD    bfReserved2;
3037
    $BITMAPFILEHEADER .= $this->LittleEndian2String(      54, 4); // DWORD   bfOffBits;
3038
3039
    // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
3040
    $BITMAPINFOHEADER  = $this->LittleEndian2String(      40, 4); // DWORD  biSize;
3041
    $BITMAPINFOHEADER .= $this->LittleEndian2String( $imageX, 4); // LONG   biWidth;
3042
    $BITMAPINFOHEADER .= $this->LittleEndian2String( $imageY, 4); // LONG   biHeight;
3043
    $BITMAPINFOHEADER .= $this->LittleEndian2String(       1, 2); // WORD   biPlanes;
3044
    $BITMAPINFOHEADER .= $this->LittleEndian2String(      24, 2); // WORD   biBitCount;
3045
    $BITMAPINFOHEADER .= $this->LittleEndian2String(       0, 4); // DWORD  biCompression;
3046
    $BITMAPINFOHEADER .= $this->LittleEndian2String(       0, 4); // DWORD  biSizeImage;
3047
    $BITMAPINFOHEADER .= $this->LittleEndian2String(    2835, 4); // LONG   biXPelsPerMeter;
3048
    $BITMAPINFOHEADER .= $this->LittleEndian2String(    2835, 4); // LONG   biYPelsPerMeter;
3049
    $BITMAPINFOHEADER .= $this->LittleEndian2String(       0, 4); // DWORD  biClrUsed;
3050
    $BITMAPINFOHEADER .= $this->LittleEndian2String(       0, 4); // DWORD  biClrImportant;
3051
3052
    return $BITMAPFILEHEADER.$BITMAPINFOHEADER.$BMP;
3053
  }
3054
3055
## --------------------------------------------------------
3056
3057
  private function GetPixelColor(&$img, $x, $y)
3058
    # Author:     James Heinrich
3059
    # Purpose:
3060
    # Param in:
3061
    # Param out:
3062
    # Reference:
3063
    # Notes:
3064
    #
3065
  {
3066
    if (!is_resource($img)) {
3067
      return false;
3068
    }
3069
    return @imagecolorsforindex($img, @imagecolorat($img, $x, $y));
3070
  }
3071
3072
## --------------------------------------------------------
3073
3074
  private function LittleEndian2String($number, $minbytes=1)
3075
    # Author:     James Heinrich
3076
    # Purpose:    BMP SUPPORT (SAVING)
3077
    # Param in:
3078
    # Param out:
3079
    # Reference:
3080
    # Notes:
3081
    #
3082
  {
3083
    $intstring = '';
3084
    while ($number > 0) {
3085
      $intstring = $intstring.chr($number & 255);
3086
      $number >>= 8;
3087
    }
3088
    return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
3089
  }
3090
3091
3092
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
3093
  BMP SUPPORT (READING)
3094
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
3095
3096
  private function ImageCreateFromBMP($filename)
3097
    # Author:     DHKold
3098
    # Date:     The 15th of June 2005
3099
  # Version:    2.0B
3100
    # Purpose:    To create an image from a BMP file.
3101
    # Param in:   BMP file to open.
3102
    # Param out:  Return a resource like the other ImageCreateFrom functions
3103
    # Reference:  http://us3.php.net/manual/en/function.imagecreate.php#53879
3104
  # Bug fix:    Author:   domelca at terra dot es
3105
  #       Date:   06 March 2008
3106
  #       Fix:    Correct 16bit BMP support
3107
    # Notes:
3108
  #
3109
  {
3110
3111
    //Ouverture du fichier en mode binaire
3112
    if (! $f1 = fopen($filename,"rb")) return FALSE;
3113
3114
    //1 : Chargement des ent�tes FICHIER
3115
    $FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
3116
    if ($FILE['file_type'] != 19778) return FALSE;
3117
3118
    //2 : Chargement des ent�tes BMP
3119
    $BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'.
3120
           '/Vcompression/Vsize_bitmap/Vhoriz_resolution'.
3121
           '/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40));
3122
    $BMP['colors'] = pow(2,$BMP['bits_per_pixel']);
3123
3124
    if ($BMP['size_bitmap'] == 0) $BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset'];
3125
3126
    $BMP['bytes_per_pixel'] = $BMP['bits_per_pixel']/8;
3127
    $BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']);
3128
    $BMP['decal'] = ($BMP['width']*$BMP['bytes_per_pixel']/4);
3129
       $BMP['decal'] -= floor($BMP['width']*$BMP['bytes_per_pixel']/4);
3130
    $BMP['decal'] = 4-(4*$BMP['decal']);
3131
3132
    if ($BMP['decal'] == 4) $BMP['decal'] = 0;
3133
3134
    //3 : Chargement des couleurs de la palette
3135
    $PALETTE = array();
3136
    if ($BMP['colors'] < 16777216)
3137
    {
3138
      $PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4));
3139
    }
3140
3141
    //4 : Cr�ation de l'image
3142
    $IMG = fread($f1,$BMP['size_bitmap']);
3143
    $VIDE = chr(0);
3144
3145
    $res = imagecreatetruecolor($BMP['width'],$BMP['height']);
3146
    $P = 0;
3147
    $Y = $BMP['height']-1;
3148
    while ($Y >= 0)
3149
    {
3150
      $X=0;
3151
      while ($X < $BMP['width'])
3152
      {
3153
        if ($BMP['bits_per_pixel'] == 24)
3154
          $COLOR = unpack("V",substr($IMG,$P,3).$VIDE);
3155
        elseif ($BMP['bits_per_pixel'] == 16)
3156
        {
3157
3158
          /*
3159
           * BMP 16bit fix
3160
           * =================
3161
           *
3162
           * Ref: http://us3.php.net/manual/en/function.imagecreate.php#81604
3163
           *
3164
           * Notes:
3165
           * "don't work with bmp 16 bits_per_pixel. change pixel
3166
           * generator for this."
3167
           *
3168
           */
3169
3170
          // *** Original code (don't work)
3171
          //$COLOR = unpack("n",substr($IMG,$P,2));
3172
          //$COLOR[1] = $PALETTE[$COLOR[1]+1];
3173
3174
          $COLOR = unpack("v",substr($IMG,$P,2));
3175
          $blue = ($COLOR[1] & 0x001f) << 3;
3176
          $green = ($COLOR[1] & 0x07e0) >> 3;
3177
          $red = ($COLOR[1] & 0xf800) >> 8;
3178
          $COLOR[1] = $red * 65536 + $green * 256 + $blue;
3179
3180
        }
3181
        elseif ($BMP['bits_per_pixel'] == 8)
3182
        {
3183
          $COLOR = unpack("n",$VIDE.substr($IMG,$P,1));
3184
          $COLOR[1] = $PALETTE[$COLOR[1]+1];
3185
        }
3186
        elseif ($BMP['bits_per_pixel'] == 4)
3187
        {
3188
          $COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
0 ignored issues
show
Bug introduced by
floor($P) of type double is incompatible with the type integer expected by parameter $offset of substr(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3188
          $COLOR = unpack("n",$VIDE.substr($IMG,/** @scrutinizer ignore-type */ floor($P),1));
Loading history...
3189
          if (($P*2)%2 == 0) $COLOR[1] = ($COLOR[1] >> 4) ; else $COLOR[1] = ($COLOR[1] & 0x0F);
3190
          $COLOR[1] = $PALETTE[$COLOR[1]+1];
3191
        }
3192
        elseif ($BMP['bits_per_pixel'] == 1)
3193
        {
3194
          $COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
3195
          if     (($P*8)%8 == 0) $COLOR[1] =  $COLOR[1]        >>7;
3196
          elseif (($P*8)%8 == 1) $COLOR[1] = ($COLOR[1] & 0x40)>>6;
3197
          elseif (($P*8)%8 == 2) $COLOR[1] = ($COLOR[1] & 0x20)>>5;
3198
          elseif (($P*8)%8 == 3) $COLOR[1] = ($COLOR[1] & 0x10)>>4;
3199
          elseif (($P*8)%8 == 4) $COLOR[1] = ($COLOR[1] & 0x8)>>3;
3200
          elseif (($P*8)%8 == 5) $COLOR[1] = ($COLOR[1] & 0x4)>>2;
3201
          elseif (($P*8)%8 == 6) $COLOR[1] = ($COLOR[1] & 0x2)>>1;
3202
          elseif (($P*8)%8 == 7) $COLOR[1] = ($COLOR[1] & 0x1);
3203
          $COLOR[1] = $PALETTE[$COLOR[1]+1];
3204
        }
3205
        else
3206
          return FALSE;
3207
3208
        imagesetpixel($res,$X,$Y,$COLOR[1]);
3209
        $X++;
3210
        $P += $BMP['bytes_per_pixel'];
3211
      }
3212
3213
      $Y--;
3214
      $P+=$BMP['decal'];
3215
    }
3216
    //Fermeture du fichier
3217
    fclose($f1);
3218
3219
    return $res;
3220
  }
3221
3222
3223
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-
3224
  PSD SUPPORT (READING)
3225
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/
3226
3227
  private function imagecreatefrompsd($fileName)
3228
  # Author:     Tim de Koning
3229
  # Version:    1.3
3230
  # Purpose:    To create an image from a PSD file.
3231
  # Param in:   PSD file to open.
3232
  # Param out:  Return a resource like the other ImageCreateFrom functions
3233
  # Reference:  http://www.kingsquare.nl/phppsdreader
3234
  # Notes:
3235
  #
3236
  {
3237
    if (file_exists($this->psdReaderPath)) {
3238
3239
3240
      include_once($this->psdReaderPath);
3241
3242
      $psdReader = new PhpPsdReader($fileName);
0 ignored issues
show
Bug introduced by
The type PhpPsdReader was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
3243
3244
      if (isset($psdReader->infoArray['error'])) return '';
3245
      else return $psdReader->getImage();
3246
    } else {
3247
      return false;
3248
    }
3249
  }
3250
3251
## --------------------------------------------------------
3252
3253
    public function __destruct() {
3254
    if (is_resource($this->imageResized)) {
3255
      imagedestroy($this->imageResized);
3256
    }
3257
  }
3258
3259
## --------------------------------------------------------
3260
3261
}
3262
3263
3264
3265
3266
/*
3267
 *    Example with some API calls (outdated):
3268
 *
3269
 *
3270
 *      ===============================
3271
 *      Compulsary
3272
 *      ===============================
3273
 *
3274
 *      include("classes/resize_class.php");
3275
 *
3276
 *      // *** Initialise object
3277
 *      $magicianObj = new resize('images/cars/large/a.jpg');
3278
 *
3279
 *      // *** Turn off stretching (optional)
3280
 *      $magicianObj -> setForceStretch(false);
3281
 *
3282
 *      // *** Resize object
3283
 *      $magicianObj -> resizeImage(150, 100, 0);
3284
 *
3285
 *      ===============================
3286
 *      Image options - can run none, one, or all.
3287
 *      ===============================
3288
 *
3289
 *      //  *** Add watermark
3290
 *        $magicianObj -> addWatermark('stamp.png');
3291
 *
3292
 *          // *** Add text
3293
 *      $magicianObj -> addText('testing...');
3294
 *
3295
 *      ===============================
3296
 *      Output options - can run one, or the other, or both.
3297
 *      ===============================
3298
 *
3299
 *      // *** Save image to disk
3300
 *      $magicianObj -> saveImage('images/cars/large/b.jpg', 100);
3301
 *
3302
 *          // *** Or output to screen (params in can be jpg, gif, png)
3303
 *      $magicianObj -> displayImage('png');
3304
 *
3305
 *      ===============================
3306
 *      Return options - return errors. nice for debuggin.
3307
 *      ===============================
3308
 *
3309
 *      // *** Return error array
3310
 *      $errorArray = $magicianObj -> getErrors();
3311
 *
3312
 *
3313
 *      ===============================
3314
 *      Cleanup options - not really neccessary, but good practice
3315
 *      ===============================
3316
 *
3317
 *      // *** Free used memory
3318
 *      $magicianObj -> __destruct();
3319
 */
3320