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