#pragma once // STPic.h: interface for the CSTPic class. // ////////////////////////////////////////////////////////////////////// #include #ifndef STPIC_H #define STPIC_H /****** SASA Picture Class Template ********************** Currently there are two types of this object ST_RGBM - CSTPic - UCHAR r,g,b,m channels ST_RGBM64 - CSTPic - USHORT r,g,b,m channels The CMAP RASTER pictures have to be converted to ST_RGBM or ST_RGBM64, but the CMAP information can be used with the help of m_raster. m_lX,m_lY - the length of the picture in X,Y direction m_pic - the buffer of the picture m_ras - stores the pointer to the original RASTER picture ************************************************************/ #include "toonz4.6/udit.h" #include "toonz4.6/raster.h" #include "toonz4.6/pixel.h" #include "SDef.h" #include "SError.h" #include "timagecache.h" #include "trasterimage.h" #define ISINPIC(x, y) (m_pic && x >= 0 && x < m_lX && y >= 0 && y < m_lY) typedef enum { ST_NIL, // EMPTY ST_RGBM, // UC_PIXEL ST_RGBM64 // US_PIXEL } ST_TYPE; //! Old 4.6 picture class template (sandor fxs). There is a significant //! modification //! to be considered starting from Toonz 6.1 - the allocated raster is now //! managed //! by the image cache. Basically, when constructing one such object, the image //! is locked //! in the Toonz cache - and you must remember to unlock and relock it along //! inactivity periods. template class CSTPic { std::string m_cacheId; TRasterImageP m_picP; public: int m_lX, m_lY; P *m_pic; const RASTER *m_ras; CSTPic(void) : m_cacheId(TImageCache::instance()->getUniqueId()) , m_lX(0) , m_lY(0) , m_pic(0) , m_ras(0) {} void nullPic() { // if ( m_pic ) { delete [] m_pic; m_pic=0; } unlock(); TImageCache::instance()->remove(m_cacheId); } //! Retrieves the raster image from the cache to work with it. void lock() { m_picP = TImageCache::instance()->get(m_cacheId, true); m_pic = (P *)m_picP->getRaster()->getRawData(); } //! Release the raster image for inactivity periods. void unlock() { m_picP = 0; m_pic = 0; } CSTPic(const int lX, const int lY) : // throw(SMemAllocError) : m_cacheId(TImageCache::instance()->getUniqueId()) , m_lX(lX) , m_lY(lY) , m_pic(0) , m_ras(0) { try { initPic(); } catch (SMemAllocError) { null(); throw; } } CSTPic(const CSTPic

&sp) : // throw(SMemAllocError) : m_lX(sp.m_lX) , m_lY(sp.m_lY) , m_pic(0) , m_ras(sp.m_ras) { try { initPic(); copyPic(sp); } catch (SMemAllocError) { null(); throw; } } ~CSTPic(void) { null(); } //! Allocates the specified raster and surrenders it to the image cache. //!\b NOTE: The raster being initialized is LOCKED after this call. //! You must remember to UNLOCK it when no more used. void initPic() // throw(SMemAllocError) { nullPic(); if (m_lX > 0 && m_lY > 0) { // m_pic=new P[m_lX*m_lY]; TRasterGR8P ras(m_lX * m_lY * sizeof(P), 1); if (!ras) throw SMemAllocError("in initPic"); TImageCache::instance()->add(m_cacheId, TRasterImageP(ras)); lock(); } else { char s[200]; sprintf(s, "in initPic lXY=(%d,%d)\n", m_lX, m_lY); throw SMemAllocError(s); } } void null() { nullPic(); m_lX = m_lY = 0; m_ras = 0; } // Draws the border of the CSTPic void drawRect(const P &ip) { SRECT rect = {0, 0, m_lX - 1, m_lY - 1}; drawRect(rect, ip); } //------------------- The following need to be *LOCKED* before the call //------------------ // Currently there are two types of STPic // ST_RGBM - UCHAR r,g,b,m channels // ST_RGBM64 - USHORT r,g,b,m channels ST_TYPE getType() const { if (!m_pic) return ST_NIL; if (sizeof(m_pic->r) == sizeof(UCHAR)) return ST_RGBM; if (sizeof(m_pic->r) == sizeof(USHORT)) return ST_RGBM64; return ST_NIL; } // Copies the 'sp' CSTPic into 'm_pic' void copyPic(const CSTPic

