]> git.mxchange.org Git - friendica.git/blob - src/Util/Images.php
Reformatted code
[friendica.git] / src / Util / Images.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Util;
23
24 use Friendica\Core\Logger;
25 use Friendica\DI;
26 use Friendica\Model\Photo;
27 use Friendica\Network\HTTPClient\Client\HttpClientAccept;
28
29 /**
30  * Image utilities
31  */
32 class Images
33 {
34         /**
35          * Maps Mime types to Imagick formats
36          *
37          * @return array Format map
38          */
39         public static function getFormatsMap()
40         {
41                 return [
42                         'image/jpeg' => 'JPG',
43                         'image/jpg' => 'JPG',
44                         'image/png' => 'PNG',
45                         'image/gif' => 'GIF',
46                 ];
47         }
48
49         /**
50          * Return file extension for MIME type
51          *
52          * @param string $mimetype MIME type
53          * @return string File extension for MIME type
54          */
55         public static function getExtensionByMimeType(string $mimetype): string
56         {
57                 switch ($mimetype) {
58                         case 'image/png':
59                                 $imagetype = IMAGETYPE_PNG;
60                                 break;
61
62                         case 'image/gif':
63                                 $imagetype = IMAGETYPE_GIF;
64                                 break;
65
66                         case 'image/jpeg':
67                         case 'image/jpg':
68                                 $imagetype = IMAGETYPE_JPEG;
69                                 break;
70
71                         default: // Unknown type must be a blob then
72                                 return 'blob';
73                                 break;
74                 }
75
76                 return image_type_to_extension($imagetype);
77         }
78
79         /**
80          * Returns supported image mimetypes and corresponding file extensions
81          *
82          * @return array
83          */
84         public static function supportedTypes(): array
85         {
86                 $types = [
87                         'image/jpeg' => 'jpg',
88                         'image/jpg' => 'jpg',
89                 ];
90
91                 if (class_exists('Imagick')) {
92                         // Imagick::queryFormats won't help us a lot there...
93                         // At least, not yet, other parts of friendica uses this array
94                         $types += [
95                                 'image/png' => 'png',
96                                 'image/gif' => 'gif'
97                         ];
98                 } elseif (imagetypes() & IMG_PNG) {
99                         $types += [
100                                 'image/png' => 'png'
101                         ];
102                 }
103
104                 return $types;
105         }
106
107         /**
108          * Fetch image mimetype from the image data or guessing from the file name
109          *
110          * @param string $image_data Image data
111          * @param string $filename   File name (for guessing the type via the extension)
112          * @param string $default    Default MIME type
113          * @return string MIME type
114          * @throws \Exception
115          */
116         public static function getMimeTypeByData(string $image_data, string $filename = '', string $default = ''): string
117         {
118                 if (substr($default, 0, 6) == 'image/') {
119                         Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $default]);
120                         return $default;
121                 }
122
123                 $image = @getimagesizefromstring($image_data);
124                 if (!empty($image['mime'])) {
125                         Logger::info('Mime type detected via data', ['filename' => $filename, 'default' => $default, 'mime' => $image['mime']]);
126                         return $image['mime'];
127                 }
128
129                 return self::guessTypeByExtension($filename);
130         }
131
132         /**
133          * Fetch image mimetype from the image data or guessing from the file name
134          *
135          * @param string $sourcefile Source file of the image
136          * @param string $filename   File name (for guessing the type via the extension)
137          * @param string $default    default MIME type
138          * @return string MIME type
139          * @throws \Exception
140          */
141         public static function getMimeTypeBySource(string $sourcefile, string $filename = '', string $default = ''): string
142         {
143                 if (substr($default, 0, 6) == 'image/') {
144                         Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $default]);
145                         return $default;
146                 }
147
148                 $image = @getimagesize($sourcefile);
149                 if (!empty($image['mime'])) {
150                         Logger::info('Mime type detected via file', ['filename' => $filename, 'default' => $default, 'image' => $image]);
151                         return $image['mime'];
152                 }
153
154                 return self::guessTypeByExtension($filename);
155         }
156
157         /**
158          * Guess image MIME type from the filename's extension
159          *
160          * @param string $filename Image filename
161          * @return string Guessed MIME type by extension
162          * @throws \Exception
163          */
164         public static function guessTypeByExtension(string $filename): string
165         {
166                 $ext = pathinfo(parse_url($filename, PHP_URL_PATH), PATHINFO_EXTENSION);
167                 $types = self::supportedTypes();
168                 $type = 'image/jpeg';
169                 foreach ($types as $m => $e) {
170                         if ($ext == $e) {
171                                 $type = $m;
172                         }
173                 }
174
175                 Logger::info('Mime type guessed via extension', ['filename' => $filename, 'type' => $type]);
176                 return $type;
177         }
178
179         /**
180          * Gets info array from given URL, cached data has priority
181          *
182          * @param string $url
183          * @return array Info
184          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
185          */
186         public static function getInfoFromURLCached(string $url): array
187         {
188                 $data = [];
189
190                 if (empty($url)) {
191                         return $data;
192                 }
193
194                 $cacheKey = 'getInfoFromURL:' . sha1($url);
195
196                 $data = DI::cache()->get($cacheKey);
197
198                 if (empty($data) || !is_array($data)) {
199                         $data = self::getInfoFromURL($url);
200
201                         DI::cache()->set($cacheKey, $data);
202                 }
203
204                 return $data ?? [];
205         }
206
207         /**
208          * Gets info from URL uncached
209          *
210          * @param string $url
211          * @return array Info array
212          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
213          */
214         public static function getInfoFromURL(string $url): array
215         {
216                 $data = [];
217
218                 if (empty($url)) {
219                         return $data;
220                 }
221
222                 if (Network::isLocalLink($url) && ($data = Photo::getResourceData($url))) {
223                         $photo = Photo::selectFirst([], ['resource-id' => $data['guid'], 'scale' => $data['scale']]);
224                         if (!empty($photo)) {
225                                 $img_str = Photo::getImageDataForPhoto($photo);
226                         }
227                         // @todo Possibly add a check for locally stored files
228                 }
229
230                 if (empty($img_str)) {
231                         $img_str = DI::httpClient()->fetch($url, HttpClientAccept::IMAGE, 4);
232                 }
233
234                 if (!$img_str) {
235                         return [];
236                 }
237
238                 $filesize = strlen($img_str);
239
240                 try {
241                         $data = @getimagesizefromstring($img_str);
242                 } catch (\Exception $e) {
243                         return [];
244                 }
245
246                 if ($data) {
247                         $data['size'] = $filesize;
248                 }
249
250                 return is_array($data) ? $data : [];
251         }
252
253         /**
254          * Returns scaling information
255          *
256          * @param integer $width Width
257          * @param integer $height Height
258          * @param integer $max Max width/height
259          * @return array Scaling dimensions
260          */
261         public static function getScalingDimensions(int $width, int $height, int $max): array
262         {
263                 if ((!$width) || (!$height)) {
264                         return ['width' => 0, 'height' => 0];
265                 }
266
267                 if ($width > $max && $height > $max) {
268                         // very tall image (greater than 16:9)
269                         // constrain the width - let the height float.
270
271                         if ((($height * 9) / 16) > $width) {
272                                 $dest_width = $max;
273                                 $dest_height = intval(($height * $max) / $width);
274                         } elseif ($width > $height) {
275                                 // else constrain both dimensions
276                                 $dest_width = $max;
277                                 $dest_height = intval(($height * $max) / $width);
278                         } else {
279                                 $dest_width = intval(($width * $max) / $height);
280                                 $dest_height = $max;
281                         }
282                 } else {
283                         if ($width > $max) {
284                                 $dest_width = $max;
285                                 $dest_height = intval(($height * $max) / $width);
286                         } else {
287                                 if ($height > $max) {
288                                         // very tall image (greater than 16:9)
289                                         // but width is OK - don't do anything
290
291                                         if ((($height * 9) / 16) > $width) {
292                                                 $dest_width = $width;
293                                                 $dest_height = $height;
294                                         } else {
295                                                 $dest_width = intval(($width * $max) / $height);
296                                                 $dest_height = $max;
297                                         }
298                                 } else {
299                                         $dest_width = $width;
300                                         $dest_height = $height;
301                                 }
302                         }
303                 }
304
305                 return ['width' => $dest_width, 'height' => $dest_height];
306         }
307 }