source: spip-zone/_plugins_/filtres_images_vectorise/trunk/lib/geometrize/src/rasterizer/Rasterizer.php @ 116199

Last change on this file since 116199 was 116199, checked in by cedric@…, 21 months ago

Un plugin pour vectoriser en SVG des images bitmap, qui propose 4 nouveaux filtres

  • extraire_palette_couleurs permet d'extraire une palette de couleur d'une image (par defaut les 3 couleurs les plus representees) en utilisant un calcul des couleurs dominantes par partitionnement en k-moyennes

`
<BOUCLE_palette(POUR){tableau #FICHIER|extraire_palette_couleurs{3}}>
<div style="display: inline-block;width: 30px;height: 15px;background-color: #VALEUR;"></div>
</BOUCLE_palette>
`

  • image_geometrize permet de creer une image SVG approchante de l'image d'origine en utilisant le lib GeometrizePHP https://github.com/Cerdic/geometrize-php/ (attention methode gourmande en temps de calcul)
  • image_potrace permet de generer un trace SVG depuis l'image d'origine, a l'aide de Potracio PHP qui est un portage PHP de PotRace? https://seenthis.net/messages/645575
  • image_geopotrize combine les 2 techniques : un background geometrize qui n'a pas besoin d'un grand nombre de shapes et un trace potrace superpose/mixe

Les 3 filtres ont tout un tas d'option pour qui veut jouer avec, mais les reglages par defaut permettent d'avoir immediatement un joli resultat exploitable
A noter que pour image_geometrize, le temps de calcul peut depasser les 30s pour generer le nombre de shapes demandees, selon les reglages utilises.
Dans ce cas le calcul est arrete au bout de 20s, on stocke et on renvoie l'image provisoire incomplete, et on stocke l'etat du calcul qui reprendra au prochain calcul de la page.

