Libraryless. Click here for Pure Java version (14638L/84K).
1 | // SSI - Simple Scanline Image |
2 | // A partial image consisting of exactly one horizontal line per row. |
3 | // All pixels are of the same color. |
4 | |
5 | // The important values are y1 and data |
6 | persistable sclass SSI extends AbstractSSI is ByteIO, StringIO { |
7 | replace X with short. |
8 | replace Y with short. |
9 | replace toX with toShort_enforce. |
10 | replace toY with toShort_enforce. |
11 | replace newXArray with newShortArrayOrNull. |
12 | |
13 | // core value (mandatory): first row occupied |
14 | settable Y y1; |
15 | |
16 | // core value (mandatory): x coordinates per row |
17 | // x_left is inclusive, x_right is exclusive |
18 | // all x coordinates are absolute in image |
19 | // |
20 | // Order in array: |
21 | // x_left at y1, x_right at y1, |
22 | // x_left at y1+1, x_right at y1+1, ,,, |
23 | settable X[] data; |
24 | |
25 | *(int y1, int y2) { |
26 | init(y1, y2); |
27 | } |
28 | |
29 | void init(int y1, int y2) { |
30 | this.y1 = toY(y1); |
31 | data = newXArray((y2-y1)*2); |
32 | } |
33 | |
34 | // all coordinates passed in are absolute |
35 | void set(int y, int xLeft, int xRight) { |
36 | data[(y-y1)*2] = toX(xLeft); |
37 | data[(y-y1)*2+1] = toX(xRight); |
38 | } |
39 | |
40 | // all coordinates passed in and out are absolute |
41 | int getLeft (int y) { ret data[(y-y1)*2]; } |
42 | int getRight(int y) { ret data[(y-y1)*2+1]; } |
43 | |
44 | // bounds can be calculated quickly from core values & are then cached |
45 | public simplyCached Rect bounds() { |
46 | int x1 = Int.MAX_VALUE, x2 = 0; |
47 | for (int i = 0; i < l(data); i += 2) { |
48 | x1 = min(x1, data[i]); |
49 | x2 = max(x2, data[i+1]); |
50 | } |
51 | ret rectFromPoints(x1, y1, x2, y2()); |
52 | } |
53 | |
54 | // same with number of pixels |
55 | int numberOfPixels_cache = -1; |
56 | public int numberOfPixels() { |
57 | if (numberOfPixels_cache < 0) { |
58 | int n = 0; |
59 | for (int i = 0; i < l(data); i += 2) |
60 | n += max(0, data[i+1]-data[i]); |
61 | numberOfPixels_cache = n; |
62 | } |
63 | ret numberOfPixels_cache; |
64 | } |
65 | |
66 | public int getHeight() { ret l(data)/2; } |
67 | int y2() { ret y1+height(); } |
68 | |
69 | public bool contains(Pt p) { ret contains(p.x, p.y); } |
70 | public bool contains(int x, int y) { |
71 | if (y < y1) false; |
72 | int i = (y-y1)*2; |
73 | if (i >= l(data)) false; |
74 | ret x >= data[i] && x < data[i+1]; |
75 | } |
76 | |
77 | selfType color(Color color) { super.color(color); this; } |
78 | public selfType hi15color(short hi15color) { super.hi15color(hi15color); this; } |
79 | |
80 | public void drawOn(Graphics2D g) { |
81 | g.setColor(color()); |
82 | int h = height(); |
83 | for y to h: { |
84 | int x1 = data[y*2], x2 = data[y*2+1]; |
85 | if (x1 < x2) |
86 | g.drawLine(x1, y1+y, x2-1, y1+y); |
87 | } |
88 | } |
89 | |
90 | // doesn't set a color |
91 | // TODO |
92 | public void drawOutline(Graphics2D g) { |
93 | int h = height(); |
94 | IntRange last = intRange(0, 0); |
95 | for y to h: { |
96 | IntRange r = intRange(data[y*2], data[y*2+1]); |
97 | |
98 | // anything to draw in this line? |
99 | if (nempty(r)) { |
100 | if (empty(last)) |
101 | // draw full line if just starting |
102 | g.drawLine(r.start, y1+y, r.end-1, y1+y); |
103 | else { |
104 | // We make a line from the left boundary that if possible goes only to last.start but is at least 1 pixel wide |
105 | int xleft = max(r.start, last.start-1); |
106 | |
107 | // Same from the right boundary |
108 | int xright = min(r.end-1, last.end); |
109 | |
110 | g.drawLine(r.start, y1+y, xleft, y1+y); |
111 | g.drawLine(xright, y1+y, r.end-1, y1+y); |
112 | } |
113 | } |
114 | |
115 | last = r; |
116 | } |
117 | } |
118 | |
119 | SSI topPart(int nLines) { |
120 | if (nLines <= 0) null; |
121 | SSI ssi = new SSI(y1, toShort_enforce(y1+nLines)).hi15color(hi15color); |
122 | arrayCopy(data, ssi.data, 0, l(ssi.data)); |
123 | ret ssi; |
124 | } |
125 | |
126 | // an SSI is coherent if all scanlines are non-empty |
127 | // and the SSI is one region |
128 | bool coherent(bool withDiagonals default false) { |
129 | int h = height(); |
130 | for y to h: { |
131 | int i = y*2; |
132 | int x1 = data[i], x2 = data[i+1]; |
133 | if (x1 >= x2) false; |
134 | if (y > 0) { |
135 | int lastx1 = data[i-2], lastx2 = data[i-1]; |
136 | if (withDiagonals) { lastx1--; lastx2++; } |
137 | if (!intRangesOverlap(x1, x2, lastx1, lastx2)) |
138 | false; |
139 | } |
140 | } |
141 | true; |
142 | } |
143 | |
144 | public void readWrite(ByteHead head) { |
145 | head.exchangeShort(-> hi15color, color -> hi15color = color); |
146 | head.exchangeShort(-> y1, y1 -> this.y1 = y1); |
147 | head.exchangeShort(-> toShort_enforce(y2()), y2 -> init(y1, y2)); |
148 | for i over data: { |
149 | reMutable i; |
150 | head.exchangeShort(-> data[i], x -> data[i] = x); |
151 | } |
152 | } |
153 | |
154 | SSI toSSI() { this; } |
155 | |
156 | public long sizeInInts() { |
157 | // "s", color, y1, height, data |
158 | ret 4+height()*2; |
159 | } |
160 | |
161 | SSI reduceToInts(int ints) { |
162 | ret topPart((ints-4)/2); |
163 | } |
164 | |
165 | public void readWrite(StringHead head) { |
166 | head.exchangeLine(l0 toLine, l1 fromLine); |
167 | } |
168 | |
169 | S toLine() { |
170 | ret spaceCombine("s", colorToString(), y1, height(), toList(data)); |
171 | } |
172 | |
173 | void fromLine(S line) { |
174 | Iterator<S> it = splitAtSpaceIterator(line); |
175 | assertEquals("s", nextFromIterator(it)); |
176 | int y1 = parseInt(nextFromIterator(it)); |
177 | int h = parseInt(nextFromIterator(it)); |
178 | init(y1, y1+h); |
179 | for i over data: |
180 | data[i] = toX(parseInt(nextFromIterator(it))); |
181 | } |
182 | } |
download show line numbers debug dex old transpilations
Travelled to 3 computer(s): elmgxqgtpvxh, mowyntqkapby, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1035561 |
Snippet name: | SSI (Simple Scanline Image) |
Eternal ID of this version: | #1035561/70 |
Text MD5: | c026241203df534140b00dd7762cfefe |
Transpilation MD5: | a1a341d2c967cb9ea377c690363584bd |
Author: | stefan |
Category: | javax / imaging |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-07-25 14:33:29 |
Source code size: | 5222 bytes / 182 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 328 / 752 |
Version history: | 69 change(s) |
Referenced in: | [show references] |