Libraryless. Click here for Pure Java version (32059L/200K).
1 | // TODO: different sorting methods, e.g. "widest SSIs" |
2 | // Note: Blur is slow. e.g. 48ms for 2 screens |
3 | // Posterization is fast, e.g. 8ms for 2 screens |
4 | // Region making speed depends on how many regions there are. |
5 | // TODO: Make regions incrementally by starting at random pixels |
6 | sclass G22DataWrangler > Stages2 is IHasChangeListeners { |
7 | replace Stage with Runnable. |
8 | |
9 | event change; |
10 | |
11 | settable BufferedImage inputImage; |
12 | |
13 | // try to re-use anything that is identical |
14 | settable G22DataWrangler stealingFrom; |
15 | |
16 | settable bool withDiagonals = true; |
17 | settableWithVar int blur = 0; // in pixels |
18 | |
19 | settableWithVar int colorsPerChannel = 2; |
20 | |
21 | settableWithVar float drift; // brightness drift for gradients (-1 to 1) |
22 | settableWithVar float antiDrift; // brightness drift after rposterization gradients (-1 to 1) |
23 | |
24 | // kilobytes per compressed image (pessimistic estimate |
25 | // counting 2 bytes for each int) |
26 | settable TargetAndActual<Double> kilobytes = new(250.0); |
27 | settable new TargetAndActual<Double> coveredPixelsPercentage; |
28 | settable new TargetAndActual<Double> detailLevel; |
29 | |
30 | settable bool vectorize = true; |
31 | settable bool allowPartialSSIs = true; |
32 | |
33 | gettable bool blackAndWhiteMode; |
34 | |
35 | settable SortMode sortMode = SortMode.compressibility; |
36 | |
37 | enum SortMode { compressibility, pixels } |
38 | |
39 | BufferedImage blurredImage; |
40 | int maxLines, maxInts; |
41 | L<? extends AbstractSSI> currentSSIs; // ssis at current stage |
42 | L<SSI> initialSSIs; |
43 | AbstractSSIList sortedSSIs, cutSSIs, |
44 | vectorizedSSIs, cutVectorizedSSIs; |
45 | CutListToBudget<AbstractSSI> cutter; |
46 | |
47 | // We store the posterized image as Hi15 |
48 | Hi15Image posterizedImage; |
49 | |
50 | // Region maker + regions |
51 | |
52 | FastRegions_Hi15Image regionMaker; |
53 | L<IImageRegion<Hi15Image>> regions, regionsBySize; |
54 | |
55 | // Constructors |
56 | |
57 | *() {} |
58 | *(BufferedImage *inputImage) {} |
59 | *(MakesBufferedImage inputImage) { this.inputImage = inputImage.getBufferedImage(); } |
60 | |
61 | // Methods |
62 | |
63 | SinglePixelPosterizer posterizer() { |
64 | ret new SinglePixelPosterizer(colorsPerChannel()).drift(drift).antiDrift(antiDrift); |
65 | } |
66 | |
67 | selfType kb(TargetAndActual<Double> kb) { ret kilobytes(kb); } |
68 | TargetAndActual<Double> kb() { ret kilobytes; } |
69 | |
70 | WidthAndHeight resolution() { |
71 | ret imageSize(inputImage); |
72 | } |
73 | |
74 | double detailDivisor() { |
75 | ret areaRoot(inputImage); |
76 | } |
77 | |
78 | int colors() { |
79 | ret blackAndWhiteMode ? 2 : cubed(colorsPerChannel()); |
80 | } |
81 | |
82 | transient simplyCached FieldVar<Int> varColors() { |
83 | ret new FieldVar<Int>(this, "colors", l0 colors, l1 colors); |
84 | } |
85 | |
86 | // choose number of colors for posterized image |
87 | selfType colors(int colors) { |
88 | int perChannel = iceil(cbrt(colors)); |
89 | blackAndWhiteMode = colors == 2; |
90 | ret colorsPerChannel(perChannel); |
91 | } |
92 | |
93 | stage "Steal" { |
94 | if (stealingFrom != null) { |
95 | if (stealingFrom.inputImage != inputImage) |
96 | ret with stealingFrom = null; |
97 | |
98 | // Avoid keeping old data wranglers around through a stealingFrom chain |
99 | stealingFrom.stealingFrom = null; |
100 | } |
101 | } |
102 | |
103 | stage "Blur" { |
104 | if (stealingFrom != null) |
105 | if (stealingFrom.blur == blur) |
106 | ret with blurredImage = stealingFrom.blurredImage; |
107 | else |
108 | stealingFrom = null; |
109 | blurredImage = blurBufferedImage(blur, inputImage); |
110 | } |
111 | |
112 | stage posterizeStage "Posterize" { |
113 | if (stealingFrom != null) |
114 | if (eq(stealingFrom.posterizer(), posterizer())) |
115 | ret with posterizedImage = stealingFrom.posterizedImage; |
116 | else |
117 | stealingFrom = null; |
118 | |
119 | var image = blurredImage; |
120 | if (blackAndWhiteMode) |
121 | image = BWImage(image).getBufferedImage(); |
122 | //image = transformBufferedImageWithSimplePixelOp(image, rgb -> 0xFFFFFF, ...); |
123 | posterizedImage = posterizeBufferedImageToHi15(image, posterizer()); |
124 | } |
125 | |
126 | stage prepareRegionsStage "Prepare regions" { |
127 | if (stealingFrom != null) |
128 | if (stealingFrom.withDiagonals == withDiagonals) { |
129 | regionMaker = stealingFrom.regionMaker; |
130 | regions = stealingFrom.regions; |
131 | ret; |
132 | } else |
133 | stealingFrom = null; |
134 | |
135 | regionMaker = new FastRegions_Hi15Image(posterizedImage); |
136 | regionMaker.withDiagonals(withDiagonals); |
137 | } |
138 | |
139 | stage regionsStage "Regions" { |
140 | regions = regionMaker!; |
141 | } |
142 | |
143 | stage biggestRegionsStage "Sort regions" { |
144 | regions = regionsBySize = biggestRegionsFirst(regions); |
145 | } |
146 | |
147 | stage "SSIs" { |
148 | initialSSIs = new L; |
149 | for (region : regions) |
150 | initialSSIs.addAll(new G22_RegionToSSIs_v2(region).withDiagonals (withDiagonals)!); |
151 | currentSSIs = initialSSIs; |
152 | } |
153 | |
154 | int initialSSILines() { |
155 | ret totalSSILines(initialSSIs); |
156 | } |
157 | |
158 | stage "Vector-Optimize" { |
159 | currentSSIs = vectorizedSSIs = vectorize |
160 | ? new VectorOptimizedSSIList(currentSSIs) |
161 | : new GeneralSSIList(currentSSIs); |
162 | } |
163 | |
164 | stage "Sort SSIs" { |
165 | if (sortMode == SortMode.compressibility) |
166 | sortedSSIs = new GeneralSSIList(sortedDesc(currentSSIs, (a, b) -> { |
167 | int x = cmp(a.compressibility(), b.compressibility()); |
168 | if (x != 0) ret x; |
169 | ret cmp(a.numberOfPixels(), b.numberOfPixels()); |
170 | })); |
171 | else if (sortMode == SortMode.pixels) |
172 | sortedSSIs = new GeneralSSIList(biggestSSIsFirst(currentSSIs)); |
173 | else |
174 | fail("Unknown sort mode"); |
175 | currentSSIs = sortedSSIs; |
176 | } |
177 | |
178 | stage "Cut SSI List by detail level" { |
179 | maxLines = !detailLevel.hasTarget() ? Int.MAX_VALUE |
180 | : iround(detailDivisor()*detailLevel.target()); |
181 | currentSSIs = cutSSIs = new GeneralSSIList(takeFirstNSSILines(maxLines, currentSSIs)); |
182 | detailLevel.set(l(cutSSIs)/detailDivisor()); |
183 | } |
184 | |
185 | stage "Cut Vector-Optimized SSIs by file size" { |
186 | maxInts = !kilobytes.hasTarget() ? Int.MAX_VALUE |
187 | : iround(kilobytes.target()*512); // assuming 16 bit ints |
188 | cutter = new CutListToBudget<AbstractSSI>(ssi -> (double) ssi.sizeInInts(), maxInts, (L) currentSSIs); |
189 | |
190 | if (allowPartialSSIs) |
191 | cutter.allowPartial((ssi, budget) -> ssi.reduceToInts(iround(budget))); |
192 | |
193 | currentSSIs = cutVectorizedSSIs = new GeneralSSIList(cutter!); |
194 | kilobytes.set(totalSizeInInts(cutVectorizedSSIs)/512.0); |
195 | } |
196 | |
197 | L<IImageRegion<Hi15Image>> regions() { |
198 | stepUntilStage(regionsStage); |
199 | ret regions; |
200 | } |
201 | |
202 | L<IImageRegion<Hi15Image>> regionsBySize() { |
203 | stepUntilStage(biggestRegionsStage); |
204 | ret regions; |
205 | } |
206 | |
207 | L<IBinaryImage> regionsAsIBinaryImages() { |
208 | ret map regionToIBinaryImage(regions()); |
209 | } |
210 | |
211 | BlurAndPosterizeSettings bnpSettings() { |
212 | ret new BlurAndPosterizeSettings() |
213 | .blur(blur) |
214 | .colors(colors()) |
215 | .colorDrift(new RGB(drift())) |
216 | .antiDrift(new RGB(antiDrift)); |
217 | } |
218 | |
219 | void importSettings(BlurAndPosterizeSettings bnp) { |
220 | blur(bnp.blur); |
221 | colors(bnp.colors); |
222 | drift(bnp.colorDrift.brightness()); |
223 | antiDrift(bnp.antiDrift.brightness()); |
224 | } |
225 | |
226 | FastRegions_Hi15Image preparedRegionMaker() { |
227 | stepUntilStage(prepareRegionsStage); |
228 | ret regionMaker; |
229 | } |
230 | |
231 | FastRegions_Hi15Image regionMaker() { |
232 | stepUntilStage(regionsStage); |
233 | ret regionMaker; |
234 | } |
235 | |
236 | toString { |
237 | ret commaCombine( |
238 | shortClassName(this), |
239 | imageSize(inputImage), |
240 | "completed stages: " + or2(joinWithComma(completedStages()), "-") |
241 | ); |
242 | } |
243 | |
244 | Hi15Image posterizedImage() { |
245 | stepUntilStage(posterizeStage); |
246 | ret posterizedImage; |
247 | } |
248 | } |
download show line numbers debug dex old transpilations
Travelled to 3 computer(s): elmgxqgtpvxh, mqqgnosmbjvj, wnsclhtenguj
No comments. add comment
Snippet ID: | #1035748 |
Snippet name: | G22DataWrangler |
Eternal ID of this version: | #1035748/89 |
Text MD5: | 61be3468a1aef32a57c634f5fc256d74 |
Transpilation MD5: | 7ebeeb6c5b2c186a0425205b7812994c |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2023-02-13 18:29:23 |
Source code size: | 7556 bytes / 248 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 342 / 830 |
Version history: | 88 change(s) |
Referenced in: | [show references] |