Libraryless. Click here for Pure Java version (21132L/129K).
1 | // fills fully transparent pixels in the image with |
2 | // the color of the (roughly) closest non-transparent neighbor pixel |
3 | |
4 | sclass ImageInfiller {
|
5 | settable BufferedImage inputImage; |
6 | |
7 | // how far to infill (pixels) |
8 | settable int maxDepth = 2; |
9 | |
10 | // whether to make the infilled pixels (semi-) transparent |
11 | settable int infillOpacity = 255; |
12 | |
13 | settable bool verbose; |
14 | |
15 | int w, h; |
16 | int[] pixels; |
17 | IntBuffer queue; // pixel indices for current round |
18 | IntBuffer nextQueue; // pixel indices for next round |
19 | BufferedImage outputImage; |
20 | gettable int rounds; |
21 | gettable int filledPixels; |
22 | |
23 | *() {}
|
24 | *(BufferedImage *inputImage) {}
|
25 | *(BufferedImage *inputImage, int *maxDepth) {}
|
26 | |
27 | run {
|
28 | prepare(); |
29 | while (!done()) |
30 | oneRound(); |
31 | } |
32 | |
33 | bool prepared() { ret pixels != null; }
|
34 | |
35 | bool done() {
|
36 | ret nextQueue != null && nextQueue.isEmpty() |
37 | || rounds >= maxDepth; |
38 | } |
39 | |
40 | BufferedImage get() {
|
41 | run(); |
42 | ret pixelsToBufferedImage(pixels, w); |
43 | } |
44 | |
45 | void prepare {
|
46 | if (pixels != null) ret; |
47 | pixels = pixelsFromBufferedImage(inputImage); |
48 | w = inputImage.getWidth(); |
49 | h = inputImage.getHeight(); |
50 | } |
51 | |
52 | void oneRound {
|
53 | ++rounds; |
54 | queue = nextQueue; |
55 | nextQueue = new IntBuffer; |
56 | new BitSet queued; |
57 | assertBetween("infillOpacity", 1, 255, infillOpacity);
|
58 | |
59 | new IntBuffer toFill; // pixel index, color, pixel index, color, ... |
60 | for (pos : queue == null ? countIterator(w*h) : queue) {
|
61 | int rgba = pixels[pos]; |
62 | if (!isFullyTransparent(rgba)) continue; |
63 | |
64 | int x = pos % w, y = pos/w; |
65 | new MultiSet<Int> surroundingColors; |
66 | for (int y2 = max(0, y-1); y2 < min(h, y+2); y2++) |
67 | for (int x2 = max(0, x-1); x2 < min(w, x+2); x2++) {
|
68 | rgba = pixels[y2*w+x2]; |
69 | if (!isFullyTransparent(rgba)) |
70 | surroundingColors.add(withOpacity(infillOpacity, rgba)); |
71 | } |
72 | |
73 | if (!surroundingColors.isEmpty()) {
|
74 | // Surrounding color found, fill pixel |
75 | toFill.add(y*w+x); |
76 | toFill.add(surroundingColors.mostPopular()); |
77 | filledPixels++; |
78 | // Schedule surrounding transparent pixels |
79 | for (int y2 = max(0, y-1); y2 < min(h, y+2); y2++) |
80 | for (int x2 = max(0, x-1); x2 < min(w, x+2); x2++) {
|
81 | int pos2 = y2*w+x2; |
82 | if (!queued.get(pos2) && isFullyTransparent(pixels[pos2])) {
|
83 | queued.set(pos2); |
84 | nextQueue.add(pos2); |
85 | } |
86 | } |
87 | } |
88 | } |
89 | |
90 | queue = null; |
91 | int n = l(toFill); |
92 | for (int i = 0; i < n; i += 2) |
93 | pixels[toFill.get(i)] = toFill.get(i+1); |
94 | |
95 | if (verbose) |
96 | print("Round " + rounds + " pixels filled: " + n2(filledPixels) + ", nextQueue: " + l(nextQueue));
|
97 | } |
98 | |
99 | selfType unlimited() {
|
100 | maxDepth(Int.MAX_VALUE); |
101 | this; |
102 | } |
103 | |
104 | void eraseOriginalPixels {
|
105 | run(); |
106 | if (infillOpacity >= 255) fail("Need semi-transparency to erase original pixels");
|
107 | int[] pixels = this.pixels; |
108 | for i over pixels: |
109 | if (!isTransparent(pixels[i])) |
110 | pixels[i] = 0; |
111 | } |
112 | |
113 | // works only after at least one round was run |
114 | int nRemainingTransparentPixels() {
|
115 | ret nextQueue.size(); |
116 | } |
117 | } |
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: | 692 / 938 |
| Version history: | 33 change(s) |
| Referenced in: | [show references] |