Passed
Push — master ( b23934...c47406 )
by Joas
13:17 queued 12s
created
lib/private/legacy/OC_Image.php 2 patches
Indentation   +1357 added lines, -1357 removed lines patch added patch discarded remove patch
@@ -47,686 +47,686 @@  discard block
 block discarded – undo
47 47
  */
48 48
 class OC_Image implements \OCP\IImage {
49 49
 
50
-	// Default memory limit for images to load (128 MBytes).
51
-	protected const DEFAULT_MEMORY_LIMIT = 128;
52
-
53
-	/** @var false|resource|\GdImage */
54
-	protected $resource = false; // tmp resource.
55
-	/** @var int */
56
-	protected $imageType = IMAGETYPE_PNG; // Default to png if file type isn't evident.
57
-	/** @var string */
58
-	protected $mimeType = 'image/png'; // Default to png
59
-	/** @var int */
60
-	protected $bitDepth = 24;
61
-	/** @var null|string */
62
-	protected $filePath = null;
63
-	/** @var finfo */
64
-	private $fileInfo;
65
-	/** @var \OCP\ILogger */
66
-	private $logger;
67
-	/** @var \OCP\IConfig */
68
-	private $config;
69
-	/** @var array */
70
-	private $exif;
71
-
72
-	/**
73
-	 * Constructor.
74
-	 *
75
-	 * @param resource|string|\GdImage $imageRef The path to a local file, a base64 encoded string or a resource created by
76
-	 * an imagecreate* function.
77
-	 * @param \OCP\ILogger $logger
78
-	 * @param \OCP\IConfig $config
79
-	 * @throws \InvalidArgumentException in case the $imageRef parameter is not null
80
-	 */
81
-	public function __construct($imageRef = null, \OCP\ILogger $logger = null, \OCP\IConfig $config = null) {
82
-		$this->logger = $logger;
83
-		if ($logger === null) {
84
-			$this->logger = \OC::$server->getLogger();
85
-		}
86
-		$this->config = $config;
87
-		if ($config === null) {
88
-			$this->config = \OC::$server->getConfig();
89
-		}
90
-
91
-		if (\OC_Util::fileInfoLoaded()) {
92
-			$this->fileInfo = new finfo(FILEINFO_MIME_TYPE);
93
-		}
94
-
95
-		if ($imageRef !== null) {
96
-			throw new \InvalidArgumentException('The first parameter in the constructor is not supported anymore. Please use any of the load* methods of the image object to load an image.');
97
-		}
98
-	}
99
-
100
-	/**
101
-	 * Determine whether the object contains an image resource.
102
-	 *
103
-	 * @return bool
104
-	 */
105
-	public function valid() {
106
-		if (is_resource($this->resource)) {
107
-			return true;
108
-		}
109
-		if (is_object($this->resource) && get_class($this->resource) === \GdImage::class) {
110
-			return true;
111
-		}
112
-
113
-		return false;
114
-	}
115
-
116
-	/**
117
-	 * Returns the MIME type of the image or an empty string if no image is loaded.
118
-	 *
119
-	 * @return string
120
-	 */
121
-	public function mimeType() {
122
-		return $this->valid() ? $this->mimeType : '';
123
-	}
124
-
125
-	/**
126
-	 * Returns the width of the image or -1 if no image is loaded.
127
-	 *
128
-	 * @return int
129
-	 */
130
-	public function width() {
131
-		if ($this->valid()) {
132
-			$width = imagesx($this->resource);
133
-			if ($width !== false) {
134
-				return $width;
135
-			}
136
-		}
137
-		return -1;
138
-	}
139
-
140
-	/**
141
-	 * Returns the height of the image or -1 if no image is loaded.
142
-	 *
143
-	 * @return int
144
-	 */
145
-	public function height() {
146
-		if ($this->valid()) {
147
-			$height = imagesy($this->resource);
148
-			if ($height !== false) {
149
-				return $height;
150
-			}
151
-		}
152
-		return -1;
153
-	}
154
-
155
-	/**
156
-	 * Returns the width when the image orientation is top-left.
157
-	 *
158
-	 * @return int
159
-	 */
160
-	public function widthTopLeft() {
161
-		$o = $this->getOrientation();
162
-		$this->logger->debug('OC_Image->widthTopLeft() Orientation: ' . $o, ['app' => 'core']);
163
-		switch ($o) {
164
-			case -1:
165
-			case 1:
166
-			case 2: // Not tested
167
-			case 3:
168
-			case 4: // Not tested
169
-				return $this->width();
170
-			case 5: // Not tested
171
-			case 6:
172
-			case 7: // Not tested
173
-			case 8:
174
-				return $this->height();
175
-		}
176
-		return $this->width();
177
-	}
178
-
179
-	/**
180
-	 * Returns the height when the image orientation is top-left.
181
-	 *
182
-	 * @return int
183
-	 */
184
-	public function heightTopLeft() {
185
-		$o = $this->getOrientation();
186
-		$this->logger->debug('OC_Image->heightTopLeft() Orientation: ' . $o, ['app' => 'core']);
187
-		switch ($o) {
188
-			case -1:
189
-			case 1:
190
-			case 2: // Not tested
191
-			case 3:
192
-			case 4: // Not tested
193
-				return $this->height();
194
-			case 5: // Not tested
195
-			case 6:
196
-			case 7: // Not tested
197
-			case 8:
198
-				return $this->width();
199
-		}
200
-		return $this->height();
201
-	}
202
-
203
-	/**
204
-	 * Outputs the image.
205
-	 *
206
-	 * @param string $mimeType
207
-	 * @return bool
208
-	 */
209
-	public function show($mimeType = null) {
210
-		if ($mimeType === null) {
211
-			$mimeType = $this->mimeType();
212
-		}
213
-		header('Content-Type: ' . $mimeType);
214
-		return $this->_output(null, $mimeType);
215
-	}
216
-
217
-	/**
218
-	 * Saves the image.
219
-	 *
220
-	 * @param string $filePath
221
-	 * @param string $mimeType
222
-	 * @return bool
223
-	 */
224
-
225
-	public function save($filePath = null, $mimeType = null) {
226
-		if ($mimeType === null) {
227
-			$mimeType = $this->mimeType();
228
-		}
229
-		if ($filePath === null) {
230
-			if ($this->filePath === null) {
231
-				$this->logger->error(__METHOD__ . '(): called with no path.', ['app' => 'core']);
232
-				return false;
233
-			} else {
234
-				$filePath = $this->filePath;
235
-			}
236
-		}
237
-		return $this->_output($filePath, $mimeType);
238
-	}
239
-
240
-	/**
241
-	 * Outputs/saves the image.
242
-	 *
243
-	 * @param string $filePath
244
-	 * @param string $mimeType
245
-	 * @return bool
246
-	 * @throws Exception
247
-	 */
248
-	private function _output($filePath = null, $mimeType = null) {
249
-		if ($filePath) {
250
-			if (!file_exists(dirname($filePath))) {
251
-				mkdir(dirname($filePath), 0777, true);
252
-			}
253
-			$isWritable = is_writable(dirname($filePath));
254
-			if (!$isWritable) {
255
-				$this->logger->error(__METHOD__ . '(): Directory \'' . dirname($filePath) . '\' is not writable.', ['app' => 'core']);
256
-				return false;
257
-			} elseif ($isWritable && file_exists($filePath) && !is_writable($filePath)) {
258
-				$this->logger->error(__METHOD__ . '(): File \'' . $filePath . '\' is not writable.', ['app' => 'core']);
259
-				return false;
260
-			}
261
-		}
262
-		if (!$this->valid()) {
263
-			return false;
264
-		}
265
-
266
-		$imageType = $this->imageType;
267
-		if ($mimeType !== null) {
268
-			switch ($mimeType) {
269
-				case 'image/gif':
270
-					$imageType = IMAGETYPE_GIF;
271
-					break;
272
-				case 'image/jpeg':
273
-					$imageType = IMAGETYPE_JPEG;
274
-					break;
275
-				case 'image/png':
276
-					$imageType = IMAGETYPE_PNG;
277
-					break;
278
-				case 'image/x-xbitmap':
279
-					$imageType = IMAGETYPE_XBM;
280
-					break;
281
-				case 'image/bmp':
282
-				case 'image/x-ms-bmp':
283
-					$imageType = IMAGETYPE_BMP;
284
-					break;
285
-				default:
286
-					throw new Exception('\OC_Image::_output(): "' . $mimeType . '" is not supported when forcing a specific output format');
287
-			}
288
-		}
289
-
290
-		switch ($imageType) {
291
-			case IMAGETYPE_GIF:
292
-				$retVal = imagegif($this->resource, $filePath);
293
-				break;
294
-			case IMAGETYPE_JPEG:
295
-				$retVal = imagejpeg($this->resource, $filePath, $this->getJpegQuality());
296
-				break;
297
-			case IMAGETYPE_PNG:
298
-				$retVal = imagepng($this->resource, $filePath);
299
-				break;
300
-			case IMAGETYPE_XBM:
301
-				if (function_exists('imagexbm')) {
302
-					$retVal = imagexbm($this->resource, $filePath);
303
-				} else {
304
-					throw new Exception('\OC_Image::_output(): imagexbm() is not supported.');
305
-				}
306
-
307
-				break;
308
-			case IMAGETYPE_WBMP:
309
-				$retVal = imagewbmp($this->resource, $filePath);
310
-				break;
311
-			case IMAGETYPE_BMP:
312
-				$retVal = imagebmp($this->resource, $filePath, $this->bitDepth);
313
-				break;
314
-			default:
315
-				$retVal = imagepng($this->resource, $filePath);
316
-		}
317
-		return $retVal;
318
-	}
319
-
320
-	/**
321
-	 * Prints the image when called as $image().
322
-	 */
323
-	public function __invoke() {
324
-		return $this->show();
325
-	}
326
-
327
-	/**
328
-	 * @param resource|\GdImage $resource
329
-	 * @throws \InvalidArgumentException in case the supplied resource does not have the type "gd"
330
-	 */
331
-	public function setResource($resource) {
332
-		// For PHP<8
333
-		if (is_resource($resource) && get_resource_type($resource) === 'gd') {
334
-			$this->resource = $resource;
335
-			return;
336
-		}
337
-		// PHP 8 has real objects for GD stuff
338
-		if (is_object($resource) && get_class($resource) === \GdImage::class) {
339
-			$this->resource = $resource;
340
-			return;
341
-		}
342
-		throw new \InvalidArgumentException('Supplied resource is not of type "gd".');
343
-	}
344
-
345
-	/**
346
-	 * @return false|resource|\GdImage Returns the image resource if any
347
-	 */
348
-	public function resource() {
349
-		return $this->resource;
350
-	}
351
-
352
-	/**
353
-	 * @return string Returns the mimetype of the data. Returns the empty string
354
-	 * if the data is not valid.
355
-	 */
356
-	public function dataMimeType() {
357
-		if (!$this->valid()) {
358
-			return '';
359
-		}
360
-
361
-		switch ($this->mimeType) {
362
-			case 'image/png':
363
-			case 'image/jpeg':
364
-			case 'image/gif':
365
-				return $this->mimeType;
366
-			default:
367
-				return 'image/png';
368
-		}
369
-	}
370
-
371
-	/**
372
-	 * @return null|string Returns the raw image data.
373
-	 */
374
-	public function data() {
375
-		if (!$this->valid()) {
376
-			return null;
377
-		}
378
-		ob_start();
379
-		switch ($this->mimeType) {
380
-			case "image/png":
381
-				$res = imagepng($this->resource);
382
-				break;
383
-			case "image/jpeg":
384
-				$quality = $this->getJpegQuality();
385
-				if ($quality !== null) {
386
-					$res = imagejpeg($this->resource, null, $quality);
387
-				} else {
388
-					$res = imagejpeg($this->resource);
389
-				}
390
-				break;
391
-			case "image/gif":
392
-				$res = imagegif($this->resource);
393
-				break;
394
-			default:
395
-				$res = imagepng($this->resource);
396
-				$this->logger->info('OC_Image->data. Could not guess mime-type, defaulting to png', ['app' => 'core']);
397
-				break;
398
-		}
399
-		if (!$res) {
400
-			$this->logger->error('OC_Image->data. Error getting image data.', ['app' => 'core']);
401
-		}
402
-		return ob_get_clean();
403
-	}
404
-
405
-	/**
406
-	 * @return string - base64 encoded, which is suitable for embedding in a VCard.
407
-	 */
408
-	public function __toString() {
409
-		return base64_encode($this->data());
410
-	}
411
-
412
-	/**
413
-	 * @return int|null
414
-	 */
415
-	protected function getJpegQuality() {
416
-		$quality = $this->config->getAppValue('preview', 'jpeg_quality', 90);
417
-		if ($quality !== null) {
418
-			$quality = min(100, max(10, (int) $quality));
419
-		}
420
-		return $quality;
421
-	}
422
-
423
-	/**
424
-	 * (I'm open for suggestions on better method name ;)
425
-	 * Get the orientation based on EXIF data.
426
-	 *
427
-	 * @return int The orientation or -1 if no EXIF data is available.
428
-	 */
429
-	public function getOrientation() {
430
-		if ($this->exif !== null) {
431
-			return $this->exif['Orientation'];
432
-		}
433
-
434
-		if ($this->imageType !== IMAGETYPE_JPEG) {
435
-			$this->logger->debug('OC_Image->fixOrientation() Image is not a JPEG.', ['app' => 'core']);
436
-			return -1;
437
-		}
438
-		if (!is_callable('exif_read_data')) {
439
-			$this->logger->debug('OC_Image->fixOrientation() Exif module not enabled.', ['app' => 'core']);
440
-			return -1;
441
-		}
442
-		if (!$this->valid()) {
443
-			$this->logger->debug('OC_Image->fixOrientation() No image loaded.', ['app' => 'core']);
444
-			return -1;
445
-		}
446
-		if (is_null($this->filePath) || !is_readable($this->filePath)) {
447
-			$this->logger->debug('OC_Image->fixOrientation() No readable file path set.', ['app' => 'core']);
448
-			return -1;
449
-		}
450
-		$exif = @exif_read_data($this->filePath, 'IFD0');
451
-		if (!$exif) {
452
-			return -1;
453
-		}
454
-		if (!isset($exif['Orientation'])) {
455
-			return -1;
456
-		}
457
-		$this->exif = $exif;
458
-		return $exif['Orientation'];
459
-	}
460
-
461
-	public function readExif($data) {
462
-		if (!is_callable('exif_read_data')) {
463
-			$this->logger->debug('OC_Image->fixOrientation() Exif module not enabled.', ['app' => 'core']);
464
-			return;
465
-		}
466
-		if (!$this->valid()) {
467
-			$this->logger->debug('OC_Image->fixOrientation() No image loaded.', ['app' => 'core']);
468
-			return;
469
-		}
470
-
471
-		$exif = @exif_read_data('data://image/jpeg;base64,' . base64_encode($data));
472
-		if (!$exif) {
473
-			return;
474
-		}
475
-		if (!isset($exif['Orientation'])) {
476
-			return;
477
-		}
478
-		$this->exif = $exif;
479
-	}
480
-
481
-	/**
482
-	 * (I'm open for suggestions on better method name ;)
483
-	 * Fixes orientation based on EXIF data.
484
-	 *
485
-	 * @return bool
486
-	 */
487
-	public function fixOrientation() {
488
-		if (!$this->valid()) {
489
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
490
-			return false;
491
-		}
492
-		$o = $this->getOrientation();
493
-		$this->logger->debug('OC_Image->fixOrientation() Orientation: ' . $o, ['app' => 'core']);
494
-		$rotate = 0;
495
-		$flip = false;
496
-		switch ($o) {
497
-			case -1:
498
-				return false; //Nothing to fix
499
-			case 1:
500
-				$rotate = 0;
501
-				break;
502
-			case 2:
503
-				$rotate = 0;
504
-				$flip = true;
505
-				break;
506
-			case 3:
507
-				$rotate = 180;
508
-				break;
509
-			case 4:
510
-				$rotate = 180;
511
-				$flip = true;
512
-				break;
513
-			case 5:
514
-				$rotate = 90;
515
-				$flip = true;
516
-				break;
517
-			case 6:
518
-				$rotate = 270;
519
-				break;
520
-			case 7:
521
-				$rotate = 270;
522
-				$flip = true;
523
-				break;
524
-			case 8:
525
-				$rotate = 90;
526
-				break;
527
-		}
528
-		if ($flip && function_exists('imageflip')) {
529
-			imageflip($this->resource, IMG_FLIP_HORIZONTAL);
530
-		}
531
-		if ($rotate) {
532
-			$res = imagerotate($this->resource, $rotate, 0);
533
-			if ($res) {
534
-				if (imagealphablending($res, true)) {
535
-					if (imagesavealpha($res, true)) {
536
-						imagedestroy($this->resource);
537
-						$this->resource = $res;
538
-						return true;
539
-					} else {
540
-						$this->logger->debug('OC_Image->fixOrientation() Error during alpha-saving', ['app' => 'core']);
541
-						return false;
542
-					}
543
-				} else {
544
-					$this->logger->debug('OC_Image->fixOrientation() Error during alpha-blending', ['app' => 'core']);
545
-					return false;
546
-				}
547
-			} else {
548
-				$this->logger->debug('OC_Image->fixOrientation() Error during orientation fixing', ['app' => 'core']);
549
-				return false;
550
-			}
551
-		}
552
-		return false;
553
-	}
554
-
555
-	/**
556
-	 * Loads an image from an open file handle.
557
-	 * It is the responsibility of the caller to position the pointer at the correct place and to close the handle again.
558
-	 *
559
-	 * @param resource $handle
560
-	 * @return resource|\GdImage|false An image resource or false on error
561
-	 */
562
-	public function loadFromFileHandle($handle) {
563
-		$contents = stream_get_contents($handle);
564
-		if ($this->loadFromData($contents)) {
565
-			return $this->resource;
566
-		}
567
-		return false;
568
-	}
569
-
570
-	/**
571
-	 * Check if allocating an image with the given size is allowed.
572
-	 *
573
-	 * @param int $width The image width.
574
-	 * @param int $height The image height.
575
-	 * @return bool true if allocating is allowed, false otherwise
576
-	 */
577
-	private function checkImageMemory($width, $height) {
578
-		$memory_limit = $this->config->getSystemValueInt('preview_max_memory', self::DEFAULT_MEMORY_LIMIT);
579
-		if ($memory_limit < 0) {
580
-			// Not limited.
581
-			return true;
582
-		}
583
-
584
-		// Assume 32 bits per pixel.
585
-		if ($width * $height * 4 > $memory_limit * 1024 * 1024) {
586
-			$this->logger->debug('Image size of ' . $width . 'x' . $height . ' would exceed allowed memory limit of ' . $memory_limit);
587
-			return false;
588
-		}
589
-
590
-		return true;
591
-	}
592
-
593
-	/**
594
-	 * Check if loading an image file from the given path is allowed.
595
-	 *
596
-	 * @param string $path The path to a local file.
597
-	 * @return bool true if allocating is allowed, false otherwise
598
-	 */
599
-	private function checkImageSize($path) {
600
-		$size = getimagesize($path);
601
-		if (!$size) {
602
-			return true;
603
-		}
604
-
605
-		$width = $size[0];
606
-		$height = $size[1];
607
-		if (!$this->checkImageMemory($width, $height)) {
608
-			return false;
609
-		}
610
-
611
-		return true;
612
-	}
613
-
614
-	/**
615
-	 * Check if loading an image from the given data is allowed.
616
-	 *
617
-	 * @param string $data A string of image data as read from a file.
618
-	 * @return bool true if allocating is allowed, false otherwise
619
-	 */
620
-	private function checkImageDataSize($data) {
621
-		$size = getimagesizefromstring($data);
622
-		if (!$size) {
623
-			return true;
624
-		}
625
-
626
-		$width = $size[0];
627
-		$height = $size[1];
628
-		if (!$this->checkImageMemory($width, $height)) {
629
-			return false;
630
-		}
631
-
632
-		return true;
633
-	}
634
-
635
-	/**
636
-	 * Loads an image from a local file.
637
-	 *
638
-	 * @param bool|string $imagePath The path to a local file.
639
-	 * @return bool|resource|\GdImage An image resource or false on error
640
-	 */
641
-	public function loadFromFile($imagePath = false) {
642
-		// exif_imagetype throws "read error!" if file is less than 12 byte
643
-		if (is_bool($imagePath) || !@is_file($imagePath) || !file_exists($imagePath) || filesize($imagePath) < 12 || !is_readable($imagePath)) {
644
-			return false;
645
-		}
646
-		$iType = exif_imagetype($imagePath);
647
-		switch ($iType) {
648
-			case IMAGETYPE_GIF:
649
-				if (imagetypes() & IMG_GIF) {
650
-					if (!$this->checkImageSize($imagePath)) {
651
-						return false;
652
-					}
653
-					$this->resource = imagecreatefromgif($imagePath);
654
-					if ($this->resource) {
655
-						// Preserve transparency
656
-						imagealphablending($this->resource, true);
657
-						imagesavealpha($this->resource, true);
658
-					} else {
659
-						$this->logger->debug('OC_Image->loadFromFile, GIF image not valid: ' . $imagePath, ['app' => 'core']);
660
-					}
661
-				} else {
662
-					$this->logger->debug('OC_Image->loadFromFile, GIF images not supported: ' . $imagePath, ['app' => 'core']);
663
-				}
664
-				break;
665
-			case IMAGETYPE_JPEG:
666
-				if (imagetypes() & IMG_JPG) {
667
-					if (!$this->checkImageSize($imagePath)) {
668
-						return false;
669
-					}
670
-					if (getimagesize($imagePath) !== false) {
671
-						$this->resource = @imagecreatefromjpeg($imagePath);
672
-					} else {
673
-						$this->logger->debug('OC_Image->loadFromFile, JPG image not valid: ' . $imagePath, ['app' => 'core']);
674
-					}
675
-				} else {
676
-					$this->logger->debug('OC_Image->loadFromFile, JPG images not supported: ' . $imagePath, ['app' => 'core']);
677
-				}
678
-				break;
679
-			case IMAGETYPE_PNG:
680
-				if (imagetypes() & IMG_PNG) {
681
-					if (!$this->checkImageSize($imagePath)) {
682
-						return false;
683
-					}
684
-					$this->resource = @imagecreatefrompng($imagePath);
685
-					if ($this->resource) {
686
-						// Preserve transparency
687
-						imagealphablending($this->resource, true);
688
-						imagesavealpha($this->resource, true);
689
-					} else {
690
-						$this->logger->debug('OC_Image->loadFromFile, PNG image not valid: ' . $imagePath, ['app' => 'core']);
691
-					}
692
-				} else {
693
-					$this->logger->debug('OC_Image->loadFromFile, PNG images not supported: ' . $imagePath, ['app' => 'core']);
694
-				}
695
-				break;
696
-			case IMAGETYPE_XBM:
697
-				if (imagetypes() & IMG_XPM) {
698
-					if (!$this->checkImageSize($imagePath)) {
699
-						return false;
700
-					}
701
-					$this->resource = @imagecreatefromxbm($imagePath);
702
-				} else {
703
-					$this->logger->debug('OC_Image->loadFromFile, XBM/XPM images not supported: ' . $imagePath, ['app' => 'core']);
704
-				}
705
-				break;
706
-			case IMAGETYPE_WBMP:
707
-				if (imagetypes() & IMG_WBMP) {
708
-					if (!$this->checkImageSize($imagePath)) {
709
-						return false;
710
-					}
711
-					$this->resource = @imagecreatefromwbmp($imagePath);
712
-				} else {
713
-					$this->logger->debug('OC_Image->loadFromFile, WBMP images not supported: ' . $imagePath, ['app' => 'core']);
714
-				}
715
-				break;
716
-			case IMAGETYPE_BMP:
717
-				$this->resource = $this->imagecreatefrombmp($imagePath);
718
-				break;
719
-			case IMAGETYPE_WEBP:
720
-				if (imagetypes() & IMG_WEBP) {
721
-					if (!$this->checkImageSize($imagePath)) {
722
-						return false;
723
-					}
724
-					$this->resource = @imagecreatefromwebp($imagePath);
725
-				} else {
726
-					$this->logger->debug('OC_Image->loadFromFile, webp images not supported: ' . $imagePath, ['app' => 'core']);
727
-				}
728
-				break;
729
-			/*
50
+    // Default memory limit for images to load (128 MBytes).
51
+    protected const DEFAULT_MEMORY_LIMIT = 128;
52
+
53
+    /** @var false|resource|\GdImage */
54
+    protected $resource = false; // tmp resource.
55
+    /** @var int */
56
+    protected $imageType = IMAGETYPE_PNG; // Default to png if file type isn't evident.
57
+    /** @var string */
58
+    protected $mimeType = 'image/png'; // Default to png
59
+    /** @var int */
60
+    protected $bitDepth = 24;
61
+    /** @var null|string */
62
+    protected $filePath = null;
63
+    /** @var finfo */
64
+    private $fileInfo;
65
+    /** @var \OCP\ILogger */
66
+    private $logger;
67
+    /** @var \OCP\IConfig */
68
+    private $config;
69
+    /** @var array */
70
+    private $exif;
71
+
72
+    /**
73
+     * Constructor.
74
+     *
75
+     * @param resource|string|\GdImage $imageRef The path to a local file, a base64 encoded string or a resource created by
76
+     * an imagecreate* function.
77
+     * @param \OCP\ILogger $logger
78
+     * @param \OCP\IConfig $config
79
+     * @throws \InvalidArgumentException in case the $imageRef parameter is not null
80
+     */
81
+    public function __construct($imageRef = null, \OCP\ILogger $logger = null, \OCP\IConfig $config = null) {
82
+        $this->logger = $logger;
83
+        if ($logger === null) {
84
+            $this->logger = \OC::$server->getLogger();
85
+        }
86
+        $this->config = $config;
87
+        if ($config === null) {
88
+            $this->config = \OC::$server->getConfig();
89
+        }
90
+
91
+        if (\OC_Util::fileInfoLoaded()) {
92
+            $this->fileInfo = new finfo(FILEINFO_MIME_TYPE);
93
+        }
94
+
95
+        if ($imageRef !== null) {
96
+            throw new \InvalidArgumentException('The first parameter in the constructor is not supported anymore. Please use any of the load* methods of the image object to load an image.');
97
+        }
98
+    }
99
+
100
+    /**
101
+     * Determine whether the object contains an image resource.
102
+     *
103
+     * @return bool
104
+     */
105
+    public function valid() {
106
+        if (is_resource($this->resource)) {
107
+            return true;
108
+        }
109
+        if (is_object($this->resource) && get_class($this->resource) === \GdImage::class) {
110
+            return true;
111
+        }
112
+
113
+        return false;
114
+    }
115
+
116
+    /**
117
+     * Returns the MIME type of the image or an empty string if no image is loaded.
118
+     *
119
+     * @return string
120
+     */
121
+    public function mimeType() {
122
+        return $this->valid() ? $this->mimeType : '';
123
+    }
124
+
125
+    /**
126
+     * Returns the width of the image or -1 if no image is loaded.
127
+     *
128
+     * @return int
129
+     */
130
+    public function width() {
131
+        if ($this->valid()) {
132
+            $width = imagesx($this->resource);
133
+            if ($width !== false) {
134
+                return $width;
135
+            }
136
+        }
137
+        return -1;
138
+    }
139
+
140
+    /**
141
+     * Returns the height of the image or -1 if no image is loaded.
142
+     *
143
+     * @return int
144
+     */
145
+    public function height() {
146
+        if ($this->valid()) {
147
+            $height = imagesy($this->resource);
148
+            if ($height !== false) {
149
+                return $height;
150
+            }
151
+        }
152
+        return -1;
153
+    }
154
+
155
+    /**
156
+     * Returns the width when the image orientation is top-left.
157
+     *
158
+     * @return int
159
+     */
160
+    public function widthTopLeft() {
161
+        $o = $this->getOrientation();
162
+        $this->logger->debug('OC_Image->widthTopLeft() Orientation: ' . $o, ['app' => 'core']);
163
+        switch ($o) {
164
+            case -1:
165
+            case 1:
166
+            case 2: // Not tested
167
+            case 3:
168
+            case 4: // Not tested
169
+                return $this->width();
170
+            case 5: // Not tested
171
+            case 6:
172
+            case 7: // Not tested
173
+            case 8:
174
+                return $this->height();
175
+        }
176
+        return $this->width();
177
+    }
178
+
179
+    /**
180
+     * Returns the height when the image orientation is top-left.
181
+     *
182
+     * @return int
183
+     */
184
+    public function heightTopLeft() {
185
+        $o = $this->getOrientation();
186
+        $this->logger->debug('OC_Image->heightTopLeft() Orientation: ' . $o, ['app' => 'core']);
187
+        switch ($o) {
188
+            case -1:
189
+            case 1:
190
+            case 2: // Not tested
191
+            case 3:
192
+            case 4: // Not tested
193
+                return $this->height();
194
+            case 5: // Not tested
195
+            case 6:
196
+            case 7: // Not tested
197
+            case 8:
198
+                return $this->width();
199
+        }
200
+        return $this->height();
201
+    }
202
+
203
+    /**
204
+     * Outputs the image.
205
+     *
206
+     * @param string $mimeType
207
+     * @return bool
208
+     */
209
+    public function show($mimeType = null) {
210
+        if ($mimeType === null) {
211
+            $mimeType = $this->mimeType();
212
+        }
213
+        header('Content-Type: ' . $mimeType);
214
+        return $this->_output(null, $mimeType);
215
+    }
216
+
217
+    /**
218
+     * Saves the image.
219
+     *
220
+     * @param string $filePath
221
+     * @param string $mimeType
222
+     * @return bool
223
+     */
224
+
225
+    public function save($filePath = null, $mimeType = null) {
226
+        if ($mimeType === null) {
227
+            $mimeType = $this->mimeType();
228
+        }
229
+        if ($filePath === null) {
230
+            if ($this->filePath === null) {
231
+                $this->logger->error(__METHOD__ . '(): called with no path.', ['app' => 'core']);
232
+                return false;
233
+            } else {
234
+                $filePath = $this->filePath;
235
+            }
236
+        }
237
+        return $this->_output($filePath, $mimeType);
238
+    }
239
+
240
+    /**
241
+     * Outputs/saves the image.
242
+     *
243
+     * @param string $filePath
244
+     * @param string $mimeType
245
+     * @return bool
246
+     * @throws Exception
247
+     */
248
+    private function _output($filePath = null, $mimeType = null) {
249
+        if ($filePath) {
250
+            if (!file_exists(dirname($filePath))) {
251
+                mkdir(dirname($filePath), 0777, true);
252
+            }
253
+            $isWritable = is_writable(dirname($filePath));
254
+            if (!$isWritable) {
255
+                $this->logger->error(__METHOD__ . '(): Directory \'' . dirname($filePath) . '\' is not writable.', ['app' => 'core']);
256
+                return false;
257
+            } elseif ($isWritable && file_exists($filePath) && !is_writable($filePath)) {
258
+                $this->logger->error(__METHOD__ . '(): File \'' . $filePath . '\' is not writable.', ['app' => 'core']);
259
+                return false;
260
+            }
261
+        }
262
+        if (!$this->valid()) {
263
+            return false;
264
+        }
265
+
266
+        $imageType = $this->imageType;
267
+        if ($mimeType !== null) {
268
+            switch ($mimeType) {
269
+                case 'image/gif':
270
+                    $imageType = IMAGETYPE_GIF;
271
+                    break;
272
+                case 'image/jpeg':
273
+                    $imageType = IMAGETYPE_JPEG;
274
+                    break;
275
+                case 'image/png':
276
+                    $imageType = IMAGETYPE_PNG;
277
+                    break;
278
+                case 'image/x-xbitmap':
279
+                    $imageType = IMAGETYPE_XBM;
280
+                    break;
281
+                case 'image/bmp':
282
+                case 'image/x-ms-bmp':
283
+                    $imageType = IMAGETYPE_BMP;
284
+                    break;
285
+                default:
286
+                    throw new Exception('\OC_Image::_output(): "' . $mimeType . '" is not supported when forcing a specific output format');
287
+            }
288
+        }
289
+
290
+        switch ($imageType) {
291
+            case IMAGETYPE_GIF:
292
+                $retVal = imagegif($this->resource, $filePath);
293
+                break;
294
+            case IMAGETYPE_JPEG:
295
+                $retVal = imagejpeg($this->resource, $filePath, $this->getJpegQuality());
296
+                break;
297
+            case IMAGETYPE_PNG:
298
+                $retVal = imagepng($this->resource, $filePath);
299
+                break;
300
+            case IMAGETYPE_XBM:
301
+                if (function_exists('imagexbm')) {
302
+                    $retVal = imagexbm($this->resource, $filePath);
303
+                } else {
304
+                    throw new Exception('\OC_Image::_output(): imagexbm() is not supported.');
305
+                }
306
+
307
+                break;
308
+            case IMAGETYPE_WBMP:
309
+                $retVal = imagewbmp($this->resource, $filePath);
310
+                break;
311
+            case IMAGETYPE_BMP:
312
+                $retVal = imagebmp($this->resource, $filePath, $this->bitDepth);
313
+                break;
314
+            default:
315
+                $retVal = imagepng($this->resource, $filePath);
316
+        }
317
+        return $retVal;
318
+    }
319
+
320
+    /**
321
+     * Prints the image when called as $image().
322
+     */
323
+    public function __invoke() {
324
+        return $this->show();
325
+    }
326
+
327
+    /**
328
+     * @param resource|\GdImage $resource
329
+     * @throws \InvalidArgumentException in case the supplied resource does not have the type "gd"
330
+     */
331
+    public function setResource($resource) {
332
+        // For PHP<8
333
+        if (is_resource($resource) && get_resource_type($resource) === 'gd') {
334
+            $this->resource = $resource;
335
+            return;
336
+        }
337
+        // PHP 8 has real objects for GD stuff
338
+        if (is_object($resource) && get_class($resource) === \GdImage::class) {
339
+            $this->resource = $resource;
340
+            return;
341
+        }
342
+        throw new \InvalidArgumentException('Supplied resource is not of type "gd".');
343
+    }
344
+
345
+    /**
346
+     * @return false|resource|\GdImage Returns the image resource if any
347
+     */
348
+    public function resource() {
349
+        return $this->resource;
350
+    }
351
+
352
+    /**
353
+     * @return string Returns the mimetype of the data. Returns the empty string
354
+     * if the data is not valid.
355
+     */
356
+    public function dataMimeType() {
357
+        if (!$this->valid()) {
358
+            return '';
359
+        }
360
+
361
+        switch ($this->mimeType) {
362
+            case 'image/png':
363
+            case 'image/jpeg':
364
+            case 'image/gif':
365
+                return $this->mimeType;
366
+            default:
367
+                return 'image/png';
368
+        }
369
+    }
370
+
371
+    /**
372
+     * @return null|string Returns the raw image data.
373
+     */
374
+    public function data() {
375
+        if (!$this->valid()) {
376
+            return null;
377
+        }
378
+        ob_start();
379
+        switch ($this->mimeType) {
380
+            case "image/png":
381
+                $res = imagepng($this->resource);
382
+                break;
383
+            case "image/jpeg":
384
+                $quality = $this->getJpegQuality();
385
+                if ($quality !== null) {
386
+                    $res = imagejpeg($this->resource, null, $quality);
387
+                } else {
388
+                    $res = imagejpeg($this->resource);
389
+                }
390
+                break;
391
+            case "image/gif":
392
+                $res = imagegif($this->resource);
393
+                break;
394
+            default:
395
+                $res = imagepng($this->resource);
396
+                $this->logger->info('OC_Image->data. Could not guess mime-type, defaulting to png', ['app' => 'core']);
397
+                break;
398
+        }
399
+        if (!$res) {
400
+            $this->logger->error('OC_Image->data. Error getting image data.', ['app' => 'core']);
401
+        }
402
+        return ob_get_clean();
403
+    }
404
+
405
+    /**
406
+     * @return string - base64 encoded, which is suitable for embedding in a VCard.
407
+     */
408
+    public function __toString() {
409
+        return base64_encode($this->data());
410
+    }
411
+
412
+    /**
413
+     * @return int|null
414
+     */
415
+    protected function getJpegQuality() {
416
+        $quality = $this->config->getAppValue('preview', 'jpeg_quality', 90);
417
+        if ($quality !== null) {
418
+            $quality = min(100, max(10, (int) $quality));
419
+        }
420
+        return $quality;
421
+    }
422
+
423
+    /**
424
+     * (I'm open for suggestions on better method name ;)
425
+     * Get the orientation based on EXIF data.
426
+     *
427
+     * @return int The orientation or -1 if no EXIF data is available.
428
+     */
429
+    public function getOrientation() {
430
+        if ($this->exif !== null) {
431
+            return $this->exif['Orientation'];
432
+        }
433
+
434
+        if ($this->imageType !== IMAGETYPE_JPEG) {
435
+            $this->logger->debug('OC_Image->fixOrientation() Image is not a JPEG.', ['app' => 'core']);
436
+            return -1;
437
+        }
438
+        if (!is_callable('exif_read_data')) {
439
+            $this->logger->debug('OC_Image->fixOrientation() Exif module not enabled.', ['app' => 'core']);
440
+            return -1;
441
+        }
442
+        if (!$this->valid()) {
443
+            $this->logger->debug('OC_Image->fixOrientation() No image loaded.', ['app' => 'core']);
444
+            return -1;
445
+        }
446
+        if (is_null($this->filePath) || !is_readable($this->filePath)) {
447
+            $this->logger->debug('OC_Image->fixOrientation() No readable file path set.', ['app' => 'core']);
448
+            return -1;
449
+        }
450
+        $exif = @exif_read_data($this->filePath, 'IFD0');
451
+        if (!$exif) {
452
+            return -1;
453
+        }
454
+        if (!isset($exif['Orientation'])) {
455
+            return -1;
456
+        }
457
+        $this->exif = $exif;
458
+        return $exif['Orientation'];
459
+    }
460
+
461
+    public function readExif($data) {
462
+        if (!is_callable('exif_read_data')) {
463
+            $this->logger->debug('OC_Image->fixOrientation() Exif module not enabled.', ['app' => 'core']);
464
+            return;
465
+        }
466
+        if (!$this->valid()) {
467
+            $this->logger->debug('OC_Image->fixOrientation() No image loaded.', ['app' => 'core']);
468
+            return;
469
+        }
470
+
471
+        $exif = @exif_read_data('data://image/jpeg;base64,' . base64_encode($data));
472
+        if (!$exif) {
473
+            return;
474
+        }
475
+        if (!isset($exif['Orientation'])) {
476
+            return;
477
+        }
478
+        $this->exif = $exif;
479
+    }
480
+
481
+    /**
482
+     * (I'm open for suggestions on better method name ;)
483
+     * Fixes orientation based on EXIF data.
484
+     *
485
+     * @return bool
486
+     */
487
+    public function fixOrientation() {
488
+        if (!$this->valid()) {
489
+            $this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
490
+            return false;
491
+        }
492
+        $o = $this->getOrientation();
493
+        $this->logger->debug('OC_Image->fixOrientation() Orientation: ' . $o, ['app' => 'core']);
494
+        $rotate = 0;
495
+        $flip = false;
496
+        switch ($o) {
497
+            case -1:
498
+                return false; //Nothing to fix
499
+            case 1:
500
+                $rotate = 0;
501
+                break;
502
+            case 2:
503
+                $rotate = 0;
504
+                $flip = true;
505
+                break;
506
+            case 3:
507
+                $rotate = 180;
508
+                break;
509
+            case 4:
510
+                $rotate = 180;
511
+                $flip = true;
512
+                break;
513
+            case 5:
514
+                $rotate = 90;
515
+                $flip = true;
516
+                break;
517
+            case 6:
518
+                $rotate = 270;
519
+                break;
520
+            case 7:
521
+                $rotate = 270;
522
+                $flip = true;
523
+                break;
524
+            case 8:
525
+                $rotate = 90;
526
+                break;
527
+        }
528
+        if ($flip && function_exists('imageflip')) {
529
+            imageflip($this->resource, IMG_FLIP_HORIZONTAL);
530
+        }
531
+        if ($rotate) {
532
+            $res = imagerotate($this->resource, $rotate, 0);
533
+            if ($res) {
534
+                if (imagealphablending($res, true)) {
535
+                    if (imagesavealpha($res, true)) {
536
+                        imagedestroy($this->resource);
537
+                        $this->resource = $res;
538
+                        return true;
539
+                    } else {
540
+                        $this->logger->debug('OC_Image->fixOrientation() Error during alpha-saving', ['app' => 'core']);
541
+                        return false;
542
+                    }
543
+                } else {
544
+                    $this->logger->debug('OC_Image->fixOrientation() Error during alpha-blending', ['app' => 'core']);
545
+                    return false;
546
+                }
547
+            } else {
548
+                $this->logger->debug('OC_Image->fixOrientation() Error during orientation fixing', ['app' => 'core']);
549
+                return false;
550
+            }
551
+        }
552
+        return false;
553
+    }
554
+
555
+    /**
556
+     * Loads an image from an open file handle.
557
+     * It is the responsibility of the caller to position the pointer at the correct place and to close the handle again.
558
+     *
559
+     * @param resource $handle
560
+     * @return resource|\GdImage|false An image resource or false on error
561
+     */
562
+    public function loadFromFileHandle($handle) {
563
+        $contents = stream_get_contents($handle);
564
+        if ($this->loadFromData($contents)) {
565
+            return $this->resource;
566
+        }
567
+        return false;
568
+    }
569
+
570
+    /**
571
+     * Check if allocating an image with the given size is allowed.
572
+     *
573
+     * @param int $width The image width.
574
+     * @param int $height The image height.
575
+     * @return bool true if allocating is allowed, false otherwise
576
+     */
577
+    private function checkImageMemory($width, $height) {
578
+        $memory_limit = $this->config->getSystemValueInt('preview_max_memory', self::DEFAULT_MEMORY_LIMIT);
579
+        if ($memory_limit < 0) {
580
+            // Not limited.
581
+            return true;
582
+        }
583
+
584
+        // Assume 32 bits per pixel.
585
+        if ($width * $height * 4 > $memory_limit * 1024 * 1024) {
586
+            $this->logger->debug('Image size of ' . $width . 'x' . $height . ' would exceed allowed memory limit of ' . $memory_limit);
587
+            return false;
588
+        }
589
+
590
+        return true;
591
+    }
592
+
593
+    /**
594
+     * Check if loading an image file from the given path is allowed.
595
+     *
596
+     * @param string $path The path to a local file.
597
+     * @return bool true if allocating is allowed, false otherwise
598
+     */
599
+    private function checkImageSize($path) {
600
+        $size = getimagesize($path);
601
+        if (!$size) {
602
+            return true;
603
+        }
604
+
605
+        $width = $size[0];
606
+        $height = $size[1];
607
+        if (!$this->checkImageMemory($width, $height)) {
608
+            return false;
609
+        }
610
+
611
+        return true;
612
+    }
613
+
614
+    /**
615
+     * Check if loading an image from the given data is allowed.
616
+     *
617
+     * @param string $data A string of image data as read from a file.
618
+     * @return bool true if allocating is allowed, false otherwise
619
+     */
620
+    private function checkImageDataSize($data) {
621
+        $size = getimagesizefromstring($data);
622
+        if (!$size) {
623
+            return true;
624
+        }
625
+
626
+        $width = $size[0];
627
+        $height = $size[1];
628
+        if (!$this->checkImageMemory($width, $height)) {
629
+            return false;
630
+        }
631
+
632
+        return true;
633
+    }
634
+
635
+    /**
636
+     * Loads an image from a local file.
637
+     *
638
+     * @param bool|string $imagePath The path to a local file.
639
+     * @return bool|resource|\GdImage An image resource or false on error
640
+     */
641
+    public function loadFromFile($imagePath = false) {
642
+        // exif_imagetype throws "read error!" if file is less than 12 byte
643
+        if (is_bool($imagePath) || !@is_file($imagePath) || !file_exists($imagePath) || filesize($imagePath) < 12 || !is_readable($imagePath)) {
644
+            return false;
645
+        }
646
+        $iType = exif_imagetype($imagePath);
647
+        switch ($iType) {
648
+            case IMAGETYPE_GIF:
649
+                if (imagetypes() & IMG_GIF) {
650
+                    if (!$this->checkImageSize($imagePath)) {
651
+                        return false;
652
+                    }
653
+                    $this->resource = imagecreatefromgif($imagePath);
654
+                    if ($this->resource) {
655
+                        // Preserve transparency
656
+                        imagealphablending($this->resource, true);
657
+                        imagesavealpha($this->resource, true);
658
+                    } else {
659
+                        $this->logger->debug('OC_Image->loadFromFile, GIF image not valid: ' . $imagePath, ['app' => 'core']);
660
+                    }
661
+                } else {
662
+                    $this->logger->debug('OC_Image->loadFromFile, GIF images not supported: ' . $imagePath, ['app' => 'core']);
663
+                }
664
+                break;
665
+            case IMAGETYPE_JPEG:
666
+                if (imagetypes() & IMG_JPG) {
667
+                    if (!$this->checkImageSize($imagePath)) {
668
+                        return false;
669
+                    }
670
+                    if (getimagesize($imagePath) !== false) {
671
+                        $this->resource = @imagecreatefromjpeg($imagePath);
672
+                    } else {
673
+                        $this->logger->debug('OC_Image->loadFromFile, JPG image not valid: ' . $imagePath, ['app' => 'core']);
674
+                    }
675
+                } else {
676
+                    $this->logger->debug('OC_Image->loadFromFile, JPG images not supported: ' . $imagePath, ['app' => 'core']);
677
+                }
678
+                break;
679
+            case IMAGETYPE_PNG:
680
+                if (imagetypes() & IMG_PNG) {
681
+                    if (!$this->checkImageSize($imagePath)) {
682
+                        return false;
683
+                    }
684
+                    $this->resource = @imagecreatefrompng($imagePath);
685
+                    if ($this->resource) {
686
+                        // Preserve transparency
687
+                        imagealphablending($this->resource, true);
688
+                        imagesavealpha($this->resource, true);
689
+                    } else {
690
+                        $this->logger->debug('OC_Image->loadFromFile, PNG image not valid: ' . $imagePath, ['app' => 'core']);
691
+                    }
692
+                } else {
693
+                    $this->logger->debug('OC_Image->loadFromFile, PNG images not supported: ' . $imagePath, ['app' => 'core']);
694
+                }
695
+                break;
696
+            case IMAGETYPE_XBM:
697
+                if (imagetypes() & IMG_XPM) {
698
+                    if (!$this->checkImageSize($imagePath)) {
699
+                        return false;
700
+                    }
701
+                    $this->resource = @imagecreatefromxbm($imagePath);
702
+                } else {
703
+                    $this->logger->debug('OC_Image->loadFromFile, XBM/XPM images not supported: ' . $imagePath, ['app' => 'core']);
704
+                }
705
+                break;
706
+            case IMAGETYPE_WBMP:
707
+                if (imagetypes() & IMG_WBMP) {
708
+                    if (!$this->checkImageSize($imagePath)) {
709
+                        return false;
710
+                    }
711
+                    $this->resource = @imagecreatefromwbmp($imagePath);
712
+                } else {
713
+                    $this->logger->debug('OC_Image->loadFromFile, WBMP images not supported: ' . $imagePath, ['app' => 'core']);
714
+                }
715
+                break;
716
+            case IMAGETYPE_BMP:
717
+                $this->resource = $this->imagecreatefrombmp($imagePath);
718
+                break;
719
+            case IMAGETYPE_WEBP:
720
+                if (imagetypes() & IMG_WEBP) {
721
+                    if (!$this->checkImageSize($imagePath)) {
722
+                        return false;
723
+                    }
724
+                    $this->resource = @imagecreatefromwebp($imagePath);
725
+                } else {
726
+                    $this->logger->debug('OC_Image->loadFromFile, webp images not supported: ' . $imagePath, ['app' => 'core']);
727
+                }
728
+                break;
729
+            /*
730 730
 			case IMAGETYPE_TIFF_II: // (intel byte order)
731 731
 				break;
732 732
 			case IMAGETYPE_TIFF_MM: // (motorola byte order)
@@ -750,687 +750,687 @@  discard block
 block discarded – undo
750 750
 			case IMAGETYPE_PSD:
751 751
 				break;
752 752
 			*/
753
-			default:
754
-
755
-				// this is mostly file created from encrypted file
756
-				$data = file_get_contents($imagePath);
757
-				if (!$this->checkImageDataSize($data)) {
758
-					return false;
759
-				}
760
-				$this->resource = imagecreatefromstring($data);
761
-				$iType = IMAGETYPE_PNG;
762
-				$this->logger->debug('OC_Image->loadFromFile, Default', ['app' => 'core']);
763
-				break;
764
-		}
765
-		if ($this->valid()) {
766
-			$this->imageType = $iType;
767
-			$this->mimeType = image_type_to_mime_type($iType);
768
-			$this->filePath = $imagePath;
769
-		}
770
-		return $this->resource;
771
-	}
772
-
773
-	/**
774
-	 * Loads an image from a string of data.
775
-	 *
776
-	 * @param string $str A string of image data as read from a file.
777
-	 * @return bool|resource|\GdImage An image resource or false on error
778
-	 */
779
-	public function loadFromData($str) {
780
-		if (!is_string($str)) {
781
-			return false;
782
-		}
783
-		if (!$this->checkImageDataSize($str)) {
784
-			return false;
785
-		}
786
-		$this->resource = @imagecreatefromstring($str);
787
-		if ($this->fileInfo) {
788
-			$this->mimeType = $this->fileInfo->buffer($str);
789
-		}
790
-		if ($this->valid()) {
791
-			imagealphablending($this->resource, false);
792
-			imagesavealpha($this->resource, true);
793
-		}
794
-
795
-		if (!$this->resource) {
796
-			$this->logger->debug('OC_Image->loadFromFile, could not load', ['app' => 'core']);
797
-			return false;
798
-		}
799
-		return $this->resource;
800
-	}
801
-
802
-	/**
803
-	 * Loads an image from a base64 encoded string.
804
-	 *
805
-	 * @param string $str A string base64 encoded string of image data.
806
-	 * @return bool|resource|\GdImage An image resource or false on error
807
-	 */
808
-	public function loadFromBase64($str) {
809
-		if (!is_string($str)) {
810
-			return false;
811
-		}
812
-		$data = base64_decode($str);
813
-		if ($data) { // try to load from string data
814
-			if (!$this->checkImageDataSize($data)) {
815
-				return false;
816
-			}
817
-			$this->resource = @imagecreatefromstring($data);
818
-			if ($this->fileInfo) {
819
-				$this->mimeType = $this->fileInfo->buffer($data);
820
-			}
821
-			if (!$this->resource) {
822
-				$this->logger->debug('OC_Image->loadFromBase64, could not load', ['app' => 'core']);
823
-				return false;
824
-			}
825
-			return $this->resource;
826
-		} else {
827
-			return false;
828
-		}
829
-	}
830
-
831
-	/**
832
-	 * Create a new image from file or URL
833
-	 *
834
-	 * @link http://www.programmierer-forum.de/function-imagecreatefrombmp-laeuft-mit-allen-bitraten-t143137.htm
835
-	 * @version 1.00
836
-	 * @param string $fileName <p>
837
-	 * Path to the BMP image.
838
-	 * </p>
839
-	 * @return bool|resource|\GdImage an image resource identifier on success, <b>FALSE</b> on errors.
840
-	 */
841
-	private function imagecreatefrombmp($fileName) {
842
-		if (!($fh = fopen($fileName, 'rb'))) {
843
-			$this->logger->warning('imagecreatefrombmp: Can not open ' . $fileName, ['app' => 'core']);
844
-			return false;
845
-		}
846
-		// read file header
847
-		$meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14));
848
-		// check for bitmap
849
-		if ($meta['type'] != 19778) {
850
-			fclose($fh);
851
-			$this->logger->warning('imagecreatefrombmp: Can not open ' . $fileName . ' is not a bitmap!', ['app' => 'core']);
852
-			return false;
853
-		}
854
-		// read image header
855
-		$meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40));
856
-		// read additional 16bit header
857
-		if ($meta['bits'] == 16) {
858
-			$meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12));
859
-		}
860
-		// set bytes and padding
861
-		$meta['bytes'] = $meta['bits'] / 8;
862
-		$this->bitDepth = $meta['bits']; //remember the bit depth for the imagebmp call
863
-		$meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4) - floor($meta['width'] * $meta['bytes'] / 4)));
864
-		if ($meta['decal'] == 4) {
865
-			$meta['decal'] = 0;
866
-		}
867
-		// obtain imagesize
868
-		if ($meta['imagesize'] < 1) {
869
-			$meta['imagesize'] = $meta['filesize'] - $meta['offset'];
870
-			// in rare cases filesize is equal to offset so we need to read physical size
871
-			if ($meta['imagesize'] < 1) {
872
-				$meta['imagesize'] = @filesize($fileName) - $meta['offset'];
873
-				if ($meta['imagesize'] < 1) {
874
-					fclose($fh);
875
-					$this->logger->warning('imagecreatefrombmp: Can not obtain file size of ' . $fileName . ' is not a bitmap!', ['app' => 'core']);
876
-					return false;
877
-				}
878
-			}
879
-		}
880
-		// calculate colors
881
-		$meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors'];
882
-		// read color palette
883
-		$palette = [];
884
-		if ($meta['bits'] < 16) {
885
-			$palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4));
886
-			// in rare cases the color value is signed
887
-			if ($palette[1] < 0) {
888
-				foreach ($palette as $i => $color) {
889
-					$palette[$i] = $color + 16777216;
890
-				}
891
-			}
892
-		}
893
-		if (!$this->checkImageMemory($meta['width'], $meta['height'])) {
894
-			fclose($fh);
895
-			return false;
896
-		}
897
-		// create gd image
898
-		$im = imagecreatetruecolor($meta['width'], $meta['height']);
899
-		if ($im == false) {
900
-			fclose($fh);
901
-			$this->logger->warning(
902
-				'imagecreatefrombmp: imagecreatetruecolor failed for file "' . $fileName . '" with dimensions ' . $meta['width'] . 'x' . $meta['height'],
903
-				['app' => 'core']);
904
-			return false;
905
-		}
906
-
907
-		$data = fread($fh, $meta['imagesize']);
908
-		$p = 0;
909
-		$vide = chr(0);
910
-		$y = $meta['height'] - 1;
911
-		$error = 'imagecreatefrombmp: ' . $fileName . ' has not enough data!';
912
-		// loop through the image data beginning with the lower left corner
913
-		while ($y >= 0) {
914
-			$x = 0;
915
-			while ($x < $meta['width']) {
916
-				switch ($meta['bits']) {
917
-					case 32:
918
-					case 24:
919
-						if (!($part = substr($data, $p, 3))) {
920
-							$this->logger->warning($error, ['app' => 'core']);
921
-							return $im;
922
-						}
923
-						$color = @unpack('V', $part . $vide);
924
-						break;
925
-					case 16:
926
-						if (!($part = substr($data, $p, 2))) {
927
-							fclose($fh);
928
-							$this->logger->warning($error, ['app' => 'core']);
929
-							return $im;
930
-						}
931
-						$color = @unpack('v', $part);
932
-						$color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3);
933
-						break;
934
-					case 8:
935
-						$color = @unpack('n', $vide . ($data[$p] ?? ''));
936
-						$color[1] = isset($palette[$color[1] + 1]) ? $palette[$color[1] + 1] : $palette[1];
937
-						break;
938
-					case 4:
939
-						$color = @unpack('n', $vide . ($data[floor($p)] ?? ''));
940
-						$color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F;
941
-						$color[1] = isset($palette[$color[1] + 1]) ? $palette[$color[1] + 1] : $palette[1];
942
-						break;
943
-					case 1:
944
-						$color = @unpack('n', $vide . ($data[floor($p)] ?? ''));
945
-						switch (($p * 8) % 8) {
946
-							case 0:
947
-								$color[1] = $color[1] >> 7;
948
-								break;
949
-							case 1:
950
-								$color[1] = ($color[1] & 0x40) >> 6;
951
-								break;
952
-							case 2:
953
-								$color[1] = ($color[1] & 0x20) >> 5;
954
-								break;
955
-							case 3:
956
-								$color[1] = ($color[1] & 0x10) >> 4;
957
-								break;
958
-							case 4:
959
-								$color[1] = ($color[1] & 0x8) >> 3;
960
-								break;
961
-							case 5:
962
-								$color[1] = ($color[1] & 0x4) >> 2;
963
-								break;
964
-							case 6:
965
-								$color[1] = ($color[1] & 0x2) >> 1;
966
-								break;
967
-							case 7:
968
-								$color[1] = ($color[1] & 0x1);
969
-								break;
970
-						}
971
-						$color[1] = isset($palette[$color[1] + 1]) ? $palette[$color[1] + 1] : $palette[1];
972
-						break;
973
-					default:
974
-						fclose($fh);
975
-						$this->logger->warning('imagecreatefrombmp: ' . $fileName . ' has ' . $meta['bits'] . ' bits and this is not supported!', ['app' => 'core']);
976
-						return false;
977
-				}
978
-				imagesetpixel($im, $x, $y, $color[1]);
979
-				$x++;
980
-				$p += $meta['bytes'];
981
-			}
982
-			$y--;
983
-			$p += $meta['decal'];
984
-		}
985
-		fclose($fh);
986
-		return $im;
987
-	}
988
-
989
-	/**
990
-	 * Resizes the image preserving ratio.
991
-	 *
992
-	 * @param integer $maxSize The maximum size of either the width or height.
993
-	 * @return bool
994
-	 */
995
-	public function resize($maxSize) {
996
-		if (!$this->valid()) {
997
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
998
-			return false;
999
-		}
1000
-		$result = $this->resizeNew($maxSize);
1001
-		imagedestroy($this->resource);
1002
-		$this->resource = $result;
1003
-		return $this->valid();
1004
-	}
1005
-
1006
-	/**
1007
-	 * @param $maxSize
1008
-	 * @return resource|bool|\GdImage
1009
-	 */
1010
-	private function resizeNew($maxSize) {
1011
-		if (!$this->valid()) {
1012
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1013
-			return false;
1014
-		}
1015
-		$widthOrig = imagesx($this->resource);
1016
-		$heightOrig = imagesy($this->resource);
1017
-		$ratioOrig = $widthOrig / $heightOrig;
1018
-
1019
-		if ($ratioOrig > 1) {
1020
-			$newHeight = round($maxSize / $ratioOrig);
1021
-			$newWidth = $maxSize;
1022
-		} else {
1023
-			$newWidth = round($maxSize * $ratioOrig);
1024
-			$newHeight = $maxSize;
1025
-		}
1026
-
1027
-		return $this->preciseResizeNew((int)round($newWidth), (int)round($newHeight));
1028
-	}
1029
-
1030
-	/**
1031
-	 * @param int $width
1032
-	 * @param int $height
1033
-	 * @return bool
1034
-	 */
1035
-	public function preciseResize(int $width, int $height): bool {
1036
-		if (!$this->valid()) {
1037
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1038
-			return false;
1039
-		}
1040
-		$result = $this->preciseResizeNew($width, $height);
1041
-		imagedestroy($this->resource);
1042
-		$this->resource = $result;
1043
-		return $this->valid();
1044
-	}
1045
-
1046
-
1047
-	/**
1048
-	 * @param int $width
1049
-	 * @param int $height
1050
-	 * @return resource|bool|\GdImage
1051
-	 */
1052
-	public function preciseResizeNew(int $width, int $height) {
1053
-		if (!($width > 0) || !($height > 0)) {
1054
-			$this->logger->info(__METHOD__ . '(): Requested image size not bigger than 0', ['app' => 'core']);
1055
-			return false;
1056
-		}
1057
-		if (!$this->valid()) {
1058
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1059
-			return false;
1060
-		}
1061
-		$widthOrig = imagesx($this->resource);
1062
-		$heightOrig = imagesy($this->resource);
1063
-		$process = imagecreatetruecolor($width, $height);
1064
-		if ($process === false) {
1065
-			$this->logger->error(__METHOD__ . '(): Error creating true color image', ['app' => 'core']);
1066
-			return false;
1067
-		}
1068
-
1069
-		// preserve transparency
1070
-		if ($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
1071
-			imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
1072
-			imagealphablending($process, false);
1073
-			imagesavealpha($process, true);
1074
-		}
1075
-
1076
-		$res = imagecopyresampled($process, $this->resource, 0, 0, 0, 0, $width, $height, $widthOrig, $heightOrig);
1077
-		if ($res === false) {
1078
-			$this->logger->error(__METHOD__ . '(): Error re-sampling process image', ['app' => 'core']);
1079
-			imagedestroy($process);
1080
-			return false;
1081
-		}
1082
-		return $process;
1083
-	}
1084
-
1085
-	/**
1086
-	 * Crops the image to the middle square. If the image is already square it just returns.
1087
-	 *
1088
-	 * @param int $size maximum size for the result (optional)
1089
-	 * @return bool for success or failure
1090
-	 */
1091
-	public function centerCrop($size = 0) {
1092
-		if (!$this->valid()) {
1093
-			$this->logger->error('OC_Image->centerCrop, No image loaded', ['app' => 'core']);
1094
-			return false;
1095
-		}
1096
-		$widthOrig = imagesx($this->resource);
1097
-		$heightOrig = imagesy($this->resource);
1098
-		if ($widthOrig === $heightOrig and $size == 0) {
1099
-			return true;
1100
-		}
1101
-		$ratioOrig = $widthOrig / $heightOrig;
1102
-		$width = $height = min($widthOrig, $heightOrig);
1103
-
1104
-		if ($ratioOrig > 1) {
1105
-			$x = ($widthOrig / 2) - ($width / 2);
1106
-			$y = 0;
1107
-		} else {
1108
-			$y = ($heightOrig / 2) - ($height / 2);
1109
-			$x = 0;
1110
-		}
1111
-		if ($size > 0) {
1112
-			$targetWidth = $size;
1113
-			$targetHeight = $size;
1114
-		} else {
1115
-			$targetWidth = $width;
1116
-			$targetHeight = $height;
1117
-		}
1118
-		$process = imagecreatetruecolor($targetWidth, $targetHeight);
1119
-		if ($process === false) {
1120
-			$this->logger->error('OC_Image->centerCrop, Error creating true color image', ['app' => 'core']);
1121
-			return false;
1122
-		}
1123
-
1124
-		// preserve transparency
1125
-		if ($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
1126
-			imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
1127
-			imagealphablending($process, false);
1128
-			imagesavealpha($process, true);
1129
-		}
1130
-
1131
-		imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $targetWidth, $targetHeight, $width, $height);
1132
-		if ($process === false) {
1133
-			$this->logger->error('OC_Image->centerCrop, Error re-sampling process image ' . $width . 'x' . $height, ['app' => 'core']);
1134
-			return false;
1135
-		}
1136
-		imagedestroy($this->resource);
1137
-		$this->resource = $process;
1138
-		return true;
1139
-	}
1140
-
1141
-	/**
1142
-	 * Crops the image from point $x$y with dimension $wx$h.
1143
-	 *
1144
-	 * @param int $x Horizontal position
1145
-	 * @param int $y Vertical position
1146
-	 * @param int $w Width
1147
-	 * @param int $h Height
1148
-	 * @return bool for success or failure
1149
-	 */
1150
-	public function crop(int $x, int $y, int $w, int $h): bool {
1151
-		if (!$this->valid()) {
1152
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1153
-			return false;
1154
-		}
1155
-		$result = $this->cropNew($x, $y, $w, $h);
1156
-		imagedestroy($this->resource);
1157
-		$this->resource = $result;
1158
-		return $this->valid();
1159
-	}
1160
-
1161
-	/**
1162
-	 * Crops the image from point $x$y with dimension $wx$h.
1163
-	 *
1164
-	 * @param int $x Horizontal position
1165
-	 * @param int $y Vertical position
1166
-	 * @param int $w Width
1167
-	 * @param int $h Height
1168
-	 * @return resource|\GdImage|false
1169
-	 */
1170
-	public function cropNew(int $x, int $y, int $w, int $h) {
1171
-		if (!$this->valid()) {
1172
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1173
-			return false;
1174
-		}
1175
-		$process = imagecreatetruecolor($w, $h);
1176
-		if ($process === false) {
1177
-			$this->logger->error(__METHOD__ . '(): Error creating true color image', ['app' => 'core']);
1178
-			return false;
1179
-		}
1180
-
1181
-		// preserve transparency
1182
-		if ($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
1183
-			imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
1184
-			imagealphablending($process, false);
1185
-			imagesavealpha($process, true);
1186
-		}
1187
-
1188
-		imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $w, $h, $w, $h);
1189
-		if ($process === false) {
1190
-			$this->logger->error(__METHOD__ . '(): Error re-sampling process image ' . $w . 'x' . $h, ['app' => 'core']);
1191
-			return false;
1192
-		}
1193
-		return $process;
1194
-	}
1195
-
1196
-	/**
1197
-	 * Resizes the image to fit within a boundary while preserving ratio.
1198
-	 *
1199
-	 * Warning: Images smaller than $maxWidth x $maxHeight will end up being scaled up
1200
-	 *
1201
-	 * @param integer $maxWidth
1202
-	 * @param integer $maxHeight
1203
-	 * @return bool
1204
-	 */
1205
-	public function fitIn($maxWidth, $maxHeight) {
1206
-		if (!$this->valid()) {
1207
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1208
-			return false;
1209
-		}
1210
-		$widthOrig = imagesx($this->resource);
1211
-		$heightOrig = imagesy($this->resource);
1212
-		$ratio = $widthOrig / $heightOrig;
1213
-
1214
-		$newWidth = min($maxWidth, $ratio * $maxHeight);
1215
-		$newHeight = min($maxHeight, $maxWidth / $ratio);
1216
-
1217
-		$this->preciseResize((int)round($newWidth), (int)round($newHeight));
1218
-		return true;
1219
-	}
1220
-
1221
-	/**
1222
-	 * Shrinks larger images to fit within specified boundaries while preserving ratio.
1223
-	 *
1224
-	 * @param integer $maxWidth
1225
-	 * @param integer $maxHeight
1226
-	 * @return bool
1227
-	 */
1228
-	public function scaleDownToFit($maxWidth, $maxHeight) {
1229
-		if (!$this->valid()) {
1230
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1231
-			return false;
1232
-		}
1233
-		$widthOrig = imagesx($this->resource);
1234
-		$heightOrig = imagesy($this->resource);
1235
-
1236
-		if ($widthOrig > $maxWidth || $heightOrig > $maxHeight) {
1237
-			return $this->fitIn($maxWidth, $maxHeight);
1238
-		}
1239
-
1240
-		return false;
1241
-	}
1242
-
1243
-	public function copy(): IImage {
1244
-		$image = new OC_Image(null, $this->logger, $this->config);
1245
-		$image->resource = imagecreatetruecolor($this->width(), $this->height());
1246
-		imagecopy(
1247
-			$image->resource(),
1248
-			$this->resource(),
1249
-			0,
1250
-			0,
1251
-			0,
1252
-			0,
1253
-			$this->width(),
1254
-			$this->height()
1255
-		);
1256
-
1257
-		return $image;
1258
-	}
1259
-
1260
-	public function cropCopy(int $x, int $y, int $w, int $h): IImage {
1261
-		$image = new OC_Image(null, $this->logger, $this->config);
1262
-		$image->imageType = $this->imageType;
1263
-		$image->mimeType = $this->mimeType;
1264
-		$image->bitDepth = $this->bitDepth;
1265
-		$image->resource = $this->cropNew($x, $y, $w, $h);
1266
-
1267
-		return $image;
1268
-	}
1269
-
1270
-	public function preciseResizeCopy(int $width, int $height): IImage {
1271
-		$image = new OC_Image(null, $this->logger, $this->config);
1272
-		$image->imageType = $this->imageType;
1273
-		$image->mimeType = $this->mimeType;
1274
-		$image->bitDepth = $this->bitDepth;
1275
-		$image->resource = $this->preciseResizeNew($width, $height);
1276
-
1277
-		return $image;
1278
-	}
1279
-
1280
-	public function resizeCopy(int $maxSize): IImage {
1281
-		$image = new OC_Image(null, $this->logger, $this->config);
1282
-		$image->imageType = $this->imageType;
1283
-		$image->mimeType = $this->mimeType;
1284
-		$image->bitDepth = $this->bitDepth;
1285
-		$image->resource = $this->resizeNew($maxSize);
1286
-
1287
-		return $image;
1288
-	}
1289
-
1290
-	/**
1291
-	 * Destroys the current image and resets the object
1292
-	 */
1293
-	public function destroy() {
1294
-		if ($this->valid()) {
1295
-			imagedestroy($this->resource);
1296
-		}
1297
-		$this->resource = false;
1298
-	}
1299
-
1300
-	public function __destruct() {
1301
-		$this->destroy();
1302
-	}
753
+            default:
754
+
755
+                // this is mostly file created from encrypted file
756
+                $data = file_get_contents($imagePath);
757
+                if (!$this->checkImageDataSize($data)) {
758
+                    return false;
759
+                }
760
+                $this->resource = imagecreatefromstring($data);
761
+                $iType = IMAGETYPE_PNG;
762
+                $this->logger->debug('OC_Image->loadFromFile, Default', ['app' => 'core']);
763
+                break;
764
+        }
765
+        if ($this->valid()) {
766
+            $this->imageType = $iType;
767
+            $this->mimeType = image_type_to_mime_type($iType);
768
+            $this->filePath = $imagePath;
769
+        }
770
+        return $this->resource;
771
+    }
772
+
773
+    /**
774
+     * Loads an image from a string of data.
775
+     *
776
+     * @param string $str A string of image data as read from a file.
777
+     * @return bool|resource|\GdImage An image resource or false on error
778
+     */
779
+    public function loadFromData($str) {
780
+        if (!is_string($str)) {
781
+            return false;
782
+        }
783
+        if (!$this->checkImageDataSize($str)) {
784
+            return false;
785
+        }
786
+        $this->resource = @imagecreatefromstring($str);
787
+        if ($this->fileInfo) {
788
+            $this->mimeType = $this->fileInfo->buffer($str);
789
+        }
790
+        if ($this->valid()) {
791
+            imagealphablending($this->resource, false);
792
+            imagesavealpha($this->resource, true);
793
+        }
794
+
795
+        if (!$this->resource) {
796
+            $this->logger->debug('OC_Image->loadFromFile, could not load', ['app' => 'core']);
797
+            return false;
798
+        }
799
+        return $this->resource;
800
+    }
801
+
802
+    /**
803
+     * Loads an image from a base64 encoded string.
804
+     *
805
+     * @param string $str A string base64 encoded string of image data.
806
+     * @return bool|resource|\GdImage An image resource or false on error
807
+     */
808
+    public function loadFromBase64($str) {
809
+        if (!is_string($str)) {
810
+            return false;
811
+        }
812
+        $data = base64_decode($str);
813
+        if ($data) { // try to load from string data
814
+            if (!$this->checkImageDataSize($data)) {
815
+                return false;
816
+            }
817
+            $this->resource = @imagecreatefromstring($data);
818
+            if ($this->fileInfo) {
819
+                $this->mimeType = $this->fileInfo->buffer($data);
820
+            }
821
+            if (!$this->resource) {
822
+                $this->logger->debug('OC_Image->loadFromBase64, could not load', ['app' => 'core']);
823
+                return false;
824
+            }
825
+            return $this->resource;
826
+        } else {
827
+            return false;
828
+        }
829
+    }
830
+
831
+    /**
832
+     * Create a new image from file or URL
833
+     *
834
+     * @link http://www.programmierer-forum.de/function-imagecreatefrombmp-laeuft-mit-allen-bitraten-t143137.htm
835
+     * @version 1.00
836
+     * @param string $fileName <p>
837
+     * Path to the BMP image.
838
+     * </p>
839
+     * @return bool|resource|\GdImage an image resource identifier on success, <b>FALSE</b> on errors.
840
+     */
841
+    private function imagecreatefrombmp($fileName) {
842
+        if (!($fh = fopen($fileName, 'rb'))) {
843
+            $this->logger->warning('imagecreatefrombmp: Can not open ' . $fileName, ['app' => 'core']);
844
+            return false;
845
+        }
846
+        // read file header
847
+        $meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14));
848
+        // check for bitmap
849
+        if ($meta['type'] != 19778) {
850
+            fclose($fh);
851
+            $this->logger->warning('imagecreatefrombmp: Can not open ' . $fileName . ' is not a bitmap!', ['app' => 'core']);
852
+            return false;
853
+        }
854
+        // read image header
855
+        $meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40));
856
+        // read additional 16bit header
857
+        if ($meta['bits'] == 16) {
858
+            $meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12));
859
+        }
860
+        // set bytes and padding
861
+        $meta['bytes'] = $meta['bits'] / 8;
862
+        $this->bitDepth = $meta['bits']; //remember the bit depth for the imagebmp call
863
+        $meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4) - floor($meta['width'] * $meta['bytes'] / 4)));
864
+        if ($meta['decal'] == 4) {
865
+            $meta['decal'] = 0;
866
+        }
867
+        // obtain imagesize
868
+        if ($meta['imagesize'] < 1) {
869
+            $meta['imagesize'] = $meta['filesize'] - $meta['offset'];
870
+            // in rare cases filesize is equal to offset so we need to read physical size
871
+            if ($meta['imagesize'] < 1) {
872
+                $meta['imagesize'] = @filesize($fileName) - $meta['offset'];
873
+                if ($meta['imagesize'] < 1) {
874
+                    fclose($fh);
875
+                    $this->logger->warning('imagecreatefrombmp: Can not obtain file size of ' . $fileName . ' is not a bitmap!', ['app' => 'core']);
876
+                    return false;
877
+                }
878
+            }
879
+        }
880
+        // calculate colors
881
+        $meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors'];
882
+        // read color palette
883
+        $palette = [];
884
+        if ($meta['bits'] < 16) {
885
+            $palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4));
886
+            // in rare cases the color value is signed
887
+            if ($palette[1] < 0) {
888
+                foreach ($palette as $i => $color) {
889
+                    $palette[$i] = $color + 16777216;
890
+                }
891
+            }
892
+        }
893
+        if (!$this->checkImageMemory($meta['width'], $meta['height'])) {
894
+            fclose($fh);
895
+            return false;
896
+        }
897
+        // create gd image
898
+        $im = imagecreatetruecolor($meta['width'], $meta['height']);
899
+        if ($im == false) {
900
+            fclose($fh);
901
+            $this->logger->warning(
902
+                'imagecreatefrombmp: imagecreatetruecolor failed for file "' . $fileName . '" with dimensions ' . $meta['width'] . 'x' . $meta['height'],
903
+                ['app' => 'core']);
904
+            return false;
905
+        }
906
+
907
+        $data = fread($fh, $meta['imagesize']);
908
+        $p = 0;
909
+        $vide = chr(0);
910
+        $y = $meta['height'] - 1;
911
+        $error = 'imagecreatefrombmp: ' . $fileName . ' has not enough data!';
912
+        // loop through the image data beginning with the lower left corner
913
+        while ($y >= 0) {
914
+            $x = 0;
915
+            while ($x < $meta['width']) {
916
+                switch ($meta['bits']) {
917
+                    case 32:
918
+                    case 24:
919
+                        if (!($part = substr($data, $p, 3))) {
920
+                            $this->logger->warning($error, ['app' => 'core']);
921
+                            return $im;
922
+                        }
923
+                        $color = @unpack('V', $part . $vide);
924
+                        break;
925
+                    case 16:
926
+                        if (!($part = substr($data, $p, 2))) {
927
+                            fclose($fh);
928
+                            $this->logger->warning($error, ['app' => 'core']);
929
+                            return $im;
930
+                        }
931
+                        $color = @unpack('v', $part);
932
+                        $color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3);
933
+                        break;
934
+                    case 8:
935
+                        $color = @unpack('n', $vide . ($data[$p] ?? ''));
936
+                        $color[1] = isset($palette[$color[1] + 1]) ? $palette[$color[1] + 1] : $palette[1];
937
+                        break;
938
+                    case 4:
939
+                        $color = @unpack('n', $vide . ($data[floor($p)] ?? ''));
940
+                        $color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F;
941
+                        $color[1] = isset($palette[$color[1] + 1]) ? $palette[$color[1] + 1] : $palette[1];
942
+                        break;
943
+                    case 1:
944
+                        $color = @unpack('n', $vide . ($data[floor($p)] ?? ''));
945
+                        switch (($p * 8) % 8) {
946
+                            case 0:
947
+                                $color[1] = $color[1] >> 7;
948
+                                break;
949
+                            case 1:
950
+                                $color[1] = ($color[1] & 0x40) >> 6;
951
+                                break;
952
+                            case 2:
953
+                                $color[1] = ($color[1] & 0x20) >> 5;
954
+                                break;
955
+                            case 3:
956
+                                $color[1] = ($color[1] & 0x10) >> 4;
957
+                                break;
958
+                            case 4:
959
+                                $color[1] = ($color[1] & 0x8) >> 3;
960
+                                break;
961
+                            case 5:
962
+                                $color[1] = ($color[1] & 0x4) >> 2;
963
+                                break;
964
+                            case 6:
965
+                                $color[1] = ($color[1] & 0x2) >> 1;
966
+                                break;
967
+                            case 7:
968
+                                $color[1] = ($color[1] & 0x1);
969
+                                break;
970
+                        }
971
+                        $color[1] = isset($palette[$color[1] + 1]) ? $palette[$color[1] + 1] : $palette[1];
972
+                        break;
973
+                    default:
974
+                        fclose($fh);
975
+                        $this->logger->warning('imagecreatefrombmp: ' . $fileName . ' has ' . $meta['bits'] . ' bits and this is not supported!', ['app' => 'core']);
976
+                        return false;
977
+                }
978
+                imagesetpixel($im, $x, $y, $color[1]);
979
+                $x++;
980
+                $p += $meta['bytes'];
981
+            }
982
+            $y--;
983
+            $p += $meta['decal'];
984
+        }
985
+        fclose($fh);
986
+        return $im;
987
+    }
988
+
989
+    /**
990
+     * Resizes the image preserving ratio.
991
+     *
992
+     * @param integer $maxSize The maximum size of either the width or height.
993
+     * @return bool
994
+     */
995
+    public function resize($maxSize) {
996
+        if (!$this->valid()) {
997
+            $this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
998
+            return false;
999
+        }
1000
+        $result = $this->resizeNew($maxSize);
1001
+        imagedestroy($this->resource);
1002
+        $this->resource = $result;
1003
+        return $this->valid();
1004
+    }
1005
+
1006
+    /**
1007
+     * @param $maxSize
1008
+     * @return resource|bool|\GdImage
1009
+     */
1010
+    private function resizeNew($maxSize) {
1011
+        if (!$this->valid()) {
1012
+            $this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1013
+            return false;
1014
+        }
1015
+        $widthOrig = imagesx($this->resource);
1016
+        $heightOrig = imagesy($this->resource);
1017
+        $ratioOrig = $widthOrig / $heightOrig;
1018
+
1019
+        if ($ratioOrig > 1) {
1020
+            $newHeight = round($maxSize / $ratioOrig);
1021
+            $newWidth = $maxSize;
1022
+        } else {
1023
+            $newWidth = round($maxSize * $ratioOrig);
1024
+            $newHeight = $maxSize;
1025
+        }
1026
+
1027
+        return $this->preciseResizeNew((int)round($newWidth), (int)round($newHeight));
1028
+    }
1029
+
1030
+    /**
1031
+     * @param int $width
1032
+     * @param int $height
1033
+     * @return bool
1034
+     */
1035
+    public function preciseResize(int $width, int $height): bool {
1036
+        if (!$this->valid()) {
1037
+            $this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1038
+            return false;
1039
+        }
1040
+        $result = $this->preciseResizeNew($width, $height);
1041
+        imagedestroy($this->resource);
1042
+        $this->resource = $result;
1043
+        return $this->valid();
1044
+    }
1045
+
1046
+
1047
+    /**
1048
+     * @param int $width
1049
+     * @param int $height
1050
+     * @return resource|bool|\GdImage
1051
+     */
1052
+    public function preciseResizeNew(int $width, int $height) {
1053
+        if (!($width > 0) || !($height > 0)) {
1054
+            $this->logger->info(__METHOD__ . '(): Requested image size not bigger than 0', ['app' => 'core']);
1055
+            return false;
1056
+        }
1057
+        if (!$this->valid()) {
1058
+            $this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1059
+            return false;
1060
+        }
1061
+        $widthOrig = imagesx($this->resource);
1062
+        $heightOrig = imagesy($this->resource);
1063
+        $process = imagecreatetruecolor($width, $height);
1064
+        if ($process === false) {
1065
+            $this->logger->error(__METHOD__ . '(): Error creating true color image', ['app' => 'core']);
1066
+            return false;
1067
+        }
1068
+
1069
+        // preserve transparency
1070
+        if ($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
1071
+            imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
1072
+            imagealphablending($process, false);
1073
+            imagesavealpha($process, true);
1074
+        }
1075
+
1076
+        $res = imagecopyresampled($process, $this->resource, 0, 0, 0, 0, $width, $height, $widthOrig, $heightOrig);
1077
+        if ($res === false) {
1078
+            $this->logger->error(__METHOD__ . '(): Error re-sampling process image', ['app' => 'core']);
1079
+            imagedestroy($process);
1080
+            return false;
1081
+        }
1082
+        return $process;
1083
+    }
1084
+
1085
+    /**
1086
+     * Crops the image to the middle square. If the image is already square it just returns.
1087
+     *
1088
+     * @param int $size maximum size for the result (optional)
1089
+     * @return bool for success or failure
1090
+     */
1091
+    public function centerCrop($size = 0) {
1092
+        if (!$this->valid()) {
1093
+            $this->logger->error('OC_Image->centerCrop, No image loaded', ['app' => 'core']);
1094
+            return false;
1095
+        }
1096
+        $widthOrig = imagesx($this->resource);
1097
+        $heightOrig = imagesy($this->resource);
1098
+        if ($widthOrig === $heightOrig and $size == 0) {
1099
+            return true;
1100
+        }
1101
+        $ratioOrig = $widthOrig / $heightOrig;
1102
+        $width = $height = min($widthOrig, $heightOrig);
1103
+
1104
+        if ($ratioOrig > 1) {
1105
+            $x = ($widthOrig / 2) - ($width / 2);
1106
+            $y = 0;
1107
+        } else {
1108
+            $y = ($heightOrig / 2) - ($height / 2);
1109
+            $x = 0;
1110
+        }
1111
+        if ($size > 0) {
1112
+            $targetWidth = $size;
1113
+            $targetHeight = $size;
1114
+        } else {
1115
+            $targetWidth = $width;
1116
+            $targetHeight = $height;
1117
+        }
1118
+        $process = imagecreatetruecolor($targetWidth, $targetHeight);
1119
+        if ($process === false) {
1120
+            $this->logger->error('OC_Image->centerCrop, Error creating true color image', ['app' => 'core']);
1121
+            return false;
1122
+        }
1123
+
1124
+        // preserve transparency
1125
+        if ($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
1126
+            imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
1127
+            imagealphablending($process, false);
1128
+            imagesavealpha($process, true);
1129
+        }
1130
+
1131
+        imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $targetWidth, $targetHeight, $width, $height);
1132
+        if ($process === false) {
1133
+            $this->logger->error('OC_Image->centerCrop, Error re-sampling process image ' . $width . 'x' . $height, ['app' => 'core']);
1134
+            return false;
1135
+        }
1136
+        imagedestroy($this->resource);
1137
+        $this->resource = $process;
1138
+        return true;
1139
+    }
1140
+
1141
+    /**
1142
+     * Crops the image from point $x$y with dimension $wx$h.
1143
+     *
1144
+     * @param int $x Horizontal position
1145
+     * @param int $y Vertical position
1146
+     * @param int $w Width
1147
+     * @param int $h Height
1148
+     * @return bool for success or failure
1149
+     */
1150
+    public function crop(int $x, int $y, int $w, int $h): bool {
1151
+        if (!$this->valid()) {
1152
+            $this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1153
+            return false;
1154
+        }
1155
+        $result = $this->cropNew($x, $y, $w, $h);
1156
+        imagedestroy($this->resource);
1157
+        $this->resource = $result;
1158
+        return $this->valid();
1159
+    }
1160
+
1161
+    /**
1162
+     * Crops the image from point $x$y with dimension $wx$h.
1163
+     *
1164
+     * @param int $x Horizontal position
1165
+     * @param int $y Vertical position
1166
+     * @param int $w Width
1167
+     * @param int $h Height
1168
+     * @return resource|\GdImage|false
1169
+     */
1170
+    public function cropNew(int $x, int $y, int $w, int $h) {
1171
+        if (!$this->valid()) {
1172
+            $this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1173
+            return false;
1174
+        }
1175
+        $process = imagecreatetruecolor($w, $h);
1176
+        if ($process === false) {
1177
+            $this->logger->error(__METHOD__ . '(): Error creating true color image', ['app' => 'core']);
1178
+            return false;
1179
+        }
1180
+
1181
+        // preserve transparency
1182
+        if ($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
1183
+            imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
1184
+            imagealphablending($process, false);
1185
+            imagesavealpha($process, true);
1186
+        }
1187
+
1188
+        imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $w, $h, $w, $h);
1189
+        if ($process === false) {
1190
+            $this->logger->error(__METHOD__ . '(): Error re-sampling process image ' . $w . 'x' . $h, ['app' => 'core']);
1191
+            return false;
1192
+        }
1193
+        return $process;
1194
+    }
1195
+
1196
+    /**
1197
+     * Resizes the image to fit within a boundary while preserving ratio.
1198
+     *
1199
+     * Warning: Images smaller than $maxWidth x $maxHeight will end up being scaled up
1200
+     *
1201
+     * @param integer $maxWidth
1202
+     * @param integer $maxHeight
1203
+     * @return bool
1204
+     */
1205
+    public function fitIn($maxWidth, $maxHeight) {
1206
+        if (!$this->valid()) {
1207
+            $this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1208
+            return false;
1209
+        }
1210
+        $widthOrig = imagesx($this->resource);
1211
+        $heightOrig = imagesy($this->resource);
1212
+        $ratio = $widthOrig / $heightOrig;
1213
+
1214
+        $newWidth = min($maxWidth, $ratio * $maxHeight);
1215
+        $newHeight = min($maxHeight, $maxWidth / $ratio);
1216
+
1217
+        $this->preciseResize((int)round($newWidth), (int)round($newHeight));
1218
+        return true;
1219
+    }
1220
+
1221
+    /**
1222
+     * Shrinks larger images to fit within specified boundaries while preserving ratio.
1223
+     *
1224
+     * @param integer $maxWidth
1225
+     * @param integer $maxHeight
1226
+     * @return bool
1227
+     */
1228
+    public function scaleDownToFit($maxWidth, $maxHeight) {
1229
+        if (!$this->valid()) {
1230
+            $this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1231
+            return false;
1232
+        }
1233
+        $widthOrig = imagesx($this->resource);
1234
+        $heightOrig = imagesy($this->resource);
1235
+
1236
+        if ($widthOrig > $maxWidth || $heightOrig > $maxHeight) {
1237
+            return $this->fitIn($maxWidth, $maxHeight);
1238
+        }
1239
+
1240
+        return false;
1241
+    }
1242
+
1243
+    public function copy(): IImage {
1244
+        $image = new OC_Image(null, $this->logger, $this->config);
1245
+        $image->resource = imagecreatetruecolor($this->width(), $this->height());
1246
+        imagecopy(
1247
+            $image->resource(),
1248
+            $this->resource(),
1249
+            0,
1250
+            0,
1251
+            0,
1252
+            0,
1253
+            $this->width(),
1254
+            $this->height()
1255
+        );
1256
+
1257
+        return $image;
1258
+    }
1259
+
1260
+    public function cropCopy(int $x, int $y, int $w, int $h): IImage {
1261
+        $image = new OC_Image(null, $this->logger, $this->config);
1262
+        $image->imageType = $this->imageType;
1263
+        $image->mimeType = $this->mimeType;
1264
+        $image->bitDepth = $this->bitDepth;
1265
+        $image->resource = $this->cropNew($x, $y, $w, $h);
1266
+
1267
+        return $image;
1268
+    }
1269
+
1270
+    public function preciseResizeCopy(int $width, int $height): IImage {
1271
+        $image = new OC_Image(null, $this->logger, $this->config);
1272
+        $image->imageType = $this->imageType;
1273
+        $image->mimeType = $this->mimeType;
1274
+        $image->bitDepth = $this->bitDepth;
1275
+        $image->resource = $this->preciseResizeNew($width, $height);
1276
+
1277
+        return $image;
1278
+    }
1279
+
1280
+    public function resizeCopy(int $maxSize): IImage {
1281
+        $image = new OC_Image(null, $this->logger, $this->config);
1282
+        $image->imageType = $this->imageType;
1283
+        $image->mimeType = $this->mimeType;
1284
+        $image->bitDepth = $this->bitDepth;
1285
+        $image->resource = $this->resizeNew($maxSize);
1286
+
1287
+        return $image;
1288
+    }
1289
+
1290
+    /**
1291
+     * Destroys the current image and resets the object
1292
+     */
1293
+    public function destroy() {
1294
+        if ($this->valid()) {
1295
+            imagedestroy($this->resource);
1296
+        }
1297
+        $this->resource = false;
1298
+    }
1299
+
1300
+    public function __destruct() {
1301
+        $this->destroy();
1302
+    }
1303 1303
 }
