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 is HasBounds, G2Drawable, ByteIO { |
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 | // |
19 | // Order in array: |
20 | // x_left at y1, x_right at y1, |
21 | // x_left at y1+1, x_right at y1+1, ,,, |
22 | settable X[] data; |
23 | |
24 | // Color in 15 bit |
25 | settable short hi15color; |
26 | |
27 | *(int y1, int y2) { |
28 | init(y1, y2); |
29 | } |
30 | |
31 | void init(int y1, int y2) { |
32 | this.y1 = toY(y1); |
33 | data = newXArray((y2-y1)*2); |
34 | } |
35 | |
36 | void set(int y, int xLeft, int xRight) { |
37 | data[(y-y1)*2] = toX(xLeft); |
38 | data[(y-y1)*2+1] = toX(xRight); |
39 | } |
40 | |
41 | // bounds can be calculated quickly from core values & are then cached |
42 | public simplyCached Rect bounds() { |
43 | int x1 = Int.MAX_VALUE, x2 = 0; |
44 | for (int i = 0; i < l(data); i += 2) { |
45 | x1 = min(x1, data[i]); |
46 | x2 = max(x2, data[i+1]); |
47 | } |
48 | ret rectFromPoints(x1, y1, x2, y2()); |
49 | } |
50 | |
51 | // same with number of pixels |
52 | int numberOfPixels_cache = -1; |
53 | public int numberOfPixels() { |
54 | if (numberOfPixels_cache < 0) { |
55 | int n = 0; |
56 | for (int i = 0; i < l(data); i += 2) |
57 | n += max(0, data[i+1]-data[i]); |
58 | numberOfPixels_cache = n; |
59 | } |
60 | ret numberOfPixels_cache; |
61 | } |
62 | |
63 | public int getHeight() { ret l(data)/2; } |
64 | int y2() { ret y1+height(); } |
65 | |
66 | bool contains(Pt p) { ret contains(p.x, p.y); } |
67 | bool contains(int x, int y) { |
68 | if (y < y1) false; |
69 | int i = (y-y1)*2; |
70 | if (i >= l(data)) false; |
71 | ret x >= data[i] && x < data[i+1]; |
72 | } |
73 | |
74 | Color color() { |
75 | ret main hi15color(hi15color); |
76 | } |
77 | |
78 | selfType color(RGB color) { |
79 | ret hi15color(rgbToHi15(color)); |
80 | } |
81 | |
82 | public void drawOn(Graphics2D g) { |
83 | g.setColor(color()); |
84 | int h = height(); |
85 | for y to h: { |
86 | int x1 = data[y*2], x2 = data[y*2+1]; |
87 | if (x1 < x2) |
88 | g.drawLine(x1, y1+y, x2-1, y1+y); |
89 | } |
90 | } |
91 | |
92 | // doesn't set a color |
93 | // TODO |
94 | public void drawOutline(Graphics2D g) { |
95 | int h = height(); |
96 | IntRange last = intRange(0, 0); |
97 | for y to h: { |
98 | IntRange r = intRange(data[y*2], data[y*2+1]); |
99 | |
100 | // anything to draw in this line? |
101 | if (nempty(r)) { |
102 | if (empty(last)) |
103 | // draw full line if just starting |
104 | g.drawLine(r.start, y1+y, r.end-1, y1+y); |
105 | else { |
106 | // We make a line from the left boundary that if possible goes only to last.start but is at least 1 pixel wide |
107 | int xleft = max(r.start, last.start-1); |
108 | |
109 | // Same from the right boundary |
110 | int xright = min(r.end-1, last.end); |
111 | |
112 | g.drawLine(r.start, y1+y, xleft, y1+y); |
113 | g.drawLine(xright, y1+y, r.end-1, y1+y); |
114 | } |
115 | } |
116 | |
117 | last = r; |
118 | } |
119 | } |
120 | |
121 | SSI topPart(int nLines) { |
122 | SSI ssi = new SSI(y1, toShort_enforce(y1+nLines)).hi15color(hi15color); |
123 | arrayCopy(data, ssi.data, 0, l(ssi.data)); |
124 | ret ssi; |
125 | } |
126 | |
127 | // an SSI is coherent if all scanlines are non-empty |
128 | // and the SSI is one region |
129 | bool coherent(bool withDiagonals default false) { |
130 | int h = height(); |
131 | for y to h: { |
132 | int i = y*2; |
133 | int x1 = data[i], x2 = data[i+1]; |
134 | if (x1 >= x2) false; |
135 | if (y > 0) { |
136 | int lastx1 = data[i-2], lastx2 = data[i-1]; |
137 | if (withDiagonals) { lastx1--; lastx2++; } |
138 | if (!intRangesOverlap(x1, x2, lastx1, lastx2)) |
139 | false; |
140 | } |
141 | } |
142 | true; |
143 | } |
144 | |
145 | public void readWrite(ByteHead head) { |
146 | head.exchangeShort(-> hi15color, color -> hi15color = color); |
147 | head.exchangeShort(-> y1, y1 -> this.y1 = y1); |
148 | head.exchangeShort(-> toShort_enforce(y2()), y2 -> init(y1, y2)); |
149 | for i over data: { |
150 | reMutable i; |
151 | head.exchangeShort(-> data[i], x -> data[i] = x); |
152 | } |
153 | } |
154 | } |
Began life as a copy of #1035561
download show line numbers debug dex old transpilations
Travelled to 1 computer(s): mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1035707 |
Snippet name: | SSI (Simple Scanline Image) backup |
Eternal ID of this version: | #1035707/1 |
Text MD5: | c73eb78aa1bfafffbe1dbfdd683dab3f |
Author: | stefan |
Category: | javax / imaging |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-07-09 23:59:29 |
Source code size: | 4259 bytes / 154 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 120 / 130 |
Referenced in: | [show references] |