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