1304 1304
 
1305 1305
 if (!function_exists('imagebmp')) {
1306
-	/**
1307
-	 * Output a BMP image to either the browser or a file
1308
-	 *
1309
-	 * @link http://www.ugia.cn/wp-data/imagebmp.php
1310
-	 * @author legend <[email protected]>
1311
-	 * @link http://www.programmierer-forum.de/imagebmp-gute-funktion-gefunden-t143716.htm
1312
-	 * @author mgutt <[email protected]>
1313
-	 * @version 1.00
1314
-	 * @param resource|\GdImage $im
1315
-	 * @param string $fileName [optional] <p>The path to save the file to.</p>
1316
-	 * @param int $bit [optional] <p>Bit depth, (default is 24).</p>
1317
-	 * @param int $compression [optional]
1318
-	 * @return bool <b>TRUE</b> on success or <b>FALSE</b> on failure.
1319
-	 */
1320
-	function imagebmp($im, $fileName = '', $bit = 24, $compression = 0) {
1321
-		if (!in_array($bit, [1, 4, 8, 16, 24, 32])) {
1322
-			$bit = 24;
1323
-		} elseif ($bit == 32) {
1324
-			$bit = 24;
1325
-		}
1326
-		$bits = (int)pow(2, $bit);
1327
-		imagetruecolortopalette($im, true, $bits);
1328
-		$width = imagesx($im);
1329
-		$height = imagesy($im);
1330
-		$colorsNum = imagecolorstotal($im);
1331
-		$rgbQuad = '';
1332
-		if ($bit <= 8) {
1333
-			for ($i = 0; $i < $colorsNum; $i++) {
1334
-				$colors = imagecolorsforindex($im, $i);
1335
-				$rgbQuad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0";
1336
-			}
1337
-			$bmpData = '';
1338
-			if ($compression == 0 || $bit < 8) {
1339
-				$compression = 0;
1340
-				$extra = '';
1341
-				$padding = 4 - ceil($width / (8 / $bit)) % 4;
1342
-				if ($padding % 4 != 0) {
1343
-					$extra = str_repeat("\0", $padding);
1344
-				}
1345
-				for ($j = $height - 1; $j >= 0; $j--) {
1346
-					$i = 0;
1347
-					while ($i < $width) {
1348
-						$bin = 0;
1349
-						$limit = $width - $i < 8 / $bit ? (8 / $bit - $width + $i) * $bit : 0;
1350
-						for ($k = 8 - $bit; $k >= $limit; $k -= $bit) {
1351
-							$index = imagecolorat($im, $i, $j);
1352
-							$bin |= $index << $k;
1353
-							$i++;
1354
-						}
1355
-						$bmpData .= chr($bin);
1356
-					}
1357
-					$bmpData .= $extra;
1358
-				}
1359
-			} // RLE8
1360
-			elseif ($compression == 1 && $bit == 8) {
1361
-				for ($j = $height - 1; $j >= 0; $j--) {
1362
-					$lastIndex = null;
1363
-					$sameNum = 0;
1364
-					for ($i = 0; $i <= $width; $i++) {
1365
-						$index = imagecolorat($im, $i, $j);
1366
-						if ($index !== $lastIndex || $sameNum > 255) {
1367
-							if ($sameNum != 0) {
1368
-								$bmpData .= chr($sameNum) . chr($lastIndex);
1369
-							}
1370
-							$lastIndex = $index;
1371
-							$sameNum = 1;
1372
-						} else {
1373
-							$sameNum++;
1374
-						}
1375
-					}
1376
-					$bmpData .= "\0\0";
1377
-				}
1378
-				$bmpData .= "\0\1";
1379
-			}
1380
-			$sizeQuad = strlen($rgbQuad);
1381
-			$sizeData = strlen($bmpData);
1382
-		} else {
1383
-			$extra = '';
1384
-			$padding = 4 - ($width * ($bit / 8)) % 4;
1385
-			if ($padding % 4 != 0) {
1386
-				$extra = str_repeat("\0", $padding);
1387
-			}
1388
-			$bmpData = '';
1389
-			for ($j = $height - 1; $j >= 0; $j--) {
1390
-				for ($i = 0; $i < $width; $i++) {
1391
-					$index = imagecolorat($im, $i, $j);
1392
-					$colors = imagecolorsforindex($im, $index);
1393
-					if ($bit == 16) {
1394
-						$bin = 0 << $bit;
1395
-						$bin |= ($colors['red'] >> 3) << 10;
1396
-						$bin |= ($colors['green'] >> 3) << 5;
1397
-						$bin |= $colors['blue'] >> 3;
1398
-						$bmpData .= pack("v", $bin);
1399
-					} else {
1400
-						$bmpData .= pack("c*", $colors['blue'], $colors['green'], $colors['red']);
1401
-					}
1402
-				}
1403
-				$bmpData .= $extra;
1404
-			}
1405
-			$sizeQuad = 0;
1406
-			$sizeData = strlen($bmpData);
1407
-			$colorsNum = 0;
1408
-		}
1409
-		$fileHeader = 'BM' . pack('V3', 54 + $sizeQuad + $sizeData, 0, 54 + $sizeQuad);
1410
-		$infoHeader = pack('V3v2V*', 0x28, $width, $height, 1, $bit, $compression, $sizeData, 0, 0, $colorsNum, 0);
1411
-		if ($fileName != '') {
1412
-			$fp = fopen($fileName, 'wb');
1413
-			fwrite($fp, $fileHeader . $infoHeader . $rgbQuad . $bmpData);
1414
-			fclose($fp);
1415
-			return true;
1416
-		}
1417
-		echo $fileHeader . $infoHeader . $rgbQuad . $bmpData;
1418
-		return true;
1419
-	}
1306
+    /**
1307
+     * Output a BMP image to either the browser or a file
1308
+     *
1309
+     * @link http://www.ugia.cn/wp-data/imagebmp.php
1310
+     * @author legend <[email protected]>
1311
+     * @link http://www.programmierer-forum.de/imagebmp-gute-funktion-gefunden-t143716.htm
1312
+     * @author mgutt <[email protected]>
1313
+     * @version 1.00
1314
+     * @param resource|\GdImage $im
1315
+     * @param string $fileName [optional] <p>The path to save the file to.</p>
1316
+     * @param int $bit [optional] <p>Bit depth, (default is 24).</p>
1317
+     * @param int $compression [optional]
1318
+     * @return bool <b>TRUE</b> on success or <b>FALSE</b> on failure.
1319
+     */
1320
+    function imagebmp($im, $fileName = '', $bit = 24, $compression = 0) {
1321
+        if (!in_array($bit, [1, 4, 8, 16, 24, 32])) {
1322
+            $bit = 24;
1323
+        } elseif ($bit == 32) {
1324
+            $bit = 24;
1325
+        }
1326
+        $bits = (int)pow(2, $bit);
1327
+        imagetruecolortopalette($im, true, $bits);
1328
+        $width = imagesx($im);
1329
+        $height = imagesy($im);
1330
+        $colorsNum = imagecolorstotal($im);
1331
+        $rgbQuad = '';
1332
+        if ($bit <= 8) {
1333
+            for ($i = 0; $i < $colorsNum; $i++) {
1334
+                $colors = imagecolorsforindex($im, $i);
1335
+                $rgbQuad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0";
1336
+            }
1337
+            $bmpData = '';
1338
+            if ($compression == 0 || $bit < 8) {
1339
+                $compression = 0;
1340
+                $extra = '';
1341
+                $padding = 4 - ceil($width / (8 / $bit)) % 4;
1342
+                if ($padding % 4 != 0) {
1343
+                    $extra = str_repeat("\0", $padding);
1344
+                }
1345
+                for ($j = $height - 1; $j >= 0; $j--) {
1346
+                    $i = 0;
1347
+                    while ($i < $width) {
1348
+                        $bin = 0;
1349
+                        $limit = $width - $i < 8 / $bit ? (8 / $bit - $width + $i) * $bit : 0;
1350
+                        for ($k = 8 - $bit; $k >= $limit; $k -= $bit) {
1351
+                            $index = imagecolorat($im, $i, $j);
1352
+                            $bin |= $index << $k;
1353
+                            $i++;
1354
+                        }
1355
+                        $bmpData .= chr($bin);
1356
+                    }
1357
+                    $bmpData .= $extra;
1358
+                }
1359
+            } // RLE8
1360
+            elseif ($compression == 1 && $bit == 8) {
1361
+                for ($j = $height - 1; $j >= 0; $j--) {
1362
+                    $lastIndex = null;
1363
+                    $sameNum = 0;
1364
+                    for ($i = 0; $i <= $width; $i++) {
1365
+                        $index = imagecolorat($im, $i, $j);
1366
+                        if ($index !== $lastIndex || $sameNum > 255) {
1367
+                            if ($sameNum != 0) {
1368
+                                $bmpData .= chr($sameNum) . chr($lastIndex);
1369
+                            }
1370
+                            $lastIndex = $index;
1371
+                            $sameNum = 1;
1372
+                        } else {
1373
+                            $sameNum++;
1374
+                        }
1375
+                    }
1376
+                    $bmpData .= "\0\0";
1377
+                }
1378
+                $bmpData .= "\0\1";
1379
+            }
1380
+            $sizeQuad = strlen($rgbQuad);
1381
+            $sizeData = strlen($bmpData);
1382
+        } else {
1383
+            $extra = '';
1384
+            $padding = 4 - ($width * ($bit / 8)) % 4;
1385
+            if ($padding % 4 != 0) {
1386
+                $extra = str_repeat("\0", $padding);
1387
+            }
1388
+            $bmpData = '';
1389
+            for ($j = $height - 1; $j >= 0; $j--) {
1390
+                for ($i = 0; $i < $width; $i++) {
1391
+                    $index = imagecolorat($im, $i, $j);
1392
+                    $colors = imagecolorsforindex($im, $index);
1393
+                    if ($bit == 16) {
1394
+                        $bin = 0 << $bit;
1395
+                        $bin |= ($colors['red'] >> 3) << 10;
1396
+                        $bin |= ($colors['green'] >> 3) << 5;
1397
+                        $bin |= $colors['blue'] >> 3;
1398
+                        $bmpData .= pack("v", $bin);
1399
+                    } else {
1400
+                        $bmpData .= pack("c*", $colors['blue'], $colors['green'], $colors['red']);
1401
+                    }
1402
+                }
1403
+                $bmpData .= $extra;
1404
+            }
1405
+            $sizeQuad = 0;
1406
+            $sizeData = strlen($bmpData);
1407
+            $colorsNum = 0;
1408
+        }
1409
+        $fileHeader = 'BM' . pack('V3', 54 + $sizeQuad + $sizeData, 0, 54 + $sizeQuad);
1410
+        $infoHeader = pack('V3v2V*', 0x28, $width, $height, 1, $bit, $compression, $sizeData, 0, 0, $colorsNum, 0);
1411
+        if ($fileName != '') {
1412
+            $fp = fopen($fileName, 'wb');
1413
+            fwrite($fp, $fileHeader . $infoHeader . $rgbQuad . $bmpData);
1414
+            fclose($fp);
1415
+            return true;
1416
+        }
1417
+        echo $fileHeader . $infoHeader . $rgbQuad . $bmpData;
1418
+        return true;
1419
+    }
1420 1420
 }
