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