]> git.mxchange.org Git - friendica.git/blob - src/Util/Images.php
e5a4da5b1953304cb75ffe1b296d4d87c580effd
[friendica.git] / src / Util / Images.php
1 <?php
2
3 namespace Friendica\Util;
4
5 use Friendica\Core\Logger;
6 use Friendica\Core\System;
7 use Friendica\DI;
8 use Imagick;
9
10 /**
11  * Image utilities
12  */
13 class Images
14 {
15         /**
16          * Maps Mime types to Imagick formats
17          *
18          * @return array
19          */
20         public static function getFormatsMap()
21         {
22                 $m = [
23                         'image/jpeg' => 'JPG',
24                         'image/png' => 'PNG',
25                         'image/gif' => 'GIF'
26                 ];
27
28                 return $m;
29         }
30
31         /**
32          * Returns supported image mimetypes and corresponding file extensions
33          *
34          * @return array
35          */
36         public static function supportedTypes()
37         {
38                 $types = [
39                         'image/jpeg' => 'jpg'
40                 ];
41                 if (class_exists('Imagick')) {
42                         // Imagick::queryFormats won't help us a lot there...
43                         // At least, not yet, other parts of friendica uses this array
44                         $types += [
45                                 'image/png' => 'png',
46                                 'image/gif' => 'gif'
47                         ];
48                 } elseif (imagetypes() & IMG_PNG) {
49                         $types += [
50                                 'image/png' => 'png'
51                         ];
52                 }
53
54                 return $types;
55         }
56
57         /**
58          * Guess image mimetype from filename or from Content-Type header
59          *
60          * @param string  $filename Image filename
61          * @param boolean $fromcurl Check Content-Type header from curl request
62          * @param string  $header   passed headers to take into account
63          *
64          * @return string|null
65          * @throws \Exception
66          */
67         public static function guessType($filename, $fromcurl = false, $header = '')
68         {
69                 Logger::info('Image: guessType: ' . $filename . ($fromcurl ? ' from curl headers' : ''));
70                 $type = null;
71                 if ($fromcurl) {
72                         $headers = [];
73                         $h = explode("\n", $header);
74                         foreach ($h as $l) {
75                                 $data = array_map("trim", explode(":", trim($l), 2));
76                                 if (count($data) > 1) {
77                                         list($k, $v) = $data;
78                                         $headers[$k] = $v;
79                                 }
80                         }
81
82                         if (array_key_exists('Content-Type', $headers)) {
83                                 $type = $headers['Content-Type'];
84                         }
85                 }
86
87                 if (is_null($type)) {
88                         // Guessing from extension? Isn't that... dangerous?
89                         if (class_exists('Imagick') && file_exists($filename) && is_readable($filename)) {
90                                 /**
91                                  * Well, this not much better,
92                                  * but at least it comes from the data inside the image,
93                                  * we won't be tricked by a manipulated extension
94                                  */
95                                 $image = new Imagick($filename);
96                                 $type = $image->getImageMimeType();
97                         } else {
98                                 $ext = pathinfo($filename, PATHINFO_EXTENSION);
99                                 $types = self::supportedTypes();
100                                 $type = 'image/jpeg';
101                                 foreach ($types as $m => $e) {
102                                         if ($ext == $e) {
103                                                 $type = $m;
104                                         }
105                                 }
106                         }
107                 }
108
109                 Logger::info('Image: guessType: type=' . $type);
110                 return $type;
111         }
112
113
114         /**
115          * @param string $url
116          * @return array
117          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
118          */
119         public static function getInfoFromURLCached($url)
120         {
121                 $data = [];
122
123                 if (empty($url)) {
124                         return $data;
125                 }
126
127                 $data = DI::cache()->get($url);
128
129                 if (empty($data) || !is_array($data)) {
130                         $data = self::getInfoFromURL($url);
131
132                         DI::cache()->set($url, $data);
133                 }
134
135                 return $data;
136         }
137
138         /**
139          * @param string $url
140          * @return array
141          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
142          */
143         public static function getInfoFromURL($url)
144         {
145                 $data = [];
146
147                 if (empty($url)) {
148                         return $data;
149                 }
150
151                 $img_str = Network::fetchUrl($url, true, 4);
152
153                 if (!$img_str) {
154                         return [];
155                 }
156
157                 $filesize = strlen($img_str);
158
159                 try {
160                         if (function_exists("getimagesizefromstring")) {
161                                 $data = @getimagesizefromstring($img_str);
162                         } else {
163                                 $tempfile = tempnam(get_temppath(), "cache");
164
165                                 $stamp1 = microtime(true);
166                                 file_put_contents($tempfile, $img_str);
167                                 DI::profiler()->saveTimestamp($stamp1, "file", System::callstack());
168
169                                 $data = getimagesize($tempfile);
170                                 unlink($tempfile);
171                         }
172                 } catch (\Exception $e) {
173                         return [];
174                 }
175
176                 if ($data) {
177                         $data['size'] = $filesize;
178                 }
179
180                 return $data;
181         }
182
183         /**
184          * @param integer $width
185          * @param integer $height
186          * @param integer $max
187          * @return array
188          */
189         public static function getScalingDimensions($width, $height, $max)
190         {
191                 if ((!$width) || (!$height)) {
192                         return ['width' => 0, 'height' => 0];
193                 }
194
195                 if ($width > $max && $height > $max) {
196                         // very tall image (greater than 16:9)
197                         // constrain the width - let the height float.
198
199                         if ((($height * 9) / 16) > $width) {
200                                 $dest_width = $max;
201                                 $dest_height = intval(($height * $max) / $width);
202                         } elseif ($width > $height) {
203                                 // else constrain both dimensions
204                                 $dest_width = $max;
205                                 $dest_height = intval(($height * $max) / $width);
206                         } else {
207                                 $dest_width = intval(($width * $max) / $height);
208                                 $dest_height = $max;
209                         }
210                 } else {
211                         if ($width > $max) {
212                                 $dest_width = $max;
213                                 $dest_height = intval(($height * $max) / $width);
214                         } else {
215                                 if ($height > $max) {
216                                         // very tall image (greater than 16:9)
217                                         // but width is OK - don't do anything
218
219                                         if ((($height * 9) / 16) > $width) {
220                                                 $dest_width = $width;
221                                                 $dest_height = $height;
222                                         } else {
223                                                 $dest_width = intval(($width * $max) / $height);
224                                                 $dest_height = $max;
225                                         }
226                                 } else {
227                                         $dest_width = $width;
228                                         $dest_height = $height;
229                                 }
230                         }
231                 }
232
233                 return ['width' => $dest_width, 'height' => $dest_height];
234         }
235 }