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

154
LINES

< > BotCompany Repo | #1035707 // SSI (Simple Scanline Image) backup

JavaX fragment (include)

// SSI - Simple Scanline Image
// A partial image consisting of exactly one horizontal line per row.
// All pixels are of the same color.

// The important values are y1 and data
persistable sclass SSI is HasBounds, G2Drawable, ByteIO {
  replace X with short.
  replace Y with short.
  replace toX with toShort_enforce.
  replace toY with toShort_enforce.
  replace newXArray with newShortArrayOrNull.
  
  // core value (mandatory): first row occupied
  settable Y y1;
  
  // core value (mandatory): x coordinates per row
  // x_left is inclusive, x_right is exclusive
  //
  // Order in array:
  //   x_left at y1, x_right at y1,
  //   x_left at y1+1, x_right at y1+1, ,,,
  settable X[] data;

  // Color in 15 bit
  settable short hi15color;
  
  *(int y1, int y2) {
    init(y1, y2);
  }
  
  void init(int y1, int y2) {
    this.y1 = toY(y1);
    data = newXArray((y2-y1)*2);
  }
  
  void set(int y, int xLeft, int xRight) {
    data[(y-y1)*2] = toX(xLeft);
    data[(y-y1)*2+1] = toX(xRight);
  }
  
  // bounds can be calculated quickly from core values & are then cached
  public simplyCached Rect bounds() {
    int x1 = Int.MAX_VALUE, x2 = 0;
    for (int i = 0; i < l(data); i += 2) {
      x1 = min(x1, data[i]);
      x2 = max(x2, data[i+1]);
    }
    ret rectFromPoints(x1, y1, x2, y2());
  }
  
  // same with number of pixels
  int numberOfPixels_cache = -1;
  public int numberOfPixels() {
    if (numberOfPixels_cache < 0) {
      int n = 0;
      for (int i = 0; i < l(data); i += 2)
        n += max(0, data[i+1]-data[i]);
      numberOfPixels_cache = n;
    }
    ret numberOfPixels_cache;
  }
  
  public int getHeight() { ret l(data)/2; }
  int y2() { ret y1+height(); }
  
  bool contains(Pt p) { ret contains(p.x, p.y); }
  bool contains(int x, int y) {
    if (y < y1) false;
    int i = (y-y1)*2;
    if (i >= l(data)) false;
    ret x >= data[i] && x < data[i+1];
  }
  
  Color color() {
    ret main hi15color(hi15color);
  }
  
  selfType color(RGB color) {
    ret hi15color(rgbToHi15(color));
  }
  
  public void drawOn(Graphics2D g) {
    g.setColor(color());
    int h = height();
    for y to h: {
      int x1 = data[y*2], x2 = data[y*2+1];
      if (x1 < x2)
        g.drawLine(x1, y1+y, x2-1, y1+y);
    }
  }
  
  // doesn't set a color
  // TODO
  public void drawOutline(Graphics2D g) {
    int h = height();
    IntRange last = intRange(0, 0);
    for y to h: {
      IntRange r = intRange(data[y*2], data[y*2+1]);
      
      // anything to draw in this line?
      if (nempty(r)) {
        if (empty(last))
          // draw full line if just starting
          g.drawLine(r.start, y1+y, r.end-1, y1+y);
        else {
          // We make a line from the left boundary that if possible goes only to last.start but is at least 1 pixel wide
          int xleft = max(r.start, last.start-1);
          
          // Same from the right boundary
          int xright = min(r.end-1, last.end);
          
          g.drawLine(r.start, y1+y, xleft, y1+y);
          g.drawLine(xright, y1+y, r.end-1, y1+y);
        }
      }
      
      last = r;
    }
  }
  
  SSI topPart(int nLines) {
    SSI ssi = new SSI(y1, toShort_enforce(y1+nLines)).hi15color(hi15color);
    arrayCopy(data, ssi.data, 0, l(ssi.data));
    ret ssi;
  }
  
  // an SSI is coherent if all scanlines are non-empty
  // and the SSI is one region
  bool coherent(bool withDiagonals default false) {
    int h = height();
    for y to h: {
      int i = y*2;
      int x1 = data[i], x2 = data[i+1];
      if (x1 >= x2) false;
      if (y > 0) {
        int lastx1 = data[i-2], lastx2 = data[i-1];
        if (withDiagonals) { lastx1--; lastx2++; }
        if (!intRangesOverlap(x1, x2, lastx1, lastx2))
          false;
      }
    }
    true;
  }
  
  public void readWrite(ByteHead head) {
    head.exchangeShort(-> hi15color, color -> hi15color = color);
    head.exchangeShort(-> y1, y1 -> this.y1 = y1);
    head.exchangeShort(-> toShort_enforce(y2()), y2 -> init(y1, y2));
    for i over data: {
      reMutable i;
      head.exchangeShort(-> data[i], x -> data[i] = x);
    }
  }
}

Author comment

Began life as a copy of #1035561

download  show line numbers  debug dex  old transpilations   

Travelled to 1 computer(s): mqqgnosmbjvj

No comments. add comment

Snippet ID: #1035707
Snippet name: SSI (Simple Scanline Image) backup
Eternal ID of this version: #1035707/1
Text MD5: c73eb78aa1bfafffbe1dbfdd683dab3f
Author: stefan
Category: javax / imaging
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-07-09 23:59:29
Source code size: 4259 bytes / 154 lines
Pitched / IR pitched: No / No
Views / Downloads: 118 / 127
Referenced in: [show references]