|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* *************************************************************************\ |
|
4
|
|
|
* SPIP, Système de publication pour l'internet * |
|
5
|
|
|
* * |
|
6
|
|
|
* Copyright © avec tendresse depuis 2001 * |
|
7
|
|
|
* Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James * |
|
8
|
|
|
* * |
|
9
|
|
|
* Ce programme est un logiciel libre distribué sous licence GNU/GPL. * |
|
10
|
|
|
* Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. * |
|
11
|
|
|
\***************************************************************************/ |
|
12
|
|
|
|
|
13
|
|
|
/** |
|
14
|
|
|
* Ce fichier contient les fonctions utilisées |
|
15
|
|
|
* par les fonctions-filtres de traitement d'image. |
|
16
|
|
|
* |
|
17
|
|
|
* @package SPIP\Core\Filtres\Images |
|
18
|
|
|
*/ |
|
19
|
|
|
|
|
20
|
|
|
|
|
21
|
|
|
if (!defined('_ECRIRE_INC_VERSION')) { |
|
22
|
|
|
return; |
|
23
|
|
|
} |
|
24
|
|
|
include_spip('inc/filtres'); // par precaution |
|
25
|
|
|
include_spip('inc/filtres_images_mini'); // par precaution |
|
26
|
|
|
|
|
27
|
|
|
define('_SVG_SUPPORTED', true); // ne sert qu'a la lisibilite du code |
|
28
|
|
|
|
|
29
|
|
|
/** |
|
30
|
|
|
* Transforme une couleur vectorielle R,G,B en hexa (par exemple pour usage css) |
|
31
|
|
|
* |
|
32
|
|
|
* @param int $red |
|
33
|
|
|
* Valeur du rouge de 0 à 255. |
|
34
|
|
|
* @param int $green |
|
35
|
|
|
* Valeur du vert de 0 à 255. |
|
36
|
|
|
* @param int $blue |
|
37
|
|
|
* Valeur du bleu de 0 à 255. |
|
38
|
|
|
* @return string |
|
39
|
|
|
* Le code de la couleur en hexadécimal. |
|
40
|
|
|
*/ |
|
41
|
|
|
function _couleur_dec_to_hex($red, $green, $blue) { |
|
42
|
|
|
$red = dechex($red); |
|
43
|
|
|
$green = dechex($green); |
|
44
|
|
|
$blue = dechex($blue); |
|
45
|
|
|
|
|
46
|
|
|
if (strlen($red) == 1) { |
|
47
|
|
|
$red = "0" . $red; |
|
48
|
|
|
} |
|
49
|
|
|
if (strlen($green) == 1) { |
|
50
|
|
|
$green = "0" . $green; |
|
51
|
|
|
} |
|
52
|
|
|
if (strlen($blue) == 1) { |
|
53
|
|
|
$blue = "0" . $blue; |
|
54
|
|
|
} |
|
55
|
|
|
|
|
56
|
|
|
return "$red$green$blue"; |
|
57
|
|
|
} |
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* Transforme une couleur hexa en vectorielle R,G,B |
|
61
|
|
|
* |
|
62
|
|
|
* @param string $couleur |
|
63
|
|
|
* Code couleur en hexa (#000000 à #FFFFFF). |
|
64
|
|
|
* @return array |
|
|
|
|
|
|
65
|
|
|
* Un tableau des 3 éléments : rouge, vert, bleu. |
|
66
|
|
|
*/ |
|
67
|
|
|
function _couleur_hex_to_dec($couleur) { |
|
68
|
|
|
$couleur = couleur_html_to_hex($couleur); |
|
69
|
|
|
$couleur = ltrim($couleur, '#'); |
|
70
|
|
|
if (strlen($couleur) === 3) { |
|
71
|
|
|
$couleur = $couleur[0] . $couleur[0] . $couleur[1] . $couleur[1] . $couleur[2] . $couleur[2]; |
|
72
|
|
|
} |
|
73
|
|
|
$retour["red"] = hexdec(substr($couleur, 0, 2)); |
|
|
|
|
|
|
74
|
|
|
$retour["green"] = hexdec(substr($couleur, 2, 2)); |
|
75
|
|
|
$retour["blue"] = hexdec(substr($couleur, 4, 2)); |
|
76
|
|
|
|
|
77
|
|
|
return $retour; |
|
78
|
|
|
} |
|
79
|
|
|
|
|
80
|
|
|
/** |
|
81
|
|
|
* Donne un statut au fichier-image intermédiaire servant au traitement d'image |
|
82
|
|
|
* selon qu'il doit être gravé (fichier .src) ou pas. |
|
83
|
|
|
* |
|
84
|
|
|
* Un appel PHP direct aux fonctions de filtre d'image produira ainsi une image |
|
85
|
|
|
* permanente (gravée) ; un appel généré par le compilateur via |
|
86
|
|
|
* `filtrer('image_xx, ...)` effacera automatiquement le fichier-image temporaire. |
|
87
|
|
|
* |
|
88
|
|
|
* @param bool|string $stat |
|
89
|
|
|
* true, false ou le statut déjà défini si traitements enchaînés. |
|
90
|
|
|
* @return bool |
|
|
|
|
|
|
91
|
|
|
* true si il faut supprimer le fichier temporaire ; false sinon. |
|
92
|
|
|
*/ |
|
93
|
|
|
function statut_effacer_images_temporaires($stat) { |
|
94
|
|
|
static $statut = false; // par defaut on grave toute les images |
|
95
|
|
|
if ($stat === 'get') { |
|
96
|
|
|
return $statut; |
|
97
|
|
|
} |
|
98
|
|
|
$statut = $stat ? true : false; |
|
99
|
|
|
} |
|
100
|
|
|
|
|
101
|
|
|
|
|
102
|
|
|
/** |
|
103
|
|
|
* Fonctions de preparation aux filtres de traitement d'image |
|
104
|
|
|
* les fonctions de lecture et d'ecriture renseignees traitent uniquement le cas GD2 |
|
105
|
|
|
* qui est le cas general des filtres images |
|
106
|
|
|
* |
|
107
|
|
|
* mais image_reduire utilise aussi cette fonction en adaptant le traitement |
|
108
|
|
|
* en fonction de la librairie graphique choisie dans la configuration de SPIP |
|
109
|
|
|
* |
|
110
|
|
|
* @pipeline_appel image_preparer_filtre |
|
111
|
|
|
* @uses extraire_attribut() |
|
112
|
|
|
* @uses inserer_attribut() |
|
113
|
|
|
* @uses tester_url_absolue() |
|
114
|
|
|
* @uses copie_locale() Si l'image est distante |
|
115
|
|
|
* @uses taille_image() |
|
116
|
|
|
* @uses _image_ratio() |
|
117
|
|
|
* @uses reconstruire_image_intermediaire() |
|
118
|
|
|
* |
|
119
|
|
|
* @param string $img |
|
120
|
|
|
* Chemin de l'image ou balise html `<img src=... />`. |
|
121
|
|
|
* @param string $effet |
|
122
|
|
|
* Les nom et paramètres de l'effet à apporter sur l'image |
|
123
|
|
|
* (par exemple : reduire-300-200). |
|
124
|
|
|
* @param bool|string $forcer_format |
|
125
|
|
|
* Un nom d'extension spécifique demandé (par exemple : jpg, png, txt...). |
|
126
|
|
|
* Par défaut false : GD se débrouille seule). |
|
127
|
|
|
* @param array $fonction_creation |
|
|
|
|
|
|
128
|
|
|
* Un tableau à 2 éléments : |
|
129
|
|
|
* 1) string : indique le nom du filtre de traitement demandé (par exemple : `image_reduire`) ; |
|
130
|
|
|
* 2) array : tableau reprenant la valeur de `$img` et chacun des arguments passés au filtre utilisé. |
|
131
|
|
|
* @param bool $find_in_path |
|
132
|
|
|
* false (par défaut) indique que l'on travaille sur un fichier |
|
133
|
|
|
* temporaire (.src) ; true, sur un fichier définitif déjà existant. |
|
134
|
|
|
* @param bool $support_svg |
|
135
|
|
|
* false (par defaut) indique que le filtre ne sait pas traiter le cas particulier du SVG |
|
136
|
|
|
* on lui substitue un filtre generique qui ne fait rien pour ne pas briser la chaine des filtres images |
|
137
|
|
|
* true si le filtre appelant sait traiter les SVG |
|
138
|
|
|
* @return bool|string|array |
|
139
|
|
|
* |
|
140
|
|
|
* - false si pas de tag `<img`, |
|
141
|
|
|
* - si l'extension n'existe pas, |
|
142
|
|
|
* - si le fichier source n'existe pas, |
|
143
|
|
|
* - si les dimensions de la source ne sont pas accessibles, |
|
144
|
|
|
* - si le fichier temporaire n'existe pas, |
|
145
|
|
|
* - si la fonction `_imagecreatefrom{extension}` n'existe pas ; |
|
146
|
|
|
* - "" (chaîne vide) si le fichier source est distant et n'a pas |
|
147
|
|
|
* réussi à être copié sur le serveur ; |
|
148
|
|
|
* - array : tableau décrivant de l'image |
|
149
|
|
|
*/ |
|
150
|
|
|
function _image_valeurs_trans($img, $effet, $forcer_format = false, $fonction_creation = null, $find_in_path = false, $support_svg = false) { |
|
151
|
|
|
static $images_recalcul = array(); |
|
152
|
|
|
if (strlen($img) == 0) { |
|
153
|
|
|
return false; |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
$source = trim(extraire_attribut($img, 'src')); |
|
157
|
|
|
if (strlen($source) < 1) { |
|
158
|
|
|
$source = $img; |
|
159
|
|
|
$img = "<img src='$source' />"; |
|
160
|
|
|
} # gerer img src="data:....base64" |
|
161
|
|
|
elseif (preg_match('@^data:image/([^;]*);base64,(.*)$@isS', $source, $regs) |
|
162
|
|
|
and $extension = _image_trouver_extension_depuis_mime("image/".$regs[1]) |
|
163
|
|
|
and in_array($extension, _image_extensions_acceptees_en_entree()) |
|
164
|
|
|
) { |
|
165
|
|
|
$local = sous_repertoire(_DIR_VAR, 'image-data') . md5($regs[2]) . '.' . _image_extension_normalisee($extension); |
|
166
|
|
|
if (!file_exists($local)) { |
|
167
|
|
|
ecrire_fichier($local, base64_decode($regs[2])); |
|
168
|
|
|
} |
|
169
|
|
|
$source = $local; |
|
170
|
|
|
$img = inserer_attribut($img, 'src', $source); |
|
171
|
|
|
# eviter les mauvaises surprises lors de conversions de format |
|
172
|
|
|
$img = inserer_attribut($img, 'width', ''); |
|
173
|
|
|
$img = inserer_attribut($img, 'height', ''); |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
// les protocoles web prennent au moins 3 lettres |
|
177
|
|
|
if (tester_url_absolue($source)) { |
|
178
|
|
|
include_spip('inc/distant'); |
|
179
|
|
|
$fichier = _DIR_RACINE . copie_locale($source); |
|
180
|
|
|
if (!$fichier) { |
|
181
|
|
|
return ""; |
|
182
|
|
|
} |
|
183
|
|
|
} else { |
|
184
|
|
|
// enlever le timestamp eventuel |
|
185
|
|
|
if (strpos($source, "?") !== false) { |
|
186
|
|
|
$source = preg_replace(',[?][0-9]+$,', '', $source); |
|
187
|
|
|
} |
|
188
|
|
|
if (strpos($source, "?") !== false |
|
189
|
|
|
and strncmp($source, _DIR_IMG, strlen(_DIR_IMG)) == 0 |
|
190
|
|
|
and file_exists($f = preg_replace(',[?].*$,', '', $source)) |
|
191
|
|
|
) { |
|
192
|
|
|
$source = $f; |
|
193
|
|
|
} |
|
194
|
|
|
$fichier = $source; |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
$terminaison_dest = ""; |
|
198
|
|
|
if ($terminaison = _image_trouver_extension($fichier)) { |
|
199
|
|
|
$terminaison_dest = ($terminaison == 'gif') ? 'png' : $terminaison; |
|
200
|
|
|
} |
|
201
|
|
|
|
|
202
|
|
|
if ($forcer_format !== false |
|
203
|
|
|
// ignorer forcer_format si on a une image svg, que le filtre appelant ne supporte pas SVG, et que le forcage est un autre format image |
|
204
|
|
|
and ($terminaison_dest !== 'svg' or $support_svg or !in_array($forcer_format,_image_extensions_acceptees_en_sortie()))) { |
|
205
|
|
|
$terminaison_dest = $forcer_format; |
|
206
|
|
|
} |
|
207
|
|
|
|
|
208
|
|
|
if (!$terminaison_dest) { |
|
209
|
|
|
return false; |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
|
$nom_fichier = substr($fichier, 0, strlen($fichier) - (strlen($terminaison) + 1)); |
|
213
|
|
|
$fichier_dest = $nom_fichier; |
|
214
|
|
|
if (($find_in_path and $f = find_in_path($fichier) and $fichier = $f) |
|
|
|
|
|
|
215
|
|
|
or @file_exists($f = $fichier) |
|
216
|
|
|
) { |
|
217
|
|
|
// on passe la balise img a taille image qui exraira les attributs si possible |
|
218
|
|
|
// au lieu de faire un acces disque sur le fichier |
|
219
|
|
|
list($ret["hauteur"], $ret["largeur"]) = taille_image($find_in_path ? $f : $img); |
|
220
|
|
|
$date_src = @filemtime($f); |
|
221
|
|
|
} elseif (@file_exists($f = "$fichier.src") |
|
222
|
|
|
and lire_fichier($f, $valeurs) |
|
223
|
|
|
and $valeurs = unserialize($valeurs) |
|
224
|
|
|
and isset($valeurs["hauteur_dest"]) |
|
225
|
|
|
and isset($valeurs["largeur_dest"]) |
|
226
|
|
|
) { |
|
227
|
|
|
$ret["hauteur"] = $valeurs["hauteur_dest"]; |
|
|
|
|
|
|
228
|
|
|
$ret["largeur"] = $valeurs["largeur_dest"]; |
|
229
|
|
|
$date_src = $valeurs["date"]; |
|
230
|
|
|
} // pas de fichier source par la |
|
231
|
|
|
else { |
|
232
|
|
|
return false; |
|
233
|
|
|
} |
|
234
|
|
|
|
|
235
|
|
|
// pas de taille mesurable |
|
236
|
|
|
if (!($ret["hauteur"] or $ret["largeur"])) { |
|
|
|
|
|
|
237
|
|
|
return false; |
|
238
|
|
|
} |
|
239
|
|
|
|
|
240
|
|
|
// les images calculees dependent du chemin du fichier source |
|
241
|
|
|
// pour une meme image source et un meme filtre on aboutira a 2 fichiers selon si l'appel est dans le public ou dans le prive |
|
242
|
|
|
// ce n'est pas totalement optimal en terme de stockage, mais chaque image est associee a un fichier .src |
|
243
|
|
|
// qui contient la methode de reconstrucion (le filtre + les arguments d'appel) et les arguments different entre prive et public |
|
244
|
|
|
// la mise en commun du fichier image cree donc un bug et des problemes qui necessiteraient beaucoup de complexite de code |
|
245
|
|
|
// alors que ca concerne peu de site au final |
|
246
|
|
|
// la release de r23632+r23633+r23634 a provoque peu de remontee de bug attestant du peu de sites impactes |
|
247
|
|
|
$identifiant = $fichier; |
|
248
|
|
|
|
|
249
|
|
|
// cas general : |
|
250
|
|
|
// on a un dossier cache commun et un nom de fichier qui varie avec l'effet |
|
251
|
|
|
// cas particulier de reduire : |
|
252
|
|
|
// un cache par dimension, et le nom de fichier est conserve, suffixe par la dimension aussi |
|
253
|
|
|
$cache = "cache-gd2"; |
|
254
|
|
|
if (substr($effet, 0, 7) == 'reduire') { |
|
255
|
|
|
list(, $maxWidth, $maxHeight) = explode('-', $effet); |
|
256
|
|
|
list($destWidth, $destHeight) = _image_ratio($ret['largeur'], $ret['hauteur'], $maxWidth, $maxHeight); |
|
257
|
|
|
$ret['largeur_dest'] = $destWidth; |
|
258
|
|
|
$ret['hauteur_dest'] = $destHeight; |
|
259
|
|
|
$effet = "L{$destWidth}xH$destHeight"; |
|
260
|
|
|
$cache = "cache-vignettes"; |
|
261
|
|
|
$fichier_dest = basename($fichier_dest); |
|
262
|
|
|
if (($ret['largeur'] <= $maxWidth) && ($ret['hauteur'] <= $maxHeight)) { |
|
263
|
|
|
// on garde la terminaison initiale car image simplement copiee |
|
264
|
|
|
// et on postfixe son nom avec un md5 du path |
|
265
|
|
|
$terminaison_dest = $terminaison; |
|
266
|
|
|
$fichier_dest .= '-' . substr(md5("$identifiant"), 0, 5); |
|
267
|
|
|
} else { |
|
268
|
|
|
$fichier_dest .= '-' . substr(md5("$identifiant-$effet"), 0, 5); |
|
269
|
|
|
} |
|
270
|
|
|
$cache = sous_repertoire(_DIR_VAR, $cache); |
|
271
|
|
|
$cache = sous_repertoire($cache, $effet); |
|
272
|
|
|
} else { |
|
273
|
|
|
$fichier_dest = md5("$identifiant-$effet"); |
|
274
|
|
|
$cache = sous_repertoire(_DIR_VAR, $cache); |
|
275
|
|
|
$cache = sous_repertoire($cache, substr($fichier_dest, 0, 2)); |
|
276
|
|
|
$fichier_dest = substr($fichier_dest, 2); |
|
277
|
|
|
} |
|
278
|
|
|
|
|
279
|
|
|
$fichier_dest = $cache . $fichier_dest . "." . $terminaison_dest; |
|
280
|
|
|
|
|
281
|
|
|
$GLOBALS["images_calculees"][] = $fichier_dest; |
|
282
|
|
|
|
|
283
|
|
|
$creer = true; |
|
284
|
|
|
// si recalcul des images demande, recalculer chaque image une fois |
|
285
|
|
|
if (defined('_VAR_IMAGES') and _VAR_IMAGES and !isset($images_recalcul[$fichier_dest])) { |
|
286
|
|
|
$images_recalcul[$fichier_dest] = true; |
|
287
|
|
|
} else { |
|
288
|
|
|
if (@file_exists($f = $fichier_dest)) { |
|
289
|
|
|
if (filemtime($f) >= $date_src) { |
|
290
|
|
|
$creer = false; |
|
291
|
|
|
} |
|
292
|
|
|
} else { |
|
293
|
|
|
if (@file_exists($f = "$fichier_dest.src") |
|
294
|
|
|
and lire_fichier($f, $valeurs) |
|
295
|
|
|
and $valeurs = unserialize($valeurs) |
|
296
|
|
|
and $valeurs["date"] >= $date_src |
|
297
|
|
|
) { |
|
298
|
|
|
$creer = false; |
|
299
|
|
|
} |
|
300
|
|
|
} |
|
301
|
|
|
} |
|
302
|
|
|
if ($creer) { |
|
303
|
|
|
if (!@file_exists($fichier)) { |
|
304
|
|
|
if (!@file_exists("$fichier.src")) { |
|
305
|
|
|
spip_log("Image absente : $fichier"); |
|
306
|
|
|
|
|
307
|
|
|
return false; |
|
308
|
|
|
} |
|
309
|
|
|
# on reconstruit l'image source absente a partir de la chaine des .src |
|
310
|
|
|
reconstruire_image_intermediaire($fichier); |
|
|
|
|
|
|
311
|
|
|
} |
|
312
|
|
|
} |
|
313
|
|
|
|
|
314
|
|
|
if ($creer) { |
|
315
|
|
|
spip_log("filtre image " . ($fonction_creation ? reset($fonction_creation) : '') . "[$effet] sur $fichier", |
|
316
|
|
|
"images" . _LOG_DEBUG); |
|
317
|
|
|
} |
|
318
|
|
|
|
|
319
|
|
|
$term_fonction = _image_trouver_extension_pertinente($fichier); |
|
|
|
|
|
|
320
|
|
|
$ret["fonction_imagecreatefrom"] = "_imagecreatefrom" . $term_fonction; |
|
321
|
|
|
$ret["fichier"] = $fichier; |
|
322
|
|
|
$ret["fonction_image"] = "_image_image" . $terminaison_dest; |
|
323
|
|
|
$ret["fichier_dest"] = $fichier_dest; |
|
324
|
|
|
$ret["format_source"] = _image_extension_normalisee($terminaison); |
|
325
|
|
|
$ret["format_dest"] = $terminaison_dest; |
|
326
|
|
|
$ret["date_src"] = $date_src; |
|
327
|
|
|
$ret["creer"] = $creer; |
|
328
|
|
|
$ret["class"] = extraire_attribut($img, 'class'); |
|
329
|
|
|
$ret["alt"] = extraire_attribut($img, 'alt'); |
|
330
|
|
|
$ret["style"] = extraire_attribut($img, 'style'); |
|
331
|
|
|
$ret["tag"] = $img; |
|
332
|
|
|
if ($fonction_creation) { |
|
333
|
|
|
$ret["reconstruction"] = $fonction_creation; |
|
334
|
|
|
# ecrire ici comment creer le fichier, car il est pas sur qu'on l'ecrira reelement |
|
335
|
|
|
# cas de image_reduire qui finalement ne reduit pas l'image source |
|
336
|
|
|
# ca evite d'essayer de le creer au prochain hit si il n'est pas la |
|
337
|
|
|
#ecrire_fichier($ret['fichier_dest'].'.src',serialize($ret),true); |
|
338
|
|
|
} |
|
339
|
|
|
|
|
340
|
|
|
$ret = pipeline('image_preparer_filtre', array( |
|
341
|
|
|
'args' => array( |
|
342
|
|
|
'img' => $img, |
|
343
|
|
|
'effet' => $effet, |
|
344
|
|
|
'forcer_format' => $forcer_format, |
|
345
|
|
|
'fonction_creation' => $fonction_creation, |
|
346
|
|
|
'find_in_path' => $find_in_path, |
|
347
|
|
|
), |
|
348
|
|
|
'data' => $ret |
|
349
|
|
|
) |
|
350
|
|
|
); |
|
351
|
|
|
|
|
352
|
|
|
// une globale pour le debug en cas de crash memoire |
|
353
|
|
|
$GLOBALS["derniere_image_calculee"] = $ret; |
|
354
|
|
|
|
|
355
|
|
|
// traiter le cas particulier des SVG : si le filtre n'a pas annonce explicitement qu'il savait faire, on delegue |
|
356
|
|
|
if ($term_fonction === 'svg') { |
|
357
|
|
|
if ($creer and !$support_svg) { |
|
358
|
|
|
process_image_svg_identite($ret); |
|
359
|
|
|
$ret['creer'] = false; |
|
360
|
|
|
} |
|
361
|
|
|
} |
|
362
|
|
|
else { |
|
363
|
|
|
if (!function_exists($ret["fonction_imagecreatefrom"])) { |
|
364
|
|
|
return false; |
|
365
|
|
|
} |
|
366
|
|
|
} |
|
367
|
|
|
|
|
368
|
|
|
return $ret; |
|
369
|
|
|
} |
|
370
|
|
|
|
|
371
|
|
|
|
|
372
|
|
|
/** |
|
373
|
|
|
* @param string $quoi |
|
|
|
|
|
|
374
|
|
|
* @return array |
|
|
|
|
|
|
375
|
|
|
*/ |
|
376
|
|
|
function _image_extensions_acceptees_en_entree() { |
|
377
|
|
|
static $extensions = null; |
|
378
|
|
|
if (empty($extensions)) { |
|
379
|
|
|
$extensions = ['png', 'gif', 'jpg', 'jpeg']; |
|
380
|
|
|
if (!empty($GLOBALS['meta']['gd_formats'])) { |
|
381
|
|
|
// action=tester renseigne gd_formats et detecte le support de webp |
|
382
|
|
|
$extensions = array_merge(explode(',', $GLOBALS['meta']['gd_formats'])); |
|
383
|
|
|
$extensions = array_map('trim', $extensions); |
|
384
|
|
|
$extensions = array_filter($extensions); |
|
385
|
|
|
$extensions = array_unique($extensions); |
|
386
|
|
|
} |
|
387
|
|
|
$extensions[] = 'svg'; // on le supporte toujours avec des fonctions specifiques |
|
388
|
|
|
} |
|
389
|
|
|
|
|
390
|
|
|
return $extensions; |
|
391
|
|
|
} |
|
392
|
|
|
|
|
393
|
|
|
/** |
|
394
|
|
|
* @return array|string[]|null |
|
395
|
|
|
*/ |
|
396
|
|
|
function _image_extensions_acceptees_en_sortie(){ |
|
397
|
|
|
static $extensions = null; |
|
398
|
|
|
if (empty($extensions)){ |
|
399
|
|
|
$extensions = _image_extensions_acceptees_en_entree(); |
|
400
|
|
|
$extensions = array_diff($extensions, ['jpeg']); |
|
401
|
|
View Code Duplication |
if (in_array('gif', $extensions) and !function_exists('imagegif')) { |
|
|
|
|
|
|
402
|
|
|
$extensions = array_diff($extensions, ['gif']); |
|
403
|
|
|
} |
|
404
|
|
View Code Duplication |
if (in_array('webp', $extensions) and !function_exists('imagewebp')) { |
|
|
|
|
|
|
405
|
|
|
$extensions = array_diff($extensions, ['webp']); |
|
406
|
|
|
} |
|
407
|
|
|
} |
|
408
|
|
|
|
|
409
|
|
|
return $extensions; |
|
410
|
|
|
} |
|
411
|
|
|
|
|
412
|
|
|
function _image_extension_normalisee($extension){ |
|
413
|
|
|
$extension = strtolower($extension); |
|
414
|
|
|
if ($extension === 'jpeg') { |
|
415
|
|
|
$extension = 'jpg'; |
|
416
|
|
|
} |
|
417
|
|
|
return $extension; |
|
418
|
|
|
} |
|
419
|
|
|
|
|
420
|
|
|
function _image_extensions_conservent_transparence(){ |
|
421
|
|
|
return ['png', 'webp']; |
|
422
|
|
|
} |
|
423
|
|
|
|
|
424
|
|
|
|
|
425
|
|
|
/** |
|
426
|
|
|
* Retourne la terminaison d’un fichier image |
|
427
|
|
|
* @param string $path |
|
428
|
|
|
* @return string |
|
429
|
|
|
*/ |
|
430
|
|
|
function _image_trouver_extension($path) { |
|
431
|
|
|
$preg_extensions = implode('|', _image_extensions_acceptees_en_entree()); |
|
432
|
|
|
if (preg_match(",\.($preg_extensions)($|[?]),i", $path, $regs)) { |
|
433
|
|
|
$terminaison = strtolower($regs[1]); |
|
434
|
|
|
return $terminaison; |
|
435
|
|
|
} |
|
436
|
|
|
return ''; |
|
437
|
|
|
} |
|
438
|
|
|
|
|
439
|
|
|
/** |
|
440
|
|
|
* Tente de trouver le véritable type d’une image, |
|
441
|
|
|
* même si une image est d’extension .jpg alors que son contenu est autre chose (gif ou png) |
|
442
|
|
|
* |
|
443
|
|
|
* @param string $path |
|
444
|
|
|
* @return string Extension, dans le format attendu par les fonctions 'gd' ('jpeg' pour les .jpg par exemple) |
|
445
|
|
|
*/ |
|
446
|
|
|
function _image_trouver_extension_pertinente($path) { |
|
447
|
|
|
$path = supprimer_timestamp($path); |
|
448
|
|
|
$terminaison = _image_trouver_extension($path); |
|
449
|
|
|
if ($terminaison == 'jpg') { |
|
450
|
|
|
$terminaison = 'jpeg'; |
|
451
|
|
|
} |
|
452
|
|
|
|
|
453
|
|
|
if (!file_exists($path)) { |
|
454
|
|
|
return $terminaison; |
|
455
|
|
|
} |
|
456
|
|
|
|
|
457
|
|
|
if (!$info = @spip_getimagesize($path)) { |
|
458
|
|
|
return $terminaison; |
|
459
|
|
|
} |
|
460
|
|
|
|
|
461
|
|
|
if (isset($info['mime'])) { |
|
462
|
|
|
$mime = $info['mime']; |
|
463
|
|
|
} |
|
464
|
|
|
else { |
|
465
|
|
|
$mime = image_type_to_mime_type($info[2]); |
|
466
|
|
|
} |
|
467
|
|
|
|
|
468
|
|
|
$_terminaison = _image_trouver_extension_depuis_mime($mime); |
|
469
|
|
|
if ($_terminaison and $_terminaison !== $terminaison) { |
|
470
|
|
|
spip_log("Mauvaise extension du fichier : $path . Son type mime est : $mime", "images." . _LOG_INFO_IMPORTANTE); |
|
471
|
|
|
$terminaison = $_terminaison; |
|
472
|
|
|
} |
|
473
|
|
|
return $terminaison; |
|
474
|
|
|
} |
|
475
|
|
|
|
|
476
|
|
|
/** |
|
477
|
|
|
* @param string $mime |
|
478
|
|
|
* @return string |
|
479
|
|
|
*/ |
|
480
|
|
|
function _image_trouver_extension_depuis_mime($mime) { |
|
481
|
|
|
switch (strtolower($mime)) { |
|
482
|
|
|
case 'image/png': |
|
483
|
|
|
case 'image/x-png': |
|
484
|
|
|
$terminaison = 'png'; |
|
485
|
|
|
break; |
|
486
|
|
|
|
|
487
|
|
|
case 'image/jpg': |
|
488
|
|
|
case 'image/jpeg': |
|
489
|
|
|
case 'image/pjpeg': |
|
490
|
|
|
$terminaison = 'jpeg'; |
|
491
|
|
|
break; |
|
492
|
|
|
|
|
493
|
|
|
case 'image/gif': |
|
494
|
|
|
$terminaison = 'gif'; |
|
495
|
|
|
break; |
|
496
|
|
|
|
|
497
|
|
|
case 'image/webp': |
|
498
|
|
|
case 'image/x-webp': |
|
499
|
|
|
$terminaison = 'webp'; |
|
500
|
|
|
break; |
|
501
|
|
|
|
|
502
|
|
|
case 'image/svg+xml': |
|
503
|
|
|
$terminaison = 'svg'; |
|
504
|
|
|
break; |
|
505
|
|
|
|
|
506
|
|
|
default: |
|
507
|
|
|
$terminaison = ''; |
|
508
|
|
|
} |
|
509
|
|
|
|
|
510
|
|
|
return $terminaison; |
|
511
|
|
|
} |
|
512
|
|
|
|
|
513
|
|
|
|
|
514
|
|
|
/** |
|
515
|
|
|
* Crée une image depuis un fichier ou une URL (un indiquant la fonction GD à utiliser) |
|
516
|
|
|
* |
|
517
|
|
|
* Utilise les fonctions spécifiques GD. |
|
518
|
|
|
* - Si la fonction GD n'existe pas (GD non actif?), génère une erreur, mais ne retourne rien |
|
519
|
|
|
* - Si l'image est impossible à créer avec la fonction indiquée, génère une erreur, et une image vide |
|
520
|
|
|
* |
|
521
|
|
|
* @param string $func |
|
522
|
|
|
* Fonction GD à utiliser tel que 'imagecreatefromjpeg' |
|
523
|
|
|
* @param string $filename |
|
524
|
|
|
* Le path vers l'image à traiter (par exemple : IMG/distant/jpg/image.jpg |
|
525
|
|
|
* ou local/cache-vignettes/L180xH51/image.jpg). |
|
526
|
|
|
* @return resource|null |
|
527
|
|
|
* Une ressource de type Image GD. |
|
528
|
|
|
*/ |
|
529
|
|
|
function _imagecreatefrom_func(string $func, string $filename) { |
|
530
|
|
View Code Duplication |
if (!function_exists($func)) { |
|
|
|
|
|
|
531
|
|
|
spip_log("GD indisponible : $func inexistante. Traitement $filename impossible.", _LOG_CRITIQUE); |
|
532
|
|
|
erreur_squelette("GD indisponible : $func inexistante. Traitement $filename impossible."); |
|
533
|
|
|
return null; |
|
534
|
|
|
} |
|
535
|
|
|
$img = @$func($filename); |
|
536
|
|
View Code Duplication |
if (!$img) { |
|
|
|
|
|
|
537
|
|
|
spip_log("Erreur lecture imagecreatefromjpeg $filename", _LOG_CRITIQUE); |
|
538
|
|
|
erreur_squelette("Erreur lecture imagecreatefromjpeg $filename"); |
|
539
|
|
|
$img = imagecreate(10, 10); |
|
540
|
|
|
} |
|
541
|
|
|
return $img; |
|
542
|
|
|
} |
|
543
|
|
|
|
|
544
|
|
|
/** |
|
545
|
|
|
* Crée une image depuis un fichier ou une URL (au format jpeg) |
|
546
|
|
|
* |
|
547
|
|
|
* Utilise les fonctions spécifiques GD. |
|
548
|
|
|
* |
|
549
|
|
|
* @uses _imagecreatefrom_func() |
|
550
|
|
|
* @param string $filename |
|
551
|
|
|
* Le path vers l'image à traiter (par exemple : IMG/distant/jpg/image.jpg |
|
552
|
|
|
* ou local/cache-vignettes/L180xH51/image.jpg). |
|
553
|
|
|
* @return resource|null |
|
554
|
|
|
* Une ressource de type Image GD. |
|
555
|
|
|
*/ |
|
556
|
|
|
function _imagecreatefromjpeg($filename) { |
|
557
|
|
|
return _imagecreatefrom_func('imagecreatefromjpeg', $filename); |
|
558
|
|
|
} |
|
559
|
|
|
|
|
560
|
|
|
/** |
|
561
|
|
|
* Crée une image depuis un fichier ou une URL (au format png) |
|
562
|
|
|
* |
|
563
|
|
|
* Utilise les fonctions spécifiques GD. |
|
564
|
|
|
* |
|
565
|
|
|
* @uses _imagecreatefrom_func() |
|
566
|
|
|
* @param string $filename |
|
567
|
|
|
* Le path vers l'image à traiter (par exemple : IMG/distant/png/image.png |
|
568
|
|
|
* ou local/cache-vignettes/L180xH51/image.png). |
|
569
|
|
|
* @return resource|null |
|
570
|
|
|
* Une ressource de type Image GD. |
|
571
|
|
|
*/ |
|
572
|
|
|
function _imagecreatefrompng($filename) { |
|
573
|
|
|
return _imagecreatefrom_func('imagecreatefrompng', $filename); |
|
574
|
|
|
} |
|
575
|
|
|
|
|
576
|
|
|
/** |
|
577
|
|
|
* Crée une image depuis un fichier ou une URL (au format gif) |
|
578
|
|
|
* |
|
579
|
|
|
* Utilise les fonctions spécifiques GD. |
|
580
|
|
|
* |
|
581
|
|
|
* @uses _imagecreatefrom_func() |
|
582
|
|
|
* @param string $filename |
|
583
|
|
|
* Le path vers l'image à traiter (par exemple : IMG/distant/gif/image.gif |
|
584
|
|
|
* ou local/cache-vignettes/L180xH51/image.gif). |
|
585
|
|
|
* @return resource|null |
|
586
|
|
|
* Une ressource de type Image GD. |
|
587
|
|
|
*/ |
|
588
|
|
|
function _imagecreatefromgif($filename) { |
|
589
|
|
|
return _imagecreatefrom_func('imagecreatefromgif', $filename); |
|
590
|
|
|
} |
|
591
|
|
|
|
|
592
|
|
|
|
|
593
|
|
|
/** |
|
594
|
|
|
* Crée une image depuis un fichier ou une URL (au format webp) |
|
595
|
|
|
* |
|
596
|
|
|
* Utilise les fonctions spécifiques GD. |
|
597
|
|
|
* |
|
598
|
|
|
* @uses _imagecreatefrom_func() |
|
599
|
|
|
* @param string $filename |
|
600
|
|
|
* Le path vers l'image à traiter (par exemple : IMG/distant/png/image.png |
|
601
|
|
|
* ou local/cache-vignettes/L180xH51/image.png). |
|
602
|
|
|
* @return resource|null |
|
603
|
|
|
* Une ressource de type Image GD. |
|
604
|
|
|
*/ |
|
605
|
|
|
function _imagecreatefromwebp($filename) { |
|
606
|
|
|
return _imagecreatefrom_func('imagecreatefromwebp', $filename); |
|
607
|
|
|
} |
|
608
|
|
|
|
|
609
|
|
|
/** |
|
610
|
|
|
* Affiche ou sauvegarde une image au format PNG |
|
611
|
|
|
* |
|
612
|
|
|
* Utilise les fonctions spécifiques GD. |
|
613
|
|
|
* |
|
614
|
|
|
* @param ressource $img |
|
615
|
|
|
* Une ressource de type Image GD. |
|
616
|
|
|
* @param string $fichier |
|
617
|
|
|
* Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png). |
|
618
|
|
|
* @return bool |
|
619
|
|
|
* |
|
620
|
|
|
* - false si l'image créée a une largeur nulle ou n'existe pas ; |
|
621
|
|
|
* - true si une image est bien retournée. |
|
622
|
|
|
*/ |
|
623
|
|
View Code Duplication |
function _image_imagepng($img, $fichier) { |
|
|
|
|
|
|
624
|
|
|
if (!function_exists('imagepng')) { |
|
625
|
|
|
return false; |
|
626
|
|
|
} |
|
627
|
|
|
$tmp = $fichier . ".tmp"; |
|
628
|
|
|
$ret = imagepng($img, $tmp); |
|
629
|
|
|
if (file_exists($tmp)) { |
|
630
|
|
|
$taille_test = getimagesize($tmp); |
|
631
|
|
|
if ($taille_test[0] < 1) { |
|
632
|
|
|
return false; |
|
633
|
|
|
} |
|
634
|
|
|
|
|
635
|
|
|
spip_unlink($fichier); // le fichier peut deja exister |
|
636
|
|
|
@rename($tmp, $fichier); |
|
|
|
|
|
|
637
|
|
|
|
|
638
|
|
|
return $ret; |
|
639
|
|
|
} |
|
640
|
|
|
|
|
641
|
|
|
return false; |
|
642
|
|
|
} |
|
643
|
|
|
|
|
644
|
|
|
/** |
|
645
|
|
|
* Affiche ou sauvegarde une image au format GIF |
|
646
|
|
|
* |
|
647
|
|
|
* Utilise les fonctions spécifiques GD. |
|
648
|
|
|
* |
|
649
|
|
|
* @param resource $img |
|
650
|
|
|
* Une ressource de type Image GD. |
|
651
|
|
|
* @param string $fichier |
|
652
|
|
|
* Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.gif). |
|
653
|
|
|
* @return bool |
|
654
|
|
|
* |
|
655
|
|
|
* - false si l'image créée a une largeur nulle ou n'existe pas ; |
|
656
|
|
|
* - true si une image est bien retournée. |
|
657
|
|
|
*/ |
|
658
|
|
View Code Duplication |
function _image_imagegif($img, $fichier) { |
|
|
|
|
|
|
659
|
|
|
if (!function_exists('imagegif')) { |
|
660
|
|
|
return false; |
|
661
|
|
|
} |
|
662
|
|
|
$tmp = $fichier . ".tmp"; |
|
663
|
|
|
$ret = imagegif($img, $tmp); |
|
664
|
|
|
if (file_exists($tmp)) { |
|
665
|
|
|
$taille_test = getimagesize($tmp); |
|
666
|
|
|
if ($taille_test[0] < 1) { |
|
667
|
|
|
return false; |
|
668
|
|
|
} |
|
669
|
|
|
|
|
670
|
|
|
spip_unlink($fichier); // le fichier peut deja exister |
|
671
|
|
|
@rename($tmp, $fichier); |
|
|
|
|
|
|
672
|
|
|
|
|
673
|
|
|
return $ret; |
|
674
|
|
|
} |
|
675
|
|
|
|
|
676
|
|
|
return false; |
|
677
|
|
|
} |
|
678
|
|
|
|
|
679
|
|
|
/** |
|
680
|
|
|
* Affiche ou sauvegarde une image au format JPG |
|
681
|
|
|
* |
|
682
|
|
|
* Utilise les fonctions spécifiques GD. |
|
683
|
|
|
* |
|
684
|
|
|
* @param resource $img |
|
685
|
|
|
* Une ressource de type Image GD. |
|
686
|
|
|
* @param string $fichier |
|
687
|
|
|
* Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg). |
|
688
|
|
|
* @param int $qualite |
|
689
|
|
|
* Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit |
|
690
|
|
|
* fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la |
|
691
|
|
|
* valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis |
|
692
|
|
|
* mes_options.php). |
|
693
|
|
|
* @return bool |
|
694
|
|
|
* |
|
695
|
|
|
* - false si l'image créée a une largeur nulle ou n'existe pas ; |
|
696
|
|
|
* - true si une image est bien retournée. |
|
697
|
|
|
*/ |
|
698
|
|
|
function _image_imagejpg($img, $fichier, $qualite = _IMG_GD_QUALITE) { |
|
699
|
|
|
if (!function_exists('imagejpeg')) { |
|
700
|
|
|
return false; |
|
701
|
|
|
} |
|
702
|
|
|
$tmp = $fichier . ".tmp"; |
|
703
|
|
|
|
|
704
|
|
|
// Enable interlancing |
|
705
|
|
|
imageinterlace($img, true); |
|
706
|
|
|
|
|
707
|
|
|
$ret = imagejpeg($img, $tmp, $qualite); |
|
708
|
|
|
|
|
709
|
|
|
if (file_exists($tmp)) { |
|
710
|
|
|
$taille_test = getimagesize($tmp); |
|
711
|
|
|
if ($taille_test[0] < 1) { |
|
712
|
|
|
return false; |
|
713
|
|
|
} |
|
714
|
|
|
|
|
715
|
|
|
spip_unlink($fichier); // le fichier peut deja exister |
|
716
|
|
|
@rename($tmp, $fichier); |
|
|
|
|
|
|
717
|
|
|
|
|
718
|
|
|
return $ret; |
|
719
|
|
|
} |
|
720
|
|
|
|
|
721
|
|
|
return false; |
|
722
|
|
|
} |
|
723
|
|
|
|
|
724
|
|
|
/** |
|
725
|
|
|
* Crée un fichier-image au format ICO |
|
726
|
|
|
* |
|
727
|
|
|
* Utilise les fonctions de la classe phpthumb_functions. |
|
728
|
|
|
* |
|
729
|
|
|
* @uses phpthumb_functions::GD2ICOstring() |
|
730
|
|
|
* |
|
731
|
|
|
* @param resource $img |
|
732
|
|
|
* Une ressource de type Image GD. |
|
733
|
|
|
* @param string $fichier |
|
734
|
|
|
* Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg). |
|
735
|
|
|
* @return bool |
|
736
|
|
|
* true si le fichier a bien été créé ; false sinon. |
|
737
|
|
|
*/ |
|
738
|
|
|
function _image_imageico($img, $fichier) { |
|
739
|
|
|
$gd_image_array = array($img); |
|
740
|
|
|
|
|
741
|
|
|
return ecrire_fichier($fichier, phpthumb_functions::GD2ICOstring($gd_image_array)); |
|
742
|
|
|
} |
|
743
|
|
|
|
|
744
|
|
|
|
|
745
|
|
|
/** |
|
746
|
|
|
* Affiche ou sauvegarde une image au format WEBP |
|
747
|
|
|
* |
|
748
|
|
|
* Utilise les fonctions spécifiques GD. |
|
749
|
|
|
* |
|
750
|
|
|
* @param resource $img |
|
751
|
|
|
* Une ressource de type Image GD. |
|
752
|
|
|
* @param string $fichier |
|
753
|
|
|
* Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png). |
|
754
|
|
|
* @return bool |
|
755
|
|
|
* |
|
756
|
|
|
* - false si l'image créée a une largeur nulle ou n'existe pas ; |
|
757
|
|
|
* - true si une image est bien retournée. |
|
758
|
|
|
*/ |
|
759
|
|
View Code Duplication |
function _image_imagewebp($img, $fichier, $qualite = _IMG_GD_QUALITE) { |
|
|
|
|
|
|
760
|
|
|
if (!function_exists('imagewebp')) { |
|
761
|
|
|
return false; |
|
762
|
|
|
} |
|
763
|
|
|
$tmp = $fichier . ".tmp"; |
|
764
|
|
|
$ret = imagewebp($img, $tmp, $qualite); |
|
765
|
|
|
if (file_exists($tmp)) { |
|
766
|
|
|
$taille_test = getimagesize($tmp); |
|
767
|
|
|
if ($taille_test[0] < 1) { |
|
768
|
|
|
return false; |
|
769
|
|
|
} |
|
770
|
|
|
|
|
771
|
|
|
spip_unlink($fichier); // le fichier peut deja exister |
|
772
|
|
|
@rename($tmp, $fichier); |
|
|
|
|
|
|
773
|
|
|
|
|
774
|
|
|
return $ret; |
|
775
|
|
|
} |
|
776
|
|
|
|
|
777
|
|
|
return false; |
|
778
|
|
|
} |
|
779
|
|
|
|
|
780
|
|
|
/** |
|
781
|
|
|
* Sauvegarde une image au format SVG |
|
782
|
|
|
* |
|
783
|
|
|
* - N'UTILISE PAS GD - |
|
784
|
|
|
* C'est une fonction derogatoire pour faciliter le traitement des SVG |
|
785
|
|
|
* |
|
786
|
|
|
* @param string $img |
|
787
|
|
|
* contenu du SVG ou chemin vers le SVG source (et c'est alors une copie) |
|
788
|
|
|
* @param string $fichier |
|
789
|
|
|
* Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png). |
|
790
|
|
|
* @return bool |
|
791
|
|
|
* |
|
792
|
|
|
* - false si l'image créée a une largeur nulle ou n'existe pas ; |
|
793
|
|
|
* - true si une image est bien retournée. |
|
794
|
|
|
*/ |
|
795
|
|
|
function _image_imagesvg($img, $fichier) { |
|
796
|
|
|
|
|
797
|
|
|
$tmp = $fichier . ".tmp"; |
|
798
|
|
|
if (strpos($img, "<") === false) { |
|
799
|
|
|
$img = supprimer_timestamp($img); |
|
800
|
|
|
if (!file_exists($img)) { |
|
801
|
|
|
return false; |
|
802
|
|
|
} |
|
803
|
|
|
@copy($img, $tmp); |
|
|
|
|
|
|
804
|
|
|
if (filesize($tmp) == filesize($img)) { |
|
805
|
|
|
spip_unlink($fichier); // le fichier peut deja exister |
|
806
|
|
|
@rename($tmp, $fichier); |
|
|
|
|
|
|
807
|
|
|
return true; |
|
808
|
|
|
} |
|
809
|
|
|
return false; |
|
810
|
|
|
} |
|
811
|
|
|
|
|
812
|
|
|
file_put_contents($tmp, $img); |
|
813
|
|
|
if (file_exists($tmp)) { |
|
814
|
|
|
$taille_test = spip_getimagesize($tmp); |
|
815
|
|
|
if ($taille_test[0] < 1) { |
|
816
|
|
|
return false; |
|
817
|
|
|
} |
|
818
|
|
|
|
|
819
|
|
|
spip_unlink($fichier); // le fichier peut deja exister |
|
820
|
|
|
@rename($tmp, $fichier); |
|
|
|
|
|
|
821
|
|
|
|
|
822
|
|
|
return true; |
|
823
|
|
|
} |
|
824
|
|
|
|
|
825
|
|
|
return false; |
|
826
|
|
|
} |
|
827
|
|
|
|
|
828
|
|
|
|
|
829
|
|
|
/** |
|
830
|
|
|
* Finalise le traitement GD |
|
831
|
|
|
* |
|
832
|
|
|
* Crée un fichier_image temporaire .src ou vérifie que le fichier_image |
|
833
|
|
|
* définitif a bien été créé. |
|
834
|
|
|
* |
|
835
|
|
|
* @uses statut_effacer_images_temporaires() |
|
836
|
|
|
* |
|
837
|
|
|
* @param resource|string $img |
|
838
|
|
|
* Une ressource de type Image GD (ou une string pour un SVG) |
|
839
|
|
|
* @param array $valeurs |
|
840
|
|
|
* Un tableau des informations (tailles, traitement, path...) accompagnant |
|
841
|
|
|
* l'image. |
|
842
|
|
|
* @param int $qualite |
|
843
|
|
|
* N'est utilisé que pour les images jpg. |
|
844
|
|
|
* Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit |
|
845
|
|
|
* fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la |
|
846
|
|
|
* valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis |
|
847
|
|
|
* mes_options.php). |
|
848
|
|
|
* @return bool |
|
849
|
|
|
* - true si le traitement GD s'est bien finalisé ; |
|
850
|
|
|
* - false sinon. |
|
851
|
|
|
*/ |
|
852
|
|
|
function _image_gd_output($img, $valeurs, $qualite = _IMG_GD_QUALITE) { |
|
853
|
|
|
$fonction = "_image_image" . $valeurs['format_dest']; |
|
854
|
|
|
$ret = false; |
|
855
|
|
|
#un flag pour reperer les images gravees |
|
856
|
|
|
$lock = |
|
857
|
|
|
!statut_effacer_images_temporaires('get') // si la fonction n'a pas ete activee, on grave tout |
|
858
|
|
|
or (@file_exists($valeurs['fichier_dest']) and !@file_exists($valeurs['fichier_dest'] . '.src')); |
|
859
|
|
|
if ( |
|
860
|
|
|
function_exists($fonction) |
|
861
|
|
|
&& ($ret = $fonction($img, $valeurs['fichier_dest'], $qualite)) # on a reussi a creer l'image |
|
862
|
|
|
&& isset($valeurs['reconstruction']) # et on sait comment la resonctruire le cas echeant |
|
863
|
|
|
&& !$lock |
|
864
|
|
|
) { |
|
865
|
|
|
if (@file_exists($valeurs['fichier_dest'])) { |
|
866
|
|
|
// dans tous les cas mettre a jour la taille de l'image finale |
|
867
|
|
|
list($valeurs["hauteur_dest"], $valeurs["largeur_dest"]) = taille_image($valeurs['fichier_dest']); |
|
868
|
|
|
$valeurs['date'] = @filemtime($valeurs['fichier_dest']); // pour la retrouver apres disparition |
|
869
|
|
|
ecrire_fichier($valeurs['fichier_dest'] . '.src', serialize($valeurs), true); |
|
870
|
|
|
} |
|
871
|
|
|
} |
|
872
|
|
|
|
|
873
|
|
|
return $ret; |
|
874
|
|
|
} |
|
875
|
|
|
|
|
876
|
|
|
/** |
|
877
|
|
|
* Reconstruit une image à partir des sources de contrôle de son ancienne |
|
878
|
|
|
* construction |
|
879
|
|
|
* |
|
880
|
|
|
* @uses ramasse_miettes() |
|
881
|
|
|
* |
|
882
|
|
|
* @param string $fichier_manquant |
|
883
|
|
|
* Chemin vers le fichier manquant |
|
884
|
|
|
**/ |
|
885
|
|
|
function reconstruire_image_intermediaire($fichier_manquant) { |
|
886
|
|
|
$reconstruire = array(); |
|
887
|
|
|
$fichier = $fichier_manquant; |
|
888
|
|
|
while (strpos($fichier,"://")===false |
|
889
|
|
|
and !@file_exists($fichier) |
|
890
|
|
|
and lire_fichier($src = "$fichier.src", $source) |
|
891
|
|
|
and $valeurs = unserialize($source) |
|
892
|
|
|
and ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...) |
|
893
|
|
|
) { |
|
894
|
|
|
spip_unlink($src); // si jamais on a un timeout pendant la reconstruction, elle se fera naturellement au hit suivant |
|
895
|
|
|
$reconstruire[] = $valeurs['reconstruction']; |
|
896
|
|
|
} |
|
897
|
|
|
while (count($reconstruire)) { |
|
898
|
|
|
$r = array_pop($reconstruire); |
|
899
|
|
|
$fonction = $r[0]; |
|
900
|
|
|
$args = $r[1]; |
|
901
|
|
|
call_user_func_array($fonction, $args); |
|
902
|
|
|
} |
|
903
|
|
|
// cette image intermediaire est commune a plusieurs series de filtre, il faut la conserver |
|
904
|
|
|
// mais l'on peut nettoyer les miettes de sa creation |
|
905
|
|
|
ramasse_miettes($fichier_manquant); |
|
906
|
|
|
} |
|
907
|
|
|
|
|
908
|
|
|
/** |
|
909
|
|
|
* Indique qu'un fichier d'image calculé est à conserver |
|
910
|
|
|
* |
|
911
|
|
|
* Permet de rendre une image définitive et de supprimer les images |
|
912
|
|
|
* intermédiaires à son calcul. |
|
913
|
|
|
* |
|
914
|
|
|
* Supprime le fichier de contrôle de l’image cible (le $fichier.src) |
|
915
|
|
|
* ce qui indique que l'image est définitive. |
|
916
|
|
|
* |
|
917
|
|
|
* Remonte ensuite la chaîne des fichiers de contrôle pour supprimer |
|
918
|
|
|
* les images temporaires (mais laisse les fichiers de contrôle permettant |
|
919
|
|
|
* de les reconstruire). |
|
920
|
|
|
* |
|
921
|
|
|
* @param string $fichier |
|
922
|
|
|
* Chemin du fichier d'image calculé |
|
923
|
|
|
**/ |
|
924
|
|
|
function ramasse_miettes($fichier) { |
|
925
|
|
|
if (strpos($fichier,"://")!==false |
|
926
|
|
|
or !lire_fichier($src = "$fichier.src", $source) |
|
927
|
|
|
or !$valeurs = unserialize($source) |
|
928
|
|
|
) { |
|
929
|
|
|
return; |
|
930
|
|
|
} |
|
931
|
|
|
spip_unlink($src); # on supprime la reference a sa source pour marquer cette image comme non intermediaire |
|
932
|
|
|
while ( |
|
933
|
|
|
($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...) |
|
934
|
|
|
and (substr($fichier, 0, strlen(_DIR_VAR)) == _DIR_VAR) # et est dans local |
|
935
|
|
|
and (lire_fichier($src = "$fichier.src", |
|
936
|
|
|
$source)) # le fichier a une source connue (c'est donc une image calculee intermediaire) |
|
937
|
|
|
and ($valeurs = unserialize($source)) # et valide |
|
938
|
|
|
) { |
|
939
|
|
|
# on efface le fichier |
|
940
|
|
|
spip_unlink($fichier); |
|
941
|
|
|
# mais laisse le .src qui permet de savoir comment reconstruire l'image si besoin |
|
942
|
|
|
#spip_unlink($src); |
|
943
|
|
|
} |
|
944
|
|
|
} |
|
945
|
|
|
|
|
946
|
|
|
|
|
947
|
|
|
/** |
|
948
|
|
|
* Clôture une série de filtres d'images |
|
949
|
|
|
* |
|
950
|
|
|
* Ce filtre est automatiquement appelé à la fin d'une série de filtres |
|
951
|
|
|
* d'images dans un squelette. |
|
952
|
|
|
* |
|
953
|
|
|
* @filtre |
|
954
|
|
|
* @uses reconstruire_image_intermediaire() |
|
955
|
|
|
* Si l'image finale a déjà été supprimée car considérée comme temporaire |
|
956
|
|
|
* par une autre série de filtres images débutant pareil |
|
957
|
|
|
* @uses ramasse_miettes() |
|
958
|
|
|
* Pour déclarer l'image définitive et nettoyer les images intermédiaires. |
|
959
|
|
|
* |
|
960
|
|
|
* @pipeline_appel post_image_filtrer |
|
961
|
|
|
* |
|
962
|
|
|
* @param string $img |
|
963
|
|
|
* Code HTML de l'image |
|
964
|
|
|
* @return string |
|
965
|
|
|
* Code HTML de l'image |
|
966
|
|
|
**/ |
|
967
|
|
|
function image_graver($img) { |
|
968
|
|
|
// appeler le filtre post_image_filtrer qui permet de faire |
|
969
|
|
|
// des traitements auto a la fin d'une serie de filtres |
|
970
|
|
|
$img = pipeline('post_image_filtrer', $img); |
|
971
|
|
|
|
|
972
|
|
|
$fichier_ori = $fichier = extraire_attribut($img, 'src'); |
|
973
|
|
View Code Duplication |
if (($p = strpos($fichier, '?')) !== false) { |
|
|
|
|
|
|
974
|
|
|
$fichier = substr($fichier, 0, $p); |
|
975
|
|
|
} |
|
976
|
|
|
if (strlen($fichier) < 1) { |
|
977
|
|
|
$fichier = $img; |
|
978
|
|
|
} |
|
979
|
|
|
# si jamais le fichier final n'a pas ete calcule car suppose temporaire |
|
980
|
|
|
# et qu'il ne s'agit pas d'une URL |
|
981
|
|
|
if (strpos($fichier,"://")===false and !@file_exists($fichier)) { |
|
982
|
|
|
reconstruire_image_intermediaire($fichier); |
|
983
|
|
|
} |
|
984
|
|
|
ramasse_miettes($fichier); |
|
985
|
|
|
|
|
986
|
|
|
// ajouter le timestamp si besoin |
|
987
|
|
|
if (strpos($fichier_ori, "?") === false) { |
|
988
|
|
|
// on utilise str_replace pour attraper le onmouseover des logo si besoin |
|
989
|
|
|
$img = str_replace($fichier_ori, timestamp($fichier_ori), $img); |
|
|
|
|
|
|
990
|
|
|
} |
|
991
|
|
|
|
|
992
|
|
|
return $img; |
|
993
|
|
|
} |
|
994
|
|
|
|
|
995
|
|
|
|
|
996
|
|
|
if (!function_exists("imagepalettetotruecolor")) { |
|
997
|
|
|
/** |
|
998
|
|
|
* Transforme une image à palette indexée (256 couleurs max) en "vraies" couleurs RGB |
|
999
|
|
|
* |
|
1000
|
|
|
* @note Pour compatibilité avec PHP < 5.5 |
|
1001
|
|
|
* |
|
1002
|
|
|
* @link http://php.net/manual/fr/function.imagepalettetotruecolor.php |
|
1003
|
|
|
* |
|
1004
|
|
|
* @param ressource $img |
|
1005
|
|
|
* @return bool |
|
1006
|
|
|
* - true si l'image est déjà en vrai RGB ou peut être transformée |
|
1007
|
|
|
* - false si la transformation ne peut être faite. |
|
1008
|
|
|
**/ |
|
1009
|
|
|
function imagepalettetotruecolor(&$img) { |
|
1010
|
|
|
if (!$img or !function_exists('imagecreatetruecolor')) { |
|
1011
|
|
|
return false; |
|
1012
|
|
|
} elseif (!imageistruecolor($img)) { |
|
1013
|
|
|
$w = imagesx($img); |
|
1014
|
|
|
$h = imagesy($img); |
|
1015
|
|
|
$img1 = imagecreatetruecolor($w, $h); |
|
1016
|
|
|
//Conserver la transparence si possible |
|
1017
|
|
|
if (function_exists('ImageCopyResampled')) { |
|
1018
|
|
|
if (function_exists("imageAntiAlias")) { |
|
1019
|
|
|
imageAntiAlias($img1, true); |
|
1020
|
|
|
} |
|
1021
|
|
|
@imagealphablending($img1, false); |
|
|
|
|
|
|
1022
|
|
|
@imagesavealpha($img1, true); |
|
|
|
|
|
|
1023
|
|
|
@ImageCopyResampled($img1, $img, 0, 0, 0, 0, $w, $h, $w, $h); |
|
|
|
|
|
|
1024
|
|
|
} else { |
|
1025
|
|
|
imagecopy($img1, $img, 0, 0, 0, 0, $w, $h); |
|
1026
|
|
|
} |
|
1027
|
|
|
|
|
1028
|
|
|
$img = $img1; |
|
1029
|
|
|
} |
|
1030
|
|
|
|
|
1031
|
|
|
return true; |
|
1032
|
|
|
} |
|
1033
|
|
|
} |
|
1034
|
|
|
|
|
1035
|
|
|
/** |
|
1036
|
|
|
* Applique des attributs de taille (width, height) à une balise HTML |
|
1037
|
|
|
* |
|
1038
|
|
|
* Utilisé avec des balises `<img>` tout particulièrement. |
|
1039
|
|
|
* |
|
1040
|
|
|
* Modifie l'attribut style s'il était renseigné, en enlevant les |
|
1041
|
|
|
* informations éventuelles width / height dedans. |
|
1042
|
|
|
* |
|
1043
|
|
|
* @uses extraire_attribut() |
|
1044
|
|
|
* @uses inserer_attribut() |
|
1045
|
|
|
* |
|
1046
|
|
|
* @param string $tag |
|
1047
|
|
|
* Code html de la balise |
|
1048
|
|
|
* @param int $width |
|
1049
|
|
|
* Hauteur |
|
1050
|
|
|
* @param int $height |
|
1051
|
|
|
* Largeur |
|
1052
|
|
|
* @param bool|string $style |
|
1053
|
|
|
* Attribut html style à appliquer. |
|
1054
|
|
|
* False extrait celui présent dans la balise |
|
1055
|
|
|
* @return string |
|
1056
|
|
|
* Code html modifié de la balise. |
|
1057
|
|
|
**/ |
|
1058
|
|
|
function _image_tag_changer_taille($tag, $width, $height, $style = false) { |
|
1059
|
|
|
if ($style === false) { |
|
1060
|
|
|
$style = extraire_attribut($tag, 'style'); |
|
1061
|
|
|
} |
|
1062
|
|
|
|
|
1063
|
|
|
// enlever le width et height du style |
|
1064
|
|
|
$style = preg_replace(",(^|;)\s*(width|height)\s*:\s*[^;]+,ims", "", $style); |
|
1065
|
|
|
if ($style and $style[0] == ';') { |
|
1066
|
|
|
$style = substr($style, 1); |
|
1067
|
|
|
} |
|
1068
|
|
|
|
|
1069
|
|
|
// mettre des attributs de width et height sur les images, |
|
1070
|
|
|
// ca accelere le rendu du navigateur |
|
1071
|
|
|
// ca permet aux navigateurs de reserver la bonne taille |
|
1072
|
|
|
// quand on a desactive l'affichage des images. |
|
1073
|
|
|
$tag = inserer_attribut($tag, 'width', round($width)); |
|
1074
|
|
|
$tag = inserer_attribut($tag, 'height', round($height)); |
|
1075
|
|
|
|
|
1076
|
|
|
// attributs deprecies. Transformer en CSS |
|
1077
|
|
|
if ($espace = extraire_attribut($tag, 'hspace')) { |
|
1078
|
|
|
$style = "margin:${espace}px;" . $style; |
|
1079
|
|
|
$tag = inserer_attribut($tag, 'hspace', ''); |
|
1080
|
|
|
} |
|
1081
|
|
|
|
|
1082
|
|
|
$tag = inserer_attribut($tag, 'style', $style, true, $style ? false : true); |
|
|
|
|
|
|
1083
|
|
|
|
|
1084
|
|
|
return $tag; |
|
1085
|
|
|
} |
|
1086
|
|
|
|
|
1087
|
|
|
|
|
1088
|
|
|
/** |
|
1089
|
|
|
* Écriture de la balise img en sortie de filtre image |
|
1090
|
|
|
* |
|
1091
|
|
|
* Reprend le tag initial et surcharge les attributs modifiés |
|
1092
|
|
|
* |
|
1093
|
|
|
* @pipeline_appel image_ecrire_tag_preparer |
|
1094
|
|
|
* @pipeline_appel image_ecrire_tag_finir |
|
1095
|
|
|
* |
|
1096
|
|
|
* @uses _image_tag_changer_taille() |
|
1097
|
|
|
* @uses extraire_attribut() |
|
1098
|
|
|
* @uses inserer_attribut() |
|
1099
|
|
|
* @see _image_valeurs_trans() |
|
1100
|
|
|
* |
|
1101
|
|
|
* @param array $valeurs |
|
1102
|
|
|
* Description de l'image tel que retourné par `_image_valeurs_trans()` |
|
1103
|
|
|
* @param array $surcharge |
|
1104
|
|
|
* Permet de surcharger certaines descriptions présentes dans `$valeurs` |
|
1105
|
|
|
* tel que 'style', 'width', 'height' |
|
1106
|
|
|
* @return string |
|
1107
|
|
|
* Retourne le code HTML de l'image |
|
1108
|
|
|
**/ |
|
1109
|
|
|
function _image_ecrire_tag($valeurs, $surcharge = array()) { |
|
1110
|
|
|
$valeurs = pipeline('image_ecrire_tag_preparer', $valeurs); |
|
1111
|
|
|
|
|
1112
|
|
|
// fermer les tags img pas bien fermes; |
|
1113
|
|
|
$tag = str_replace(">", "/>", str_replace("/>", ">", $valeurs['tag'])); |
|
1114
|
|
|
|
|
1115
|
|
|
// le style |
|
1116
|
|
|
$style = $valeurs['style']; |
|
1117
|
|
|
if (isset($surcharge['style'])) { |
|
1118
|
|
|
$style = $surcharge['style']; |
|
1119
|
|
|
unset($surcharge['style']); |
|
1120
|
|
|
} |
|
1121
|
|
|
|
|
1122
|
|
|
// traiter specifiquement la largeur et la hauteur |
|
1123
|
|
|
$width = $valeurs['largeur']; |
|
1124
|
|
|
if (isset($surcharge['width'])) { |
|
1125
|
|
|
$width = $surcharge['width']; |
|
1126
|
|
|
unset($surcharge['width']); |
|
1127
|
|
|
} |
|
1128
|
|
|
$height = $valeurs['hauteur']; |
|
1129
|
|
|
if (isset($surcharge['height'])) { |
|
1130
|
|
|
$height = $surcharge['height']; |
|
1131
|
|
|
unset($surcharge['height']); |
|
1132
|
|
|
} |
|
1133
|
|
|
|
|
1134
|
|
|
$tag = _image_tag_changer_taille($tag, $width, $height, $style); |
|
1135
|
|
|
// traiter specifiquement le src qui peut etre repris dans un onmouseout |
|
1136
|
|
|
// on remplace toute les ref a src dans le tag |
|
1137
|
|
|
$src = extraire_attribut($tag, 'src'); |
|
1138
|
|
|
if (isset($surcharge['src'])) { |
|
1139
|
|
|
$tag = str_replace($src, $surcharge['src'], $tag); |
|
1140
|
|
|
// si il y a des & dans src, alors ils peuvent provenir d'un & |
|
1141
|
|
|
// pas garanti comme methode, mais mieux que rien |
|
1142
|
|
|
if (strpos($src, '&') !== false) { |
|
1143
|
|
|
$tag = str_replace(str_replace("&", "&", $src), $surcharge['src'], $tag); |
|
1144
|
|
|
} |
|
1145
|
|
|
$src = $surcharge['src']; |
|
|
|
|
|
|
1146
|
|
|
unset($surcharge['src']); |
|
1147
|
|
|
} |
|
1148
|
|
|
|
|
1149
|
|
|
$class = $valeurs['class']; |
|
1150
|
|
|
if (isset($surcharge['class'])) { |
|
1151
|
|
|
$class = $surcharge['class']; |
|
1152
|
|
|
unset($surcharge['class']); |
|
1153
|
|
|
} |
|
1154
|
|
|
if (strlen($class)) { |
|
1155
|
|
|
$tag = inserer_attribut($tag, 'class', $class); |
|
1156
|
|
|
} |
|
1157
|
|
|
|
|
1158
|
|
|
if (count($surcharge)) { |
|
1159
|
|
|
foreach ($surcharge as $attribut => $valeur) { |
|
1160
|
|
|
$tag = inserer_attribut($tag, $attribut, $valeur); |
|
1161
|
|
|
} |
|
1162
|
|
|
} |
|
1163
|
|
|
|
|
1164
|
|
|
$tag = pipeline('image_ecrire_tag_finir', |
|
1165
|
|
|
array( |
|
1166
|
|
|
'args' => array( |
|
1167
|
|
|
'valeurs' => $valeurs, |
|
1168
|
|
|
'surcharge' => $surcharge, |
|
1169
|
|
|
), |
|
1170
|
|
|
'data' => $tag |
|
1171
|
|
|
) |
|
1172
|
|
|
); |
|
1173
|
|
|
|
|
1174
|
|
|
return $tag; |
|
1175
|
|
|
} |
|
1176
|
|
|
|
|
1177
|
|
|
/** |
|
1178
|
|
|
* Crée si possible une miniature d'une image |
|
1179
|
|
|
* |
|
1180
|
|
|
* @see _image_valeurs_trans() |
|
1181
|
|
|
* @uses _image_ratio() |
|
1182
|
|
|
* |
|
1183
|
|
|
* @param array $valeurs |
|
1184
|
|
|
* Description de l'image, telle que retournée par `_image_valeurs_trans()` |
|
1185
|
|
|
* @param int $maxWidth |
|
1186
|
|
|
* Largeur maximum en px de la miniature à réaliser |
|
1187
|
|
|
* @param int $maxHeight |
|
1188
|
|
|
* Hauteur maximum en px de la miniateure à réaliser |
|
1189
|
|
|
* @param string $process |
|
1190
|
|
|
* Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick). |
|
1191
|
|
|
* AUTO utilise la librairie sélectionnée dans la configuration. |
|
1192
|
|
|
* @param bool $force |
|
1193
|
|
|
* @return array|null |
|
|
|
|
|
|
1194
|
|
|
* Description de l'image, sinon null. |
|
1195
|
|
|
**/ |
|
1196
|
|
|
function _image_creer_vignette($valeurs, $maxWidth, $maxHeight, $process = 'AUTO', $force = false) { |
|
1197
|
|
|
// ordre de preference des formats graphiques pour creer les vignettes |
|
1198
|
|
|
// le premier format disponible, selon la methode demandee, est utilise |
|
1199
|
|
|
$image = $valeurs['fichier']; |
|
1200
|
|
|
$format = $valeurs['format_source']; |
|
1201
|
|
|
$destdir = dirname($valeurs['fichier_dest']); |
|
1202
|
|
|
$destfile = basename($valeurs['fichier_dest'], "." . $valeurs["format_dest"]); |
|
1203
|
|
|
|
|
1204
|
|
|
$format_sortie = $valeurs['format_dest']; |
|
1205
|
|
|
|
|
1206
|
|
View Code Duplication |
if (($process == 'AUTO') and isset($GLOBALS['meta']['image_process'])) { |
|
|
|
|
|
|
1207
|
|
|
$process = $GLOBALS['meta']['image_process']; |
|
1208
|
|
|
} |
|
1209
|
|
|
|
|
1210
|
|
|
// si le doc n'est pas une image dans un format accetpable, refuser |
|
1211
|
|
|
if (!$force and !in_array($format, formats_image_acceptables(in_array($process, ['gd1', 'gd2'])))) { |
|
1212
|
|
|
return; |
|
1213
|
|
|
} |
|
1214
|
|
|
$destination = "$destdir/$destfile"; |
|
1215
|
|
|
|
|
1216
|
|
|
// calculer la taille |
|
1217
|
|
|
if (($srcWidth = $valeurs['largeur']) && ($srcHeight = $valeurs['hauteur'])) { |
|
1218
|
|
|
if (!($destWidth = $valeurs['largeur_dest']) || !($destHeight = $valeurs['hauteur_dest'])) { |
|
1219
|
|
|
list($destWidth, $destHeight) = _image_ratio($valeurs['largeur'], $valeurs['hauteur'], $maxWidth, $maxHeight); |
|
1220
|
|
|
} |
|
1221
|
|
|
} elseif ($process == 'convert' or $process == 'imagick') { |
|
1222
|
|
|
$destWidth = $maxWidth; |
|
1223
|
|
|
$destHeight = $maxHeight; |
|
1224
|
|
|
} else { |
|
1225
|
|
|
spip_log("echec $process sur $image"); |
|
1226
|
|
|
|
|
1227
|
|
|
return; |
|
1228
|
|
|
} |
|
1229
|
|
|
|
|
1230
|
|
|
$vignette = ''; |
|
1231
|
|
|
|
|
1232
|
|
|
// Si l'image est de la taille demandee (ou plus petite), simplement la retourner |
|
1233
|
|
|
if ($srcWidth and $srcWidth <= $maxWidth and $srcHeight <= $maxHeight) { |
|
1234
|
|
|
$vignette = $destination . '.' . $format; |
|
1235
|
|
|
@copy($image, $vignette); |
|
|
|
|
|
|
1236
|
|
|
} |
|
1237
|
|
|
|
|
1238
|
|
|
elseif ($valeurs["format_source"] === 'svg') { |
|
1239
|
|
|
if ($svg = svg_redimensionner($valeurs['fichier'], $destWidth, $destHeight)){ |
|
1240
|
|
|
$format_sortie = 'svg'; |
|
1241
|
|
|
$vignette = $destination . "." . $format_sortie; |
|
1242
|
|
|
$valeurs['fichier_dest'] = $vignette; |
|
1243
|
|
|
_image_gd_output($svg, $valeurs); |
|
|
|
|
|
|
1244
|
|
|
} |
|
1245
|
|
|
} |
|
1246
|
|
|
|
|
1247
|
|
|
// imagemagick en ligne de commande |
|
1248
|
|
|
elseif ($process == 'convert') { |
|
1249
|
|
|
if (!defined('_CONVERT_COMMAND')) { |
|
1250
|
|
|
define('_CONVERT_COMMAND', 'convert'); |
|
1251
|
|
|
} // Securite : mes_options.php peut preciser le chemin absolu |
|
1252
|
|
|
if (!defined('_RESIZE_COMMAND')) { |
|
1253
|
|
|
define('_RESIZE_COMMAND', _CONVERT_COMMAND . ' -quality ' . _IMG_CONVERT_QUALITE . ' -resize %xx%y! %src %dest'); |
|
1254
|
|
|
} |
|
1255
|
|
|
$vignette = $destination . "." . $format_sortie; |
|
1256
|
|
|
$commande = str_replace( |
|
1257
|
|
|
array('%x', '%y', '%src', '%dest'), |
|
1258
|
|
|
array( |
|
1259
|
|
|
$destWidth, |
|
1260
|
|
|
$destHeight, |
|
1261
|
|
|
escapeshellcmd($image), |
|
1262
|
|
|
escapeshellcmd($vignette) |
|
1263
|
|
|
), |
|
1264
|
|
|
_RESIZE_COMMAND); |
|
1265
|
|
|
spip_log($commande); |
|
1266
|
|
|
exec($commande); |
|
1267
|
|
|
if (!@file_exists($vignette)) { |
|
1268
|
|
|
spip_log("echec convert sur $vignette"); |
|
1269
|
|
|
|
|
1270
|
|
|
return; // echec commande |
|
1271
|
|
|
} |
|
1272
|
|
|
} |
|
1273
|
|
|
|
|
1274
|
|
|
// php5 imagemagick |
|
1275
|
|
|
elseif ($process == 'imagick') { |
|
1276
|
|
|
$vignette = "$destination." . $format_sortie; |
|
1277
|
|
|
|
|
1278
|
|
|
if (!class_exists('Imagick')) { |
|
1279
|
|
|
spip_log("Classe Imagick absente !", _LOG_ERREUR); |
|
1280
|
|
|
|
|
1281
|
|
|
return; |
|
1282
|
|
|
} |
|
1283
|
|
|
$imagick = new Imagick(); |
|
1284
|
|
|
$imagick->readImage($image); |
|
1285
|
|
|
$imagick->resizeImage($destWidth, $destHeight, Imagick::FILTER_LANCZOS, |
|
1286
|
|
|
1);//, IMAGICK_FILTER_LANCZOS, _IMG_IMAGICK_QUALITE / 100); |
|
1287
|
|
|
$imagick->writeImage($vignette); |
|
1288
|
|
|
|
|
1289
|
|
|
if (!@file_exists($vignette)) { |
|
1290
|
|
|
spip_log("echec imagick sur $vignette"); |
|
1291
|
|
|
|
|
1292
|
|
|
return; |
|
1293
|
|
|
} |
|
1294
|
|
|
} |
|
1295
|
|
|
|
|
1296
|
|
|
// netpbm |
|
1297
|
|
|
elseif ($process == "netpbm") { |
|
1298
|
|
|
if (!defined('_PNMSCALE_COMMAND')) { |
|
1299
|
|
|
define('_PNMSCALE_COMMAND', 'pnmscale'); |
|
1300
|
|
|
} // Securite : mes_options.php peut preciser le chemin absolu |
|
1301
|
|
|
if (_PNMSCALE_COMMAND == '') { |
|
1302
|
|
|
return; |
|
1303
|
|
|
} |
|
1304
|
|
|
$vignette = $destination . "." . $format_sortie; |
|
1305
|
|
|
$pnmtojpeg_command = str_replace("pnmscale", "pnmtojpeg", _PNMSCALE_COMMAND); |
|
1306
|
|
|
if ($format == "jpg") { |
|
1307
|
|
|
|
|
1308
|
|
|
$jpegtopnm_command = str_replace("pnmscale", "jpegtopnm", _PNMSCALE_COMMAND); |
|
1309
|
|
|
exec("$jpegtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette"); |
|
1310
|
|
|
if (!($s = @filesize($vignette))) { |
|
1311
|
|
|
spip_unlink($vignette); |
|
1312
|
|
|
} |
|
1313
|
|
|
if (!@file_exists($vignette)) { |
|
1314
|
|
|
spip_log("echec netpbm-jpg sur $vignette"); |
|
1315
|
|
|
|
|
1316
|
|
|
return; |
|
1317
|
|
|
} |
|
1318
|
|
|
} else { |
|
1319
|
|
|
if ($format == "gif") { |
|
1320
|
|
|
$giftopnm_command = str_replace("pnmscale", "giftopnm", _PNMSCALE_COMMAND); |
|
1321
|
|
|
exec("$giftopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette"); |
|
1322
|
|
|
if (!($s = @filesize($vignette))) { |
|
1323
|
|
|
spip_unlink($vignette); |
|
1324
|
|
|
} |
|
1325
|
|
|
if (!@file_exists($vignette)) { |
|
1326
|
|
|
spip_log("echec netpbm-gif sur $vignette"); |
|
1327
|
|
|
|
|
1328
|
|
|
return; |
|
1329
|
|
|
} |
|
1330
|
|
|
} else { |
|
1331
|
|
|
if ($format == "png") { |
|
1332
|
|
|
$pngtopnm_command = str_replace("pnmscale", "pngtopnm", _PNMSCALE_COMMAND); |
|
1333
|
|
|
exec("$pngtopnm_command $image | " . _PNMSCALE_COMMAND . " -width $destWidth | $pnmtojpeg_command > $vignette"); |
|
1334
|
|
|
if (!($s = @filesize($vignette))) { |
|
1335
|
|
|
spip_unlink($vignette); |
|
1336
|
|
|
} |
|
1337
|
|
|
if (!@file_exists($vignette)) { |
|
1338
|
|
|
spip_log("echec netpbm-png sur $vignette"); |
|
1339
|
|
|
|
|
1340
|
|
|
return; |
|
1341
|
|
|
} |
|
1342
|
|
|
} |
|
1343
|
|
|
} |
|
1344
|
|
|
} |
|
1345
|
|
|
} |
|
1346
|
|
|
|
|
1347
|
|
|
// gd ou gd2 |
|
1348
|
|
|
elseif ($process == 'gd1' or $process == 'gd2') { |
|
1349
|
|
|
if (!function_exists('gd_info')) { |
|
1350
|
|
|
spip_log("Librairie GD absente !", _LOG_ERREUR); |
|
1351
|
|
|
|
|
1352
|
|
|
return; |
|
1353
|
|
|
} |
|
1354
|
|
|
if (_IMG_GD_MAX_PIXELS && $srcWidth * $srcHeight > _IMG_GD_MAX_PIXELS) { |
|
1355
|
|
|
spip_log("vignette gd1/gd2 impossible : " . $srcWidth * $srcHeight . "pixels"); |
|
|
|
|
|
|
1356
|
|
|
|
|
1357
|
|
|
return; |
|
1358
|
|
|
} |
|
1359
|
|
|
$destFormat = $format_sortie; |
|
1360
|
|
|
if (!$destFormat) { |
|
1361
|
|
|
spip_log("pas de format pour $image"); |
|
1362
|
|
|
|
|
1363
|
|
|
return; |
|
1364
|
|
|
} |
|
1365
|
|
|
|
|
1366
|
|
|
$fonction_imagecreatefrom = $valeurs['fonction_imagecreatefrom']; |
|
1367
|
|
|
if (!function_exists($fonction_imagecreatefrom)) { |
|
1368
|
|
|
return ''; |
|
1369
|
|
|
} |
|
1370
|
|
|
$srcImage = @$fonction_imagecreatefrom($image); |
|
1371
|
|
|
if (!$srcImage) { |
|
1372
|
|
|
spip_log("echec gd1/gd2"); |
|
1373
|
|
|
|
|
1374
|
|
|
return; |
|
1375
|
|
|
} |
|
1376
|
|
|
|
|
1377
|
|
|
// Initialisation de l'image destination |
|
1378
|
|
|
$destImage = null; |
|
1379
|
|
|
if ($process == 'gd2' and $destFormat != "gif") { |
|
1380
|
|
|
$destImage = ImageCreateTrueColor($destWidth, $destHeight); |
|
1381
|
|
|
} |
|
1382
|
|
|
if (!$destImage) { |
|
1383
|
|
|
$destImage = ImageCreate($destWidth, $destHeight); |
|
1384
|
|
|
} |
|
1385
|
|
|
|
|
1386
|
|
|
// Recopie de l'image d'origine avec adaptation de la taille |
|
1387
|
|
|
$ok = false; |
|
1388
|
|
|
if (($process == 'gd2') and function_exists('ImageCopyResampled')) { |
|
1389
|
|
|
if ($format == "gif") { |
|
1390
|
|
|
// Si un GIF est transparent, |
|
1391
|
|
|
// fabriquer un PNG transparent |
|
1392
|
|
|
$transp = imagecolortransparent($srcImage); |
|
1393
|
|
|
if ($transp > 0) { |
|
1394
|
|
|
$destFormat = "png"; |
|
1395
|
|
|
} |
|
1396
|
|
|
} |
|
1397
|
|
|
if (in_array($destFormat, _image_extensions_conservent_transparence())) { |
|
1398
|
|
|
// Conserver la transparence |
|
1399
|
|
|
if (function_exists("imageAntiAlias")) { |
|
1400
|
|
|
imageAntiAlias($destImage, true); |
|
1401
|
|
|
} |
|
1402
|
|
|
@imagealphablending($destImage, false); |
|
|
|
|
|
|
1403
|
|
|
@imagesavealpha($destImage, true); |
|
|
|
|
|
|
1404
|
|
|
} |
|
1405
|
|
|
$ok = @ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight); |
|
1406
|
|
|
} |
|
1407
|
|
|
if (!$ok) { |
|
1408
|
|
|
$ok = ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight); |
|
|
|
|
|
|
1409
|
|
|
} |
|
1410
|
|
|
|
|
1411
|
|
|
// Sauvegarde de l'image destination |
|
1412
|
|
|
$valeurs['fichier_dest'] = $vignette = "$destination.$destFormat"; |
|
1413
|
|
|
$valeurs['format_dest'] = $format = $destFormat; |
|
1414
|
|
|
_image_gd_output($destImage, $valeurs); |
|
1415
|
|
|
|
|
1416
|
|
|
if ($srcImage) { |
|
1417
|
|
|
ImageDestroy($srcImage); |
|
1418
|
|
|
} |
|
1419
|
|
|
ImageDestroy($destImage); |
|
1420
|
|
|
} |
|
1421
|
|
|
|
|
1422
|
|
|
if (!$vignette or !$size = @spip_getimagesize($vignette)) { |
|
1423
|
|
|
$size = array($destWidth, $destHeight); |
|
1424
|
|
|
} |
|
1425
|
|
|
|
|
1426
|
|
|
// Gaffe: en safe mode, pas d'acces a la vignette, |
|
1427
|
|
|
// donc risque de balancer "width='0'", ce qui masque l'image sous MSIE |
|
1428
|
|
|
if ($size[0] < 1) { |
|
1429
|
|
|
$size[0] = $destWidth; |
|
1430
|
|
|
} |
|
1431
|
|
|
if ($size[1] < 1) { |
|
1432
|
|
|
$size[1] = $destHeight; |
|
1433
|
|
|
} |
|
1434
|
|
|
|
|
1435
|
|
|
$retour['width'] = $largeur = $size[0]; |
|
|
|
|
|
|
1436
|
|
|
$retour['height'] = $hauteur = $size[1]; |
|
|
|
|
|
|
1437
|
|
|
|
|
1438
|
|
|
$retour['fichier'] = $vignette; |
|
1439
|
|
|
$retour['format'] = $format; |
|
1440
|
|
|
$retour['date'] = @filemtime($vignette); |
|
1441
|
|
|
|
|
1442
|
|
|
// renvoyer l'image |
|
1443
|
|
|
return $retour; |
|
1444
|
|
|
} |
|
1445
|
|
|
|
|
1446
|
|
|
/** |
|
1447
|
|
|
* Réduire des dimensions en respectant un ratio |
|
1448
|
|
|
* |
|
1449
|
|
|
* Réduit des dimensions (hauteur, largeur) pour qu'elles |
|
1450
|
|
|
* soient incluses dans une hauteur et largeur maximum fournies |
|
1451
|
|
|
* en respectant la proportion d'origine |
|
1452
|
|
|
* |
|
1453
|
|
|
* @example `image_ratio(1000, 1000, 100, 10)` donne `array(10, 10, 100)` |
|
1454
|
|
|
* @see ratio_passe_partout() Assez proche. |
|
1455
|
|
|
* |
|
1456
|
|
|
* @param int $srcWidth Largeur de l'image source |
|
1457
|
|
|
* @param int $srcHeight Hauteur de l'image source |
|
1458
|
|
|
* @param int $maxWidth Largeur maximum souhaitée |
|
1459
|
|
|
* @param int $maxHeight Hauteur maximum souhaitée |
|
1460
|
|
|
* @return array Liste [ largeur, hauteur, ratio de réduction ] |
|
|
|
|
|
|
1461
|
|
|
**/ |
|
1462
|
|
View Code Duplication |
function _image_ratio($srcWidth, $srcHeight, $maxWidth, $maxHeight) { |
|
|
|
|
|
|
1463
|
|
|
$ratioWidth = $srcWidth / $maxWidth; |
|
1464
|
|
|
$ratioHeight = $srcHeight / $maxHeight; |
|
1465
|
|
|
|
|
1466
|
|
|
if ($srcWidth <= $maxWidth and $srcHeight <= $maxHeight) { |
|
1467
|
|
|
$destWidth = $srcWidth; |
|
1468
|
|
|
$destHeight = $srcHeight; |
|
1469
|
|
|
} elseif ($ratioWidth < $ratioHeight) { |
|
1470
|
|
|
$destWidth = $srcWidth / $ratioHeight; |
|
1471
|
|
|
$destHeight = $maxHeight; |
|
1472
|
|
|
} else { |
|
1473
|
|
|
$destWidth = $maxWidth; |
|
1474
|
|
|
$destHeight = $srcHeight / $ratioWidth; |
|
1475
|
|
|
} |
|
1476
|
|
|
|
|
1477
|
|
|
return array( |
|
1478
|
|
|
intval(round($destWidth)), |
|
1479
|
|
|
intval(round($destHeight)), |
|
1480
|
|
|
max($ratioWidth, $ratioHeight) |
|
1481
|
|
|
); |
|
1482
|
|
|
} |
|
1483
|
|
|
|
|
1484
|
|
|
/** |
|
1485
|
|
|
* Réduire des dimensions en respectant un ratio sur la plus petite dimension |
|
1486
|
|
|
* |
|
1487
|
|
|
* Réduit des dimensions (hauteur, largeur) pour qu'elles |
|
1488
|
|
|
* soient incluses dans la plus grande hauteur ou largeur maximum fournie |
|
1489
|
|
|
* en respectant la proportion d'origine |
|
1490
|
|
|
* |
|
1491
|
|
|
* @example `ratio_passe_partout(1000, 1000, 100, 10)` donne `array(100, 100, 10)` |
|
1492
|
|
|
* @see _image_ratio() Assez proche. |
|
1493
|
|
|
* |
|
1494
|
|
|
* @param int $srcWidth Largeur de l'image source |
|
1495
|
|
|
* @param int $srcHeight Hauteur de l'image source |
|
1496
|
|
|
* @param int $maxWidth Largeur maximum souhaitée |
|
1497
|
|
|
* @param int $maxHeight Hauteur maximum souhaitée |
|
1498
|
|
|
* @return array Liste [ largeur, hauteur, ratio de réduction ] |
|
|
|
|
|
|
1499
|
|
|
**/ |
|
1500
|
|
View Code Duplication |
function ratio_passe_partout($srcWidth, $srcHeight, $maxWidth, $maxHeight) { |
|
|
|
|
|
|
1501
|
|
|
$ratioWidth = $srcWidth / $maxWidth; |
|
1502
|
|
|
$ratioHeight = $srcHeight / $maxHeight; |
|
1503
|
|
|
|
|
1504
|
|
|
if ($srcWidth <= $maxWidth and $srcHeight <= $maxHeight) { |
|
1505
|
|
|
$destWidth = $srcWidth; |
|
1506
|
|
|
$destHeight = $srcHeight; |
|
1507
|
|
|
} elseif ($ratioWidth > $ratioHeight) { |
|
1508
|
|
|
$destWidth = $srcWidth / $ratioHeight; |
|
1509
|
|
|
$destHeight = $maxHeight; |
|
1510
|
|
|
} else { |
|
1511
|
|
|
$destWidth = $maxWidth; |
|
1512
|
|
|
$destHeight = $srcHeight / $ratioWidth; |
|
1513
|
|
|
} |
|
1514
|
|
|
|
|
1515
|
|
|
return array( |
|
1516
|
|
|
intval(round($destWidth)), |
|
1517
|
|
|
intval(round($destHeight)), |
|
1518
|
|
|
min($ratioWidth, $ratioHeight) |
|
1519
|
|
|
); |
|
1520
|
|
|
} |
|
1521
|
|
|
|
|
1522
|
|
|
|
|
1523
|
|
|
/** |
|
1524
|
|
|
* Fonction identite de traitement par defaut des images SVG |
|
1525
|
|
|
* (quand un filtre n'annonce pas qu'il sait traiter un SVG on applique cette fonction a la place) |
|
1526
|
|
|
* |
|
1527
|
|
|
* @param array $image |
|
1528
|
|
|
* tableau des valeurs crees par _image_valeurs_trans |
|
1529
|
|
|
* @return string |
|
1530
|
|
|
*/ |
|
1531
|
|
|
function process_image_svg_identite($image) { |
|
1532
|
|
|
if ($image['creer']) { |
|
1533
|
|
|
$source = $image['fichier']; |
|
1534
|
|
|
_image_gd_output($source, $image); |
|
1535
|
|
|
} |
|
1536
|
|
|
|
|
1537
|
|
|
return _image_ecrire_tag($image, array('src' => $image['fichier_dest'])); |
|
1538
|
|
|
} |
|
1539
|
|
|
|
|
1540
|
|
|
|
|
1541
|
|
|
/** |
|
1542
|
|
|
* Réduit une image |
|
1543
|
|
|
* |
|
1544
|
|
|
* @uses extraire_attribut() |
|
1545
|
|
|
* @uses inserer_attribut() |
|
1546
|
|
|
* @uses _image_valeurs_trans() |
|
1547
|
|
|
* @uses _image_ratio() |
|
1548
|
|
|
* @uses _image_tag_changer_taille() |
|
1549
|
|
|
* @uses _image_ecrire_tag() |
|
1550
|
|
|
* @uses _image_creer_vignette() |
|
1551
|
|
|
* |
|
1552
|
|
|
* @param array $fonction |
|
1553
|
|
|
* Un tableau à 2 éléments : |
|
1554
|
|
|
* 1) string : indique le nom du filtre de traitement demandé (par exemple : `image_reduire`) ; |
|
1555
|
|
|
* 2) array : tableau reprenant la valeur de `$img` et chacun des arguments passés au filtre utilisé. |
|
1556
|
|
|
* @param string $img |
|
1557
|
|
|
* Chemin de l'image ou texte contenant une balise img |
|
1558
|
|
|
* @param int $taille |
|
1559
|
|
|
* Largeur désirée |
|
1560
|
|
|
* @param int $taille_y |
|
1561
|
|
|
* Hauteur désirée |
|
1562
|
|
|
* @param bool $force |
|
1563
|
|
|
* @param string $process |
|
1564
|
|
|
* Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick). |
|
1565
|
|
|
* AUTO utilise la librairie sélectionnée dans la configuration. |
|
1566
|
|
|
* @return string |
|
1567
|
|
|
* Code HTML de la balise img produite |
|
1568
|
|
|
**/ |
|
1569
|
|
|
function process_image_reduire($fonction, $img, $taille, $taille_y, $force, $process = 'AUTO') { |
|
1570
|
|
|
$image = false; |
|
1571
|
|
View Code Duplication |
if (($process == 'AUTO') and isset($GLOBALS['meta']['image_process'])) { |
|
|
|
|
|
|
1572
|
|
|
$process = $GLOBALS['meta']['image_process']; |
|
1573
|
|
|
} |
|
1574
|
|
|
# determiner le format de sortie |
|
1575
|
|
|
$format_sortie = false; // le choix par defaut sera bon |
|
1576
|
|
|
if ($process == "netpbm") { |
|
1577
|
|
|
$format_sortie = "jpg"; |
|
1578
|
|
|
} elseif ($process == 'gd1' or $process == 'gd2') { |
|
1579
|
|
|
$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED); |
|
1580
|
|
|
// on verifie que l'extension choisie est bonne (en principe oui) |
|
1581
|
|
|
$gd_formats = formats_image_acceptables(true); |
|
1582
|
|
|
if (is_array($image) |
|
1583
|
|
|
and (!in_array($image['format_dest'], $gd_formats) |
|
1584
|
|
|
or (!in_array($image['format_dest'], _image_extensions_acceptees_en_sortie())) |
|
1585
|
|
|
) |
|
1586
|
|
|
) { |
|
1587
|
|
|
if ($image['format_source'] == 'jpg') { |
|
1588
|
|
|
$formats_sortie = array('jpg', 'png', 'gif'); |
|
1589
|
|
|
} else // les gif sont passes en png preferentiellement pour etre homogene aux autres filtres images |
|
1590
|
|
|
{ |
|
1591
|
|
|
$formats_sortie = array('png', 'jpg', 'gif'); |
|
1592
|
|
|
} |
|
1593
|
|
|
// Choisir le format destination |
|
1594
|
|
|
// - on sauve de preference en JPEG (meilleure compression) |
|
1595
|
|
|
// - pour le GIF : les GD recentes peuvent le lire mais pas l'ecrire |
|
1596
|
|
|
# bug : gd_formats contient la liste des fichiers qu'on sait *lire*, |
|
1597
|
|
|
# pas *ecrire* |
|
1598
|
|
|
$format_sortie = ""; |
|
1599
|
|
|
foreach ($formats_sortie as $fmt) { |
|
1600
|
|
|
if (in_array($fmt, $gd_formats) and in_array($fmt, _image_extensions_acceptees_en_sortie())) { |
|
1601
|
|
|
$format_sortie = $fmt; |
|
1602
|
|
|
break; |
|
1603
|
|
|
} |
|
1604
|
|
|
} |
|
1605
|
|
|
$image = false; |
|
1606
|
|
|
} |
|
1607
|
|
|
} |
|
1608
|
|
|
|
|
1609
|
|
|
if (!is_array($image)) { |
|
1610
|
|
|
$image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}", $format_sortie, $fonction, false, _SVG_SUPPORTED); |
|
1611
|
|
|
} |
|
1612
|
|
|
|
|
1613
|
|
|
if (!is_array($image) or !$image['largeur'] or !$image['hauteur']) { |
|
1614
|
|
|
spip_log("image_reduire_src:pas de version locale de $img"); |
|
1615
|
|
|
// on peut resizer en mode html si on dispose des elements |
|
1616
|
|
|
if ($srcw = extraire_attribut($img, 'width') |
|
1617
|
|
|
and $srch = extraire_attribut($img, 'height') |
|
1618
|
|
|
) { |
|
1619
|
|
|
list($w, $h) = _image_ratio($srcw, $srch, $taille, $taille_y); |
|
1620
|
|
|
|
|
1621
|
|
|
return _image_tag_changer_taille($img, $w, $h); |
|
1622
|
|
|
} |
|
1623
|
|
|
// la on n'a pas d'infos sur l'image source... on refile le truc a css |
|
1624
|
|
|
// sous la forme style='max-width: NNpx;' |
|
1625
|
|
|
return inserer_attribut($img, 'style', |
|
1626
|
|
|
"max-width: ${taille}px; max-height: ${taille_y}px"); |
|
1627
|
|
|
} |
|
1628
|
|
|
|
|
1629
|
|
|
// si l'image est plus petite que la cible retourner une copie cachee de l'image |
|
1630
|
|
|
if (($image['largeur'] <= $taille) && ($image['hauteur'] <= $taille_y)) { |
|
1631
|
|
|
if ($image['creer']) { |
|
1632
|
|
|
@copy($image['fichier'], $image['fichier_dest']); |
|
|
|
|
|
|
1633
|
|
|
} |
|
1634
|
|
|
|
|
1635
|
|
|
return _image_ecrire_tag($image, array('src' => $image['fichier_dest'])); |
|
1636
|
|
|
} |
|
1637
|
|
|
|
|
1638
|
|
|
if ($image['creer'] == false && !$force) { |
|
1639
|
|
|
return _image_ecrire_tag($image, |
|
1640
|
|
|
array('src' => $image['fichier_dest'], 'width' => $image['largeur_dest'], 'height' => $image['hauteur_dest'])); |
|
1641
|
|
|
} |
|
1642
|
|
|
|
|
1643
|
|
|
if (in_array($image["format_source"], _image_extensions_acceptees_en_entree())) { |
|
1644
|
|
|
$destWidth = $image['largeur_dest']; |
|
1645
|
|
|
$destHeight = $image['hauteur_dest']; |
|
1646
|
|
|
$logo = $image['fichier']; |
|
1647
|
|
|
$date = $image["date_src"]; |
|
1648
|
|
|
$preview = _image_creer_vignette($image, $taille, $taille_y, $process, $force); |
|
1649
|
|
|
|
|
1650
|
|
|
if ($preview && $preview['fichier']) { |
|
1651
|
|
|
$logo = $preview['fichier']; |
|
1652
|
|
|
$destWidth = $preview['width']; |
|
1653
|
|
|
$destHeight = $preview['height']; |
|
1654
|
|
|
$date = $preview['date']; |
|
1655
|
|
|
} |
|
1656
|
|
|
// dans l'espace prive mettre un timestamp sur l'adresse |
|
1657
|
|
|
// de l'image, de facon a tromper le cache du navigateur |
|
1658
|
|
|
// quand on fait supprimer/reuploader un logo |
|
1659
|
|
|
// (pas de filemtime si SAFE MODE) |
|
1660
|
|
|
$date = test_espace_prive() ? ('?' . $date) : ''; |
|
1661
|
|
|
|
|
1662
|
|
|
return _image_ecrire_tag($image, array('src' => "$logo$date", 'width' => $destWidth, 'height' => $destHeight)); |
|
1663
|
|
|
} |
|
1664
|
|
|
else { |
|
1665
|
|
|
# BMP, tiff ... les redacteurs osent tout! |
|
1666
|
|
|
return $img; |
|
1667
|
|
|
} |
|
1668
|
|
|
} |
|
1669
|
|
|
|
|
1670
|
|
|
/** |
|
1671
|
|
|
* Produire des fichiers au format .ico |
|
1672
|
|
|
* |
|
1673
|
|
|
* Avec du code récupéré de phpThumb() |
|
1674
|
|
|
* |
|
1675
|
|
|
* @author James Heinrich <[email protected]> |
|
1676
|
|
|
* @link http://phpthumb.sourceforge.net |
|
1677
|
|
|
* |
|
1678
|
|
|
* Class phpthumb_functions |
|
1679
|
|
|
*/ |
|
1680
|
|
|
class phpthumb_functions { |
|
1681
|
|
|
|
|
1682
|
|
|
/** |
|
1683
|
|
|
* Retourne la couleur d'un pixel dans une image |
|
1684
|
|
|
* |
|
1685
|
|
|
* @param ressource $img |
|
1686
|
|
|
* @param int $x |
|
1687
|
|
|
* @param int $y |
|
1688
|
|
|
* @return array|bool |
|
1689
|
|
|
*/ |
|
1690
|
|
|
public static function GetPixelColor(&$img, $x, $y) { |
|
1691
|
|
|
if (is_resource($img) || (is_object($img) && $img instanceof \GdImage)) { |
|
|
|
|
|
|
1692
|
|
|
return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y)); |
|
1693
|
|
|
} |
|
1694
|
|
|
return false; |
|
1695
|
|
|
} |
|
1696
|
|
|
|
|
1697
|
|
|
/** |
|
1698
|
|
|
* Retourne un nombre dans une représentation en Little Endian |
|
1699
|
|
|
* |
|
1700
|
|
|
* @param int $number |
|
1701
|
|
|
* @param int $minbytes |
|
1702
|
|
|
* @return string |
|
1703
|
|
|
*/ |
|
1704
|
|
|
public static function LittleEndian2String($number, $minbytes = 1) { |
|
1705
|
|
|
$intstring = ''; |
|
1706
|
|
|
while ($number > 0) { |
|
1707
|
|
|
$intstring = $intstring . chr($number & 255); |
|
1708
|
|
|
$number >>= 8; |
|
1709
|
|
|
} |
|
1710
|
|
|
|
|
1711
|
|
|
return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); |
|
1712
|
|
|
} |
|
1713
|
|
|
|
|
1714
|
|
|
/** |
|
1715
|
|
|
* Transforme une ressource GD en image au format ICO |
|
1716
|
|
|
* |
|
1717
|
|
|
* @param array $gd_image_array |
|
1718
|
|
|
* Tableau de ressources d'images GD |
|
1719
|
|
|
* @return string |
|
1720
|
|
|
* Image au format ICO |
|
1721
|
|
|
*/ |
|
1722
|
|
|
public static function GD2ICOstring(&$gd_image_array) { |
|
1723
|
|
|
foreach ($gd_image_array as $key => $gd_image) { |
|
1724
|
|
|
|
|
1725
|
|
|
$ImageWidths[$key] = ImageSX($gd_image); |
|
|
|
|
|
|
1726
|
|
|
$ImageHeights[$key] = ImageSY($gd_image); |
|
|
|
|
|
|
1727
|
|
|
$bpp[$key] = ImageIsTrueColor($gd_image) ? 32 : 24; |
|
|
|
|
|
|
1728
|
|
|
$totalcolors[$key] = ImageColorsTotal($gd_image); |
|
|
|
|
|
|
1729
|
|
|
|
|
1730
|
|
|
$icXOR[$key] = ''; |
|
|
|
|
|
|
1731
|
|
|
for ($y = $ImageHeights[$key] - 1; $y >= 0; $y--) { |
|
|
|
|
|
|
1732
|
|
|
for ($x = 0; $x < $ImageWidths[$key]; $x++) { |
|
|
|
|
|
|
1733
|
|
|
$argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y); |
|
1734
|
|
|
$a = round(255 * ((127 - $argb['alpha']) / 127)); |
|
1735
|
|
|
$r = $argb['red']; |
|
1736
|
|
|
$g = $argb['green']; |
|
1737
|
|
|
$b = $argb['blue']; |
|
1738
|
|
|
|
|
1739
|
|
|
if ($bpp[$key] == 32) { |
|
1740
|
|
|
$icXOR[$key] .= chr($b) . chr($g) . chr($r) . chr($a); |
|
|
|
|
|
|
1741
|
|
|
} elseif ($bpp[$key] == 24) { |
|
|
|
|
|
|
1742
|
|
|
$icXOR[$key] .= chr($b) . chr($g) . chr($r); |
|
1743
|
|
|
} |
|
1744
|
|
|
|
|
1745
|
|
|
if ($a < 128) { |
|
1746
|
|
|
@$icANDmask[$key][$y] .= '1'; |
|
|
|
|
|
|
1747
|
|
|
} else { |
|
1748
|
|
|
@$icANDmask[$key][$y] .= '0'; |
|
|
|
|
|
|
1749
|
|
|
} |
|
1750
|
|
|
} |
|
1751
|
|
|
// mask bits are 32-bit aligned per scanline |
|
1752
|
|
|
while (strlen($icANDmask[$key][$y]) % 32) { |
|
1753
|
|
|
$icANDmask[$key][$y] .= '0'; |
|
1754
|
|
|
} |
|
1755
|
|
|
} |
|
1756
|
|
|
$icAND[$key] = ''; |
|
|
|
|
|
|
1757
|
|
|
foreach ($icANDmask[$key] as $y => $scanlinemaskbits) { |
|
1758
|
|
|
for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) { |
|
1759
|
|
|
$icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT))); |
|
|
|
|
|
|
1760
|
|
|
} |
|
1761
|
|
|
} |
|
1762
|
|
|
|
|
1763
|
|
|
} |
|
1764
|
|
|
|
|
1765
|
|
|
foreach ($gd_image_array as $key => $gd_image) { |
|
1766
|
|
|
$biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8); |
|
1767
|
|
|
|
|
1768
|
|
|
// BITMAPINFOHEADER - 40 bytes |
|
1769
|
|
|
$BitmapInfoHeader[$key] = ''; |
|
|
|
|
|
|
1770
|
|
|
$BitmapInfoHeader[$key] .= "\x28\x00\x00\x00"; // DWORD biSize; |
|
1771
|
|
|
$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4); // LONG biWidth; |
|
1772
|
|
|
// The biHeight member specifies the combined |
|
1773
|
|
|
// height of the XOR and AND masks. |
|
1774
|
|
|
$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG biHeight; |
|
1775
|
|
|
$BitmapInfoHeader[$key] .= "\x01\x00"; // WORD biPlanes; |
|
1776
|
|
|
$BitmapInfoHeader[$key] .= chr($bpp[$key]) . "\x00"; // wBitCount; |
|
1777
|
|
|
$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biCompression; |
|
1778
|
|
|
$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4); // DWORD biSizeImage; |
|
1779
|
|
|
$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // LONG biXPelsPerMeter; |
|
1780
|
|
|
$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // LONG biYPelsPerMeter; |
|
1781
|
|
|
$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biClrUsed; |
|
1782
|
|
|
$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biClrImportant; |
|
1783
|
|
|
} |
|
1784
|
|
|
|
|
1785
|
|
|
|
|
1786
|
|
|
$icondata = "\x00\x00"; // idReserved; // Reserved (must be 0) |
|
1787
|
|
|
$icondata .= "\x01\x00"; // idType; // Resource Type (1 for icons) |
|
1788
|
|
|
$icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2); // idCount; // How many images? |
|
1789
|
|
|
|
|
1790
|
|
|
$dwImageOffset = 6 + (count($gd_image_array) * 16); |
|
1791
|
|
|
foreach ($gd_image_array as $key => $gd_image) { |
|
1792
|
|
|
// ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em) |
|
1793
|
|
|
|
|
1794
|
|
|
$icondata .= chr($ImageWidths[$key]); // bWidth; // Width, in pixels, of the image |
|
1795
|
|
|
$icondata .= chr($ImageHeights[$key]); // bHeight; // Height, in pixels, of the image |
|
1796
|
|
|
$icondata .= chr($totalcolors[$key]); // bColorCount; // Number of colors in image (0 if >=8bpp) |
|
|
|
|
|
|
1797
|
|
|
$icondata .= "\x00"; // bReserved; // Reserved ( must be 0) |
|
1798
|
|
|
|
|
1799
|
|
|
$icondata .= "\x01\x00"; // wPlanes; // Color Planes |
|
1800
|
|
|
$icondata .= chr($bpp[$key]) . "\x00"; // wBitCount; // Bits per pixel |
|
1801
|
|
|
|
|
1802
|
|
|
$dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]); |
|
1803
|
|
|
$icondata .= phpthumb_functions::LittleEndian2String($dwBytesInRes, |
|
1804
|
|
|
4); // dwBytesInRes; // How many bytes in this resource? |
|
1805
|
|
|
|
|
1806
|
|
|
$icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset, |
|
1807
|
|
|
4); // dwImageOffset; // Where in the file is this image? |
|
1808
|
|
|
$dwImageOffset += strlen($BitmapInfoHeader[$key]); |
|
|
|
|
|
|
1809
|
|
|
$dwImageOffset += strlen($icXOR[$key]); |
|
1810
|
|
|
$dwImageOffset += strlen($icAND[$key]); |
|
1811
|
|
|
} |
|
1812
|
|
|
|
|
1813
|
|
|
foreach ($gd_image_array as $key => $gd_image) { |
|
1814
|
|
|
$icondata .= $BitmapInfoHeader[$key]; |
|
1815
|
|
|
$icondata .= $icXOR[$key]; |
|
1816
|
|
|
$icondata .= $icAND[$key]; |
|
1817
|
|
|
} |
|
1818
|
|
|
|
|
1819
|
|
|
return $icondata; |
|
1820
|
|
|
} |
|
1821
|
|
|
|
|
1822
|
|
|
} |
|
1823
|
|
|
|
This check looks for the generic type
arrayas a return type and suggests a more specific type. This type is inferred from the actual code.