Warning: session_start(): open(/var/lib/php/sessions/sess_6dhh7trth5uqpc8uro5u3j5ot4, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
// fills fully transparent pixels in the image with
// the color of the (roughly) closest non-transparent neighbor pixel
sclass ImageInfiller {
settable BufferedImage inputImage;
// how far to infill (pixels)
settable int maxDepth = 2;
// whether to make the infilled pixels (semi-) transparent
settable int infillOpacity = 255;
settable bool verbose;
int w, h;
int[] pixels;
IntBuffer queue; // pixel indices for current round
IntBuffer nextQueue; // pixel indices for next round
BufferedImage outputImage;
gettable int rounds;
gettable int filledPixels;
*() {}
*(BufferedImage *inputImage) {}
*(BufferedImage *inputImage, int *maxDepth) {}
run {
prepare();
while (!done())
oneRound();
}
bool prepared() { ret pixels != null; }
bool done() {
ret nextQueue != null && nextQueue.isEmpty()
|| rounds >= maxDepth;
}
BufferedImage get() {
run();
ret pixelsToBufferedImage(pixels, w);
}
void prepare {
if (pixels != null) ret;
pixels = pixelsFromBufferedImage(inputImage);
w = inputImage.getWidth();
h = inputImage.getHeight();
}
void oneRound {
++rounds;
queue = nextQueue;
nextQueue = new IntBuffer;
new BitSet queued;
assertBetween("infillOpacity", 1, 255, infillOpacity);
new IntBuffer toFill; // pixel index, color, pixel index, color, ...
for (pos : queue == null ? countIterator(w*h) : queue) {
int rgba = pixels[pos];
if (!isFullyTransparent(rgba)) continue;
int x = pos % w, y = pos/w;
new MultiSet surroundingColors;
for (int y2 = max(0, y-1); y2 < min(h, y+2); y2++)
for (int x2 = max(0, x-1); x2 < min(w, x+2); x2++) {
rgba = pixels[y2*w+x2];
if (!isFullyTransparent(rgba))
surroundingColors.add(withOpacity(infillOpacity, rgba));
}
if (!surroundingColors.isEmpty()) {
// Surrounding color found, fill pixel
toFill.add(y*w+x);
toFill.add(surroundingColors.mostPopular());
filledPixels++;
// Schedule surrounding transparent pixels
for (int y2 = max(0, y-1); y2 < min(h, y+2); y2++)
for (int x2 = max(0, x-1); x2 < min(w, x+2); x2++) {
int pos2 = y2*w+x2;
if (!queued.get(pos2) && isFullyTransparent(pixels[pos2])) {
queued.set(pos2);
nextQueue.add(pos2);
}
}
}
}
queue = null;
int n = l(toFill);
for (int i = 0; i < n; i += 2)
pixels[toFill.get(i)] = toFill.get(i+1);
if (verbose)
print("Round " + rounds + " pixels filled: " + n2(filledPixels) + ", nextQueue: " + l(nextQueue));
}
selfType unlimited() {
maxDepth(Int.MAX_VALUE);
this;
}
void eraseOriginalPixels {
run();
if (infillOpacity >= 255) fail("Need semi-transparency to erase original pixels");
int[] pixels = this.pixels;
for i over pixels:
if (!isTransparent(pixels[i]))
pixels[i] = 0;
}
// works only after at least one round was run
int nRemainingTransparentPixels() {
ret nextQueue.size();
}
}