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

268
LINES

< > BotCompany Repo | #1004247 // BWImage (8 bit grayscale)

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

Libraryless. Click here for Pure Java version (10724L/61K).

static final class BWImage extends Meta implements MakesBufferedImage, IBWImage {
  int width, height;
  byte[] pixels;

  // color returned when getPixel is called with a position outside the actual image
  float borderColor = 0.0f;
  
  // for unstructure()
  *() {}

  // BLACK!
  *(int *width, int *height) {
    pixels = new byte[width*height];
  }

  *(int *width, int *height, float brightness) {
    pixels = new byte[width*height];
    fillArrayUnlessZero(pixels, _toByte(brightness));
  }
  
  *(int *width, int *height, float[] pixels) {
    this.pixels = new byte[pixels.length];
    for (int i = 0; i < pixels.length; i++)
      this.pixels[i] = _toByte(pixels[i]);
  }

  public BWImage(int width, int height, byte[] pixels) {
    this.height = height;
    this.width = width;
    this.pixels = pixels;
  }

  public BWImage(BWImage image) {
    width = image.getWidth();
    height = image.getHeight();
    byte[] pixels = this.pixels = new byte[width*height];
    for (int y = 0; y < height; y++)
      for (int x = 0; x < width; x++)
        pixels[y*width+x] = image.getByte(x, y);
  }

  // TODO: optimize!
  *(RGBImage image) {
    width = image.getWidth();
    height = image.getHeight();
    byte[] pixels = this.pixels = new byte[height*width];
    for (int y = 0; y < height; y++)
      for (int x = 0; x < width; x++) {
        RGB rgb = image.getRGB(x, y);
        pixels[y*width+x] = BWImage._toByte(rgb.getBrightness());
      }
  }

  /*public BWImage(BufferedImage image) {
    this(new RGBImage(image));
  }*/

  *(BufferedImage image) ctex {
    width = image.getWidth();
    height = image.getHeight();
    int[] pixels = new int[width*height];
    byte[] bytePixels = this.pixels = new byte[width*height];
    PixelGrabber pixelGrabber = new PixelGrabber(image, 0, 0, width, height, pixels, 0, width);
    if (!pixelGrabber.grabPixels())
      fail("Could not grab pixels");
    int n = width*height;
    
    for (int i = 0; i < n; i++) {
      //bytePixels[i] = pixelToByte(pixels[i]);
      int packed = pixels[i];
      /*float r = ((packed >> 16) & 0xFF)/255f;
      float g = ((packed >> 8) & 0xFF)/255f;
      float b = (packed & 0xFF)/255f;
      bytePixels[i] = (byte) iround((r+g+b)/3.0f*255f);*/
      int r = ((packed >> 16) & 0xFF);
      int g = ((packed >> 8) & 0xFF);
      int b = (packed & 0xFF);
      bytePixels[i] = (byte) ((r+g+b+1)/3);
    }
  }
  
  // TODO: does it exactly match the other method? (asRGB+getBrightness+_toByte)
  static byte pixelToByte(int packed) {
    /*int r = (packed >> 16) & 0xFF;
    int g = (packed >> 8) & 0xFF;
    int b = packed & 0xFF;
    ret (byte) ((r+g+b)/3.0f);*/
    float r = ((packed >> 16) & 0xFF)/255f;
    float g = ((packed >> 8) & 0xFF)/255f;
    float b = (packed & 0xFF)/255f;
    ret (byte) ((r+g+b)/3.0f*255f);
  }

  public byte getByte(int x, int y) {
    return inRange(x, y) ? getByte_noRangeCheck(x, y) : _toByte(borderColor);
  }
  
  // pretty bad function name
  // gets brightness (0 to 255) at pixel
  public int getInt(int x, int y) {
    ret ubyteToInt(getByte(x, y));
  }
  
  // idx = index in pixel array
  public int getInt_noRangeCheck(int idx) {
    ret ubyteToInt(pixels[idx]);
  }
  
  // gets brightness (0 to 255) at pixel with default if out of image
  public int getInt(int x, int y, int defaultValue) {
    ret inRange(x, y) ? getInt(x, y) : defaultValue;
  }
  
  public double averageBrightness() {
    double sum = 0;
    int n = width*height;
    for i to n:
      sum += getInt_noRangeCheck(i);
    ret sum/n;
  }

  public float minimumBrightness() {
    float min = 1;
    for (int y = 0; y < height; y++)
      for (int x = 0; x < width; x++)
        min = Math.min(min, getPixel(x, y));
    return min;
  }