&sp) { P p; for (int y = 0; y < m_lY && y < sp.m_lY; y++) for (int x = 0; x < m_lX && x < sp.m_lX; x++) { sp.getPixel(x, y, p); setRGBM(x, y, p); } } // Copies the 'r' rectangle of 'sp' CSTPic into the 'p' position // of 'm_pic' void copyPic(const CSTPic

&sp, const SRECT &r, const SPOINT &p) { P ip; int xs, ys, xd, yd; for (ys = r.y0, yd = p.y; ys <= r.y1; ys++, yd++) for (xs = r.x0, xd = p.x; xs <= r.x1; xs++, xd++) { sp.getPixel(xs, ys, ip); setRGBM(xd, yd, ip); } } // Draws a rectangle into CSTPic void drawRect(const SRECT &rect, const P &ip) { for (int x = rect.x0; x <= rect.x1; x++) { setRGBM(x, rect.y0, ip); setRGBM(x, rect.y1, ip); } for (int y = rect.y0; y <= rect.y1; y++) { setRGBM(rect.x0, y, ip); setRGBM(rect.x1, y, ip); } } void erease() { P p = {0, 0, 0, 0}; fill(p); } void fill(const P &ip) { for (int y = 0; y < m_lY; y++) for (int x = 0; x < m_lX; x++) setRGBM(x, y, ip); } // Checks whether (x,y) is a proper coordinate inline bool isInPic(const int x, const int y) const { return (m_pic && x >= 0 && x < m_lX && y >= 0 && y < m_lY); } // Sets the color of the CSTPic pixel void setRGB(const int x, const int y, const P &ip) { if (ISINPIC(x, y)) { P *p = m_pic + y * m_lX + x; p->r = ip.r; p->g = ip.g; p->b = ip.b; } } void setRGBM(const int x, const int y, const P &ip) { if (ISINPIC(x, y)) { P *p = m_pic + y * m_lX + x; p->r = ip.r; p->g = ip.g; p->b = ip.b; p->m = ip.m; } } // Sets the color of the CSTPic pixel void setRGB(const int x, const int y, const I_PIXEL &ip) { if (ISINPIC(x, y)) { P *p = m_pic + y * m_lX + x; if (getType() == ST_RGBM) { p->r = (UCHAR)I_CUT_0_255(ip.r); p->g = (UCHAR)I_CUT_0_255(ip.g); p->b = (UCHAR)I_CUT_0_255(ip.b); } else if (getType() == ST_RGBM64) { p->r = (USHORT)I_CUT_0_65535(ip.r); p->g = (USHORT)I_CUT_0_65535(ip.g); p->b = (USHORT)I_CUT_0_65535(ip.b); } } } void setRGBM(const int x, const int y, const I_PIXEL &ip) { if (ISINPIC(x, y)) { P *p = m_pic + y * m_lX + x; if (getType() == ST_RGBM) { p->r = (UCHAR)I_CUT_0_255(ip.r); p->g = (UCHAR)I_CUT_0_255(ip.g); p->b = (UCHAR)I_CUT_0_255(ip.b); p->m = (UCHAR)I_CUT_0_255(ip.m); } else if (getType() == ST_RGBM64) { p->r = I_CUT_0_65535(ip.r); p->g = I_CUT_0_65535(ip.g); p->b = I_CUT_0_65535(ip.b); p->m = I_CUT_0_65535(ip.m); } } } // Gets the color of the CSTPic pixel void getPixel(const int x, const int y, P &ip) const { if (ISINPIC(x, y)) { const P *p = m_pic + y * m_lX + x; ASSIGN_PIXEL(&ip, p); return; } ip.r = ip.g = ip.b = ip.m = 0; } void getPixel(const int x, const int y, I_PIXEL &ip) const { if (ISINPIC(x, y)) { const P *p = m_pic + y * m_lX + x; ip.r = (int)p->r; ip.g = (int)p->g; ip.b = (int)p->b; ip.m = (int)p->m; return; } ip.r = ip.g = ip.b = ip.m = 0; } // Gets the color of a RASTER pixel // RASTER operation always gets I_PIXEL color and I_PIXEL is casted // to the right type void getRasterPixel(const RASTER *ras, const int x, const int y, I_PIXEL &ip) const { if (x >= 0 && x < ras->lx && y >= 0 && y < ras->ly && ras->buffer) { LPIXEL *pL; LPIXEL pLL; SPIXEL *pS; UD44_CMAPINDEX32 *ci32; // UD44_PIXEL32* pen; UD44_PIXEL32 *col; switch (ras->type) { case (RAS_RGBM): pL = (LPIXEL *)(ras->buffer) + y * ras->wrap + x; ip.r = (int)pL->r; ip.g = (int)pL->g; ip.b = (int)pL->b; ip.m = (int)pL->m; break; case (RAS_RGBM64): pS = (SPIXEL *)(ras->buffer) + y * ras->wrap + x; ip.r = (int)pS->r; ip.g = (int)pS->g; ip.b = (int)pS->b; ip.m = (int)pS->m; break; case (RAS_CM32): ci32 = (UD44_CMAPINDEX32 *)(ras->buffer) + y * ras->wrap + x; col = (UD44_PIXEL32 *)(ras->cmap.buffer); PIX_CM32_MAP_TO_RGBM(*ci32, col, pLL) ip.r = (int)pLL.r; ip.g = (int)pLL.g; ip.b = (int)pLL.b; ip.m = (int)pLL.m; break; } } else ip.r = ip.g = ip.b = ip.m = 0; } void getRasterPixel(const int x, const int y, I_PIXEL &ip) const { if (m_ras) getRasterPixel(m_ras, x, y, ip); else ip.r = ip.g = ip.b = ip.m = 0; } // Sets the color of a RASTER pixel // RASTER operation always gets I_PIXEL color and I_PIXEL is casted // to the right type void setRasterPixel(RASTER *ras, const int x, const int y, const I_PIXEL &ip) const { if (x >= 0 && x < ras->lx && y >= 0 && y < ras->ly && ras->buffer) { LPIXEL *pL; SPIXEL *pS; switch (ras->type) { case (RAS_RGBM): pL = (LPIXEL *)(ras->buffer) + y * ras->wrap + x; pL->r = (UCHAR)ip.r; pL->g = (UCHAR)ip.g; pL->b = (UCHAR)ip.b; pL->m = (UCHAR)ip.m; break; case (RAS_RGBM64): pS = (SPIXEL *)(ras->buffer) + y * ras->wrap + x; pS->r = (USHORT)ip.r; pS->g = (USHORT)ip.g; pS->b = (USHORT)ip.b; pS->m = (USHORT)ip.m; break; } } } bool copy_raster(const RASTER *ir, RASTER *out_r, const int xBeg, const int yBeg, const int xEnd, const int yEnd, const int ox, const int oy) { if ((ir->lx <= 0) || (ir->ly <= 0) || (out_r->lx <= 0) || (out_r->ly <= 0)) return false; if (ir->buffer == NULL || out_r->buffer == NULL) return false; if (out_r->type == RAS_CM32) return false; if (ir->type == RAS_CM32 && (ir->cmap.buffer == NULL)) return false; for (int y = yBeg, yy = oy; y <= yEnd; y++, yy++) for (int x = xBeg, xx = ox; x <= xEnd; x++, xx++) { I_PIXEL ip; getRasterPixel(ir, x, y, ip); if (xx >= 0 && yy >= 0 && xx < out_r->lx && yy < out_r->ly) { LPIXEL *pL; SPIXEL *pS; if (out_r->type == RAS_RGBM && (ir->type == RAS_RGBM || ir->type == RAS_CM32)) { pL = (LPIXEL *)(out_r->buffer) + yy * out_r->wrap + xx; pL->r = (UCHAR)ip.r; pL->g = (UCHAR)ip.g; pL->b = (UCHAR)ip.b; pL->m = (UCHAR)ip.m; } else if (out_r->type == RAS_RGBM && ir->type == RAS_RGBM64) { pL = (LPIXEL *)(out_r->buffer) + yy * out_r->wrap + xx; pL->r = PIX_BYTE_FROM_USHORT((USHORT)ip.r); pL->g = PIX_BYTE_FROM_USHORT((USHORT)ip.g); pL->b = PIX_BYTE_FROM_USHORT((USHORT)ip.b); pL->m = PIX_BYTE_FROM_USHORT((USHORT)ip.m); } else if (out_r->type == RAS_RGBM64 && (ir->type == RAS_RGBM || ir->type == RAS_CM32)) { pS = (SPIXEL *)(out_r->buffer) + yy * out_r->wrap + xx; pS->r = PIX_USHORT_FROM_BYTE((UCHAR)ip.r); pS->g = PIX_USHORT_FROM_BYTE((UCHAR)ip.g); pS->b = PIX_USHORT_FROM_BYTE((UCHAR)ip.b); pS->m = PIX_USHORT_FROM_BYTE((UCHAR)ip.m); } else if (out_r->type == RAS_RGBM64 && ir->type == RAS_RGBM64) { pS = (SPIXEL *)(out_r->buffer) + yy * out_r->wrap + xx; pS->r = (USHORT)ip.r; pS->g = (USHORT)ip.g; pS->b = (USHORT)ip.b; pS->m = (USHORT)ip.m; } } } return true; } // Generates and reads the CSTPic using RASTER. // \b NOTE: This LOCKS the raster being read. You must remember to unlock it // afterwards // when it is needed no more. virtual void read(const RASTER *ras) // throw(SMemAllocError) { try { null(); if (((ras->type == RAS_RGBM || ras->type == RAS_RGBM64) && ras->buffer && ras->lx > 0 && ras->ly > 0) || (ras->type == RAS_CM32 && ras->buffer && ras->cmap.buffer && ras->lx > 0 && ras->ly > 0)) { m_lX = ras->lx; m_lY = ras->ly; m_ras = ras; initPic(); lock(); ST_TYPE type = getType(); P *p = m_pic; I_PIXEL ip; memset(&ip, 0, sizeof(I_PIXEL)); for (int y = 0; y < m_lY; y++) for (int x = 0; x < m_lX; x++, p++) { getRasterPixel(ras, x, y, ip); switch (type) { case (ST_RGBM): if (ras->type == RAS_RGBM64) { // RGBM have to be 'scaled' from USHORT to UCHAR p->r = PIX_BYTE_FROM_USHORT((USHORT)ip.r); p->g = PIX_BYTE_FROM_USHORT((USHORT)ip.g); p->b = PIX_BYTE_FROM_USHORT((USHORT)ip.b); p->m = PIX_BYTE_FROM_USHORT((USHORT)ip.m); } else { // RGBM are UCHAR in the raster p->r = (UCHAR)ip.r; p->g = (UCHAR)ip.g; p->b = (UCHAR)ip.b; p->m = (UCHAR)ip.m; } break; case (ST_RGBM64): if (ras->type == RAS_RGBM64) { // RGBM are USHORT in the raster p->r = ip.r; p->g = ip.g; p->b = ip.b; p->m = ip.m; } else { // RGBM have to be 'scaled' from UCHAR to USHORT p->r = PIX_USHORT_FROM_BYTE((UCHAR)ip.r); p->g = PIX_USHORT_FROM_BYTE((UCHAR)ip.g); p->b = PIX_USHORT_FROM_BYTE((UCHAR)ip.b); p->m = PIX_USHORT_FROM_BYTE((UCHAR)ip.m); } break; } } } } catch (SMemAllocError) { null(); throw; } } const CSTPic

