]> git.mxchange.org Git - friendica.git/blob - src/Util/Images.php
f0aefb9f2c298822a315555e2d4b76a6d8fddbba
[friendica.git] / src / Util / Images.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2020, Friendica
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\Core\System;
26 use Friendica\DI;
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          * Returns supported image mimetypes and corresponding file extensions
51          *
52          * @return array
53          */
54         public static function supportedTypes()
55         {
56                 $types = [
57                         'image/jpeg' => 'jpg'
58                 ];
59                 if (class_exists('Imagick')) {
60                         // Imagick::queryFormats won't help us a lot there...
61                         // At least, not yet, other parts of friendica uses this array
62                         $types += [
63                                 'image/png' => 'png',
64                                 'image/gif' => 'gif'
65                         ];
66                 } elseif (imagetypes() & IMG_PNG) {
67                         $types += [
68                                 'image/png' => 'png'
69                         ];
70                 }
71
72                 return $types;
73         }
74
75         /**
76          * Fetch image mimetype from the image data or guessing from the file name
77          *
78          * @param string   $image_data Image data
79          * @param string   $filename   File name (for guessing the type via the extension)
80          * @param string[] $mimeTypes  possible mime types
81          *
82          * @return string
83          * @throws \Exception
84          */
85         public static function getMimeTypeByData(string $image_data, string $filename = '', array $mimeTypes = [])
86         {
87                 foreach ($mimeTypes as $mimeType) {
88                         if (substr($mimeType, 0, 6) == 'image/') {
89                                 Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $mimeTypes]);
90                                 return $mimeType;
91                         }
92                 }
93
94                 $image = @getimagesizefromstring($image_data);
95                 if (!empty($image['mime'])) {
96                         Logger::info('Mime type detected via data', ['filename' => $filename, 'default' => $mimeTypes, 'mime' => $image['mime']]);
97                         return $image['mime'];
98                 }
99
100                 return self::guessTypeByExtension($filename);
101         }
102
103         /**
104          * Fetch image mimetype from the image data or guessing from the file name
105          *
106          * @param string $sourcefile Source file of the image
107          * @param string $filename   File name (for guessing the type via the extension)
108          * @param string $mime       default mime type
109          *
110          * @return string
111          * @throws \Exception
112          */
113         public static function getMimeTypeBySource(string $sourcefile, string $filename = '', string $mime = '')
114         {
115                 if (substr($mime, 0, 6) == 'image/') {
116                         Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $mime]);
117                         return $mime;
118                 }
119
120                 $image = @getimagesize($sourcefile);
121                 if (!empty($image['mime'])) {
122                         Logger::info('Mime type detected via file', ['filename' => $filename, 'default' => $mime, 'image' => $image]);
123                         return $image['mime'];
124                 }
125
126                 return self::guessTypeByExtension($filename);
127         }
128
129         /**
130          * Guess image mimetype from the filename
131          *
132          * @param string $filename   Image filename
133          *
134          * @return string
135          * @throws \Exception
136          */
137         public static function guessTypeByExtension(string $filename)
138         {
139                 $ext = pathinfo(parse_url($filename, PHP_URL_PATH), PATHINFO_EXTENSION);
140                 $types = self::supportedTypes();
141                 $type = 'image/jpeg';
142                 foreach ($types as $m => $e) {
143                         if ($ext == $e) {
144                                 $type = $m;
145                         }
146                 }
147
148                 Logger::info('Mime type guessed via extension', ['filename' => $filename, 'type' => $type]);
149                 return $type;
150         }
151
152         /**
153          * @param string $url
154          * @return array
155          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
156          */
157         public static function getInfoFromURLCached($url)
158         {
159                 $data = [];
160
161                 if (empty($url)) {
162                         return $data;
163                 }
164
165                 $data = DI::cache()->get($url);
166
167                 if (empty($data) || !is_array($data)) {
168                         $data = self::getInfoFromURL($url);
169
170                         DI::cache()->set($url, $data);
171                 }
172
173                 return $data;
174         }
175
176         /**
177          * @param string $url
178          * @return array
179          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
180          */
181         public static function getInfoFromURL($url)
182         {
183                 $data = [];
184
185                 if (empty($url)) {
186                         return $data;
187                 }
188
189                 $img_str = DI::httpRequest()->fetch($url, true, 4);
190
191                 if (!$img_str) {
192                         return [];
193                 }
194
195                 $filesize = strlen($img_str);
196
197                 try {
198                         if (function_exists("getimagesizefromstring")) {
199                                 $data = @getimagesizefromstring($img_str);
200                         } else {
201                                 $tempfile = tempnam(get_temppath(), "cache");
202
203                                 $stamp1 = microtime(true);
204                                 file_put_contents($tempfile, $img_str);
205                                 DI::profiler()->saveTimestamp($stamp1, "file");
206
207                                 $data = getimagesize($tempfile);
208                                 unlink($tempfile);
209                         }
210                 } catch (\Exception $e) {
211                         return [];
212                 }
213
214                 if ($data) {
215                         $data['size'] = $filesize;
216                 }
217
218                 return $data;
219         }
220
221         /**
222          * @param integer $width
223          * @param integer $height
224          * @param integer $max
225          * @return array
226          */
227         public static function getScalingDimensions($width, $height, $max)
228         {
229                 if ((!$width) || (!$height)) {
230                         return ['width' => 0, 'height' => 0];
231                 }
232
233                 if ($width > $max && $height > $max) {
234                         // very tall image (greater than 16:9)
235                         // constrain the width - let the height float.
236
237                         if ((($height * 9) / 16) > $width) {
238                                 $dest_width = $max;
239                                 $dest_height = intval(($height * $max) / $width);
240                         } elseif ($width > $height) {
241                                 // else constrain both dimensions
242                                 $dest_width = $max;
243                                 $dest_height = intval(($height * $max) / $width);
244                         } else {
245                                 $dest_width = intval(($width * $max) / $height);
246                                 $dest_height = $max;
247                         }
248                 } else {
249                         if ($width > $max) {
250                                 $dest_width = $max;
251                                 $dest_height = intval(($height * $max) / $width);
252                         } else {
253                                 if ($height > $max) {
254                                         // very tall image (greater than 16:9)
255                                         // but width is OK - don't do anything
256
257                                         if ((($height * 9) / 16) > $width) {
258                                                 $dest_width = $width;
259                                                 $dest_height = $height;
260                                         } else {
261                                                 $dest_width = intval(($width * $max) / $height);
262                                                 $dest_height = $max;
263                                         }
264                                 } else {
265                                         $dest_width = $width;
266                                         $dest_height = $height;
267                                 }
268                         }
269                 }
270
271                 return ['width' => $dest_width, 'height' => $dest_height];
272         }
273 }