Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

117
LINES

< > BotCompany Repo | #1035715 // ImageInfiller [fills transparent pixels with surrounding color]

JavaX fragment (include) [tags: use-pretranspiled]

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]