Libraryless. Click here for Pure Java version (21132L/129K).
// 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<Int> 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(); } }
download show line numbers debug dex old transpilations
Travelled to 2 computer(s): elmgxqgtpvxh, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1035715 |
Snippet name: | ImageInfiller [fills transparent pixels with surrounding color] |
Eternal ID of this version: | #1035715/34 |
Text MD5: | ae29d7a03063176ad6c5b499718298c1 |
Transpilation MD5: | 289050c37ba3dd54ac837edaaefd8c98 |
Author: | stefan |
Category: | javax / imaging |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-07-29 22:33:47 |
Source code size: | 3297 bytes / 117 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 235 / 423 |
Version history: | 33 change(s) |
Referenced in: | #1003674 - Standard Classes + Interfaces (LIVE continued in #1034167) |