1421 1421
 
1422 1422
 if (!function_exists('exif_imagetype')) {
1423
-	/**
1424
-	 * Workaround if exif_imagetype does not exist
1425
-	 *
1426
-	 * @link https://www.php.net/manual/en/function.exif-imagetype.php#80383
1427
-	 * @param string $fileName
1428
-	 * @return string|boolean
1429
-	 */
1430
-	function exif_imagetype($fileName) {
1431
-		if (($info = getimagesize($fileName)) !== false) {
1432
-			return $info[2];
1433
-		}
1434
-		return false;
1435
-	}
1423
+    /**
1424
+     * Workaround if exif_imagetype does not exist
1425
+     *
1426
+     * @link https://www.php.net/manual/en/function.exif-imagetype.php#80383
1427
+     * @param string $fileName
1428
+     * @return string|boolean
1429
+     */
1430
+    function exif_imagetype($fileName) {
1431
+        if (($info = getimagesize($fileName)) !== false) {
1432
+            return $info[2];
1433
+        }
1434
+        return false;
1435
+    }
1436 1436
 }
Please login to merge, or discard this patch.
Spacing   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
 	 */
160 160
 	public function widthTopLeft() {
161 161
 		$o = $this->getOrientation();
162
-		$this->logger->debug('OC_Image->widthTopLeft() Orientation: ' . $o, ['app' => 'core']);
162
+		$this->logger->debug('OC_Image->widthTopLeft() Orientation: '.$o, ['app' => 'core']);
163 163
 		switch ($o) {
164 164
 			case -1:
165 165
 			case 1:
@@ -183,7 +183,7 @@  discard block
 block discarded – undo
183 183
 	 */
184 184
 	public function heightTopLeft() {
185 185
 		$o = $this->getOrientation();
186
-		$this->logger->debug('OC_Image->heightTopLeft() Orientation: ' . $o, ['app' => 'core']);
186
+		$this->logger->debug('OC_Image->heightTopLeft() Orientation: '.$o, ['app' => 'core']);
187 187
 		switch ($o) {
188 188
 			case -1:
189 189
 			case 1:
@@ -210,7 +210,7 @@  discard block
 block discarded – undo
210 210
 		if ($mimeType === null) {
211 211
 			$mimeType = $this->mimeType();
212 212
 		}
213
-		header('Content-Type: ' . $mimeType);
213
+		header('Content-Type: '.$mimeType);
214 214
 		return $this->_output(null, $mimeType);
215 215
 	}
216 216
 
@@ -228,7 +228,7 @@  discard block
 block discarded – undo
228 228
 		}
229 229
 		if ($filePath === null) {
230 230
 			if ($this->filePath === null) {
231
-				$this->logger->error(__METHOD__ . '(): called with no path.', ['app' => 'core']);
231
+				$this->logger->error(__METHOD__.'(): called with no path.', ['app' => 'core']);
232 232
 				return false;
233 233
 			} else {
234 234
 				$filePath = $this->filePath;
@@ -252,10 +252,10 @@  discard block
 block discarded – undo
252 252
 			}
253 253
 			$isWritable = is_writable(dirname($filePath));
254 254
 			if (!$isWritable) {
255
-				$this->logger->error(__METHOD__ . '(): Directory \'' . dirname($filePath) . '\' is not writable.', ['app' => 'core']);
255
+				$this->logger->error(__METHOD__.'(): Directory \''.dirname($filePath).'\' is not writable.', ['app' => 'core']);
256 256
 				return false;
257 257
 			} elseif ($isWritable && file_exists($filePath) && !is_writable($filePath)) {
258
-				$this->logger->error(__METHOD__ . '(): File \'' . $filePath . '\' is not writable.', ['app' => 'core']);
258
+				$this->logger->error(__METHOD__.'(): File \''.$filePath.'\' is not writable.', ['app' => 'core']);
259 259
 				return false;
260 260
 			}
261 261
 		}
@@ -283,7 +283,7 @@  discard block
 block discarded – undo
283 283
 					$imageType = IMAGETYPE_BMP;
284 284
 					break;
285 285
 				default:
286
-					throw new Exception('\OC_Image::_output(): "' . $mimeType . '" is not supported when forcing a specific output format');
286
+					throw new Exception('\OC_Image::_output(): "'.$mimeType.'" is not supported when forcing a specific output format');
287 287
 			}
288 288
 		}