  public float maximumBrightness() {
    float max = 0;
    for (int y = 0; y < height; y++)
      for (int x = 0; x < width; x++)
        max = Math.max(max, getPixel(x, y));
    return max;
  }

  float getPixel(int x, int y) {
    return inRange(x, y) ? _toFloat(getByte(x,y )) : borderColor;
  }
  
  public float getFloatPixel(int x, int y) { ret getPixel(x, y); }
  
  float getPixel(Pt p) { ret getPixel(p.x, p.y); }

  static byte _toByte(float pixel) {
    return (byte) (pixel*255f);
  }

  static float _toFloat(byte pixel) {
    return (((int) pixel) & 255)/255f;
  }

  private boolean inRange(int x, int y) {
    return x >= 0 && x < width && y >= 0 && y < height;
  }

  public int getWidth() { return width; }
  public int getHeight() { return height; }

  public RGBImage toRGB() {
    int[] rgbs = new int[width*height];
    for (int y = 0; y < height; y++)
      for (int x = 0; x < width; x++) {
        int b = getByte(x, y) & 0xFF;
        rgbs[y*width+x] = 0xFF000000 | b*0x010101;
      }
    return new RGBImage(width, height, rgbs);
  }
  
  public RGBImage toRGB_slow() {
    RGB[] rgbs = new RGB[width*height];
    for (int y = 0; y < height; y++)
      for (int x = 0; x < width; x++) {
        float p = getPixel(x, y);
        rgbs[y*width+x] = new RGB(p, p, p);
      }
    return new RGBImage(width, height, rgbs);
  }


  public BWImage clip(int x, int y, int w, int h) {
    return clip(new Rectangle(x, y, w, h));
  }

  private Rectangle fixClipRect(Rectangle r) {
    return r.intersection(new Rectangle(0, 0, width, height));
  }

  BWImage clip(Rect r) {
    ret clip(r.getRectangle());
  }
  
  /** this should be multithread-safe */
  public BWImage clip(Rectangle r) {
    r = fixClipRect(r);
    byte[] newPixels = new byte[r.height*r.width];
    for (int y = 0; y < r.height; y++)
      for (int x = 0; x < r.width; x++)
        newPixels[y*r.width+x] = getByte(r.x+x, r.y+y);
    return new BWImage(r.width, r.height, newPixels);
  }

  public void setPixel(int x, int y, float brightness) {
    setByte(x, y, _toByte(fixPixel(brightness)));
  }
  
  // i = 0 to 255
  public void setInt(int x, int y, int i) {
    setByte(x, y, (byte) limitToUByte(i));
  }
  
  public void setInt(Pt p, int i) {
    setInt(p.x, p.y, i);
  }
  
  public void setByte(int x, int y, byte b) {
    if (x >= 0 && x < width && y >= 0 && y < height)
      pixels[y*width+x] = b;
  }

  byte getByte_noRangeCheck(int x, int y) {
    return pixels[y*width+x];
  }

  public void setByte(int x, int y, int brightness) {
    setByte(x, y, (byte) brightness);
  }

  private float fixPixel(float pixel) {
    return Math.max(0, Math.min(1, pixel));
  }

  public float getBorderColor() {
    return borderColor;
  }

  public void setBorderColor(float borderColor) {
    this.borderColor = borderColor;
  }

  public boolean anyPixelBrighterThan(double threshold) {
    for (int y = 0; y < height; y++)
      for (int x = 0; x < width; x++)
        if (getPixel(x, y) > threshold)
          return true;
    return false;
  }
  
  int[] getRGBPixels() {
    int n = width*height;
    int[] out = new[n];
    for i to n: {
      var b = ubyteToInt(pixels[i]);
      b |= (b << 8) | (b << 16);
      out[i] = b | 0xFF000000;
    }
    ret out;
  }
  
  public BufferedImage getBufferedImage() {
    ret bufferedImage(getRGBPixels(), width, height);
  }
  
  byte[] getBytes() {
    ret pixels;
  }
}

download  show line numbers  debug dex  old transpilations   

Travelled to 20 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mowyntqkapby, mqqgnosmbjvj, ofpaelxlmzfo, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, sawdedvomwva, tslmcundralx, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1004247
Snippet name: BWImage (8 bit grayscale)
Eternal ID of this version: #1004247/40
Text MD5: bec097e59aadd3a79597341d9837dc8e
Transpilation MD5: 64916b5bedf5faa1a3393fbced4fb2a5
Author: stefan
Category: javax / imaging
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-07-21 19:02:58
Source code size: 7431 bytes / 268 lines
Pitched / IR pitched: No / No
Views / Downloads: 1159 / 5828
Version history: 39 change(s)
Referenced in: [show references]