root/as3/PotrAs/src/com/nitoyon/potras/PathList.as

リビジョン 91, 5.0 kB (コミッタ: nitoyon, コミット時期: 4 年 前)

高速化した
mx 名前空間を使わないようにした

Line 
1 /* Copyright (C) 2001-2007 Peter Selinger and nitoyon.
2    Original code(Potrace v1.8) by Peter Selinger.
3    Ported to ActionScript 3.0 by nitoyon.
4    This file is part of PotrAs. It is free software and it is covered
5    by the GNU General Public License. See the file COPYING for details. */
6
7 package com.nitoyon.potras
8 {
9         import flash.display.BitmapData;
10         import flash.geom.Point;
11         import flash.geom.Rectangle;
12         import flash.geom.Matrix;
13         import flash.filters.ColorMatrixFilter;
14
15         /**
16          * Decompose the given bitmap into paths.
17          */
18         public class PathList
19         {
20                 /**
21                  * Decompose the given bitmap into paths.
22                  *
23                  * @param bitmapData BitmapData to create paths.
24                  * @return paths.
25                  */
26                 public static function create(bitmapData:BitmapData):Array
27                 {
28                         var pathList:Array = [];
29                         var y:int = 0;
30
31                         var bmdCopy:BitmapData = bitmapData.clone();
32                         var param:Object = {turdSize : 3};
33
34                         // XOR
35                         var filter:ColorMatrixFilter = new ColorMatrixFilter([
36                                 -1, 0, 0, 0, 255,
37                                 -1, 0, 0, 0, 255,
38                                 -1, 0, 0, 0, 255,
39                                  0, 0, 0, 1, 0
40                         ]);
41
42                         var point:Point = new Point();
43                         while(findNext(bmdCopy, point))
44                         {
45                                 // calculate the sign by looking at the original
46                                 var sign:String = bmdCopy.getPixel(point.x, point.y) == 0 ? '+' : '-';
47
48                                 // calculate the path
49                                 var p:Object = findPath(bmdCopy, new Point(point.x, point.y - 1), sign, param.turnPolicy);
50                                 if(!p)
51                                 {
52                                         pathList = null;
53                                         break;
54                                 }
55
56                                 // update buffered image
57                                 xorPath(bmdCopy, p, filter);
58
59                                 // if it's a turd, eliminate it, else append it to the list
60                                 if(p.area > param.turdSize)
61                                 {
62                                         pathList.push(p);
63                                 }
64                         }
65
66                         bmdCopy.dispose();
67                         return pathList;
68                 }
69
70                 /**
71                  * find the next set pixel in a row <= y.
72                  *
73                  * <p>Pixels are searched first left-to-right, then top-down.</p>
74                  *
75                  * <p>If found, return Point object. Else return null.</p>
76                  */
77                 private static function findNext(bmd:BitmapData, pt:Point):Boolean
78                 {
79                         for(var y:int = pt.y; y < bmd.height; y++)
80                         {
81                                 for(var x:int = 0; x < bmd.width; x++)
82                                 {
83                                         if(bmd.getPixel(x, y) == 0x000000)
84                                         {
85                                                 pt.x = x;
86                                                 pt.y = y;
87                                                 return true;
88                                         }
89                                 }
90                         }
91
92                         return false;
93                 }
94
95                 /**
96                  * compute a path in the given pixmap, separating black from white.
97                  *
98                  * <p>Start path at the <code>startPoint</code>, which must be an upper
99                  * left corner of the path.
100                  * Also compute the area enclosed by the path. Return a
101                  * new path object. (note that a legitimate path
102                  * cannot have length 0).</p>
103                  *
104                  * @param sign Required for correct interpretation of turnpolicies.
105                  */
106                 private static function findPath(bmd:BitmapData, startPoint:Point, sign:String, turnpolicy:int):Object
107                 {
108                         var area:int = 0;
109                         var pointList:Array = [];
110
111                         var pt:Point = startPoint.clone();
112                         var dir:Point = new Point(0, 1);
113
114                         var rotateRight:Matrix = new Matrix(0, -1, 1, 0);
115                         var rotateLeft:Matrix  = new Matrix(0, 1, -1, 0);
116
117                         while(true)
118                         {
119                                 // add point to path
120                                 pointList.push(pt.clone());
121
122                                 // move to next point
123                                 pt.offset(dir.x, dir.y);
124                                 area += pt.x * -dir.y;
125
126                                 // path complete?
127                                 if(pt.equals(startPoint))
128                                 {
129                                         break;
130                                 }
131
132                                 // determine next direction
133                                 var c:Boolean = bmd.getPixel32(pt.x + (dir.x - dir.y - 1) /2, pt.y + (dir.y + dir.x + 1) / 2) == 0xff000000;
134                                 var d:Boolean = bmd.getPixel32(pt.x + (dir.x + dir.y - 1) /2, pt.y + (dir.y - dir.x + 1) / 2) == 0xff000000;
135
136                                 // c d
137                                 // X _
138                                 if(c && !d) // ambiguous turn
139                                 {
140                                         if(true) // TODO: left turn only by nitoyon
141                                         {
142                                                 dir = rotateLeft.transformPoint(dir);
143                                         }
144                                         else
145                                         {
146                                                 dir = rotateRight.transformPoint(dir);
147                                         }
148                                 }
149                                 else if(c) // left turn
150                                 {
151                                         dir = rotateLeft.transformPoint(dir);
152                                 }
153                                 else if(!d) // right turn
154                                 {
155                                         dir = rotateRight.transformPoint(dir);
156                                 }
157                         }
158
159                         // allocate new path object
160                         var path:Object = {};
161                         path.priv = pointList;
162                         path.area = area;
163                         path.sign = sign;
164
165                         return path;
166                 }
167
168                 /**
169                  *  xor the given pixmap with the interior of the given path.
170                  *  Note: the path must be within the dimensions of the pixmap.
171                  */
172                 private static function xorPath(bm:BitmapData, p:Object, filter:ColorMatrixFilter):void
173                 {
174                         var priv:Array = p.priv as Array;
175                         var len:int = priv.length;
176
177                         // get minimum x
178                         var minX:int = 99999;
179                         for(var i:int = 0; i < len; i++)
180                         {
181                                 minX = Math.min(minX, priv[i].x);
182                         }
183
184                         var y1:int = priv[len - 1].y;
185                         var pt:Point = new Point();
186                         var rect:Rectangle = new Rectangle;
187                         for(i = 0; i < len; i++)
188                         {
189                                 var x:int = priv[i].x;
190                                 var y:int = priv[i].y;
191
192                                 if(y != y1)
193                                 {
194                                         // efficiently invert the rectangle [minX, x] x [y,y1]
195                                         var y2:int = Math.max(y, y1);
196                                         pt.x = minX; pt.y = y2;
197                                         rect.x = minX; rect.y = y2; rect.width = x - minX; rect.height = 1;
198                                         bm.applyFilter(bm, rect, pt, filter);
199                                         y1 = y;
200                                 }
201                         }
202                 }
203         }
204 }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。