(J'evite les screenshots dans le message de commit mais le coeur y est)

File size: 6.2 KB
Line 
1<?php
2
3namespace Cerdic\Geometrize\Rasterizer;
4
5class Rasterizer {
6        public function __construct(){
7        }
8
9        static function drawLines($image, $c, $lines){
10
11                // easy case: opacity=1, just a copy of the color $c, much faster
12                if ($c & 255===255){
13                        foreach ($lines as &$line) {
14                                $_g1 = $line['x2']+1;
15                                $y = $line['y'];
16                                for ($x = $line['x1']; $x<$_g1; $x++){
17                                        $image->data[$y][$x] = $c;
18                                        if (isset($image->errorCache[$y][$x])){
19                                                unset($image->errorCache[$y][$x]);
20                                        }
21                                }
22                        }
23                } else {
24                        $sr = $c >> 24 & 255;
25                        $sr = $sr | $sr << 8;
26                        $sr = $sr*($c & 255);
27                        $sr = intval($sr/255);
28                        $sg = $c >> 16 & 255;
29                        $sg = $sg | $sg << 8;
30                        $sg = $sg*($c & 255);
31                        $sg = intval($sg/255);
32                        $sb = $c >> 8 & 255;
33                        $sb = $sb | $sb << 8;
34                        $sb = $sb*($c & 255);
35                        $sb = intval($sb/255);
36                        $sa = $c & 255;
37                        $sa = $sa | $sa << 8;
38
39                        foreach ($lines as &$line) {
40                                $y = $line['y'];
41                                $ma = 65535;
42                                $m = 65535;
43                                $as = ($m-$sa*($ma/$m))*257;
44                                $a = intval($as);
45
46                                $_g2 = $line['x1'];
47                                $_g1 = $line['x2']+1;
48                                while ($_g2<$_g1){
49                                        $_g2 = $_g2+1;
50                                        $x = $_g2-1;
51                                        $d = $image->data[$y][$x];
52                                        $dr = $d >> 24 & 255;
53                                        $dg = $d >> 16 & 255;
54                                        $db = $d >> 8 & 255;
55                                        $da = $d & 255;
56                                        $int = $dr*$a+$sr*$ma;
57                                        $r = null;
58                                        if ($int<0){
59                                                $r = 4294967296.0+$int;
60                                        } else {
61                                                $r = $int+0.0;
62                                        }
63                                        $int1 = $m;
64                                        $r1 = null;
65                                        if ($int1<0){
66                                                $r1 = 4294967296.0+$int1;
67                                        } else {
68                                                $r1 = $int1+0.0;
69                                        }
70                                        $r2 = intval($r/$r1) >> 8;
71                                        $int2 = $dg*$a+$sg*$ma;
72                                        $g = null;
73                                        if ($int2<0){
74                                                $g = 4294967296.0+$int2;
75                                        } else {
76                                                $g = $int2+0.0;
77                                        }
78                                        $int3 = $m;
79                                        $g1 = null;
80                                        if ($int3<0){
81                                                $g1 = 4294967296.0+$int3;
82                                        } else {
83                                                $g1 = $int3+0.0;
84                                        }
85                                        $g2 = intval($g/$g1) >> 8;
86                                        $int4 = $db*$a+$sb*$ma;
87                                        $b = null;
88                                        if ($int4<0){
89                                                $b = 4294967296.0+$int4;
90                                        } else {
91                                                $b = $int4+0.0;
92                                        }
93                                        $int5 = $m;
94                                        $b1 = null;
95                                        if ($int5<0){
96                                                $b1 = 4294967296.0+$int5;
97                                        } else {
98                                                $b1 = $int5+0.0;
99                                        }
100                                        $b2 = intval($b/$b1) >> 8;
101                                        $int6 = $da*$a+$sa*$ma;
102                                        $a1 = null;
103                                        if ($int6<0){
104                                                $a1 = 4294967296.0+$int6;
105                                        } else {
106                                                $a1 = $int6+0.0;
107                                        }
108                                        $int7 = $m;
109                                        $a2 = null;
110                                        if ($int7<0){
111                                                $a2 = 4294967296.0+$int7;
112                                        } else {
113                                                $a2 = $int7+0.0;
114                                        }
115                                        $a3 = intval($a1/$a2) >> 8;
116                                        {
117                                                if (!true){
118                                                        throw new \Exception("FAIL: min <= max");
119                                                }
120                                                $color = null;
121                                                if ($r2<0){
122                                                        $color = 0;
123                                                } else {
124                                                        if ($r2>255){
125                                                                $color = 255;
126                                                        } else {
127                                                                $color = $r2;
128                                                        }
129                                                }
130                                                if (!true){
131                                                        throw new \Exception("FAIL: min <= max");
132                                                }
133                                                $color1 = null;
134                                                if ($g2<0){
135                                                        $color1 = 0;
136                                                } else {
137                                                        if ($g2>255){
138                                                                $color1 = 255;
139                                                        } else {
140                                                                $color1 = $g2;
141                                                        }
142                                                }
143                                                if (!true){
144                                                        throw new \Exception("FAIL: min <= max");
145                                                }
146                                                $color2 = null;
147                                                if ($b2<0){
148                                                        $color2 = 0;
149                                                } else {
150                                                        if ($b2>255){
151                                                                $color2 = 255;
152                                                        } else {
153                                                                $color2 = $b2;
154                                                        }
155                                                }
156                                                if (!true){
157                                                        throw new \Exception("FAIL: min <= max");
158                                                }
159                                                $color3 = null;
160                                                if ($a3<0){
161                                                        $color3 = 0;
162                                                } else {
163                                                        if ($a3>255){
164                                                                $color3 = 255;
165                                                        } else {
166                                                                $color3 = $a3;
167                                                        }
168                                                }
169                                                $image->data[$y][$x] = ($color << 24)+($color1 << 16)+($color2 << 8)+$color3;
170                                                if (isset($image->errorCache[$y][$x])){
171                                                        unset($image->errorCache[$y][$x]);
172                                                }
173                                        }
174                                }
175                        }
176                }
177        }
178
179        static function copyLines($destination, $source, $lines){
180                if (!($destination!==null)){
181                        throw new \Exception("FAIL: destination != null");
182                }
183                if (!($source!==null)){
184                        throw new \Exception("FAIL: source != null");
185                }
186                if (!($lines!==null)){
187                        throw new \Exception("FAIL: lines != null");
188                }
189
190                foreach ($lines as &$line) {
191                        $y = $line['y'];
192                        $_g1 = $line['x2']+1;
193                        for ($x = $line['x1']; $x<$_g1; $x++){
194                                $destination->data[$y][$x] = $source->data[$y][$x];
195                        }
196                }
197        }
198
199        /**
200         * @param int $x1
201         * @param int $y1
202         * @param int $x2
203         * @param int $y2
204         * @param &array
205         * @return array
206         */
207        static function bresenham($x1, $y1, $x2, $y2, &$points){
208                $dx = $x2-$x1;
209                $ix1 = ($dx>0 ? 1 : 0);
210                $ix2 = ($dx<0 ? 1 : 0);
211                $ix = $ix1-$ix2;
212
213                if ($dx<0){
214                        $dx *= -1;
215                }
216                $dx = $dx << 1;
217
218                $dy = $y2-$y1;
219                $iy1 = ($dy>0 ? 1 : 0);
220                $iy2 = ($dy<0 ? 1 : 0);
221                $iy = $iy1-$iy2;
222
223                if ($dy<0){
224                        $dy *= -1;
225                }
226                $dy = $dy << 1;
227
228
229                if (!isset($points[$y1])) {
230                        $points[$y1] = [];
231                }
232                $points[$y1][] = $x1;
233                if ($dx>=$dy){
234                        $error = $dy-($dx >> 1);
235                        while ($x1!==$x2){
236                                if ($error>0 or ($error===0 and $ix>0)){
237                                        $error -= $dx;
238                                        $y1 += $iy;
239                                        if (!isset($points[$y1])) {
240                                                $points[$y1] = [];
241                                        }
242                                }
243                                $error += $dy;
244                                $x1 += $ix;
245                                $points[$y1][] = $x1;
246                        }
247                } else {
248                        $error = $dx-($dy >> 1);
249                        while ($y1!==$y2){
250                                if ($error>0 or ($error===0 and $iy>0)){
251                                        $error -= $dy;
252                                        $x1 += $ix;
253                                }
254                                $error += $dx;
255                                $y1 += $iy;
256                                if (!isset($points[$y1])) {
257                                        $points[$y1] = [];
258                                }
259                                $points[$y1][] = $x1;
260                        }
261                }
262                return $points;
263        }
264
265        /**
266         * @param array $points
267         * @param int $xBound
268         * @param int $yBound
269         * @return array
270         */
271        static function scanlinesForPolygon($points, $xBound, $yBound){
272                return Rasterizer::scanlinesForPath($points, $xBound, $yBound, true);
273        }
274
275        /**
276         * @param array $points
277         * @param int $xBound
278         * @param int $yBound
279         * @param bool $isClosed
280         * @return array
281         */
282        static function scanlinesForPath($points, $xBound, $yBound, $isClosed = false){
283                $lines = [];
284
285                if ($isClosed) {
286                        $prevPoint = end($points);
287                }
288                else {
289                        $prevPoint = array_shift($points);
290                }
291
292                $YXpoints = [];
293
294                foreach ($points as $point) {
295                        Rasterizer::bresenham($prevPoint['x'], $prevPoint['y'], $point['x'], $point['y'], $YXpoints);
296                        $prevPoint = $point;
297                }
298
299                // not super useful
300                // ksort($YXpoints);
301
302                foreach ($YXpoints as $y => $xs){
303                        if ($y>=0 and $y<$yBound){
304                                $minx = min($xs);
305                                $maxx = max($xs);
306                                if ($minx<$xBound and $maxx>=0){
307                                        $lines[] = ['y' => $y, 'x1'=>max($minx, 0), 'x2' =>min($maxx, $xBound-1)];
308                                }
309                        }
310                }
311
312                return $lines;
313        }
314
315}
Note: See TracBrowser for help on using the repository browser.