]> git.mxchange.org Git - friendica.git/blob - src/Util/Images.php
Catch exceptions for Worker::AddContact()
[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
38          */
39         public static function getFormatsMap()
40         {
41                 $m = [
42                         'image/jpeg' => 'JPG',
43                         'image/png' => 'PNG',
44                         'image/gif' => 'GIF'
45                 ];
46
47                 return $m;
48         }
49
50         /**
51          * Return file extension for mime type
52          * @param string $mimetype
53          * @return string
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                         default:
67                                 $imagetype = IMAGETYPE_JPEG;
68                                 break;
69                 }
70
71                 return image_type_to_extension($imagetype);
72         }
73
74         /**
75          * Returns supported image mimetypes and corresponding file extensions
76          *
77          * @return array
78          */
79         public static function supportedTypes()
80         {
81                 $types = [
82                         'image/jpeg' => 'jpg'
83                 ];
84                 if (class_exists('Imagick')) {
85                         // Imagick::queryFormats won't help us a lot there...
86                         // At least, not yet, other parts of friendica uses this array
87                         $types += [
88                                 'image/png' => 'png',
89                                 'image/gif' => 'gif'
90                         ];
91                 } elseif (imagetypes() & IMG_PNG) {
92                         $types += [
93                                 'image/png' => 'png'
94                         ];
95                 }
96
97                 return $types;
98         }
99
100         /**
101          * Fetch image mimetype from the image data or guessing from the file name
102          *
103          * @param string $image_data Image data
104          * @param string $filename   File name (for guessing the type via the extension)
105          * @param string $mime       default mime type
106          *
107          * @return string
108          * @throws \Exception
109          */
110         public static function getMimeTypeByData(string $image_data, string $filename = '', string $mime = '')
111         {
112                 if (substr($mime, 0, 6) == 'image/') {
113                         Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $mime]);
114                         return $mime;
115                 }
116
117                 $image = @getimagesizefromstring($image_data);
118                 if (!empty($image['mime'])) {
119                         Logger::info('Mime type detected via data', ['filename' => $filename, 'default' => $mime, 'mime' => $image['mime']]);
120                         return $image['mime'];
121                 }
122
123                 return self::guessTypeByExtension($filename);
124         }
125
126         /**
127          * Fetch image mimetype from the image data or guessing from the file name
128          *
129          * @param string $sourcefile Source file of the image
130          * @param string $filename   File name (for guessing the type via the extension)
131          * @param string $mime       default mime type
132          *
133          * @return string
134          * @throws \Exception
135          */
136         public static function getMimeTypeBySource(string $sourcefile, string $filename = '', string $mime = '')
137         {
138                 if (substr($mime, 0, 6) == 'image/') {
139                         Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $mime]);
140                         return $mime;
141                 }
142
143                 $image = @getimagesize($sourcefile);
144                 if (!empty($image['mime'])) {
145                         Logger::info('Mime type detected via file', ['filename' => $filename, 'default' => $mime, 'image' => $image]);
146                         return $image['mime'];
147                 }
148
149                 return self::guessTypeByExtension($filename);
150         }
151
152         /**
153          * Guess image mimetype from the filename
154          *
155          * @param string $filename   Image filename
156          *
157          * @return string
158          * @throws \Exception
159          */
160         public static function guessTypeByExtension(string $filename)
161         {
162                 $ext = pathinfo(parse_url($filename, PHP_URL_PATH), PATHINFO_EXTENSION);
163                 $types = self::supportedTypes();
164                 $type = 'image/jpeg';
165                 foreach ($types as $m => $e) {
166                         if ($ext == $e) {
167                                 $type = $m;
168                         }
169                 }
170
171                 Logger::info('Mime type guessed via extension', ['filename' => $filename, 'type' => $type]);
172                 return $type;
173         }
174
175         /**
176          * @param string $url
177          * @return array
178          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
179          */
180         public static function getInfoFromURLCached($url)
181         {
182                 $data = [];
183
184                 if (empty($url)) {
185                         return $data;
186                 }
187
188                 $cacheKey = 'getInfoFromURL:' . sha1($url);
189
190                 $data = DI::cache()->get($cacheKey);
191
192                 if (empty($data) || !is_array($data)) {
193                         $data = self::getInfoFromURL($url);
194
195                         DI::cache()->set($cacheKey, $data);
196                 }
197
198                 return $data;
199         }
200
201         /**
202          * @param string $url
203          * @return array
204          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
205          */
206         public static function getInfoFromURL($url)
207         {
208                 $data = [];
209
210                 if (empty($url)) {
211                         return $data;
212                 }
213
214                 if (Network::isLocalLink($url) && ($data = Photo::getResourceData($url))) {
215                         $photo = Photo::selectFirst([], ['resource-id' => $data['guid'], 'scale' => $data['scale']]);
216                         if (!empty($photo)) {
217                                 $img_str = Photo::getImageDataForPhoto($photo);
218                         }
219                         // @todo Possibly add a check for locally stored files
220                 }
221
222                 if (empty($img_str)) {
223                         $img_str = DI::httpClient()->fetch($url, HttpClientAccept::IMAGE, 4);
224                 }
225
226                 if (!$img_str) {
227                         return [];
228                 }
229
230                 $filesize = strlen($img_str);
231
232                 try {
233                         $data = @getimagesizefromstring($img_str);
234                 } catch (\Exception $e) {
235                         return [];
236                 }
237
238                 if ($data) {
239                         $data['size'] = $filesize;
240                 }
241
242                 return $data;
243         }
244
245         /**
246          * @param integer $width
247          * @param integer $height
248          * @param integer $max
249          * @return array
250          */
251         public static function getScalingDimensions($width, $height, $max)
252         {
253                 if ((!$width) || (!$height)) {
254                         return ['width' => 0, 'height' => 0];
255                 }
256
257                 if ($width > $max && $height > $max) {
258                         // very tall image (greater than 16:9)
259                         // constrain the width - let the height float.
260
261                         if ((($height * 9) / 16) > $width) {
262                                 $dest_width = $max;
263                                 $dest_height = intval(($height * $max) / $width);
264                         } elseif ($width > $height) {
265                                 // else constrain both dimensions
266                                 $dest_width = $max;
267                                 $dest_height = intval(($height * $max) / $width);
268                         } else {
269                                 $dest_width = intval(($width * $max) / $height);
270                                 $dest_height = $max;
271                         }
272                 } else {
273                         if ($width > $max) {
274                                 $dest_width = $max;
275                                 $dest_height = intval(($height * $max) / $width);
276                         } else {
277                                 if ($height > $max) {
278                                         // very tall image (greater than 16:9)
279                                         // but width is OK - don't do anything
280
281                                         if ((($height * 9) / 16) > $width) {
282                                                 $dest_width = $width;
283                                                 $dest_height = $height;
284                                         } else {
285                                                 $dest_width = intval(($width * $max) / $height);
286                                                 $dest_height = $max;
287                                         }
288                                 } else {
289                                         $dest_width = $width;
290                                         $dest_height = $height;
291                                 }
292                         }
293                 }
294
295                 return ['width' => $dest_width, 'height' => $dest_height];
296         }
297 }