19
19
package pl .asie .zima .image ;
20
20
21
21
import lombok .AllArgsConstructor ;
22
+ import lombok .Data ;
22
23
import lombok .Getter ;
23
24
import pl .asie .libzzt .Board ;
24
25
import pl .asie .libzzt .Element ;
37
38
import java .util .ArrayList ;
38
39
import java .util .Comparator ;
39
40
import java .util .HashSet ;
40
- import java .util .LinkedHashMap ;
41
41
import java .util .List ;
42
- import java .util .Map ;
43
42
import java .util .Set ;
44
43
import java .util .function .IntPredicate ;
45
44
import java .util .stream .Collectors ;
@@ -107,17 +106,27 @@ private Pair<Result, BufferedImage> convertBoardless(BufferedImage inputImage, i
107
106
List <ElementResult > rules = new ArrayList <>(256 * 256 );
108
107
final int progressSize = width * height ;
109
108
ElementResult [] previewResults = new ElementResult [width * height ];
109
+ ElementResult emptyResult = null ;
110
110
BufferedImage preview = null ;
111
111
112
112
for (int ich = 0 ; ich < 256 ; ich ++) {
113
113
if (fast && (ich != 32 && ich != 176 && ich != 177 && ich != 178 && ich != 219 )) continue ;
114
114
if (charCheck != null && !charCheck .test (ich )) continue ;
115
115
for (int ico = 0 ; ico < 256 ; ico ++) {
116
116
if (colorCheck != null && !colorCheck .test (ico )) continue ;
117
- rules .add (new ElementResult (null , false , false , ich , ico ));
117
+ ElementResult result = new ElementResult (null , false , false , ich , ico );
118
+ if (emptyResult == null ) {
119
+ emptyResult = result ;
120
+ }
121
+ rules .add (result );
118
122
}
119
123
}
120
124
125
+ if (emptyResult == null ) {
126
+ emptyResult = new ElementResult (null , false , false , 0 , 0 );
127
+ }
128
+ final ElementResult emptyResultFinal = emptyResult ;
129
+
121
130
// find lowest-MSE results for each tile, in parallel
122
131
IntStream .range (0 , width * height ).parallel ().forEach (pos -> {
123
132
synchronized (progressCallback ) {
@@ -127,7 +136,7 @@ private Pair<Result, BufferedImage> convertBoardless(BufferedImage inputImage, i
127
136
int ix = pos % width ;
128
137
int iy = pos / width ;
129
138
130
- ElementResult minResult = null ;
139
+ ElementResult minResult = emptyResultFinal ;
131
140
float minMse = Float .MAX_VALUE ;
132
141
ImageMseCalculator .Applier applyMseFunc = mseCalculator .applyMse (inputImage , ix * visual .getCharWidth (), iy * visual .getCharHeight ());
133
142
@@ -166,6 +175,12 @@ private Pair<Result, BufferedImage> convertBoardless(BufferedImage inputImage, i
166
175
return new Pair <>(result , preview );
167
176
}
168
177
178
+ @ Data
179
+ private static class ElementRuleResult {
180
+ private final ElementRule rule ;
181
+ private final List <ElementResult > result ;
182
+ }
183
+
169
184
public Pair <Result , BufferedImage > convert (BufferedImage inputImage , ImageConverterRuleset ruleset ,
170
185
int x , int y , int width , int height , int playerX , int playerY , int maxStatCount , boolean blinkingDisabled ,
171
186
int maxBoardSize ,
@@ -190,7 +205,7 @@ public Pair<Result, BufferedImage> convert(BufferedImage inputImage, ImageConver
190
205
final BufferedImage image = inputImage ;
191
206
192
207
List <Triplet <Coord2D , ElementResult , Float >> statfulStrategies = new ArrayList <>();
193
- Map < ElementRule , List <ElementResult >> ruleResultMap = new LinkedHashMap <>();
208
+ List <ElementRuleResult > ruleResultList = new ArrayList <>(ruleset . getRules (). size () );
194
209
Set <Element > allowedElements = new HashSet <>();
195
210
ElementResult [] previewResults = new ElementResult [width * height ];
196
211
float [] previewMse = new float [width * height ];
@@ -248,7 +263,7 @@ public Pair<Result, BufferedImage> convert(BufferedImage inputImage, ImageConver
248
263
break ;
249
264
}
250
265
251
- ruleResultMap . put ( rule , proposals .collect (Collectors .toList ()));
266
+ ruleResultList . add ( new ElementRuleResult ( rule , proposals .collect (Collectors .toList () )));
252
267
}
253
268
254
269
// find lowest-MSE results for each tile, in parallel
@@ -276,8 +291,8 @@ public Pair<Result, BufferedImage> convert(BufferedImage inputImage, ImageConver
276
291
float statfulMse = Float .MAX_VALUE ;
277
292
ImageMseCalculator .Applier applyMseFunc = mseCalculator .applyMse (image , ix * visual .getCharWidth (), iy * visual .getCharHeight ());
278
293
279
- for (Map . Entry < ElementRule , List < ElementResult >> ruleResult : ruleResultMap . entrySet () ) {
280
- List <ElementResult > proposals = ruleResult .getValue ();
294
+ for (ElementRuleResult ruleResult : ruleResultList ) {
295
+ List <ElementResult > proposals = ruleResult .getResult ();
281
296
282
297
float lowestLocalMse = statlessMse ;
283
298
ElementResult lowestLocalResult = null ;
@@ -336,10 +351,8 @@ public Pair<Result, BufferedImage> convert(BufferedImage inputImage, ImageConver
336
351
int boardSerializationSize = count (board ::writeZ );
337
352
int addedStats = 0 ;
338
353
354
+ Stat stat = new Stat ();
339
355
for (int i = 0 ; i < statfulStrategies .size (); i ++) {
340
- if (addedStats >= realMaxStatCount ) {
341
- break ;
342
- }
343
356
Triplet <Coord2D , ElementResult , Float > strategyData = statfulStrategies .get (i );
344
357
Coord2D coords = strategyData .getFirst ();
345
358
ElementResult result = strategyData .getSecond ();
@@ -352,25 +365,28 @@ public Pair<Result, BufferedImage> convert(BufferedImage inputImage, ImageConver
352
365
previewResults [coords .getY () * width + coords .getX ()] = result ;
353
366
board .setElement (x + coords .getX (), y + coords .getY (), result .getElement ());
354
367
board .setColor (x + coords .getX (), y + coords .getY (), result .getColor ());
355
- Stat stat = new Stat ();
368
+
356
369
stat .setX (x + coords .getX ());
357
370
stat .setY (y + coords .getY ());
358
371
stat .setCycle (1 ); // maybe we can reduce this to save CPU cycles?
359
372
stat .setP1 (result .getCharacter ());
360
373
361
374
if (boardSerializationSize < (realMaxBoardSize - 128 )) {
362
375
// optimization: don't recalc full board size if only RLE could be impacted
363
- boardSerializationSize += count ( stat :: writeZ );
376
+ boardSerializationSize += stat . lengthZ ( platform );
364
377
} else {
365
- boardSerializationSize = count (board ::writeZ ) + count ( stat :: writeZ );
378
+ boardSerializationSize = count (board ::writeZ ) + stat . lengthZ ( platform );
366
379
}
367
380
if (boardSerializationSize > realMaxBoardSize ) {
368
381
previewResults [coords .getY () * width + coords .getX ()] = prevResult ;
369
382
board .setElement (x + coords .getX (), y + coords .getY (), prevElement );
370
383
board .setColor (x + coords .getX (), y + coords .getY (), prevColor );
371
384
} else {
372
385
board .addStat (stat );
373
- addedStats ++;
386
+ if ((++addedStats ) >= realMaxStatCount ) {
387
+ break ;
388
+ }
389
+ stat = new Stat ();
374
390
}
375
391
}
376
392
@@ -388,7 +404,7 @@ public Pair<Result, BufferedImage> convert(BufferedImage inputImage, ImageConver
388
404
Element element = board .getElement (x + ix , y + iy );
389
405
int color = board .getColor (x + ix , y + iy );
390
406
391
- if (!element .isText () && !element .isStat ()) {
407
+ if (!element .isText () && ( !element .isStat () || board . getStatAt ( x + ix , y + iy ) == null )) {
392
408
if (!blinkingDisabled && color >= 0x80 ) {
393
409
continue ;
394
410
}
0 commit comments