source: spip-zone/_plugins_/adaptive_images/trunk/preview/image_geometrize.php @ 115933

Last change on this file since 115933 was 115933, checked in by cedric@…, 6 weeks ago

Passage en production des methodes alternatives de generation de vignette apercu (gradients, potrace, geometrize) activable dans la page de config du plugin
+ mise a jour de la lib geometrize, en partie refactoree et optimisee
+ un mode debug activable par la config pour voir les apercus au survol des images (permet de tester sur un echantillon d'image et de choisir la methode la plus adaptee au site)

File size: 9.2 KB
Line 
1<?php
2/**
3 * Generation d'une preview svg
4 *
5 * @plugin     Adaptive Images
6 * @copyright  2013-2019
7 * @author     Cedric
8 * @licence    GNU/GPL
9 * @package    SPIP\Adaptive_Images\Preview
10 */
11
12
13/**
14 * Generation d'une preview svg a base de geometrize
15 *
16 * @param string $img
17 * @param array $options
18 * @return string
19 */
20function preview_image_geometrize_dist($img, $options){
21        static $deja = [];
22
23        // seulement un calcul par image par hit pour ne pas surcharger si la meme image apparait plusieurs fois dans la page
24        if (isset($deja[$img])) {
25                return $deja[$img];
26        }
27
28        include_spip("inc/filtres_images_lib_mini");
29        include_spip('filtres/couleurs');
30        include_spip('lib/geometrize/geometrize.init');
31
32        // dimension de la miniature a vectoriser
33        $geometrize_options = [
34                // toutes ces shapes sont viables : rapides a calculer et compact a l'export SVG
35                // "shapeTypes" => [geometrize_shape_ShapeTypes::T_TRIANGLE,geometrize_shape_ShapeTypes::T_RECTANGLE,geometrize_shape_ShapeTypes::T_LINE],
36                // mais c'est plus joli avec juste des triangles :)
37                "shapeTypes" => [geometrize_shape_ShapeTypes::T_TRIANGLE],
38                "alpha" => 255, // beaucoup plus rapide qu'avec une transparence
39                "candidateShapesPerStep" => 100,
40                "shapeMutationsPerStep" => 75,
41                "steps" => 85, // budget pour une taille acceptable de miniature (~4ko en texte, 2ko en Base 64+Gzip)
42        ];
43        if (defined('_ADAPTIVE_IMAGES_GEOMETRIZE_SHAPES')) {
44                $geometrize_options['shapeTypes'] = explode(',', _ADAPTIVE_IMAGES_GEOMETRIZE_SHAPES);
45        }
46
47        $time_budget = 5; // temps maxi en secondes par iteration
48
49        // le premieres iterations sont sur une petite miniature
50        // et plus on veut de details plus on augmente la taille de l'image de travail
51        // les sizes sont tricky pour avoir un x rescale = 2 = (129 - 1) / (65 - 1) car on rescale de 0 à 64px -> 0 à 128px
52        $resize_strategy = [
53                65 => 20,
54                129 => 100,
55                257 => 1000,
56                513 => 5000,
57        ];
58
59        $cache = _image_valeurs_trans($img, "svg-thumb-geometrize-" . json_encode($geometrize_options), "svg");
60        if (!$cache){
61                return false;
62        }
63
64        $fichier = $cache["fichier"];
65        $dest = $cache["fichier_dest"];
66
67        if ($cache["creer"]){
68                if (!@file_exists($fichier)){
69                        return false;
70                }
71
72                $runnerVersion = 2;
73                $runner = false;
74                $results = [];
75                $couleur_bg = _image_couleur_moyenne($fichier);
76                //$couleur_bg = couleur_extraire($fichier);
77                $width_thumb = array_keys($resize_strategy);
78                $width_thumb = reset($width_thumb);
79
80                if (file_exists("$dest.runner")){
81                        lire_fichier("$dest.runner", $r);
82                        if ($r = unserialize($r)
83                                and $version = array_shift($r)
84                                and $version === $runnerVersion){
85                                list($runner, $results) = $r;
86                                $w = $runner->model->width;
87                                $h = $runner->model->height;
88
89                                foreach ($resize_strategy as $wt => $n){
90                                        if ($wt<=$w){
91                                                $width_thumb = $wt;
92                                        }
93                                }
94                        }
95                        unset($r);
96                }
97
98                if (!$runner){
99                        list($runner, $results) = _init_geometrize_runner($img, $width_thumb, $couleur_bg);
100                        $w = $runner->model->width;
101                        $h = $runner->model->height;
102                }
103
104                //var_dump("WIDTHUMB $width_thumb");
105
106                $start_time = time();
107                spip_timer('runner');
108                for ($i = count($results); $i<$geometrize_options['steps']; $i++){
109
110                        // faut-il passer a une taille de vignette superieure ?
111                        if ($i>$resize_strategy[$width_thumb]){
112
113                                foreach ($resize_strategy as $wt => $n){
114                                        $width_thumb = $wt;
115                                        if ($n>$i){
116                                                break;
117                                        }
118                                }
119
120                                //var_dump("NEW WIDTHUMB $width_thumb");
121                                if ($width_thumb>$runner->model->width){
122                                        // reinit le modele et resizer les shapes au passage
123                                        list($runner, $results) = _init_geometrize_runner($img, $width_thumb, $couleur_bg, $results);
124                                        $w = $runner->model->width;
125                                        $h = $runner->model->height;
126                                }
127                        }
128
129                        $r = $runner->step($geometrize_options);
130                        $results = array_merge($results,$r);
131                        if (time()>$start_time+$time_budget){
132                                break;
133                        }
134                }
135                $time_compute = spip_timer('runner');
136
137                //var_dump($r,'<hr/>',$results);
138
139                $svg_image = trim(geometrize_exporter_SvgExporter::export($results, $w, $h));
140
141                $svg_image = explode('>', $svg_image, 2);
142                if (strpos($svg_image[0], "<" . "?xml")===0){
143                        $svg_image = explode('>', trim($svg_image[1]), 2);
144                }
145
146                $t = $svg_image[0] . '>';
147                $w = extraire_attribut($t, "width")-1;
148                $h = extraire_attribut($t, "height")-1;
149
150                $svg_image[0] = "<svg viewBox=\"0 0 $w $h\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"$w\" height=\"$h\" fill=\"#$couleur_bg\"/>";
151
152                // optimize the size :
153                $svg_image[1] = str_replace(' fill-opacity="1"/>', '/>', $svg_image[1]);
154                $svg_image[1] = str_replace(' />', '/>', $svg_image[1]);
155                $svg_image[1] = preg_replace_callback("/rgb\((\d+),(\d+),(\d+)\)/ims", "svg_color_hexa", $svg_image[1]);
156
157                #$svg_image[1] = preg_replace(',fill="(#[0-9a-f]+)",Uims', 'fill=\\1', $svg_image[1]);
158
159                $svg_image[1] = str_replace(">\n", ">", $svg_image[1]);
160                $svg_image[1] = trim($svg_image[1]);
161
162
163                //$svg_image[1] = str_replace("black", "#".$couleur_dark, $svg_image[1]);
164                $svg_image = $svg_image[0] . $svg_image[1];
165
166                #               var_dump(entites_html($svg_image));
167                #var_dump(strlen($svg_image),strlen(base64_encode($svg_image)),strlen(gzdeflate(base64_encode($svg_image))));
168
169
170                ecrire_fichier($dest, $svg_image);
171                $nsteps = count($results);
172                if ($nsteps<$geometrize_options['steps']){
173                        @touch($dest, 1); // on antidate l'image pour revenir ici au prochain affichage
174                        ecrire_fichier("$dest.runner", serialize([$runnerVersion, $runner, $results]));
175                        spip_log("PROGRESS: $fichier t=$time_compute Steps:$nsteps length:" . strlen($svg_image), 'ai_geometrize');
176                        //var_dump("STEPS:" . $nsteps);
177                } else {
178                        @unlink("$dest.runner");
179                        //var_dump("FINISHED:" . $results->length);
180                        spip_log("FINISHED: $fichier t=$time_compute Steps:$nsteps length:" . strlen($svg_image), 'ai_geometrize');
181                }
182        }
183
184        if (!@file_exists($dest)){
185                return $deja[$img] = false;
186        }
187
188        return $deja[$img] = $dest;
189}
190
191function _init_geometrize_runner($img, $width_thumb, $couleur_bg, $results = null){
192        $thumb = image_reduire($img, $width_thumb);
193        $source = extraire_attribut($thumb, 'src');
194        $bitmap = geometrize_bitmap_Bitmap::createFromImageFile($source);
195        $runner = new geometrize_runner_ImageRunner($bitmap, _couleur_to_geometrize($couleur_bg));
196
197        $new_results = [];
198        if ($results){
199                $w = $bitmap->width;
200                $h = $bitmap->height;
201                foreach ($results as $result) {
202                        $alpha = $result['shape']->color & 255;
203                        $result['shape']->rescale($w, $h); // rescale on new bounds
204                        $new_results[] = $runner->model->addShape($result['shape'], $alpha);
205                }
206        }
207        return [$runner, $new_results];
208}
209
210function svg_color_hexa($m){
211        $c = _couleur_dec_to_hex($m[1], $m[2], $m[3]);
212        return "#$c";
213}
214
215function _couleur_to_geometrize($c){
216        if (is_string($c)){
217                $c = _couleur_hex_to_dec($c);
218        }
219        if (isset($c['alpha'])){
220                // alpha definition is the opposite (255 is opaque, 0 is transparent)
221                $c['alpha'] = round((127-$c['alpha'])*255/127);
222        } else {
223                $c['alpha'] = 255;
224        }
225        $couleur = ($c['red'] << 24)+($c['green'] << 16)+($c['blue'] << 8)+$c['alpha'];
226        return $couleur;
227}
228
229
230if (!function_exists('_image_couleur_moyenne')){
231
232// A partir d'une image,
233// calcule la couleur moyenne sur une version reduire de l'image
234        function _image_couleur_moyenne($img, $w = 20, $h = 20){
235                static $couleur_moyenne = array();
236
237                if (isset($couleur_moyenne["$img-$w-$h"])){
238                        return $couleur_moyenne["$img-$w-$h"];
239                }
240
241                // valeur par defaut si l'image ne peut etre lue
242                $defaut = "F26C4E";
243
244                $cache = _image_valeurs_trans($img, "coul-moyenne-$w-$h", "txt");
245                if (!$cache){
246                        return $couleur_moyenne["$img-$w-$h"] = $defaut;
247                }
248
249
250                $fichier = $cache["fichier"];
251                $dest = $cache["fichier_dest"];
252
253                if (isset($couleur_moyenne["$fichier-$w-$h"])){
254                        return $couleur_moyenne["$fichier-$w-$h"];
255                }
256
257                $creer = $cache["creer"];
258
259                if ($creer){
260                        if (@file_exists($fichier)){
261                                $width = $cache["largeur"];
262                                $height = $cache["hauteur"];
263
264                                $newwidth = $w;
265                                $newheight = $h;
266
267                                $thumb = imagecreate($newwidth, $newheight);
268
269                                $source = $cache["fonction_imagecreatefrom"]($fichier);
270
271                                imagepalettetotruecolor($source);
272
273                                imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
274
275                                $moyenne = null;
276                                $nb_points = 0;
277                                for ($x = 0; $x<$w; $x++){
278                                        for ($y = 0; $y<$h; $y++){
279                                                // get a color
280                                                $color_index = imagecolorat($thumb, $x, $y);
281                                                // make it human readable
282                                                $color_tran = imagecolorsforindex($thumb, $color_index);
283                                                if ($color_tran['alpha']!=127){
284                                                        if (is_null($moyenne)){
285                                                                $moyenne = $color_tran;
286                                                        } else {
287                                                                $moyenne['red'] += $color_tran['red'];
288                                                                $moyenne['green'] += $color_tran['green'];
289                                                                $moyenne['blue'] += $color_tran['blue'];
290                                                        }
291                                                        $nb_points++;
292                                                }
293                                        }
294                                }
295                                if (is_null($moyenne)){
296                                        $couleur = $defaut;
297                                } else {
298                                        if ($nb_points>1){
299                                                $moyenne['red'] = round($moyenne['red']/$nb_points);
300                                                $moyenne['green'] = round($moyenne['green']/$nb_points);
301                                                $moyenne['blue'] = round($moyenne['blue']/$nb_points);
302                                        }
303
304                                        $couleur = _couleur_dec_to_hex($moyenne["red"], $moyenne["green"], $moyenne["blue"]);
305                                }
306                        } else {
307                                $couleur = $defaut;
308                        }
309
310                        // Mettre en cache le resultat
311                        $couleur_moyenne["$fichier-$w-$h"] = $couleur;
312                        ecrire_fichier($dest, $couleur_moyenne["$fichier-$w-$h"]);
313                } else {
314                        lire_fichier($dest, $couleur_moyenne["$fichier-$w-$h"]);
315                }
316
317                return $couleur_moyenne["$img-$w-$h"] = $couleur_moyenne["$fichier-$w-$h"];
318        }
319}
Note: See TracBrowser for help on using the repository browser.