// TODO: different sorting methods, e.g. "widest SSIs" sclass G22DataWrangler > Stages is IHasChangeListeners { event change; settable BufferedImage inputImage; settable bool withDiagonals = true; settableWithVar int blur = 1; // in pixels // kilobytes per compressed image (pessimistic estimate // counting 2 bytes for each int) settable TargetAndActual kilobytes = new(250.0); settable new TargetAndActual coveredPixelsPercentage; settable new TargetAndActual detailLevel; settable bool vectorize = true; settable bool allowPartialSSIs = true; settable IPosterizer posterizer = new SinglePixelPosterizer(4); BufferedImage blurredImage; int maxLines, maxInts; AbstractSSIList vectorizedSSIs, cutVectorizedSSIs; CutListToBudget cutter; // We store the posterized image as Hi15 Hi15Image posterizedImage; FastRegions_Hi15Image regionMaker; L> regions; L initialSSIs, sortedSSIs, cutSSIs; selfType kb(TargetAndActual kb) { ret kilobytes(kb); } TargetAndActual kb() { ret kilobytes; } WidthAndHeight resolution() { ret imageSize(inputImage); } double detailDivisor() { ret areaRoot(inputImage); } // choose number of colors for posterized image selfType colors(int colors) { int perChannel = iceil(cbrt(colors)); posterizer = new SinglePixelPosterizer(perChannel); this; } stage "Blur" { blurredImage = blurBufferedImage(blur, inputImage); } stage "Posterize" { posterizedImage = new Hi15Image(posterizeBufferedImage(blurredImage, posterizer)); } stage "Regions" { regionMaker = new FastRegions_Hi15Image(posterizedImage); regionMaker.withDiagonals(withDiagonals); regions = regionMaker!; } stage "SSIs" { initialSSIs = new L; for (region : regions) initialSSIs.addAll(new G22_RegionToSSIs_v2(region).withDiagonals (withDiagonals)!); } stage "Sort SSIs" { sortedSSIs = biggestSSIsFirst(initialSSIs); } int initialSSILines() { ret totalSSILines(sortedSSIs); } stage "Cut SSI List" { maxLines = !detailLevel.hasTarget() ? Int.MAX_VALUE : iround(detailDivisor()*detailLevel.target()); cutSSIs = takeFirstNSSILines(maxLines, sortedSSIs); detailLevel.set(l(cutSSIs)/detailDivisor()); } stage "Vector-Optimize" { vectorizedSSIs = vectorize ? new VectorOptimizedSSIList(initialSSIs) : new GeneralSSIList(initialSSIs); } stage "Cut Vector-Optimized SSIs by file size" { maxInts = !kilobytes.hasTarget() ? Int.MAX_VALUE : iround(kilobytes.target()*512); // assuming 16 bit ints cutter = new CutListToBudget(ssi -> (double) ssi.sizeInInts(), maxInts, vectorizedSSIs); if (allowPartialSSIs) cutter.allowPartial((ssi, budget) -> ssi.reduceToInts(iround(budget))); cutVectorizedSSIs = new GeneralSSIList(cutter!); kilobytes.set(totalSizeInInts(cutVectorizedSSIs)/512.0); } }