289 289
 
@@ -468,7 +468,7 @@  discard block
 block discarded – undo
468 468
 			return;
469 469
 		}
470 470
 
471
-		$exif = @exif_read_data('data://image/jpeg;base64,' . base64_encode($data));
471
+		$exif = @exif_read_data('data://image/jpeg;base64,'.base64_encode($data));
472 472
 		if (!$exif) {
473 473
 			return;
474 474
 		}
@@ -486,11 +486,11 @@  discard block
 block discarded – undo
486 486
 	 */
487 487
 	public function fixOrientation() {
488 488
 		if (!$this->valid()) {
489
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
489
+			$this->logger->error(__METHOD__.'(): No image loaded', ['app' => 'core']);
490 490
 			return false;
491 491
 		}
492 492
 		$o = $this->getOrientation();
493
-		$this->logger->debug('OC_Image->fixOrientation() Orientation: ' . $o, ['app' => 'core']);
493
+		$this->logger->debug('OC_Image->fixOrientation() Orientation: '.$o, ['app' => 'core']);
494 494
 		$rotate = 0;
495 495
 		$flip = false;
496 496
 		switch ($o) {
@@ -583,7 +583,7 @@  discard block
 block discarded – undo
583 583
 
584 584
 		// Assume 32 bits per pixel.
585 585
 		if ($width * $height * 4 > $memory_limit * 1024 * 1024) {
586
-			$this->logger->debug('Image size of ' . $width . 'x' . $height . ' would exceed allowed memory limit of ' . $memory_limit);
586
+			$this->logger->debug('Image size of '.$width.'x'.$height.' would exceed allowed memory limit of '.$memory_limit);
587 587
 			return false;
588 588
 		}
589 589
 
@@ -656,10 +656,10 @@  discard block
 block discarded – undo
656 656
 						imagealphablending($this->resource, true);
657 657
 						imagesavealpha($this->resource, true);
658 658
 					} else {
659
-						$this->logger->debug('OC_Image->loadFromFile, GIF image not valid: ' . $imagePath, ['app' => 'core']);
659
+						$this->logger->debug('OC_Image->loadFromFile, GIF image not valid: '.$imagePath, ['app' => 'core']);
660 660
 					}
661 661
 				} else {
662
-					$this->logger->debug('OC_Image->loadFromFile, GIF images not supported: ' . $imagePath, ['app' => 'core']);
662
+					$this->logger->debug('OC_Image->loadFromFile, GIF images not supported: '.$imagePath, ['app' => 'core']);
663 663
 				}
