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: | 236 / 425 |
Version history: | 33 change(s) |
Referenced in: | [show references] |