The ZX Ecosystem v5.1.0;_GUI_v3.1.0
Loading...
Searching...
No Matches
ColorImages.h
Go to the documentation of this file.
1
2/* *************************************************************************/
20#ifndef COLORIMAGES
21#define COLORIMAGES
22
23#include <type_traits>
24#include <climits>
25#include <memory>
26#include <vector>
27#include <string>
28#include "CppAddons.h"
29
30
31
32/* =============================================================================
33
34 RGB COLORS AND PALETTES
35
36==============================================================================*/
37
38
39/* ***************************************************************************
40*
41* Class: RGBColor
42*
43*******************************************************************************/
44
47{
48 public:
49
51 using CompLevel = uint8_t;
52
54 static constexpr double kMaxRGBDist2 = 255.0 * 255.0 * 3.0;
55
56
58 RGBColor(CompLevel r = 0, CompLevel g = 0, CompLevel b = 0) { set(r,g,b); }
59
61 RGBColor(const CompLevel * rgb) { set(rgb); }
62
64 RGBColor(const RGBColor &) = default;
65 RGBColor(RGBColor &&) = default;
66 RGBColor & operator=(const RGBColor &) = default;
67 RGBColor & operator=(RGBColor &&) = default;
68
69 virtual ~RGBColor(void) = default;
70
71
73 CompLevel r(void) const noexcept { return(rgb_[0]); }
74
76 CompLevel g(void) const noexcept { return(rgb_[1]); }
77
79 CompLevel b(void) const noexcept { return(rgb_[2]); }
80
82 const CompLevel * rgb(void) const noexcept { return(rgb_); }
83
85 void rgbRead(CompLevel * rgb) const noexcept { std::copy(rgb_,rgb_+3,rgb); }
86
88 void setR(CompLevel r) noexcept { rgb_[0] = r; }
89
91 void setG(CompLevel g) noexcept { rgb_[1] = g; }
92
94 void setB(CompLevel b) noexcept { rgb_[2] = b; }
95
97 void set(CompLevel r, CompLevel g, CompLevel b) noexcept
98 { rgb_[0] = r; rgb_[1] = g; rgb_[2] = b; }
99
101 void set(const CompLevel * rgb) noexcept { std::copy(rgb,rgb + 3,rgb_); }
102
103
105
108 void vector(const RGBColor & oth, double * rgbv) const noexcept;
109
111 double rgbDistance2(const RGBColor & oth) const;
112
114 void setFromHTMLString(const std::string & c);
115
117 std::string getHTMLString(void) const;
118
119
120 bool operator==(const RGBColor & oth) const noexcept
121 { return((rgb_[0] == oth.rgb_[0]) &&
122 (rgb_[1] == oth.rgb_[1]) &&
123 (rgb_[2] == oth.rgb_[2])); }
124
125 bool operator!=(const RGBColor & oth) const noexcept
126 { return(!operator==(oth)); }
127
128
130 std::string to_string(void) const;
131
132
133 private:
134
135 CompLevel rgb_[3];
136};
137
138
139/* ***************************************************************************
140*
141* Class: RGBPalette
142*
143*******************************************************************************/
144
147{
148 public:
149
151 using Size = uint32_t;
152
154 using Index = Size;
155
156
159
161
163
165 RGBPalette(const RGBPalette &) = delete;
166 RGBPalette & operator=(const RGBPalette &) = delete;
167 RGBPalette(RGBPalette && oth) = default;
168 RGBPalette & operator=(RGBPalette &&) = default;
169
170 virtual ~RGBPalette(void) = default;
171
173 Size numColors(void) const noexcept { return(static_cast<Size>(pal_.size())); }
174
176 const RGBColor & operator[](Index ind) const;
177
180
182
184 Index closestColor(const RGBColor & col) const noexcept;
185
187 std::string to_string(void) const;
188
189 private:
190
191 std::vector<RGBColor> pal_;
192};
193
194
195
196/* =============================================================================
197
198 IMAGES
199
200==============================================================================*/
201
202
203/* ***************************************************************************
204*
205* Type: ImageCoordDim
206*
207*******************************************************************************/
208
210using ImageCoordDim = unsigned;
211
212
213/* ***************************************************************************
214*
215* Template class: RasterCursor
216*
217*******************************************************************************/
218
220
225template <ImageCoordDim CELLW = 1, ImageCoordDim CELLH = 1>
227{
228 public:
229
231
235 ImageCoordDim himage): wimg_{wimage},himg_{himage}
236 { if ((wimage == 0) || (himage == 0))
237 RUNTIMEEXCEP("Cannot create cursor for empty image");
238 resetRegion(); }
239
240 RasterCursor(const RasterCursor &) = default;
241 RasterCursor(RasterCursor &&) = default;
242 RasterCursor & operator=(const RasterCursor &) = default;
243 RasterCursor & operator=(RasterCursor &&) = default;
244 virtual ~RasterCursor(void) = default;
245
246
248 constexpr ImageCoordDim cellW(void) const noexcept { return(CELLW); }
249
251 constexpr ImageCoordDim cellH(void) const noexcept { return(CELLH); }
252
254
260 ImageCoordDim ymin, ImageCoordDim ylength)
261 { regionleft_ = xmin; regionright_ = xmin + xlength - 1;
262 regiontop_ = ymin; regionbottom_ = ymin + ylength - 1;
263 if (regionright_ >= wimg_)
264 { regionright_ = wimg_ - 1;
265 xlength = regionright_ - xmin + 1; }
266 if (regionbottom_ >= himg_)
267 { regionbottom_ = himg_ - 1;
268 ylength = regionbottom_ - ymin + 1; }
269 if ((xlength == 0) || (ylength == 0) ||
270 (regionright_ < xmin) || (regionbottom_ < ymin))
271 RUNTIMEEXCEP("Invalid region [l" +
272 std::to_string(xmin) + ",w" +
273 std::to_string(xlength) + ",t" +
274 std::to_string(ymin) + ",h" +
275 std::to_string(ylength) +
276 " within image of " +
277 std::to_string(wimg_) + "x" +
278 std::to_string(himg_) +
279 " for a cursor");
280 reset();
281 lastcellx_ = xmin + lastAllowedCoord(xlength,CELLW);
282 regionwidthm1cell_ = lastcellx_ - xmin;
283 sizeonecellrow_ = static_cast<size_t>(CELLH) *
284 static_cast<size_t>(wimg_); }
285
287 void resetRegion(void) { setRegion(0,wimg_,0,himg_); }
288
290 bool inside(void) const noexcept
291 { return((x_ >= regionleft_) && (x_ <= regionright_) &&
292 (y_ >= regiontop_) && (y_ <= regionbottom_)); }
293
295
299 { checkInside(); RasterCursor<1,1> resc{wimg_,himg_};
300 resc.setRegion(x_,CELLW,y_,CELLH);
301 return(resc); }
302
303
305
308 void set(ImageCoordDim xc, ImageCoordDim yc) noexcept
309 { setPixel(regionleft_ + xc * CELLW, regiontop_ + yc * CELLH); }
310
312 void reset(void) noexcept { setPixel(regionleft_,regiontop_); }
313
315
316 ImageCoordDim x(void) const noexcept
317 { return((x_ - regionleft_) / CELLW); }
318
320
321 ImageCoordDim y(void) const noexcept
322 { return((y_ - regiontop_) / CELLH);}
323
325
326 ImageCoordDim xPixel(void) const noexcept { return(x_); }
327
329
330 ImageCoordDim yPixel(void) const noexcept { return(y_); }
331
333
335 size_t globalOffset(void) const { checkInside(); return(offset_); }
336
338
340 bool right(void) noexcept
341 { if ((!inside()) || (x_ >= lastcellx_)) return(false);
342 x_ += CELLW; offset_ += CELLW; return(true); }
343
345
347 bool forward(void) noexcept
348 { if (!inside()) return(false);
349 if (!right()) // then, x_ == lastcellx_
350 { x_ = regionleft_; y_ += CELLH;
351 offset_ = offset_ -
352 static_cast<size_t>(regionwidthm1cell_) +
353 sizeonecellrow_;
354 lastrowchange_ = true; }
355 else lastrowchange_ = false;
356 return(inside()); }
357
359
360 bool lastChangedRow(void) const noexcept { return(lastrowchange_); }
361
362
364 std::string to_string(bool summary = true) const
365 { std::string res{"RasterCursor<"};
366 res += std::to_string(CELLW) + "," + std::to_string(CELLH) +
367 ">[@(" + std::to_string(x_) + "," + std::to_string(y_) +
368 "), offs " + std::to_string(offset_) + ", region (l" +
369 std::to_string(regionleft_) + ",r" +
370 std::to_string(regionright_) + ",t" +
371 std::to_string(regiontop_) + ",b" +
372 std::to_string(regionbottom_);
373 if (!summary)
374 res += "; lastcellx " +
375 std::to_string(lastcellx_) + ", regionwidth-1cell " +
376 std::to_string(regionwidthm1cell_) + ")," +
377 (inside() ? "in" : "out") + "," +
378 (lastChangedRow() ? "changedRow" : "no-row-changed");
379 res += "]";
380 return(res); }
381
382 private:
383
384 static constexpr ImageCoordDim lastAllowedCoord(ImageCoordDim avdim,
385 ImageCoordDim celldim)
386 noexcept
387 { return(celldim <= avdim ? // cell length <= available length
388 (avdim % celldim == 0 ? avdim - celldim :
389 avdim - (avdim % celldim)) :
390 0); } // cell length > available length
391
392
393 ImageCoordDim wimg_,himg_;
394
395 ImageCoordDim x_,y_; // in pixels, not in cells, ignoring region.
396 size_t offset_; // in the whole image, ignoring region.
397 ImageCoordDim regionleft_,regionright_,regiontop_,regionbottom_;
398 ImageCoordDim regionwidthm1cell_,lastcellx_;
399 size_t sizeonecellrow_;
400 bool lastrowchange_;
401
402
403 void checkInside(void) const
404 { if (!inside())
405 RUNTIMEEXCEP("Tried to access out of range RasterImage cursor: "
406 + to_string()); }
407
408 constexpr size_t offsetOfPixel(ImageCoordDim x,ImageCoordDim y) noexcept
409 { return(static_cast<size_t>(x_) + static_cast<size_t>(y_) *
410 static_cast<size_t>(wimg_)); }
411
412 void setPixel(ImageCoordDim x, ImageCoordDim y) noexcept
413 { x_ = x; y_ = y; offset_ = offsetOfPixel(x_,y_);
414 lastrowchange_ = false; }
415
416
417 static_assert((CELLW > 0) && (CELLH > 0),
418 "RasterCursor tessellation must have non-empty cells");
419};
420
421
422/* ***************************************************************************
423*
424* Template class: RasterImage
425*
426*******************************************************************************/
427
429
432template <typename PixelType>
434{
435 public:
436
438 RasterImage(void) = default;
439
441
443 { if ((w != 0) && (h != 0))
444 { numofpxs_ = static_cast<size_t>(w_) * static_cast<size_t>(h_);
445 pimg_ = SafeImgPtr(new PixelType [numofpxs_]); } }
446
448 RasterImage(const RasterImage &) = delete;
449 RasterImage(RasterImage && oth) { moveFrom(std::move(oth)); }
450 RasterImage & operator=(const RasterImage &) = delete;
451 RasterImage & operator=(RasterImage && oth)
452 { if (this != &oth) moveFrom(std::move(oth)); return(*this); }
453
454
455 virtual ~RasterImage(void) = default;
456
457 bool empty(void) const noexcept { return(!pimg_); }
458 ImageCoordDim width(void) const noexcept { checkEmptied(); return(w_); }
459 ImageCoordDim height(void) const noexcept { checkEmptied(); return(h_); }
460 size_t numPixels(void) const noexcept { checkEmptied(); return(numofpxs_); }
461
462 template <ImageCoordDim CELLW = 1, ImageCoordDim CELLH = 1>
463 RasterCursor<CELLW,CELLH> makeCursor(void) const
464 { checkEmptied(); return(RasterCursor<CELLW,CELLH>{w_,h_}); }
465
466 template <ImageCoordDim CELLW = 1, ImageCoordDim CELLH = 1>
467 PixelType & pixel(const RasterCursor<CELLW,CELLH> & cursor)
468 { checkEmptied(); return(pimg_.get()[cursor.globalOffset()]); }
469
470 template <ImageCoordDim CELLW = 1, ImageCoordDim CELLH = 1>
471 const PixelType & pixel(const RasterCursor<CELLW,CELLH> & cursor) const
472 { checkEmptied(); return(pimg_.get()[cursor.globalOffset()]); }
473
474 PixelType * contigContent(void) noexcept
475 { checkEmptied(); return(pimg_.get()); }
476 const PixelType * contigContent(void) const noexcept
477 { checkEmptied(); return(pimg_.get()); }
478
479 private:
480
481 using SafeImgPtr = std::unique_ptr< PixelType [] >;
482
483 ImageCoordDim w_,h_;
484 size_t numofpxs_;
485 SafeImgPtr pimg_;
486
487 void checkEmptied(void) const
488 { if (empty()) RUNTIMEEXCEP("Emptied RasterImage"); }
489
490 void moveFrom(RasterImage && oth)
491 { w_ = oth.w_; h_ = oth.h_; numofpxs_ = oth.numofpxs_;
492 pimg_ = std::move(oth.pimg_); }
493
494};
495
496
497/* ***************************************************************************
498*
499* Template class: RGBImage
500*
501*******************************************************************************/
502
504
505using ThreeBytes = uint8_t[3];
506
508
514
515
516/* ***************************************************************************
517*
518* Template class: PalettizedImage
519*
520*******************************************************************************/
521
523
528template <typename ColorIndex>
529class PalettizedImage: public RasterImage<ColorIndex>
530{
531 public:
532
534
536 PalettizedImage(void) = default;
537
539
542 unsigned w, unsigned h):Base{w,h},
543 pal_{&pal}
544 { if (bits_of_value(pal.numColors()) >
546 RUNTIMEEXCEP("Incompatible palette for given PalettizedImage"); }
547
550 const RGBImage & img): PalettizedImage{pal,
551 img.width(),
552 img.height()}
553 {
554 auto rgbcur = img.makeCursor(); // 1 pixel resolution
555 auto thiscur = this->makeCursor(); // 1 pixel resolution
556 do this->pixel(thiscur) = pal.closestColor(
557 RGBColor{reinterpret_cast<const uint8_t *>(
558 img.pixel(rgbcur))});
559 while (rgbcur.forward() && thiscur.forward());
560 }
561
564 PalettizedImage(PalettizedImage && oth) { moveFrom(std::move(oth)); }
565 PalettizedImage & operator=(const PalettizedImage &) = delete;
566 PalettizedImage & operator=(PalettizedImage && oth)
567 { if (this != &oth) moveFrom(std::move(oth)); return(*this); }
568
569 virtual ~PalettizedImage(void) = default;
570
571
572 const RGBPalette & palette(void) const noexcept
573 { checkEmptied(); return(*pal_); }
574
576 RGBImage toRGBImg(void) const
577 {
578 RGBImage res{Base::width(),Base::height()};
579 auto pixcur = Base::makeCursor(); // scan pixel per pixel
580 auto rgbcur = res.makeCursor();
581 do
582 {
583 auto pixcolind = Base::pixel(pixcur);
584 const RGBColor & rgbc = (*pal_)[pixcolind];
585 auto & p = res.pixel(rgbcur);
586 p[0] = rgbc.r();
587 p[1] = rgbc.g();
588 p[2] = rgbc.b();
589 } while (pixcur.forward() && rgbcur.forward());
590 return(res);
591 }
592
593 private:
594
595 const RGBPalette * pal_;
596
597 void checkEmptied(void) const
598 { if (Base::empty()) RUNTIMEEXCEP("Emptied palettized image"); }
599
600 void moveFrom(PalettizedImage && oth)
601 { Base::operator=(std::move(oth)); pal_ = oth.pal_; }
602
603 static_assert(std::is_arithmetic<ColorIndex>::value &&
604 std::is_unsigned<ColorIndex>::value,
605 "ColorIndex template argument must be an unsigned type");
606};
607
608
609
610#endif
611 // ColorPalettes
613
uint32_t Size
Size of a palette.
Definition: ColorImages.h:151
constexpr ImageCoordDim cellW(void) const noexcept
To get the tesselation in X from any RasterCursor object.
Definition: ColorImages.h:248
RGBColor(const CompLevel *rgb)
Constructor from an array of 3 components in R-G-B order.
Definition: ColorImages.h:61
void set(const CompLevel *rgb) noexcept
Change all components in R-G-B order.
Definition: ColorImages.h:101
void resetRegion(void)
Change area of the image reachable by the cursor to the whole image.
Definition: ColorImages.h:287
RGBColor(const RGBColor &)=default
Moves are just copies.
RasterImage(ImageCoordDim w, ImageCoordDim h)
Constructor: image of certain size; content not set, just stored.
Definition: ColorImages.h:442
CompLevel g(void) const noexcept
Return the green component.
Definition: ColorImages.h:76
const RGBColor & operator[](Index ind) const
Read one of the colors. Throw if out of range index.
double rgbDistance2(const RGBColor &oth) const
Return the squared Euclidean distance between THIS and OTH.
void setB(CompLevel b) noexcept
Change the red component.
Definition: ColorImages.h:94
RGBPalette(Size s)
Constructor: S colors, all (0,0,0). If S is 0, throws.
RasterImage(const RasterImage &)=delete
Copies forbidden; moves leave the original without content.
RGBImage toRGBImg(void) const
Create and return a new RGBImage with the content of this image.
Definition: ColorImages.h:576
CompLevel b(void) const noexcept
Return the blue component.
Definition: ColorImages.h:79
bool forward(void) noexcept
Move the cursor one cell forward.
Definition: ColorImages.h:347
ImageCoordDim y(void) const noexcept
Return the Y-cell coordinate within current region.
Definition: ColorImages.h:321
CompLevel r(void) const noexcept
Return the red component.
Definition: ColorImages.h:73
void setRegion(ImageCoordDim xmin, ImageCoordDim xlength, ImageCoordDim ymin, ImageCoordDim ylength)
Change the region of the image reachable by the cursor.
Definition: ColorImages.h:259
Size numColors(void) const noexcept
Return the number of colors in the palette.
Definition: ColorImages.h:173
RGBPalette(const RGBColor::CompLevel *rgbs, Size s)
Constructor: from an array of R-G-B bytes for S colors.
std::string to_string(bool summary=true) const
Return a text describing the cursor.
Definition: ColorImages.h:364
PalettizedImage(const PalettizedImage &)=delete
Copies forbidden; moves leave the original without content.
RGBColor & operator[](Index ind)
Read/write one of the colors. Throw if out of range index.
Size Index
Index of a color in a palette.
Definition: ColorImages.h:154
void setG(CompLevel g) noexcept
Change the green component.
Definition: ColorImages.h:91
bool lastChangedRow(void) const noexcept
Return TRUE if the last movement caused a change of row.
Definition: ColorImages.h:360
RasterCursor< 1, 1 > subCursor(void) const
Return a cursor limited to the cell where this cursor is.
Definition: ColorImages.h:298
void rgbRead(CompLevel *rgb) const noexcept
Fill the three components into RGB.
Definition: ColorImages.h:85
uint8_t CompLevel
A component level, from 0 to 255.
Definition: ColorImages.h:51
RGBColor(CompLevel r=0, CompLevel g=0, CompLevel b=0)
Default constructor.
Definition: ColorImages.h:58
std::string getHTMLString(void) const
In '#......' HTML format.
std::string to_string(void) const
Return a text describing the color.
static constexpr double kMaxRGBDist2
Maximum squared Euclidean distance between 2 rgb colors.
Definition: ColorImages.h:54
void setFromHTMLString(const std::string &c)
C must be in '#......' HTML format. Otherwise, throw.
RGBPalette(const RGBPalette &)=delete
No copies; only moves.
PalettizedImage(const RGBPalette &pal, const RGBImage &img)
Build a palettized version of RGBIMG.
Definition: ColorImages.h:549
PalettizedImage(const RGBPalette &pal, unsigned w, unsigned h)
Create storage for an image with the given palette and dimensions.
Definition: ColorImages.h:541
void set(ImageCoordDim xc, ImageCoordDim yc) noexcept
Set the cursor to the given cell coords. Do not throw if outside.
Definition: ColorImages.h:308
const CompLevel * rgb(void) const noexcept
Return the three components in R-G-B order.
Definition: ColorImages.h:82
constexpr ImageCoordDim cellH(void) const noexcept
To get the tesselation in Y from any RasterCursor object.
Definition: ColorImages.h:251
std::string to_string(void) const
Return a multi-line description of the palette.
bool right(void) noexcept
Move the cursor one cell to the right (no row change).
Definition: ColorImages.h:340
ImageCoordDim xPixel(void) const noexcept
Return the X-pixel coordinate within current region.
Definition: ColorImages.h:326
void set(CompLevel r, CompLevel g, CompLevel b) noexcept
Change all components.
Definition: ColorImages.h:97
ImageCoordDim x(void) const noexcept
Return the X-cell coordinate within current region.
Definition: ColorImages.h:316
PalettizedImage(void)=default
Default constructor: emptied palettized image.
RasterCursor(ImageCoordDim wimage, ImageCoordDim himage)
Default constructor / position constructor for a given sized image.
Definition: ColorImages.h:234
bool inside(void) const noexcept
Return TRUE if the cursor is inside the current region of the image.
Definition: ColorImages.h:290
void setR(CompLevel r) noexcept
Change the red component.
Definition: ColorImages.h:88
Index closestColor(const RGBColor &col) const noexcept
Find the closest color in the palette to COL.
void reset(void) noexcept
Set the cursor to the top-left cell coords of the current region.
Definition: ColorImages.h:312
RasterImage(void)=default
Default constructor: undefined content.
ImageCoordDim yPixel(void) const noexcept
Return the Y-pixel coordinate within current region.
Definition: ColorImages.h:330
size_t globalOffset(void) const
Return the linear offset within the image corresponding to cursor.
Definition: ColorImages.h:335
void vector(const RGBColor &oth, double *rgbv) const noexcept
Fill RGBV with the three components of a vector going from THIS to OTH.
An image that stores pixel colors contiguously as palette indexes.
Definition: ColorImages.h:530
A RGB color with 8 bits per component.
Definition: ColorImages.h:47
A palette defining a number of RGB colors.
Definition: ColorImages.h:147
A cursor to access RasterImage pixels bi-linearly with certain tesselation.
Definition: ColorImages.h:227
A 2D matrix of certain type that has contiguous storage.
Definition: ColorImages.h:434
unsigned ImageCoordDim
Type for coordinates and dimensions of images.
Definition: ColorImages.h:210
uint8_t[3] ThreeBytes
Auxiliary type needed for RGBImage.
Definition: ColorImages.h:505
Collect diverse traits for the fixed integer type T.
Definition: CppAddons.h:124
#define RUNTIMEEXCEP(txt)
Raise a runtime exception with the given std::string TXT + additional info.
Definition: CppAddons.h:93
unsigned char bits_of_value(T v)
The same as bits_of_constexprvalue(v) but for any variable value.
Definition: CppAddons.h:1037