664 664
 				break;
665 665
 			case IMAGETYPE_JPEG:
@@ -670,10 +670,10 @@  discard block
 block discarded – undo
670 670
 					if (getimagesize($imagePath) !== false) {
671 671
 						$this->resource = @imagecreatefromjpeg($imagePath);
672 672
 					} else {
673
-						$this->logger->debug('OC_Image->loadFromFile, JPG image not valid: ' . $imagePath, ['app' => 'core']);
673
+						$this->logger->debug('OC_Image->loadFromFile, JPG image not valid: '.$imagePath, ['app' => 'core']);
674 674
 					}
675 675
 				} else {
676
-					$this->logger->debug('OC_Image->loadFromFile, JPG images not supported: ' . $imagePath, ['app' => 'core']);
676
+					$this->logger->debug('OC_Image->loadFromFile, JPG images not supported: '.$imagePath, ['app' => 'core']);
677 677
 				}
678 678
 				break;
679 679
 			case IMAGETYPE_PNG:
@@ -687,10 +687,10 @@  discard block
 block discarded – undo
687 687
 						imagealphablending($this->resource, true);
688 688
 						imagesavealpha($this->resource, true);
689 689
 					} else {
690
-						$this->logger->debug('OC_Image->loadFromFile, PNG image not valid: ' . $imagePath, ['app' => 'core']);
690
+						$this->logger->debug('OC_Image->loadFromFile, PNG image not valid: '.$imagePath, ['app' => 'core']);
691 691
 					}
