[SPIP] ~v3.0.20-->v3.0.25
[lhc/web/clavette_www.git] / www / ecrire / inc / filtres_images_lib_mini.php
1 <?php
2
3 /* *************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2016 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details 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\image
18 */
19
20
21 if (!defined('_ECRIRE_INC_VERSION')) return;
22 include_spip('inc/filtres'); // par precaution
23 include_spip('inc/filtres_images_mini'); // par precaution
24
25 /**
26 * Transforme une couleur vectorielle R,G,B en hexa (par exemple pour usage css)
27 *
28 * @param int $red
29 * Valeur du rouge de 0 à 255.
30 * @param int $green
31 * Valeur du vert de 0 à 255.
32 * @param int $blue
33 * Valeur du bleu de 0 à 255.
34 * @return string
35 * le code de la couleur en hexadécimal.
36 */
37 function _couleur_dec_to_hex($red, $green, $blue) {
38 $red = dechex($red);
39 $green = dechex($green);
40 $blue = dechex($blue);
41
42 if (strlen($red) == 1) $red = "0".$red;
43 if (strlen($green) == 1) $green = "0".$green;
44 if (strlen($blue) == 1) $blue = "0".$blue;
45
46 return "$red$green$blue";
47 }
48
49 /**
50 * Transforme une couleur hexa en vectorielle R,G,B
51 *
52 * @param string $couleur
53 * Code couleur en hexa (#000000 à #FFFFFF).
54 * @return array
55 * Un tableau des 3 éléments : rouge, vert, bleu.
56 */
57 function _couleur_hex_to_dec($couleur) {
58 $couleur = couleur_html_to_hex($couleur);
59 $couleur = preg_replace(",^#,","",$couleur);
60 $retour["red"] = hexdec(substr($couleur, 0, 2));
61 $retour["green"] = hexdec(substr($couleur, 2, 2));
62 $retour["blue"] = hexdec(substr($couleur, 4, 2));
63
64 return $retour;
65 }
66
67
68 /**
69 * Donne un statut au fichier-image intermédiaire servant au traitement d'image
70 * selon qu'il doit être gravé (fichier .src) ou pas.
71 * Un appel php direct aux fonctions de filtre d'image produira ainsi une image
72 * permanente (gravée) ; un appel généré par le compilateur via
73 * filtrer('image_xx, ...) effacera automatiquement le fichier-image temporaire.
74 *
75 * @param bool|string $stat
76 * true, false ou le statut déjà défini si traitements enchaînés.
77 * @return bool
78 * true si il faut supprimer le fichier temporaire ; false sinon.
79 */
80 function statut_effacer_images_temporaires($stat){
81 static $statut = false; // par defaut on grave toute les images
82 if ($stat==='get') return $statut;
83 $statut = $stat?true:false;
84 }
85
86
87 /**
88 * Fonctions de traitement d'image
89 * Uniquement pour GD2.
90 *
91 * @param string $img
92 * Un tag html <img src=... />.
93 * @param string $effet
94 * Les nom et paramètres de l'effet à apporter sur l'image
95 * (par exemple : reduire-300-200).
96 * @param bool|string $forcer_format
97 * Un nom d'extension spécifique demandé (par exemple : jpg, png, txt...
98 * par défaut false : GD se débrouille seule).
99 * @param array $fonction_creation
100 * Un tableau à 2 éléments. Le premier (string) indique le nom du
101 * filtre de traitement demandé (par exemple : image_reduire) ; le
102 * second (array) est lui-même un tableau reprenant la valeur de $img
103 * et chacun des paramètres passés au filtre.
104 * @param bool $find_in_path
105 * false (par défaut) indique que l'on travaille sur un fichier
106 * temporaire (.src) ; true, sur un fichier définitif déjà existant.
107 * @return bool|string|array
108 * false si pas de tag <img,
109 * si l'extension n'existe pas,
110 * si le fichier source n'existe pas,
111 * si les dimensions de la source ne sont pas accessibles,
112 * si le fichier temporaire n'existe pas,
113 * si la fonction _imagecreatefrom{extension} n'existe pas ;
114 * "" (chaîne vide) si le fichier source est distant et n'a pas
115 * réussi à être copié sur le serveur ;
116 * l'appel à la fonction pipeline image_preparer_filtre.
117 */
118 function _image_valeurs_trans($img, $effet, $forcer_format = false, $fonction_creation = NULL, $find_in_path = false) {
119 static $images_recalcul = array();
120 if (strlen($img)==0) return false;
121
122 $source = trim(extraire_attribut($img, 'src'));
123 if (strlen($source) < 1){
124 $source = $img;
125 $img = "<img src='$source' />";
126 }
127 # gerer img src="data:....base64"
128 else if (preg_match('@^data:image/(jpe?g|png|gif);base64,(.*)$@isS', $source, $regs)) {
129 $local = sous_repertoire(_DIR_VAR,'image-data').md5($regs[2]).'.'.str_replace('jpeg', 'jpg', $regs[1]);
130 if (!file_exists($local)) {
131 ecrire_fichier($local, base64_decode($regs[2]));
132 }
133 $source = $local;
134 $img = inserer_attribut($img, 'src', $source);
135 # eviter les mauvaises surprises lors de conversions de format
136 $img = inserer_attribut($img, 'width', '');
137 $img = inserer_attribut($img, 'height', '');
138 }
139
140 // les protocoles web prennent au moins 3 lettres
141 if (preg_match(';^(\w{3,7}://);', $source)){
142 include_spip('inc/distant');
143 $fichier = _DIR_RACINE . copie_locale($source);
144 if (!$fichier) return "";
145 } else {
146 // enlever le timestamp eventuel
147 $source=preg_replace(',[?][0-9]+$,','',$source);
148 if (strpos($source,"?")!==false
149 AND strncmp($source,_DIR_IMG,strlen(_DIR_IMG))==0
150 AND file_exists($f=preg_replace(',[?].*$,','',$source))){
151 $source = $f;
152 }
153 $fichier = $source;
154 }
155
156 $terminaison_dest = "";
157 if (preg_match(",\.(gif|jpe?g|png)($|[?]),i", $fichier, $regs)) {
158 $terminaison = strtolower($regs[1]);
159 $terminaison_dest = $terminaison;
160
161 if ($terminaison == "gif") $terminaison_dest = "png";
162 }
163 if ($forcer_format!==false) $terminaison_dest = $forcer_format;
164
165 if (!$terminaison_dest) return false;
166
167 $term_fonction = $terminaison;
168 if ($term_fonction == "jpg") $term_fonction = "jpeg";
169
170 $nom_fichier = substr($fichier, 0, strlen($fichier) - (strlen($terminaison) + 1));
171 $fichier_dest = $nom_fichier;
172 if (($find_in_path AND $f=find_in_path($fichier) AND $fichier=$f)
173 OR @file_exists($f = $fichier)){
174 // on passe la balise img a taille image qui exraira les attributs si possible
175 // au lieu de faire un acces disque sur le fichier
176 list ($ret["hauteur"],$ret["largeur"]) = taille_image($find_in_path?$f:$img);
177 $date_src = @filemtime($f);
178 }
179 elseif (@file_exists($f = "$fichier.src")
180 AND lire_fichier($f,$valeurs)
181 AND $valeurs=unserialize($valeurs)
182 AND isset($valeurs["hauteur_dest"])
183 AND isset($valeurs["largeur_dest"])) {
184 $ret["hauteur"] = $valeurs["hauteur_dest"];
185 $ret["largeur"] = $valeurs["largeur_dest"];
186 $date_src = $valeurs["date"];
187 }
188 // pas de fichier source par la
189 else
190 return false;
191
192 // pas de taille mesurable
193 if (!($ret["hauteur"] OR $ret["largeur"]))
194 return false;
195
196
197 // cas general :
198 // on a un dossier cache commun et un nom de fichier qui varie avec l'effet
199 // cas particulier de reduire :
200 // un cache par dimension, et le nom de fichier est conserve, suffixe par la dimension aussi
201 $cache = "cache-gd2";
202 if (substr($effet,0,7)=='reduire') {
203 list(,$maxWidth,$maxHeight) = explode('-',$effet);
204 list ($destWidth,$destHeight) = _image_ratio($ret['largeur'], $ret['hauteur'], $maxWidth, $maxHeight);
205 $ret['largeur_dest'] = $destWidth;
206 $ret['hauteur_dest'] = $destHeight;
207 $effet = "L{$destWidth}xH$destHeight";
208 $cache = "cache-vignettes";
209 $fichier_dest = basename($fichier_dest);
210 if (($ret['largeur']<=$maxWidth)&&($ret['hauteur']<=$maxHeight)){
211 // on garde la terminaison initiale car image simplement copiee
212 // et on postfixe son nom avec un md5 du path
213 $terminaison_dest = $terminaison;
214 $fichier_dest .= '-'.substr(md5("$fichier"),0,5);
215 }
216 else
217 $fichier_dest .= '-'.substr(md5("$fichier-$effet"),0,5);
218 $cache = sous_repertoire(_DIR_VAR, $cache);
219 $cache = sous_repertoire($cache, $effet);
220 # cherche un cache existant
221 /*foreach (array('gif','jpg','png') as $fmt)
222 if (@file_exists($cache . $fichier_dest . '.' . $fmt)) {
223 $terminaison_dest = $fmt;
224 }*/
225 }
226 else {
227 $fichier_dest = md5("$fichier-$effet");
228 $cache = sous_repertoire(_DIR_VAR, $cache);
229 }
230
231 $fichier_dest = $cache . $fichier_dest . "." .$terminaison_dest;
232
233 $GLOBALS["images_calculees"][] = $fichier_dest;
234
235 $creer = true;
236 // si recalcul des images demande, recalculer chaque image une fois
237 if (defined('_VAR_IMAGES') AND _VAR_IMAGES AND !isset($images_recalcul[$fichier_dest])){
238 $images_recalcul[$fichier_dest] = true;
239 }
240 else {
241 if (@file_exists($f = $fichier_dest)){
242 if (filemtime($f)>=$date_src)
243 $creer = false;
244 }
245 else if (@file_exists($f = "$fichier_dest.src")
246 AND lire_fichier($f,$valeurs)
247 AND $valeurs=unserialize($valeurs)
248 AND $valeurs["date"]>=$date_src)
249 $creer = false;
250 }
251 if ($creer) {
252 if (!@file_exists($fichier)) {
253 if (!@file_exists("$fichier.src")) {
254 spip_log("Image absente : $fichier");
255 return false;
256 }
257 # on reconstruit l'image source absente a partir de la chaine des .src
258 reconstruire_image_intermediaire($fichier);
259 }
260 }
261
262 if ($creer)
263 spip_log("filtre image ".($fonction_creation?reset($fonction_creation):'')."[$effet] sur $fichier","images"._LOG_DEBUG);
264
265 // TODO: si une image png est nommee .jpg, le reconnaitre avec le bon $f
266 $ret["fonction_imagecreatefrom"] = "_imagecreatefrom".$term_fonction;
267 $ret["fichier"] = $fichier;
268 $ret["fonction_image"] = "_image_image".$terminaison_dest;
269 $ret["fichier_dest"] = $fichier_dest;
270 $ret["format_source"] = ($terminaison != 'jpeg' ? $terminaison : 'jpg');
271 $ret["format_dest"] = $terminaison_dest;
272 $ret["date_src"] = $date_src;
273 $ret["creer"] = $creer;
274 $ret["class"] = extraire_attribut($img, 'class');
275 $ret["alt"] = extraire_attribut($img, 'alt');
276 $ret["style"] = extraire_attribut($img, 'style');
277 $ret["tag"] = $img;
278 if ($fonction_creation){
279 $ret["reconstruction"] = $fonction_creation;
280 # ecrire ici comment creer le fichier, car il est pas sur qu'on l'ecrira reelement
281 # cas de image_reduire qui finalement ne reduit pas l'image source
282 # ca evite d'essayer de le creer au prochain hit si il n'est pas la
283 #ecrire_fichier($ret['fichier_dest'].'.src',serialize($ret),true);
284 }
285
286 $ret = pipeline('image_preparer_filtre',array(
287 'args'=>array(
288 'img'=>$img,
289 'effet'=>$effet,
290 'forcer_format'=>$forcer_format,
291 'fonction_creation'=>$fonction_creation,
292 'find_in_path'=>$find_in_path,
293 ),
294 'data'=>$ret)
295 );
296
297 // une globale pour le debug en cas de crash memoire
298 $GLOBALS["derniere_image_calculee"] = $ret;
299
300 if (!function_exists($ret["fonction_imagecreatefrom"])) return false;
301 return $ret;
302 }
303
304 /**
305 * Crée une image depuis un fichier ou une URL
306 * Utilise les fonctions spécifiques GD.
307 *
308 * @param string $filename
309 * Le path vers l'image à traiter (par exemple : IMG/distant/jpg/image.jpg
310 * ou local/cache-vignettes/L180xH51/image.jpg).
311 * @return ressource
312 * Une ressource de type Image GD.
313 */
314 function _imagecreatefromjpeg($filename){
315 $img = @imagecreatefromjpeg($filename);
316 if (!$img) {
317 spip_log("Erreur lecture imagecreatefromjpeg $filename",_LOG_CRITIQUE);
318 erreur_squelette("Erreur lecture imagecreatefromjpeg $filename");
319 $img = imagecreate(10,10);
320 }
321 return $img;
322 }
323
324 /**
325 * Crée une image depuis un fichier ou une URL
326 * Utilise les fonctions spécifiques GD.
327 *
328 * @param string $filename
329 * Le path vers l'image à traiter (par exemple : IMG/distant/png/image.png
330 * ou local/cache-vignettes/L180xH51/image.png).
331 * @return ressource
332 * Une ressource de type Image GD.
333 */
334 function _imagecreatefrompng($filename){
335 $img = @imagecreatefrompng($filename);
336 if (!$img) {
337 spip_log("Erreur lecture imagecreatefrompng $filename",_LOG_CRITIQUE);
338 erreur_squelette("Erreur lecture imagecreatefrompng $filename");
339 $img = imagecreate(10,10);
340 }
341 return $img;
342 }
343
344 /**
345 * Crée une image depuis un fichier ou une URL
346 * Utilise les fonctions spécifiques GD.
347 *
348 * @param string $filename
349 * Le path vers l'image à traiter (par exemple : IMG/distant/gif/image.gif
350 * ou local/cache-vignettes/L180xH51/image.gif).
351 * @return ressource
352 * Une ressource de type Image GD.
353 */
354 function _imagecreatefromgif($filename){
355 $img = @imagecreatefromgif($filename);
356 if (!$img) {
357 spip_log("Erreur lecture imagecreatefromgif $filename",_LOG_CRITIQUE);
358 erreur_squelette("Erreur lecture imagecreatefromgif $filename");
359 $img = imagecreate(10,10);
360 }
361 return $img;
362 }
363
364 /**
365 * Affiche ou sauvegarde une image au format PNG
366 * Utilise les fonctions spécifiques GD.
367 *
368 * @param ressource $img
369 * Une ressource de type Image GD.
370 * @param string $fichier
371 * Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png).
372 * @return bool
373 * false si l'image créée a une largeur nulle ou n'existe pas ;
374 * true si une image est bien retournée.
375 */
376 function _image_imagepng($img, $fichier) {
377 if (!function_exists('imagepng')) return false;
378 $tmp = $fichier.".tmp";
379 $ret = imagepng($img,$tmp);
380
381 if(file_exists($tmp)){
382 $taille_test = getimagesize($tmp);
383 if ($taille_test[0] < 1) return false;
384
385 spip_unlink($fichier); // le fichier peut deja exister
386 @rename($tmp, $fichier);
387 return $ret;
388 }
389 return false;
390 }
391
392 /**
393 * Affiche ou sauvegarde une image au format GIF
394 * Utilise les fonctions spécifiques GD.
395 *
396 * @param ressource $img
397 * Une ressource de type Image GD.
398 * @param string $fichier
399 * Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.gif).
400 * @return bool
401 * false si l'image créée a une largeur nulle ou n'existe pas;
402 * true si une image est bien retournée.
403 */
404 function _image_imagegif($img,$fichier) {
405 if (!function_exists('imagegif')) return false;
406 $tmp = $fichier.".tmp";
407 $ret = imagegif($img,$tmp);
408
409 if(file_exists($tmp)){
410 $taille_test = getimagesize($tmp);
411 if ($taille_test[0] < 1) return false;
412
413 spip_unlink($fichier); // le fichier peut deja exister
414 @rename($tmp, $fichier);
415 return $ret;
416 }
417 return false;
418 }
419
420 /**
421 * Affiche ou sauvegarde une image au format JPG
422 * Utilise les fonctions spécifiques GD.
423 *
424 * @param ressource $img
425 * Une ressource de type Image GD.
426 * @param string $fichier
427 * Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg).
428 * @param int $qualite
429 * Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit
430 * fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la
431 * valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis
432 * mes_options.php).
433 * @return bool
434 * false si l'image créée a une largeur nulle ou n'existe pas ;
435 * true si une image est bien retournée.
436 */
437 function _image_imagejpg($img,$fichier,$qualite=_IMG_GD_QUALITE) {
438 if (!function_exists('imagejpeg')) return false;
439 $tmp = $fichier.".tmp";
440 $ret = imagejpeg($img,$tmp, $qualite);
441
442 if(file_exists($tmp)){
443 $taille_test = getimagesize($tmp);
444 if ($taille_test[0] < 1) return false;
445
446 spip_unlink($fichier); // le fichier peut deja exister
447 @rename($tmp, $fichier);
448 return $ret;
449 }
450 return false;
451 }
452
453 /**
454 * Crée un fichier-image au format ICO
455 * Utilise les fonctions de la classe phpthumb_functions.
456 *
457 * @param ressource $img
458 * Une ressource de type Image GD.
459 * @param string $fichier
460 * Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg).
461 * @return bool
462 * true si le fichier a bien été créé ; false sinon.
463 */
464 function _image_imageico($img, $fichier) {
465 $gd_image_array = array($img);
466
467 return ecrire_fichier($fichier, phpthumb_functions::GD2ICOstring($gd_image_array));
468 }
469
470 /**
471 * Finalise le traitement GD
472 * Crée un fichier_image temporaire .src ou vérifie que le fichier_image
473 * définitif a bien été créé.
474 *
475 * @param ressource $img
476 * Une ressource de type Image GD.
477 * @param array $valeurs
478 * Un tableau des informations (tailles, traitement, path...) accompagnant
479 * l'image.
480 * @param int $qualite
481 * N'est utilisé que pour les images jpg.
482 * Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit
483 * fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la
484 * valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis
485 * mes_options.php).
486 * @return bool
487 * true si le traitement GD s'est bien finalisé ;
488 * false sinon.
489 */
490 function _image_gd_output($img,$valeurs, $qualite=_IMG_GD_QUALITE){
491 $fonction = "_image_image".$valeurs['format_dest'];
492 $ret = false;
493 #un flag pour reperer les images gravees
494 $lock =
495 !statut_effacer_images_temporaires('get') // si la fonction n'a pas ete activee, on grave tout
496 OR (@file_exists($valeurs['fichier_dest']) AND !@file_exists($valeurs['fichier_dest'].'.src'));
497 if (
498 function_exists($fonction)
499 && ($ret = $fonction($img,$valeurs['fichier_dest'],$qualite)) # on a reussi a creer l'image
500 && isset($valeurs['reconstruction']) # et on sait comment la resonctruire le cas echeant
501 && !$lock
502 )
503 if (@file_exists($valeurs['fichier_dest'])){
504 // dans tous les cas mettre a jour la taille de l'image finale
505 list ($valeurs["hauteur_dest"],$valeurs["largeur_dest"]) = taille_image($valeurs['fichier_dest']);
506 $valeurs['date'] = @filemtime($valeurs['fichier_dest']); // pour la retrouver apres disparition
507 ecrire_fichier($valeurs['fichier_dest'].'.src',serialize($valeurs),true);
508 }
509 return $ret;
510 }
511
512 // http://doc.spip.org/@reconstruire_image_intermediaire
513 function reconstruire_image_intermediaire($fichier_manquant){
514 $reconstruire = array();
515 $fichier = $fichier_manquant;
516 while (strpos($fichier,"://")===false
517 and !@file_exists($fichier)
518 AND lire_fichier($src = "$fichier.src",$source)
519 AND $valeurs=unserialize($source)
520 AND ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
521 ) {
522 spip_unlink($src); // si jamais on a un timeout pendant la reconstruction, elle se fera naturellement au hit suivant
523 $reconstruire[] = $valeurs['reconstruction'];
524 }
525 while (count($reconstruire)){
526 $r = array_pop($reconstruire);
527 $fonction = $r[0];
528 $args = $r[1];
529 call_user_func_array($fonction, $args);
530 }
531 // cette image intermediaire est commune a plusieurs series de filtre, il faut la conserver
532 // mais l'on peut nettoyer les miettes de sa creation
533 ramasse_miettes($fichier_manquant);
534 }
535
536 /**
537 * Indique qu'un fichier d'image calculé est à conserver
538 *
539 * Permet de rendre une image définitive et de supprimer les images
540 * intermédiaires à son calcul.
541 *
542 * Supprime le fichier de contrôle de l’image cible (le $fichier.src)
543 * ce qui indique que l'image est définitive.
544 *
545 * Remonte ensuite la chaîne des fichiers de contrôle pour supprimer
546 * les images temporaires (mais laisse les fichiers de contrôle permettant
547 * de les reconstruire).
548 *
549 * @param string $fichier
550 * Chemin du fichier d'image calculé
551 **/
552 function ramasse_miettes($fichier) {
553 if (strpos($fichier,"://")!==false
554 or !lire_fichier($src = "$fichier.src", $source)
555 or !$valeurs = unserialize($source)
556 ) {
557 return;
558 }
559 spip_unlink($src); # on supprime la reference a sa source pour marquer cette image comme non intermediaire
560 while (
561 ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
562 AND (substr($fichier,0,strlen(_DIR_VAR))==_DIR_VAR) # et est dans local
563 AND (lire_fichier($src = "$fichier.src",$source)) # le fichier a une source connue (c'est donc une image calculee intermediaire)
564 AND ($valeurs=unserialize($source)) # et valide
565 ) {
566 # on efface le fichier
567 spip_unlink($fichier);
568 # mais laisse le .src qui permet de savoir comment reconstruire l'image si besoin
569 #spip_unlink($src);
570 }
571 }
572
573 // http://doc.spip.org/@image_graver
574 function image_graver($img){
575 // appeler le filtre post_image_filtrer qui permet de faire
576 // des traitements auto a la fin d'une serie de filtres
577 $img = pipeline('post_image_filtrer',$img);
578
579 $fichier = extraire_attribut($img, 'src');
580 if (($p=strpos($fichier,'?'))!==FALSE)
581 $fichier=substr($fichier,0,$p);
582 if (strlen($fichier) < 1)
583 $fichier = $img;
584 # si jamais le fichier final n'a pas ete calcule car suppose temporaire
585 # et qu'il ne s'agit pas d'une URL
586 if (strpos($fichier,"://")===false and !@file_exists($fichier)) {
587 reconstruire_image_intermediaire($fichier);
588 }
589 ramasse_miettes($fichier);
590 return $img; // on ne change rien
591 }
592
593 // Transforme une image a palette indexee (256 couleurs max) en "vraies" couleurs RGB
594 // Existe seulement pour compatibilite avec PHP < 5.5
595 // http://doc.spip.org/@imagepalettetotruecolor
596 if (!function_exists("imagepalettetotruecolor")) {
597 function imagepalettetotruecolor(&$img) {
598 if ($img AND !imageistruecolor($img) AND function_exists('imagecreatetruecolor')) {
599 $w = imagesx($img);
600 $h = imagesy($img);
601 $img1 = imagecreatetruecolor($w,$h);
602 //Conserver la transparence si possible
603 if(function_exists('ImageCopyResampled')) {
604 if (function_exists("imageAntiAlias")) imageAntiAlias($img1,true);
605 @imagealphablending($img1, false);
606 @imagesavealpha($img1,true);
607 @ImageCopyResampled($img1, $img, 0, 0, 0, 0, $w, $h, $w, $h);
608 } else {
609 imagecopy($img1,$img,0,0,0,0,$w,$h);
610 }
611
612 $img = $img1;
613 }
614 }
615 }
616
617 // http://doc.spip.org/@image_tag_changer_taille
618 function _image_tag_changer_taille($tag,$width,$height,$style=false){
619 if ($style===false) $style = extraire_attribut($tag,'style');
620 // enlever le width et height du style
621 $style = preg_replace(",(^|;)\s*(width|height)\s*:\s*[^;]+,ims","",$style);
622 if ($style AND $style{0}==';') $style=substr($style,1);
623 // mettre des attributs de width et height sur les images,
624 // ca accelere le rendu du navigateur
625 // ca permet aux navigateurs de reserver la bonne taille
626 // quand on a desactive l'affichage des images.
627 $tag = inserer_attribut($tag,'width',$width);
628 $tag = inserer_attribut($tag,'height',$height);
629
630 // Ancien style inline pour IE6 mais qui casse la possibilité de surcharger en CSS
631 //$style = "height:".$height."px;width:".$width."px;".$style;
632
633 // attributs deprecies. Transformer en CSS
634 if ($espace = extraire_attribut($tag, 'hspace')){
635 $style = "margin:${espace}px;".$style;
636 $tag = inserer_attribut($tag,'hspace','');
637 }
638 $tag = inserer_attribut($tag,'style',$style, true, $style ? false : true);
639 return $tag;
640 }
641
642 // function d'ecriture du de la balise img en sortie des filtre image
643 // reprend le tag initial et surcharge les tags modifies
644 function _image_ecrire_tag($valeurs,$surcharge=array()){
645 $valeurs = pipeline('image_ecrire_tag_preparer',$valeurs);
646
647 $tag = str_replace(">","/>",str_replace("/>",">",$valeurs['tag'])); // fermer les tags img pas bien fermes;
648
649 // le style
650 $style = $valeurs['style'];
651 if (isset($surcharge['style'])){
652 $style = $surcharge['style'];
653 unset($surcharge['style']);
654 }
655
656 // traiter specifiquement la largeur et la hauteur
657 $width = $valeurs['largeur'];
658 if (isset($surcharge['width'])){
659 $width = $surcharge['width'];
660 unset($surcharge['width']);
661 }
662 $height = $valeurs['hauteur'];
663 if (isset($surcharge['height'])){
664 $height = $surcharge['height'];
665 unset($surcharge['height']);
666 }
667
668 $tag = _image_tag_changer_taille($tag,$width,$height,$style);
669 // traiter specifiquement le src qui peut etre repris dans un onmouseout
670 // on remplace toute les ref a src dans le tag
671 $src = extraire_attribut($tag,'src');
672 if (isset($surcharge['src'])){
673 $tag = str_replace($src,$surcharge['src'],$tag);
674 // si il y a des & dans src, alors ils peuvent provenir d'un &amp
675 // pas garanti comme methode, mais mieux que rien
676 if (strpos($src,'&') !== false)
677 $tag = str_replace(str_replace("&","&amp;",$src),$surcharge['src'],$tag);
678 $src = $surcharge['src'];
679 unset($surcharge['src']);
680 }
681
682 $class = $valeurs['class'];
683 if (isset($surcharge['class'])){
684 $class = $surcharge['class'];
685 unset($surcharge['class']);
686 }
687 if(strlen($class))
688 $tag = inserer_attribut($tag,'class',$class);
689
690 if (count($surcharge))
691 foreach($surcharge as $attribut=>$valeur)
692 $tag = inserer_attribut($tag,$attribut,$valeur);
693
694 $tag = pipeline('image_ecrire_tag_finir',
695 array(
696 'args' => array(
697 'valeurs' => $valeurs,
698 'surcharge' => $surcharge,
699 ),
700 'data' => $tag
701 )
702 );
703
704 return $tag;
705 }
706
707 function _image_creer_vignette($valeurs, $maxWidth, $maxHeight, $process='AUTO', $force=false, $test_cache_only = false) {
708 // ordre de preference des formats graphiques pour creer les vignettes
709 // le premier format disponible, selon la methode demandee, est utilise
710 $image = $valeurs['fichier'];
711 $format = $valeurs['format_source'];
712 $destdir = dirname($valeurs['fichier_dest']);
713 $destfile = basename($valeurs['fichier_dest'],".".$valeurs["format_dest"]);
714
715 $format_sortie = $valeurs['format_dest'];
716
717 // liste des formats qu'on sait lire
718 $img = isset($GLOBALS['meta']['formats_graphiques'])
719 ? (strpos($GLOBALS['meta']['formats_graphiques'], $format)!==false)
720 : false;
721
722 // si le doc n'est pas une image, refuser
723 if (!$force AND !$img) return;
724 $destination = "$destdir/$destfile";
725
726 // chercher un cache
727 $vignette = '';
728 if ($test_cache_only AND !$vignette) return;
729
730 // utiliser le cache ?
731 if (!$test_cache_only)
732 if ($force OR !$vignette OR (@filemtime($vignette) < @filemtime($image))) {
733
734 $creation = true;
735 // calculer la taille
736 if (($srcWidth=$valeurs['largeur']) && ($srcHeight=$valeurs['hauteur'])){
737 if (!($destWidth=$valeurs['largeur_dest']) || !($destHeight=$valeurs['hauteur_dest']))
738 list ($destWidth,$destHeight) = _image_ratio($valeurs['largeur'], $valeurs['hauteur'], $maxWidth, $maxHeight);
739 }
740 elseif ($process == 'convert' OR $process == 'imagick') {
741 $destWidth = $maxWidth;
742 $destHeight = $maxHeight;
743 } else {
744 spip_log("echec $process sur $image");
745 return;
746 }
747
748 // Si l'image est de la taille demandee (ou plus petite), simplement
749 // la retourner
750 if ($srcWidth
751 AND $srcWidth <= $maxWidth AND $srcHeight <= $maxHeight) {
752 $vignette = $destination.'.'.$format;
753 @copy($image, $vignette);
754 }
755 // imagemagick en ligne de commande
756 else if ($process == 'convert') {
757 define('_CONVERT_COMMAND', 'convert');
758 define ('_RESIZE_COMMAND', _CONVERT_COMMAND.' -quality '._IMG_CONVERT_QUALITE.' -resize %xx%y! %src %dest');
759 $vignette = $destination.".".$format_sortie;
760 $commande = str_replace(
761 array('%x', '%y', '%src', '%dest'),
762 array(
763 $destWidth,
764 $destHeight,
765 escapeshellcmd($image),
766 escapeshellcmd($vignette)
767 ),
768 _RESIZE_COMMAND);
769 spip_log($commande);
770 exec($commande);
771 if (!@file_exists($vignette)) {
772 spip_log("echec convert sur $vignette");
773 return; // echec commande
774 }
775 }
776 else
777 // imagick (php4-imagemagick)
778 if ($process == 'imagick') {
779
780 $vignette = "$destination.".$format_sortie;
781
782 $imagick = new Imagick();
783 $imagick->readImage($image);
784 $imagick->resizeImage($destWidth, $destHeight, Imagick::FILTER_LANCZOS, 1 );//, IMAGICK_FILTER_LANCZOS, _IMG_IMAGICK_QUALITE / 100);
785 $imagick->writeImage($vignette);
786
787 if (!@file_exists($vignette)) {
788 spip_log("echec imagick sur $vignette");
789 return;
790 }
791 }
792 else
793 // netpbm
794 if ($process == "netpbm") {
795 define('_PNMSCALE_COMMAND', 'pnmscale'); // chemin a changer dans mes_options
796 if (_PNMSCALE_COMMAND == '') return;
797 $vignette = $destination.".".$format_sortie;
798 $pnmtojpeg_command = str_replace("pnmscale", "pnmtojpeg", _PNMSCALE_COMMAND);
799 if ($format == "jpg") {
800
801 $jpegtopnm_command = str_replace("pnmscale", "jpegtopnm", _PNMSCALE_COMMAND);
802 exec("$jpegtopnm_command $image | "._PNMSCALE_COMMAND." -width $destWidth | $pnmtojpeg_command > $vignette");
803 if (!($s = @filesize($vignette)))
804 spip_unlink($vignette);
805 if (!@file_exists($vignette)) {
806 spip_log("echec netpbm-jpg sur $vignette");
807 return;
808 }
809 } else if ($format == "gif") {
810 $giftopnm_command = str_replace("pnmscale", "giftopnm", _PNMSCALE_COMMAND);
811 exec("$giftopnm_command $image | "._PNMSCALE_COMMAND." -width $destWidth | $pnmtojpeg_command > $vignette");
812 if (!($s = @filesize($vignette)))
813 spip_unlink($vignette);
814 if (!@file_exists($vignette)) {
815 spip_log("echec netpbm-gif sur $vignette");
816 return;
817 }
818 } else if ($format == "png") {
819 $pngtopnm_command = str_replace("pnmscale", "pngtopnm", _PNMSCALE_COMMAND);
820 exec("$pngtopnm_command $image | "._PNMSCALE_COMMAND." -width $destWidth | $pnmtojpeg_command > $vignette");
821 if (!($s = @filesize($vignette)))
822 spip_unlink($vignette);
823 if (!@file_exists($vignette)) {
824 spip_log("echec netpbm-png sur $vignette");
825 return;
826 }
827 }
828 }
829 // gd ou gd2
830 else if ($process == 'gd1' OR $process == 'gd2') {
831 if (_IMG_GD_MAX_PIXELS && $srcWidth*$srcHeight>_IMG_GD_MAX_PIXELS){
832 spip_log("vignette gd1/gd2 impossible : ".$srcWidth*$srcHeight."pixels");
833 return;
834 }
835 $destFormat = $format_sortie;
836 if (!$destFormat) {
837 spip_log("pas de format pour $image");
838 return;
839 }
840
841 $fonction_imagecreatefrom = $valeurs['fonction_imagecreatefrom'];
842 if (!function_exists($fonction_imagecreatefrom))
843 return '';
844 $srcImage = @$fonction_imagecreatefrom($image);
845 if (!$srcImage) {
846 spip_log("echec gd1/gd2");
847 return;
848 }
849
850 // Initialisation de l'image destination
851 if ($process == 'gd2' AND $destFormat != "gif")
852 $destImage = ImageCreateTrueColor($destWidth, $destHeight);
853 if (!$destImage)
854 $destImage = ImageCreate($destWidth, $destHeight);
855
856 // Recopie de l'image d'origine avec adaptation de la taille
857 $ok = false;
858 if (($process == 'gd2') AND function_exists('ImageCopyResampled')) {
859 if ($format == "gif") {
860 // Si un GIF est transparent,
861 // fabriquer un PNG transparent
862 $transp = imagecolortransparent($srcImage);
863 if ($transp > 0) $destFormat = "png";
864 }
865 if ($destFormat == "png") {
866 // Conserver la transparence
867 if (function_exists("imageAntiAlias")) imageAntiAlias($destImage,true);
868 @imagealphablending($destImage, false);
869 @imagesavealpha($destImage,true);
870 }
871 $ok = @ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
872 }
873 if (!$ok)
874 $ok = ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
875
876 // Sauvegarde de l'image destination
877 $valeurs['fichier_dest'] = $vignette = "$destination.$destFormat";
878 $valeurs['format_dest'] = $format = $destFormat;
879 _image_gd_output($destImage,$valeurs);
880
881 if ($srcImage)
882 ImageDestroy($srcImage);
883 ImageDestroy($destImage);
884 }
885 }
886 $size = @getimagesize($vignette);
887 // Gaffe: en safe mode, pas d'acces a la vignette,
888 // donc risque de balancer "width='0'", ce qui masque l'image sous MSIE
889 if ($size[0] < 1) $size[0] = $destWidth;
890 if ($size[1] < 1) $size[1] = $destHeight;
891
892 $retour['width'] = $largeur = $size[0];
893 $retour['height'] = $hauteur = $size[1];
894
895 $retour['fichier'] = $vignette;
896 $retour['format'] = $format;
897 $retour['date'] = @filemtime($vignette);
898
899 // renvoyer l'image
900 return $retour;
901 }
902
903 // Calculer le ratio
904 // http://doc.spip.org/@image_ratio
905 function _image_ratio ($srcWidth, $srcHeight, $maxWidth, $maxHeight) {
906 $ratioWidth = $srcWidth/$maxWidth;
907 $ratioHeight = $srcHeight/$maxHeight;
908
909 if ($ratioWidth <=1 AND $ratioHeight <=1) {
910 $destWidth = $srcWidth;
911 $destHeight = $srcHeight;
912 } else if ($ratioWidth < $ratioHeight) {
913 $destWidth = $srcWidth/$ratioHeight;
914 $destHeight = $maxHeight;
915 }
916 else {
917 $destWidth = $maxWidth;
918 $destHeight = $srcHeight/$ratioWidth;
919 }
920 return array (ceil($destWidth), ceil($destHeight),
921 max($ratioWidth,$ratioHeight));
922 }
923
924 // Calculer le ratio ajuste sur la plus petite dimension
925 // http://doc.spip.org/@ratio_passe_partout
926 function ratio_passe_partout ($srcWidth, $srcHeight, $maxWidth, $maxHeight) {
927 $ratioWidth = $srcWidth/$maxWidth;
928 $ratioHeight = $srcHeight/$maxHeight;
929
930 if ($ratioWidth <=1 AND $ratioHeight <=1) {
931 $destWidth = $srcWidth;
932 $destHeight = $srcHeight;
933 } else if ($ratioWidth > $ratioHeight) {
934 $destWidth = $srcWidth/$ratioHeight;
935 $destHeight = $maxHeight;
936 }
937 else {
938 $destWidth = $maxWidth;
939 $destHeight = $srcHeight/$ratioWidth;
940 }
941 return array (ceil($destWidth), ceil($destHeight),
942 min($ratioWidth,$ratioHeight));
943 }
944
945 // http://doc.spip.org/@process_image_reduire
946 function process_image_reduire($fonction,$img,$taille,$taille_y,$force,$cherche_image,$process){
947 $image = false;
948 if (($process == 'AUTO') AND isset($GLOBALS['meta']['image_process']))
949 $process = $GLOBALS['meta']['image_process'];
950 # determiner le format de sortie
951 $format_sortie = false; // le choix par defaut sera bon
952 if ($process == "netpbm") $format_sortie = "jpg";
953 else if ($process == 'gd1' OR $process == 'gd2') {
954 $image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}",$format_sortie,$fonction);
955
956 // on verifie que l'extension choisie est bonne (en principe oui)
957 $gd_formats = explode(',',$GLOBALS['meta']["gd_formats"]);
958 if (!in_array($image['format_dest'],$gd_formats)
959 OR ($image['format_dest']=='gif' AND !function_exists('ImageGif'))
960 ) {
961 if ($image['format_source'] == 'jpg')
962 $formats_sortie = array('jpg','png','gif');
963 else // les gif sont passes en png preferentiellement pour etre homogene aux autres filtres images
964 $formats_sortie = array('png','jpg','gif');
965 // Choisir le format destination
966 // - on sauve de preference en JPEG (meilleure compression)
967 // - pour le GIF : les GD recentes peuvent le lire mais pas l'ecrire
968 # bug : gd_formats contient la liste des fichiers qu'on sait *lire*,
969 # pas *ecrire*
970 $format_sortie = "";
971 foreach ($formats_sortie as $fmt) {
972 if (in_array($fmt, $gd_formats)) {
973 if ($fmt <> "gif" OR function_exists('ImageGif'))
974 $format_sortie = $fmt;
975 break;
976 }
977 }
978 $image = false;
979 }
980 }
981
982 if (!$image)
983 $image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}",$format_sortie,$fonction);
984
985 if (!$image OR !$image['largeur'] OR !$image['hauteur']){
986 spip_log("image_reduire_src:pas de version locale de $img");
987 // on peut resizer en mode html si on dispose des elements
988 if ($srcw = extraire_attribut($img, 'width')
989 AND $srch = extraire_attribut($img, 'height')) {
990 list($w,$h) = _image_ratio($srcw, $srch, $taille, $taille_y);
991 return _image_tag_changer_taille($img,$w,$h);
992 }
993 // la on n'a pas d'infos sur l'image source... on refile le truc a css
994 // sous la forme style='max-width: NNpx;'
995 return inserer_attribut($img, 'style',
996 "max-width: ${taille}px; max-height: ${taille_y}px");
997 }
998
999 // si l'image est plus petite que la cible retourner une copie cachee de l'image
1000 if (($image['largeur']<=$taille)&&($image['hauteur']<=$taille_y)){
1001 if ($image['creer']){
1002 @copy($image['fichier'], $image['fichier_dest']);
1003 }
1004 return _image_ecrire_tag($image,array('src'=>$image['fichier_dest']));
1005 }
1006
1007 if ($image['creer']==false && !$force)
1008 return _image_ecrire_tag($image,array('src'=>$image['fichier_dest'],'width'=>$image['largeur_dest'],'height'=>$image['hauteur_dest']));
1009
1010 if (in_array($image["format_source"],array('jpg','gif','png'))){
1011 $destWidth = $image['largeur_dest'];
1012 $destHeight = $image['hauteur_dest'];
1013 $logo = $image['fichier'];
1014 $date = $image["date_src"];
1015 $preview = _image_creer_vignette($image, $taille, $taille_y,$process,$force);
1016
1017 if ($preview && $preview['fichier']) {
1018 $logo = $preview['fichier'];
1019 $destWidth = $preview['width'];
1020 $destHeight = $preview['height'];
1021 $date = $preview['date'];
1022 }
1023 // dans l'espace prive mettre un timestamp sur l'adresse
1024 // de l'image, de facon a tromper le cache du navigateur
1025 // quand on fait supprimer/reuploader un logo
1026 // (pas de filemtime si SAFE MODE)
1027 $date = test_espace_prive() ? ('?'.$date) : '';
1028 return _image_ecrire_tag($image,array('src'=>"$logo$date",'width'=>$destWidth,'height'=>$destHeight));
1029 }
1030 else
1031 # SVG par exemple ? BMP, tiff ... les redacteurs osent tout!
1032 return $img;
1033 }
1034
1035 /**
1036 * Produire des fichiers au format .ico
1037 * avec du code recupere de :
1038 * phpThumb() by James Heinrich <info@silisoftware.com>
1039 * available at http://phpthumb.sourceforge.net
1040 *
1041 * Class phpthumb_functions
1042 */
1043 class phpthumb_functions {
1044
1045 /**
1046 * @param ressource $img
1047 * @param int $x
1048 * @param int $y
1049 * @return array|bool
1050 */
1051 public static function GetPixelColor(&$img, $x, $y) {
1052 if (!is_resource($img)) {
1053 return false;
1054 }
1055 return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y));
1056 }
1057
1058 /**
1059 * @param int $number
1060 * @param int $minbytes
1061 * @return string
1062 */
1063 public static function LittleEndian2String($number, $minbytes=1) {
1064 $intstring = '';
1065 while ($number > 0) {
1066 $intstring = $intstring.chr($number & 255);
1067 $number >>= 8;
1068 }
1069 return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
1070 }
1071
1072 /**
1073 * @param array $gd_image_array
1074 * @return string
1075 */
1076 public static function GD2ICOstring(&$gd_image_array) {
1077 foreach ($gd_image_array as $key => $gd_image) {
1078
1079 $ImageWidths[$key] = ImageSX($gd_image);
1080 $ImageHeights[$key] = ImageSY($gd_image);
1081 $bpp[$key] = ImageIsTrueColor($gd_image) ? 32 : 24;
1082 $totalcolors[$key] = ImageColorsTotal($gd_image);
1083
1084 $icXOR[$key] = '';
1085 for ($y = $ImageHeights[$key] - 1; $y >= 0; $y--) {
1086 for ($x = 0; $x < $ImageWidths[$key]; $x++) {
1087 $argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
1088 $a = round(255 * ((127 - $argb['alpha']) / 127));
1089 $r = $argb['red'];
1090 $g = $argb['green'];
1091 $b = $argb['blue'];
1092
1093 if ($bpp[$key] == 32) {
1094 $icXOR[$key] .= chr($b).chr($g).chr($r).chr($a);
1095 } elseif ($bpp[$key] == 24) {
1096 $icXOR[$key] .= chr($b).chr($g).chr($r);
1097 }
1098
1099 if ($a < 128) {
1100 @$icANDmask[$key][$y] .= '1';
1101 } else {
1102 @$icANDmask[$key][$y] .= '0';
1103 }
1104 }
1105 // mask bits are 32-bit aligned per scanline
1106 while (strlen($icANDmask[$key][$y]) % 32) {
1107 $icANDmask[$key][$y] .= '0';
1108 }
1109 }
1110 $icAND[$key] = '';
1111 foreach ($icANDmask[$key] as $y => $scanlinemaskbits) {
1112 for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) {
1113 $icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT)));
1114 }
1115 }
1116
1117 }
1118
1119 foreach ($gd_image_array as $key => $gd_image) {
1120 $biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8);
1121
1122 // BITMAPINFOHEADER - 40 bytes
1123 $BitmapInfoHeader[$key] = '';
1124 $BitmapInfoHeader[$key] .= "\x28\x00\x00\x00"; // DWORD biSize;
1125 $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4); // LONG biWidth;
1126 // The biHeight member specifies the combined
1127 // height of the XOR and AND masks.
1128 $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG biHeight;
1129 $BitmapInfoHeader[$key] .= "\x01\x00"; // WORD biPlanes;
1130 $BitmapInfoHeader[$key] .= chr($bpp[$key])."\x00"; // wBitCount;
1131 $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biCompression;
1132 $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4); // DWORD biSizeImage;
1133 $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // LONG biXPelsPerMeter;
1134 $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // LONG biYPelsPerMeter;
1135 $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biClrUsed;
1136 $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biClrImportant;
1137 }
1138
1139
1140 $icondata = "\x00\x00"; // idReserved; // Reserved (must be 0)
1141 $icondata .= "\x01\x00"; // idType; // Resource Type (1 for icons)
1142 $icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2); // idCount; // How many images?
1143
1144 $dwImageOffset = 6 + (count($gd_image_array) * 16);
1145 foreach ($gd_image_array as $key => $gd_image) {
1146 // ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
1147
1148 $icondata .= chr($ImageWidths[$key]); // bWidth; // Width, in pixels, of the image
1149 $icondata .= chr($ImageHeights[$key]); // bHeight; // Height, in pixels, of the image
1150 $icondata .= chr($totalcolors[$key]); // bColorCount; // Number of colors in image (0 if >=8bpp)
1151 $icondata .= "\x00"; // bReserved; // Reserved ( must be 0)
1152
1153 $icondata .= "\x01\x00"; // wPlanes; // Color Planes
1154 $icondata .= chr($bpp[$key])."\x00"; // wBitCount; // Bits per pixel
1155
1156 $dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]);
1157 $icondata .= phpthumb_functions::LittleEndian2String($dwBytesInRes, 4); // dwBytesInRes; // How many bytes in this resource?
1158
1159 $icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset, 4); // dwImageOffset; // Where in the file is this image?
1160 $dwImageOffset += strlen($BitmapInfoHeader[$key]);
1161 $dwImageOffset += strlen($icXOR[$key]);
1162 $dwImageOffset += strlen($icAND[$key]);
1163 }
1164
1165 foreach ($gd_image_array as $key => $gd_image) {
1166 $icondata .= $BitmapInfoHeader[$key];
1167 $icondata .= $icXOR[$key];
1168 $icondata .= $icAND[$key];
1169 }
1170
1171 return $icondata;
1172 }
1173
1174 }
1175
1176 ?>