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

182
LINES

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

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

Libraryless. Click here for Pure Java version (14638L/84K).

// 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 extends AbstractSSI is ByteIO, StringIO {
  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
  // all x coordinates are absolute in image
  //
  // Order in array:
  //   x_left at y1, x_right at y1,
  //   x_left at y1+1, x_right at y1+1, ,,,
  settable X[] data;

  *(int y1, int y2) {
    init(y1, y2);
  }
  
  void init(int y1, int y2) {
    this.y1 = toY(y1);
    data = newXArray((y2-y1)*2);
  }
  
  // all coordinates passed in are absolute
  void set(int y, int xLeft, int xRight) {
    data[(y-y1)*2] = toX(xLeft);
    data[(y-y1)*2+1] = toX(xRight);
  }
  
  // all coordinates passed in and out are absolute
  int getLeft (int y) { ret data[(y-y1)*2]; }
  int getRight(int y) { ret data[(y-y1)*2+1]; }
  
  // 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(); }
  
  public bool contains(Pt p) { ret contains(p.x, p.y); }
  public 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];
  }
  
  selfType color(Color color) { super.color(color); this; }
  public selfType hi15color(short hi15color) { super.hi15color(hi15color); this; }
  
  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) {
    if (nLines <= 0) null;
    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);
    }
  }
  
  SSI toSSI() { this; }
  
  public long sizeInInts() {
    // "s", color, y1, height, data
    ret 4+height()*2;
  }
  
  SSI reduceToInts(int ints) {
    ret topPart((ints-4)/2);
  }
  
  public void readWrite(StringHead head) {
    head.exchangeLine(l0 toLine, l1 fromLine);
  }
  
  S toLine() {
    ret spaceCombine("s", colorToString(), y1, height(), toList(data));
  }
  
  void fromLine(S line) {
    Iterator<S> it = splitAtSpaceIterator(line);
    assertEquals("s", nextFromIterator(it));
    int y1 = parseInt(nextFromIterator(it));
    int h = parseInt(nextFromIterator(it));
    init(y1, y1+h);
    for i over data:
      data[i] = toX(parseInt(nextFromIterator(it)));
  }
}

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): elmgxqgtpvxh, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1035561
Snippet name: SSI (Simple Scanline Image)
Eternal ID of this version: #1035561/70
Text MD5: c026241203df534140b00dd7762cfefe
Transpilation MD5: a1a341d2c967cb9ea377c690363584bd
Author: stefan
Category: javax / imaging
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-07-25 14:33:29
Source code size: 5222 bytes / 182 lines
Pitched / IR pitched: No / No
Views / Downloads: 225 / 633
Version history: 69 change(s)
Referenced in: [show references]