692 692
 				} else {
693
-					$this->logger->debug('OC_Image->loadFromFile, PNG images not supported: ' . $imagePath, ['app' => 'core']);
693
+					$this->logger->debug('OC_Image->loadFromFile, PNG images not supported: '.$imagePath, ['app' => 'core']);
694 694
 				}
695 695
 				break;
696 696
 			case IMAGETYPE_XBM:
@@ -700,7 +700,7 @@  discard block
 block discarded – undo
700 700
 					}
701 701
 					$this->resource = @imagecreatefromxbm($imagePath);
702 702
 				} else {
703
-					$this->logger->debug('OC_Image->loadFromFile, XBM/XPM images not supported: ' . $imagePath, ['app' => 'core']);
703
+					$this->logger->debug('OC_Image->loadFromFile, XBM/XPM images not supported: '.$imagePath, ['app' => 'core']);
704 704
 				}
705 705
 				break;
706 706
 			case IMAGETYPE_WBMP:
@@ -710,7 +710,7 @@  discard block
 block discarded – undo
710 710
 					}
711 711
 					$this->resource = @imagecreatefromwbmp($imagePath);
712 712
 				} else {
713
-					$this->logger->debug('OC_Image->loadFromFile, WBMP images not supported: ' . $imagePath, ['app' => 'core']);
713
+					$this->logger->debug('OC_Image->loadFromFile, WBMP images not supported: '.$imagePath, ['app' => 'core']);
714 714
 				}
