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