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).

// 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)