715 715
 				break;
716 716
 			case IMAGETYPE_BMP:
@@ -723,7 +723,7 @@  discard block
 block discarded – undo
723 723
 					}
724 724
 					$this->resource = @imagecreatefromwebp($imagePath);
725 725
 				} else {
726
-					$this->logger->debug('OC_Image->loadFromFile, webp images not supported: ' . $imagePath, ['app' => 'core']);
726
+					$this->logger->debug('OC_Image->loadFromFile, webp images not supported: '.$imagePath, ['app' => 'core']);
727 727
 				}
728 728
 				break;
729 729
 			/*
@@ -840,7 +840,7 @@  discard block
 block discarded – undo
840 840
 	 */
841 841
 	private function imagecreatefrombmp($fileName) {
842 842
 		if (!($fh = fopen($fileName, 'rb'))) {
843
-			$this->logger->warning('imagecreatefrombmp: Can not open ' . $fileName, ['app' => 'core']);
843
+			$this->logger->warning('imagecreatefrombmp: Can not open '.$fileName, ['app' => 'core']);
844 844
 			return false;
845 845
 		}
846 846
 		// read file header
@@ -848,7 +848,7 @@  discard block
 block discarded – undo
848 848
 		// check for bitmap
849 849
 		if ($meta['type'] != 19778) {
850 850
 			fclose($fh);
851
-			$this->logger->warning('imagecreatefrombmp: Can not open ' . $fileName . ' is not a bitmap!', ['app' => 'core']);
851
+			$this->logger->warning('imagecreatefrombmp: Can not open '.$fileName.' is not a bitmap!', ['app' => 'core']);
852 852
 			return false;
853 853
 		}
854 854
 		// read image header
@@ -872,7 +872,7 @@  discard block
 block discarded – undo
872 872
 				$meta['imagesize'] = @filesize($fileName) - $meta['offset'];
873 873
 				if ($meta['imagesize'] < 1) {
874 874
 					fclose($fh);
875
-					$this->logger->warning('imagecreatefrombmp: Can not obtain file size of ' . $fileName . ' is not a bitmap!', ['app' => 'core']);
875
+					$this->logger->warning('imagecreatefrombmp: Can not obtain file size of '.$fileName.' is not a bitmap!', ['app' => 'core']);
876 876
 					return false;
877 877
 				}
878 878
 			}