&operator=(const CSTPic

&sp) // throw(SMemAllocError) { try { null(); m_lX = sp.m_lX; m_lY = sp.m_lY; m_ras = sp.m_ras; initPic(); copyPic(sp); } catch (SMemAllocError) { null(); throw; } return (*this); } // Writes the CSTPic into the RASTER virtual void write(RASTER *ras) const // throw(SWriteRasterError) { if ((ras->type == RAS_RGBM || ras->type == RAS_RGBM64) && ras->lx > 0 && ras->ly > 0 && ras->buffer) { int x, y; I_PIXEL ip; const P *p; for (y = 0; y < m_lY && y < ras->ly; y++) for (x = 0; x < m_lX && x < ras->lx; x++) { p = m_pic + y * m_lX + x; ip.r = (int)p->r; ip.g = (int)p->g; ip.b = (int)p->b; ip.m = (int)p->m; setRasterPixel(ras, x, y, ip); } } else throw SWriteRasterError("(bad Raster type)"); } // Writes the 'r' rectangle of CSTPic into the 'p' position in RASTER virtual void write(RASTER *ras, const SRECT &r, const SPOINT &p) const // throw(SWriteRasterError) { if (ras->type == RAS_RGBM || ras->type == RAS_RGBM64) { int xs, ys, xd, yd; P pp; I_PIXEL ip; for (ys = r.y0, yd = p.y; ys <= r.y1; ys++, yd++) for (xs = r.x0, xd = p.x; xs <= r.x1; xs++, xd++) { getPixel(xs, ys, pp); ip.r = (int)pp.r; ip.g = (int)pp.g; ip.b = (int)pp.b; ip.m = (int)pp.m; setRasterPixel(ras, xd, yd, ip); } } else throw SWriteRasterError("(bad Raster type)"); } virtual void writeOutBorder(const RASTER *rasin, const int border, RASTER *ras, const SRECT &r, const SPOINT &p) const // throw(SWriteRasterError) { assert(rasin->type == RAS_CM32); UD44_PIXEL32 *col = (UD44_PIXEL32 *)(rasin->cmap.buffer); if (ras->type == RAS_RGBM || ras->type == RAS_RGBM64) { int xs, ys, xd, yd; I_PIXEL ip; for (ys = r.y0, yd = p.y; ys <= r.y1; ys++, yd++) for (xs = r.x0, xd = p.x; xs <= r.x1; xs++, xd++) { int x = xd - border; int y = yd - border; if (x >= 0 && y >= 0 && x < rasin->lx && y < rasin->ly) { UD44_CMAPINDEX32 pixel = *(((UD44_CMAPINDEX32 *)rasin->buffer) + y * rasin->wrap + x); // int tone = (pix&0xff); // int paint = ((pix>>8)&0xfff); if ((pixel & 0xff) == 0 || ((pixel >> 8) & 0xfff) != 0) { LPIXEL pLL; PIX_CM32_MAP_TO_RGBM(pixel, col, pLL) ip.r = (int)pLL.r; ip.g = (int)pLL.g; ip.b = (int)pLL.b; ip.m = (int)pLL.m; setRasterPixel(ras, xd, yd, ip); continue; } } P pp; getPixel(xs, ys, pp); ip.r = (int)pp.r; ip.g = (int)pp.g; ip.b = (int)pp.b; ip.m = (int)pp.m; setRasterPixel(ras, xd, yd, ip); } } else throw SWriteRasterError("(bad Raster type)"); } void convertToCurrentType(P &d, const I_PIXEL &s) const { if (getType() == ST_RGBM) { d.r = (UCHAR)s.r; d.g = (UCHAR)s.g; d.b = (UCHAR)s.b; d.m = (UCHAR)s.m; } if (getType() == ST_RGBM64) { d.r = (USHORT)s.r; d.g = (USHORT)s.g; d.b = (USHORT)s.b; d.m = (USHORT)s.m; } } bool isSameColor(const P *a, const P *b) const { if (a->r == b->r && a->g == b->g && a->b == b->b) return true; return false; } void colorNoise(const I_PIXEL &cc1, const I_PIXEL &cc2, const double d) { P c1, c2; if (d <= 0) return; convertToCurrentType(c1, cc1); convertToCurrentType(c2, cc2); int xy = m_lX * m_lY; P *pPic = m_pic; for (int i = 0; i < xy; i++, pPic++) if (isSameColor(&c1, pPic)) { double q = (rand() % 101) / 100.0; q = d * q; q = q > 1.0 ? 1.0 : q; double r = (1.0 - q) * (double)c1.r + q * (double)c2.r; double g = (1.0 - q) * (double)c1.g + q * (double)c2.g; double b = (1.0 - q) * (double)c1.b + q * (double)c2.b; r = D_CUT_0_255(r); g = D_CUT_0_255(g); b = D_CUT_0_255(b); pPic->r = UC_ROUND(r); pPic->g = UC_ROUND(g); pPic->b = UC_ROUND(b); } } /* void hlsNoise(const double d) { int xy=m_lX*m_lY; P* p=m_pic; for( int i=0; im>0 ) { double h,l,s,q; rgb2hls(p->r,p->g,p->b,&h,&l,&s); q=1.0-d*(double)((rand()%201)-100)/100.0; l*=q; hls2rgb(h,l,s,&(p->r),&(p->g),&(p->b)); } } */ void rgb2hls(UCHAR r, UCHAR g, UCHAR b, double *h, double *l, double *s) { double ma, mi, delta, sum; double rf, gf, bf; rf = (double)r / 255.0; gf = (double)g / 255.0; bf = (double)b / 255.0; ma = rf > gf ? rf : gf; ma = ma > bf ? ma : bf; mi = rf < gf ? rf : gf; mi = mi < bf ? mi : bf; sum = ma + mi; delta = ma - mi; *l = sum / 2.0; if (fabs(delta) < 0.000001) { *s = 0.0; *h = UNDEFINED; } else { *s = *l <= 0.5 ? delta / sum : delta / (2.0 - sum); *h = fabs((rf - ma)) < 0.000001 ? (gf - bf) / delta : (fabs((gf - ma)) < 0.000001 ? 2.0 + (bf - rf) / delta : 4.0 + (rf - gf) / delta); *h *= 60; *h = *h < 0.0 ? *h + 360.0 : *h; } } double fromHue(double n1, double n2, double hue) { double v, h; h = hue > 360.0 ? hue - 360.0 : hue; h = h < 0.0 ? h + 360.0 : h; if (h < 60.0) { v = n1 + (n2 - n1) * h / 60.0; } else if (h < 180.0) { v = n2; } else if (h < 240.0) { v = n1 + (n2 - n1) * (240.0 - h) / 60.0; } else v = n1; return (v); } void hls2rgb(double h, double l, double s, UCHAR *r, UCHAR *g, UCHAR *b) { double rf, gf, bf; double m1, m2; m2 = l <= 0.5 ? l * (1.0 + s) : l + s - l * s; m1 = 2 * l - m2; if (fabs(s - 0.0) < 0.000001) { if (fabs(h - UNDEFINED) < 0.000001) { rf = gf = bf = l * 255.0; } else rf = gf = bf = 0.0; } else { rf = fromHue(m1, m2, h + 120.0) * 255.0; gf = fromHue(m1, m2, h) * 255.0; bf = fromHue(m1, m2, h - 120.0) * 255.0; } rf = D_CUT_0_255(rf); gf = D_CUT_0_255(gf); bf = D_CUT_0_255(bf); *r = UC_ROUND(rf); *g = UC_ROUND(gf); *b = UC_ROUND(bf); } }; #endif // !defined(AFX_STPIC_H__BABE9488_F054_11D5_B927_0040F674BE6A__INCLUDED_)