Changeset 116236 in spip-zone


Ignore:
Timestamp:
Aug 5, 2019, 1:29:57 PM (2 weeks ago)
Author:
cedric@…
Message:

On revoit completement le fonctionnement du filtre |image_potrace
A force de fouiller j'ai fini par comprendre qu'il est fait pour vectoriser du noir et blanc uniquement.
Pour vectoriser une image en couleur, il faut donc extraire les N couleurs principales (la palette), pour chaque couleur creer une image N&B pour laquelle les points noirs sont les points de la couleur que l'on veut vectoriser, et vectoriser
Ensuite on superpose toutes les shapes obtenues, ce qui permet donc d'avoir un trace en N couleurs
Le calcul de la couleur de background pour les zones qui restent est complique pour trouver un compromis. Pour le moment c'est pas toujours heureux, mais il est toujours possible de passer en parametre du filtre la couleur que l'on veut ou transparent
Du coup le filtre image_geopotrize est un peu revu dans ses reglages pour tirer profit du meilleur trace rendu par potrace

Location:
_plugins_/filtres_images_vectorise/trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/filtres_images_vectorise/trunk/filtres/image_geopotrize.php

    r116232 r116236  
    2121 * @return string
    2222 */
    23 function image_geopotrize($img, $nb_shapes = 'auto', $opacite_trace = 0.75, $mix_mode='soft-light', $geometrizeOptions = [], $potraceOptions=[]) {
     23function image_geopotrize($img, $nb_shapes = 'auto', $opacite_trace = 0.66, $mix_mode='multiply', $geometrizeOptions = [], $potraceOptions=[]) {
    2424
    2525        if (!in_array($mix_mode, ['color', 'color-burn', 'color-dodge', 'darken', 'difference', 'exclusion', 'hard-ligt', 'hue', 'lighten', 'luminosity', 'multiply', 'normal', 'overlay', 'rever', 'saturation', 'screen', 'soft-light'])) {
    2626                $mix_mode = 'soft-light';
    2727        }
    28         $cache = _image_valeurs_trans($img, "image_geopotrize-".json_encode([$nb_shapes, $opacite_trace, $mix_mode, $geometrizeOptions, $potraceOptions]), "svg");
     28        $fonction = "image_geopotrize";
     29        $args = func_get_args();
     30        $cache = _image_valeurs_trans($img, "image_geopotrize-".json_encode([$nb_shapes, $opacite_trace, $mix_mode, $geometrizeOptions, $potraceOptions]), "svg", [$fonction, $args]);
    2931        if (!$cache) {
    3032                return false;
     
    8486
    8587                // on genere ensuite un trace PotRace plus fin, sans background
    86                 $potraceOptions['rounding'] = "width=$width_geo";
    87                 $potraceOptions['bgcolor'] = 'transparent';
     88                if (!isset($potraceOptions['bgcolor'])) {
     89                        $potraceOptions['bgcolor'] = 'transparent';
     90                }
     91                if (!isset($potraceOptions['colors'])){
     92                        $potraceOptions['colors'] = '8';
     93                }
    8894
    89                 $thumbnail = filtrer('image_reduire', $img, 512);
    90                 $thumbnail_renf = filtrer('image_renforcement', $thumbnail);
    91                 $img_svg_pot = image_potrace($thumbnail_renf, $potraceOptions);
     95                $img_svg_pot = image_potrace($img, $potraceOptions);
    9296                $file_svg_pot = supprimer_timestamp(extraire_attribut($img_svg_pot, 'src'));
    9397                $svg_pot = file_get_contents($file_svg_pot);
     
    97101                        $svg_pot = explode('>', trim($svg_pot[1]), 2);
    98102                }
     103                $viewboxP = extraire_attribut($svg_pot[0] . '>', 'viewBox');
     104                $viewboxP = explode(' ', $viewboxP);
     105                $width_pot = $viewboxP[2];
     106                $scale = $width_geo / $width_pot;
    99107
    100108                // et on superpose
     109                if ($potraceOptions['bgcolor'] != 'transparent') {
     110                        $potrace = explode("fill=", $svg_pot[1], 2);
     111                        $svg_pot[1] = $potrace[0] . "opacity=\"0.5\" fill=" . $potrace[1];
     112                }
    101113                $opacity = max(min(floatval($opacite_trace),1),0);
    102                 $svg_pot[1] = str_replace("fill=", 'opacity="'.$opacity.'" style="mix-blend-mode: '.$mix_mode.'" fill=', $svg_pot[1]);
     114                $svg_pot[1] = '<g transform="scale('.$scale.')" opacity="'.$opacity.'" style="mix-blend-mode: '.$mix_mode.'">'
     115                 . str_replace('</svg>', '</g></svg>', $svg_pot[1]);
    103116
    104                 $svg_geo[1] = str_replace('</svg>', $svg_pot[1], $svg_geo[1]);
     117                $svg_geo[1] = "<g>" . str_replace('</svg>', "</g>" . $svg_pot[1], $svg_geo[1]);
    105118
    106119                $svg_image = $svg_geo[0] . '>' . $svg_geo[1];
  • _plugins_/filtres_images_vectorise/trunk/filtres/image_potrace.php

    r116232 r116236  
    2828
    2929        // dimension de la miniature a vectoriser
    30         $width_thumb = 512;
     30        $width_thumb = 256;
    3131        if (isset($options['width_thumb'])) {
    3232                $width_thumb = $options['width_thumb'];
     
    4141                'rounding' => 1,
    4242                'bgcolor' => 'auto',
    43                 'color' => 'auto'
     43                'colors' => 16,
    4444        ];
    4545        $potconfig = array_merge($potconfig, $options);
    4646
    47         $cache = _image_valeurs_trans($img, "image_potrace-$width_thumb-".json_encode($potconfig), "svg");
     47        $cache = _image_valeurs_trans($img, "image_potrace2-$width_thumb-".json_encode($potconfig), "svg");
    4848        if (!$cache) {
    4949                return false;
     
    5858                $dest = $cache["fichier_dest"];
    5959
     60                // temps maxi en secondes par iteration
     61                // si on a pas fini on renvoie une image incomplete et on finira au calcul suivant
     62                $start_time = time();
     63                $time_budget = 20;
     64                $time_out = $_SERVER['REQUEST_TIME']+25;
     65                if (time()>$time_out) {
     66                        return $img;
     67                }
     68
    6069                if (!@file_exists($fichier)) {
    6170                        return false;
     
    6372
    6473                $thumb = image_reduire($img,$width_thumb);
    65                 $width_thumb = largeur($img);
    66                 $source = extraire_attribut($thumb, 'src');
    67 
    68                 if ($potconfig['bgcolor'] === 'auto' or $potconfig['color'] === 'auto') {
    69                         $palette = extraire_palette_couleurs($img, 5, 32);
    70 
    71                         $couleur_bg = array_shift($palette);
    72                         $couleur_1 = reset($palette);
    73                         if (couleur_luminance_relative($couleur_bg) < couleur_luminance_relative($couleur_1)) {
    74                                 $couleur_1 = $couleur_bg;
    75                                 $couleur_bg = reset($palette);
    76                         }
    77                         $couleur_bg = '#'.ltrim(couleur_eclaircir_si_foncee($couleur_bg),'#');
    78                         $couleur_1 = '#'.ltrim(couleur_foncer_si_claire($couleur_1),'#');
    79                 }
    80                 if ($potconfig['bgcolor'] !== 'auto') {
    81                         $couleur_bg = $potconfig['bgcolor'];
    82                 }
    83                 if ($potconfig['color'] !== 'auto') {
    84                         $couleur_1 = $potconfig['color'];
     74                $width_thumb = largeur($thumb);
     75
     76                $nb_colors = 16;
     77                if (is_numeric($potconfig['colors'])) {
     78                        $nb_colors = max(1,intval($potconfig['colors']));
     79                        $potconfig['colors'] = 'auto';
     80                }
     81                elseif(is_array($potconfig['colors'])) {
     82                        $nb_colors = count($potconfig['colors']);
     83                }
     84                if ($potconfig['bgcolor'] === 'auto' or $potconfig['colors'] === 'auto') {
     85
     86                        $palette = extraire_palette_couleurs($img, max($nb_colors, 5), 32);
     87                        $couleurs = [];
     88                        while (count($couleurs) < $nb_colors and count($palette)>1) {
     89                                $couleurs[] = array_shift($palette);
     90                        }
     91                        #$couleurs[] = '#ffffff';
     92                }
     93                if (is_array($potconfig['colors']) and count($potconfig['colors'])) {
     94                        $couleurs = $potconfig['colors'];
    8595                }
    8696
    8797                $rounding = $potconfig['rounding'];
    8898                unset($potconfig['rounding']);
    89 
    90                 $pot = new Potracio();
    91                 $pot->loadImageFromFile($source);
    92                 $pot->setParameter($potconfig);
    93 
    94                 $pot->process();
    9599                $coeffSize = 1;
    96100                if ($rounding !== false and $rounding !== 'off') {
     
    106110                        }
    107111                }
    108                 $svg_image = $pot->getSVG($coeffSize);
    109 
    110                 $svg_image = explode('>', $svg_image, 2);
    111 
    112                 $t = $svg_image[0] . '>';
    113                 $w = extraire_attribut($t, "width");
    114                 $h = extraire_attribut($t, "height");
    115 
    116                 $svg_image[0] = "<svg viewBox=\"0 0 $w $h\" xmlns=\"http://www.w3.org/2000/svg\">";
     112
     113                spip_timer('potrace');
     114                $img_bg = $thumb;
     115                if ($potconfig['bgcolor'] === 'auto'){
     116                        $img_bg = image_reduire($img_bg, 128);
     117                        $img_bg = filtrer('image_fond_transparent', $img_bg, 'ffffff');
     118                }
     119                $svg_layers = [];
     120                $offset_rayon = 50;
     121                //$couleurs = array_reverse($couleurs);
     122                foreach ($couleurs as $couleur) {
     123                        $couleur = '#' . ltrim(couleur_html_to_hex($couleur), '#');
     124                        //var_dump("<div style='display: inline-block;width: 30px;height: 15px;background-color:$couleur'></div>");
     125
     126                        $luminance = couleur_luminance_relative($couleur);
     127                        $rayon = max(50,0.5 * round(255 * (1 - $luminance)) + $offset_rayon);
     128                        $offset_rayon = max(0, $offset_rayon - 10);
     129
     130                        $thumbc = filtrer('image_filtrer_couleur', $thumb, $couleur,$rayon);
     131                        if ($potconfig['bgcolor'] === 'auto'){
     132                                $img_bg = filtrer('image_filtrer_couleur', $img_bg, $couleur, $rayon, 'remove');
     133                        }
     134
     135                        $source = extraire_attribut($thumbc, 'src');
     136                        $pot = new Potracio();
     137                        $pot->loadImageFromFile($source);
     138                        $pot->setParameter($potconfig);
     139                        $pot->process();
     140                        $svg_image = $pot->getSVG($coeffSize);
     141
     142                        $svg_image = explode('>', $svg_image, 2);
     143                        $balise_svg = $svg_image[0] . '>';
     144
     145                        // optimize the size : round all points to integer
     146                        if ($rounding !== false and $rounding !== 'off'){
     147                                $svg_image[1] = preg_replace_callback(",\b(\d+\.\d+)\b,ims", "_svg_round_point", $svg_image[1]);
     148                        }
     149                        //$svg_image[1] = preg_replace(",(\s)\s+,", "\\1", $svg_image[1]);
     150                        $svg_image[1] = str_replace("black", $couleur, $svg_image[1]);
     151                        $svg_layers[] = str_replace("</svg>", "", $svg_image[1]);
     152
     153                        if (time()>$start_time+$time_budget or time()>$time_out){
     154                                break;
     155                        }
     156                }
     157                $svg_layers = array_reverse($svg_layers);
     158
     159                $w = extraire_attribut($balise_svg, "width");
     160                $h = extraire_attribut($balise_svg, "height");
     161
     162                $time_compute = spip_timer('potrace');
     163
     164                $balise_svg = "<svg viewBox=\"0 0 $w $h\" xmlns=\"http://www.w3.org/2000/svg\">";
     165
     166                if ($potconfig['bgcolor'] === 'auto'){
     167                        //$img_bg = filtrer('image_fond_transparent', $img_bg,'00ff00');
     168                        #var_dump($img_bg);
     169                        $couleur_bg = _image_extraire_couleur_moyenne_restante($img_bg, 64);
     170                        #var_dump($couleur_bg);
     171                        $couleur_bg = couleur_eclaircir($couleur_bg);
     172                        #var_dump($couleur_bg);
     173                }
     174                else {
     175                        $couleur_bg = $potconfig['bgcolor'];
     176                }
    117177                if ($couleur_bg !== 'transparent') {
    118                         $svg_image[0] .= "<rect width=\"100%\" height=\"100%\" fill=\"$couleur_bg\"/>";
    119                 }
    120 
    121                 // optimize the size : round all points to integer
    122                 if ($rounding !== false and $rounding !== 'off'){
    123                         $svg_image[1] = preg_replace_callback(",\b(\d+\.\d+)\b,ims", "_svg_round_point", $svg_image[1]);
    124                 }
    125                 $svg_image[1] = preg_replace(",(\s)\s+,", "\\1", $svg_image[1]);
    126                 $svg_image[1] = str_replace("black", $couleur_1, $svg_image[1]);
    127                 $svg_image = $svg_image[0] . $svg_image[1];
     178                        $couleur_bg = '#' . ltrim(couleur_html_to_hex($couleur_bg), '#');
     179                        //$balise_svg .= "<rect width=\"100%\" height=\"100%\" fill=\"$couleur_bg\"/>";
     180                        $balise_svg .= "<path d=\"M-1,-1V{$h}H{$w}V-1z\" fill=\"$couleur_bg\"/>";
     181                }
     182
     183                $svg_image = $balise_svg . implode('', $svg_layers) . "</svg>";
    128184
    129185                ecrire_fichier($dest, $svg_image);
     186                spip_log("FINISHED: $fichier t=$time_compute length:" . strlen($svg_image), 'image_potrace');
    130187        }
    131188
     
    142199        }
    143200}
     201
     202
     203// A partir d'une image,
     204// calcule la couleur moyenne sur une version reduite de l'image
     205function _image_extraire_couleur_moyenne_restante($img, $seuil_opacite = 64){
     206        // valeur par defaut si l'image ne peut etre lue
     207        $defaut = "F26C4E";
     208
     209        include_spip('inc/filtres_images_lib_mini');
     210        $cache = _image_valeurs_trans($img, "_image_extraire_couleur_moyenne_restante-$seuil_opacite", "txt");
     211        if (!$cache){
     212                return [$defaut];
     213        }
     214
     215
     216        $fichier = $cache["fichier"];
     217        $dest = $cache["fichier_dest"];
     218
     219        if (true or $cache["creer"]){
     220
     221                if (@file_exists($fichier)){
     222                        $im = $cache["fonction_imagecreatefrom"]($fichier);
     223                        $w = $cache["largeur"];
     224                        $h = $cache["hauteur"];
     225
     226                        $m = ['red' => 0, 'green' => 0, 'blue' => 0];
     227                        $nb = 0;
     228                        for ($x = 0; $x < $w; $x++) {
     229                                for ($y=0; $y < $h; $y++) {
     230
     231                                        $rgb = ImageColorAt($im, $x, $y);
     232                                        $a = ($rgb >> 24) & 0xFF;
     233                                        if ($a < $seuil_opacite) {
     234                                                $m['red'] += ($rgb >> 16) & 0xFF;
     235                                                $m['green'] += ($rgb >> 8) & 0xFF;
     236                                                $m['blue'] += $rgb & 0xFF;
     237                                                $nb++;
     238                                        }
     239                                }
     240                        }
     241
     242                        $couleur = $defaut;
     243                        if ($nb>0) {
     244                                $m['red'] = round($m['red']/$nb);
     245                                $m['green'] = round($m['green']/$nb);
     246                                $m['blue'] = round($m['blue']/$nb);
     247                                $couleur = _couleur_dec_to_hex($m['red'], $m['green'], $m['blue']);
     248                        }
     249
     250                } else {
     251                        $couleur = $defaut;
     252                }
     253
     254                // Mettre en cache le resultat
     255                ecrire_fichier($dest, $couleur);
     256        } else {
     257                lire_fichier($dest, $couleur);
     258                if (!$couleur) {
     259                        $couleur = $defaut;
     260                }
     261        }
     262
     263        return $couleur;
     264}
  • _plugins_/filtres_images_vectorise/trunk/paquet.xml

    r116233 r116236  
    22        prefix="filtres_images_vectorise"
    33        categorie="multimedia"
    4         version="1.0.1"
     4        version="1.1.0"
    55        etat="test"
    66        compatibilite="[3.1.0;3.3.*]"
Note: See TracChangeset for help on using the changeset viewer.