@@ -882,7 +882,7 @@  discard block
 block discarded – undo
882 882
 		// read color palette
883 883
 		$palette = [];
884 884
 		if ($meta['bits'] < 16) {
885
-			$palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4));
885
+			$palette = unpack('l'.$meta['colors'], fread($fh, $meta['colors'] * 4));
886 886
 			// in rare cases the color value is signed
887 887
 			if ($palette[1] < 0) {
888 888
 				foreach ($palette as $i => $color) {
@@ -899,7 +899,7 @@  discard block
 block discarded – undo
899 899
 		if ($im == false) {
900 900
 			fclose($fh);
901 901
 			$this->logger->warning(
902
-				'imagecreatefrombmp: imagecreatetruecolor failed for file "' . $fileName . '" with dimensions ' . $meta['width'] . 'x' . $meta['height'],
902
+				'imagecreatefrombmp: imagecreatetruecolor failed for file "'.$fileName.'" with dimensions '.$meta['width'].'x'.$meta['height'],
903 903
 				['app' => 'core']);
904 904
 			return false;
905 905
 		}
@@ -908,7 +908,7 @@  discard block
 block discarded – undo
908 908
 		$p = 0;
909 909
 		$vide = chr(0);
910 910
 		$y = $meta['height'] - 1;
911
-		$error = 'imagecreatefrombmp: ' . $fileName . ' has not enough data!';
911
+		$error = 'imagecreatefrombmp: '.$fileName.' has not enough data!';
912 912
 		// loop through the image data beginning with the lower left corner
913 913
 		while ($y >= 0) {
914 914
 			$x = 0;
@@ -920,7 +920,7 @@  discard block
 block discarded – undo
920 920
 							$this->logger->warning($error, ['app' => 'core']);
921 921
 							return $im;
922 922
 						}
923
-						$color = @unpack('V', $part . $vide);
923
+						$color = @unpack('V', $part.$vide);
924 924
 						break;
925 925
 					case 16:
926 926
 						if (!($part = substr($data, $p, 2))) {
@@ -932,16 +932,16 @@  discard block
 block discarded – undo
932 932
 						$color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3);
933 933
 						break;
934 934
 					case 8:
935
-						$color = @unpack('n', $vide . ($data[$p] ?? ''));
935
+						$color = @unpack('n', $vide.($data[$p] ?? ''));
936 936
 						$color[1] = isset($palette[$color[1] + 1]) ? $palette[$color[1] + 1] : $palette[1];
937 937
 						break;
938 938
 					case 4:
939
-						$color = @unpack('n', $vide . ($data[floor($p)] ?? ''));
939
+						$color = @unpack('n', $vide.($data[floor($p)] ?? ''));
940 940
 						$color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F;
941 941
 						$color[1] = isset($palette[$color[1] + 1]) ? $palette[$color[1] + 1] : $palette[1];
942 942
 						break;
943 943
 					case 1:
944
-						$color = @unpack('n', $vide . ($data[floor($p)] ?? ''));
944
+						$color = @unpack('n', $vide.($data[floor($p)] ?? ''));
945 945
 						switch (($p * 8) % 8) {
946 946
 							case 0:
947 947
 								$color[1] = $color[1] >> 7;
@@ -972,7 +972,7 @@  discard block
 block discarded – undo
972 972
 						break;
973 973
 					default:
974 974
 						fclose($fh);
975
-						$this->logger->warning('imagecreatefrombmp: ' . $fileName . ' has ' . $meta['bits'] . ' bits and this is not supported!', ['app' => 'core']);
975
+						$this->logger->warning('imagecreatefrombmp: '.$fileName.' has '.$meta['bits'].' bits and this is not supported!', ['app' => 'core']);
976 976
 						return false;
977 977
 				}
978 978
 				imagesetpixel($im, $x, $y, $color[1]);
@@ -994,7 +994,7 @@  discard block
 block discarded – undo
994 994
 	 */
995 995
 	public function resize($maxSize) {
996 996
 		if (!$this->valid()) {
997
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
997
+			$this->logger->error(__METHOD__.'(): No image loaded', ['app' => 'core']);
998 998
 			return false;
999 999
 		}
1000 1000
 		$result = $this->resizeNew($maxSize);
@@ -1009,7 +1009,7 @@  discard block
 block discarded – undo
1009 1009
 	 */
1010 1010
 	private function resizeNew($maxSize) {
1011 1011
 		if (!$this->valid()) {
1012
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1012
+			$this->logger->error(__METHOD__.'(): No image loaded', ['app' => 'core']);
1013 1013
 			return false;
1014 1014
 		}
1015 1015
 		$widthOrig = imagesx($this->resource);
@@ -1024,7 +1024,7 @@  discard block
 block discarded – undo
1024 1024
 			$newHeight = $maxSize;
1025 1025
 		}
1026 1026
 
1027
-		return $this->preciseResizeNew((int)round($newWidth), (int)round($newHeight));
1027
+		return $this->preciseResizeNew((int) round($newWidth), (int) round($newHeight));
1028 1028
 	}
1029 1029
 
1030 1030
 	/**
@@ -1034,7 +1034,7 @@  discard block
 block discarded – undo
1034 1034
 	 */
1035 1035
 	public function preciseResize(int $width, int $height): bool {
1036 1036
 		if (!$this->valid()) {
1037
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1037
+			$this->logger->error(__METHOD__.'(): No image loaded', ['app' => 'core']);
1038 1038
 			return false;
1039 1039
 		}
1040 1040
 		$result = $this->preciseResizeNew($width, $height);
@@ -1051,18 +1051,18 @@  discard block
 block discarded – undo
1051 1051
 	 */
1052 1052
 	public function preciseResizeNew(int $width, int $height) {
1053 1053
 		if (!($width > 0) || !($height > 0)) {
1054
-			$this->logger->info(__METHOD__ . '(): Requested image size not bigger than 0', ['app' => 'core']);
1054
+			$this->logger->info(__METHOD__.'(): Requested image size not bigger than 0', ['app' => 'core']);
1055 1055
 			return false;
1056 1056
 		}
1057 1057
 		if (!$this->valid()) {
1058
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1058
+			$this->logger->error(__METHOD__.'(): No image loaded', ['app' => 'core']);
1059 1059
 			return false;
1060 1060
 		}
1061 1061
 		$widthOrig = imagesx($this->resource);
1062 1062
 		$heightOrig = imagesy($this->resource);
1063 1063
 		$process = imagecreatetruecolor($width, $height);
1064 1064
 		if ($process === false) {
1065
-			$this->logger->error(__METHOD__ . '(): Error creating true color image', ['app' => 'core']);
1065
+			$this->logger->error(__METHOD__.'(): Error creating true color image', ['app' => 'core']);
1066 1066
 			return false;
1067 1067
 		}
1068 1068
 
@@ -1075,7 +1075,7 @@  discard block
 block discarded – undo
1075 1075
 
1076 1076
 		$res = imagecopyresampled($process, $this->resource, 0, 0, 0, 0, $width, $height, $widthOrig, $heightOrig);
1077 1077
 		if ($res === false) {
1078
-			$this->logger->error(__METHOD__ . '(): Error re-sampling process image', ['app' => 'core']);
1078
+			$this->logger->error(__METHOD__.'(): Error re-sampling process image', ['app' => 'core']);
1079 1079
 			imagedestroy($process);
1080 1080
 			return false;
1081 1081
 		}
@@ -1130,7 +1130,7 @@  discard block
 block discarded – undo
1130 1130
 
1131 1131
 		imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $targetWidth, $targetHeight, $width, $height);
1132 1132
 		if ($process === false) {
1133
-			$this->logger->error('OC_Image->centerCrop, Error re-sampling process image ' . $width . 'x' . $height, ['app' => 'core']);
1133
+			$this->logger->error('OC_Image->centerCrop, Error re-sampling process image '.$width.'x'.$height, ['app' => 'core']);
1134 1134
 			return false;
1135 1135
 		}
1136 1136
 		imagedestroy($this->resource);
@@ -1149,7 +1149,7 @@  discard block
 block discarded – undo
1149 1149
 	 */
1150 1150
 	public function crop(int $x, int $y, int $w, int $h): bool {
1151 1151
 		if (!$this->valid()) {
1152
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1152
+			$this->logger->error(__METHOD__.'(): No image loaded', ['app' => 'core']);
1153 1153
 			return false;
1154 1154
 		}
1155 1155
 		$result = $this->cropNew($x, $y, $w, $h);
@@ -1169,12 +1169,12 @@  discard block
 block discarded – undo
1169 1169
 	 */
1170 1170
 	public function cropNew(int $x, int $y, int $w, int $h) {
1171 1171
 		if (!$this->valid()) {
1172
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1172
+			$this->logger->error(__METHOD__.'(): No image loaded', ['app' => 'core']);
1173 1173
 			return false;
1174 1174
 		}
1175 1175
 		$process = imagecreatetruecolor($w, $h);
1176 1176
 		if ($process === false) {
1177
-			$this->logger->error(__METHOD__ . '(): Error creating true color image', ['app' => 'core']);
1177
+			$this->logger->error(__METHOD__.'(): Error creating true color image', ['app' => 'core']);
1178 1178
 			return false;
1179 1179
 		}
1180 1180
 
@@ -1187,7 +1187,7 @@  discard block
 block discarded – undo
1187 1187
 
1188 1188
 		imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $w, $h, $w, $h);
1189 1189
 		if ($process === false) {
1190
-			$this->logger->error(__METHOD__ . '(): Error re-sampling process image ' . $w . 'x' . $h, ['app' => 'core']);
1190
+			$this->logger->error(__METHOD__.'(): Error re-sampling process image '.$w.'x'.$h, ['app' => 'core']);
1191 1191
 			return false;
1192 1192
 		}
1193 1193
 		return $process;
@@ -1204,7 +1204,7 @@  discard block
 block discarded – undo
1204 1204
 	 */
1205 1205
 	public function fitIn($maxWidth, $maxHeight) {
1206 1206
 		if (!$this->valid()) {
1207
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1207
+			$this->logger->error(__METHOD__.'(): No image loaded', ['app' => 'core']);
1208 1208
 			return false;
1209 1209
 		}
1210 1210
 		$widthOrig = imagesx($this->resource);
@@ -1214,7 +1214,7 @@  discard block
 block discarded – undo
1214 1214
 		$newWidth = min($maxWidth, $ratio * $maxHeight);
1215 1215
 		$newHeight = min($maxHeight, $maxWidth / $ratio);
1216 1216
 
1217
-		$this->preciseResize((int)round($newWidth), (int)round($newHeight));
1217
+		$this->preciseResize((int) round($newWidth), (int) round($newHeight));
1218 1218
 		return true;
1219 1219
 	}
1220 1220
 
@@ -1227,7 +1227,7 @@  discard block
 block discarded – undo
1227 1227
 	 */
1228 1228
 	public function scaleDownToFit($maxWidth, $maxHeight) {
1229 1229
 		if (!$this->valid()) {
1230
-			$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
1230
+			$this->logger->error(__METHOD__.'(): No image loaded', ['app' => 'core']);
1231 1231
 			return false;
1232 1232
 		}
1233 1233
 		$widthOrig = imagesx($this->resource);
@@ -1323,7 +1323,7 @@  discard block
 block discarded – undo
1323 1323
 		} elseif ($bit == 32) {
1324 1324
 			$bit = 24;
1325 1325
 		}
1326
-		$bits = (int)pow(2, $bit);
1326
+		$bits = (int) pow(2, $bit);
1327 1327
 		imagetruecolortopalette($im, true, $bits);
1328 1328
 		$width = imagesx($im);
1329 1329
 		$height = imagesy($im);
@@ -1332,7 +1332,7 @@  discard block
 block discarded – undo
1332 1332
 		if ($bit <= 8) {
1333 1333
 			for ($i = 0; $i < $colorsNum; $i++) {
1334 1334
 				$colors = imagecolorsforindex($im, $i);
1335
-				$rgbQuad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0";
1335
+				$rgbQuad .= chr($colors['blue']).chr($colors['green']).chr($colors['red'])."\0";
1336 1336
 			}
1337 1337
 			$bmpData = '';
1338 1338
 			if ($compression == 0 || $bit < 8) {
@@ -1365,7 +1365,7 @@  discard block
 block discarded – undo
1365 1365
 						$index = imagecolorat($im, $i, $j);
1366 1366
 						if ($index !== $lastIndex || $sameNum > 255) {
1367 1367
 							if ($sameNum != 0) {
1368
-								$bmpData .= chr($sameNum) . chr($lastIndex);
1368
+								$bmpData .= chr($sameNum).chr($lastIndex);
1369 1369
 							}
1370 1370
 							$lastIndex = $index;
1371 1371
 							$sameNum = 1;
@@ -1406,15 +1406,15 @@  discard block
 block discarded – undo
1406 1406
 			$sizeData = strlen($bmpData);
1407 1407
 			$colorsNum = 0;
1408 1408
 		}
1409
-		$fileHeader = 'BM' . pack('V3', 54 + $sizeQuad + $sizeData, 0, 54 + $sizeQuad);
1409
+		$fileHeader = 'BM'.pack('V3', 54 + $sizeQuad + $sizeData, 0, 54 + $sizeQuad);
1410 1410
 		$infoHeader = pack('V3v2V*', 0x28, $width, $height, 1, $bit, $compression, $sizeData, 0, 0, $colorsNum, 0);
1411 1411
 		if ($fileName != '') {
1412 1412
 			$fp = fopen($fileName, 'wb');
1413
-			fwrite($fp, $fileHeader . $infoHeader . $rgbQuad . $bmpData);
1413
+			fwrite($fp, $fileHeader.$infoHeader.$rgbQuad.$bmpData);
1414 1414
 			fclose($fp);
1415 1415
 			return true;
1416 1416
 		}
1417
-		echo $fileHeader . $infoHeader . $rgbQuad . $bmpData;
1417
+		echo $fileHeader.$infoHeader.$rgbQuad.$bmpData;
1418 1418
 		return true;
1419 1419
 	}
1420 1420
 }
Please login to merge, or discard this patch.