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

1  
// SSI - Simple Scanline Image
2  
// A partial image consisting of exactly one horizontal line per row.
3  
// All pixels are of the same color.
4  
5  
// The important values are y1 and data
6  
persistable sclass SSI extends AbstractSSI is ByteIO, StringIO {
7  
  replace X with short.
8  
  replace Y with short.
9  
  replace toX with toShort_enforce.
10  
  replace toY with toShort_enforce.
11  
  replace newXArray with newShortArrayOrNull.
12  
  
13  
  // core value (mandatory): first row occupied
14  
  settable Y y1;
15  
  
16  
  // core value (mandatory): x coordinates per row
17  
  // x_left is inclusive, x_right is exclusive
18  
  // all x coordinates are absolute in image
19  
  //
20  
  // Order in array:
21  
  //   x_left at y1, x_right at y1,
22  
  //   x_left at y1+1, x_right at y1+1, ,,,
23  
  settable X[] data;
24  
25  
  *(int y1, int y2) {
26  
    init(y1, y2);
27  
  }
28  
  
29  
  void init(int y1, int y2) {
30  
    this.y1 = toY(y1);
31  
    data = newXArray((y2-y1)*2);
32  
  }
33  
  
34  
  // all coordinates passed in are absolute
35  
  void set(int y, int xLeft, int xRight) {
36  
    data[(y-y1)*2] = toX(xLeft);
37  
    data[(y-y1)*2+1] = toX(xRight);
38  
  }
39  
  
40  
  // all coordinates passed in and out are absolute
41  
  int getLeft (int y) { ret data[(y-y1)*2]; }
42  
  int getRight(int y) { ret data[(y-y1)*2+1]; }
43  
  
44  
  // bounds can be calculated quickly from core values & are then cached
45  
  public simplyCached Rect bounds() {
46  
    int x1 = Int.MAX_VALUE, x2 = 0;
47  
    for (int i = 0; i < l(data); i += 2) {
48  
      x1 = min(x1, data[i]);
49  
      x2 = max(x2, data[i+1]);
50  
    }
51  
    ret rectFromPoints(x1, y1, x2, y2());
52  
  }
53  
  
54  
  // same with number of pixels
55  
  int numberOfPixels_cache = -1;
56  
  public int numberOfPixels() {
57  
    if (numberOfPixels_cache < 0) {
58  
      int n = 0;
59  
      for (int i = 0; i < l(data); i += 2)
60  
        n += max(0, data[i+1]-data[i]);
61  
      numberOfPixels_cache = n;
62  
    }
63  
    ret numberOfPixels_cache;
64  
  }
65  
  
66  
  public int getHeight() { ret l(data)/2; }
67  
  int y2() { ret y1+height(); }
68  
  
69  
  public bool contains(Pt p) { ret contains(p.x, p.y); }
70  
  public bool contains(int x, int y) {
71  
    if (y < y1) false;
72  
    int i = (y-y1)*2;
73  
    if (i >= l(data)) false;
74  
    ret x >= data[i] && x < data[i+1];
75  
  }
76  
  
77  
  selfType color(Color color) { super.color(color); this; }
78  
  public selfType hi15color(short hi15color) { super.hi15color(hi15color); this; }
79  
  
80  
  public void drawOn(Graphics2D g) {
81  
    g.setColor(color());
82  
    int h = height();
83  
    for y to h: {
84  
      int x1 = data[y*2], x2 = data[y*2+1];
85  
      if (x1 < x2)
86  
        g.drawLine(x1, y1+y, x2-1, y1+y);
87  
    }
88  
  }
89  
  
90  
  // doesn't set a color
91  
  // TODO
92  
  public void drawOutline(Graphics2D g) {
93  
    int h = height();
94  
    IntRange last = intRange(0, 0);
95  
    for y to h: {
96  
      IntRange r = intRange(data[y*2], data[y*2+1]);
97  
      
98  
      // anything to draw in this line?
99  
      if (nempty(r)) {
100  
        if (empty(last))
101  
          // draw full line if just starting
102  
          g.drawLine(r.start, y1+y, r.end-1, y1+y);
103  
        else {
104  
          // We make a line from the left boundary that if possible goes only to last.start but is at least 1 pixel wide
105  
          int xleft = max(r.start, last.start-1);
106  
          
107  
          // Same from the right boundary
108  
          int xright = min(r.end-1, last.end);
109  
          
110  
          g.drawLine(r.start, y1+y, xleft, y1+y);
111  
          g.drawLine(xright, y1+y, r.end-1, y1+y);
112  
        }
113  
      }
114  
      
115  
      last = r;
116  
    }
117  
  }
118  
  
119  
  SSI topPart(int nLines) {
120  
    if (nLines <= 0) null;
121  
    SSI ssi = new SSI(y1, toShort_enforce(y1+nLines)).hi15color(hi15color);
122  
    arrayCopy(data, ssi.data, 0, l(ssi.data));
123  
    ret ssi;
124  
  }
125  
  
126  
  // an SSI is coherent if all scanlines are non-empty
127  
  // and the SSI is one region
128  
  bool coherent(bool withDiagonals default false) {
129  
    int h = height();
130  
    for y to h: {
131  
      int i = y*2;
132  
      int x1 = data[i], x2 = data[i+1];
133  
      if (x1 >= x2) false;
134  
      if (y > 0) {
135  
        int lastx1 = data[i-2], lastx2 = data[i-1];
136  
        if (withDiagonals) { lastx1--; lastx2++; }
137  
        if (!intRangesOverlap(x1, x2, lastx1, lastx2))
138  
          false;
139  
      }
140  
    }
141  
    true;
142  
  }
143  
  
144  
  public void readWrite(ByteHead head) {
145  
    head.exchangeShort(-> hi15color, color -> hi15color = color);
146  
    head.exchangeShort(-> y1, y1 -> this.y1 = y1);
147  
    head.exchangeShort(-> toShort_enforce(y2()), y2 -> init(y1, y2));
148  
    for i over data: {
149  
      reMutable i;
150  
      head.exchangeShort(-> data[i], x -> data[i] = x);
151  
    }
152  
  }
153  
  
154  
  SSI toSSI() { this; }
155  
  
156  
  public long sizeInInts() {
157  
    // "s", color, y1, height, data
158  
    ret 4+height()*2;
159  
  }
160  
  
161  
  SSI reduceToInts(int ints) {
162  
    ret topPart((ints-4)/2);
163  
  }
164  
  
165  
  public void readWrite(StringHead head) {
166  
    head.exchangeLine(l0 toLine, l1 fromLine);
167  
  }
168  
  
169  
  S toLine() {
170  
    ret spaceCombine("s", colorToString(), y1, height(), toList(data));
171  
  }
172  
  
173  
  void fromLine(S line) {
174  
    Iterator<S> it = splitAtSpaceIterator(line);
175  
    assertEquals("s", nextFromIterator(it));
176  
    int y1 = parseInt(nextFromIterator(it));
177  
    int h = parseInt(nextFromIterator(it));
178  
    init(y1, y1+h);
179  
    for i over data:
180  
      data[i] = toX(parseInt(nextFromIterator(it)));
181  
  }
182  
}

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: 228 / 637
Version history: 69 change(s)
Referenced in: [show references]