1 
2 
3 #include "tools/stylepicker.h"
4 #include "tcolorstyles.h"
5 #include "tstroke.h"
6 #include "tofflinegl.h"
7 #include "tvectorrenderdata.h"
8 #include "tvectorimage.h"
9 #include "ttoonzimage.h"
10 #include "trasterimage.h"
11 #include "toonz/dpiscale.h"
12 #include "tpixelutils.h"
13 #include "tregion.h"
14 #include "toonzqt/gutil.h"
15 
16 #include <QRect>
17 
18 //---------------------------------------------------------
19 
StylePicker(const TImageP & image)20 StylePicker::StylePicker(const TImageP &image)
21     : m_image(image), m_palette(image->getPalette()) {}
22 
23 //---------------------------------------------------------
24 
StylePicker(const TImageP & image,const TPaletteP & palette)25 StylePicker::StylePicker(const TImageP &image, const TPaletteP &palette)
26     : m_image(image), m_palette(palette) {}
27 
28 //---------------------------------------------------------
29 
getRasterPoint(const TPointD & p) const30 TPoint StylePicker::getRasterPoint(const TPointD &p) const {
31   if (TToonzImageP ti = m_image) {
32     // DpiScale dpiScale(ti);
33     TDimension size = ti->getSize();
34     return TPoint(tround(0.5 * size.lx + p.x),   /// dpiScale.getSx()),
35                   tround(0.5 * size.ly + p.y));  /// dpiScale.getSy()));
36   } else if (TRasterImageP ri = m_image) {
37     // DpiScale dpiScale(ri);
38     TDimension size = ri->getRaster()->getSize();
39     return TPoint(tround(0.5 * size.lx + p.x),   // /dpiScale.getSx()),
40                   tround(0.5 * size.ly + p.y));  // /dpiScale.getSy()));
41   } else
42     return TPoint(tround(p.x), tround(p.y));
43 }
44 
45 //---------------------------------------------------------
46 /*-- (StylePickerTool内で)LineとAreaを切り替えてPickできる。mode: 0=Area,
47  * 1=Line, 2=Line&Areas(default)  --*/
pickStyleId(const TPointD & pos,double radius,double scale2,int mode) const48 int StylePicker::pickStyleId(const TPointD &pos, double radius, double scale2,
49                              int mode) const {
50   int styleId = 0;
51   if (TToonzImageP ti = m_image) {
52     TRasterCM32P ras = ti->getRaster();
53     TPoint point     = getRasterPoint(pos);
54     if (!ras->getBounds().contains(point)) return -1;
55     TPixelCM32 col = ras->pixels(point.y)[point.x];
56 
57     switch (mode) {
58     case 0:  // AREAS
59       styleId = col.getPaint();
60       break;
61     case 1:  // LINES
62       styleId = col.getInk();
63       break;
64     case 2:  // ALL (Line & Area)
65     default:
66       styleId = col.isPurePaint() ? col.getPaint() : col.getInk();
67       break;
68     }
69   } else if (TRasterImageP ri = m_image) {
70     const TPalette *palette = m_palette.getPointer();
71     if (!palette) return -1;
72     TRaster32P ras = ri->getRaster();
73     if (!ras) return -1;
74     TPoint point = getRasterPoint(pos);
75     if (!ras->getBounds().contains(point)) return -1;
76     TPixel32 col = ras->pixels(point.y)[point.x];
77     styleId      = palette->getClosestStyle(col);
78   } else if (TVectorImageP vi = m_image) {
79     // prima cerca lo stile della regione piu' vicina
80     TRegion *r = vi->getRegion(pos);
81     if (r) styleId = r->getStyle();
82     bool strokeFound;
83     double dist2, w, thick;
84     UINT index;
85     //! funzionerebbe ancora meglio con un getNearestStroke che considera
86     // la thickness, cioe' la min distance dalla outline e non dalla centerLine
87     strokeFound = vi->getNearestStroke(pos, w, index, dist2);
88     if (strokeFound) {
89       int devPixRatio = getDevPixRatio();
90       dist2 *= scale2;
91       TStroke *stroke = vi->getStroke(index);
92       thick           = stroke->getThickPoint(w).thick;
93       double len2     = thick * thick * scale2;
94       const double minDist2 =
95           (styleId == 0) ? radius * radius * (double)(devPixRatio * devPixRatio)
96                          : 0;
97       double checkDist = std::max(minDist2, len2);
98       if (dist2 < checkDist) {
99         assert(stroke);
100         styleId = stroke->getStyle();
101       }
102     }
103   }
104   return styleId;
105 }
106 
107 //---------------------------------------------------------
108 /*--- Toonz Raster LevelのToneを拾う。 ---*/
pickTone(const TPointD & pos) const109 int StylePicker::pickTone(const TPointD &pos) const {
110   if (TToonzImageP ti = m_image) {
111     TRasterCM32P ras = ti->getRaster();
112     if (!ras) return -1;
113     TPoint point = getRasterPoint(pos);
114     if (!ras->getBounds().contains(point)) return -1;
115     TPixelCM32 col = ras->pixels(point.y)[point.x];
116 
117     return col.getTone();
118   } else
119     return -1;
120 }
121 
122 //---------------------------------------------------------
123 
pickColor(const TPointD & pos,double radius,double scale2) const124 TPixel32 StylePicker::pickColor(const TPointD &pos, double radius,
125                                 double scale2) const {
126   TToonzImageP ti  = m_image;
127   TRasterImageP ri = m_image;
128   TVectorImageP vi = m_image;
129   if (!!ri)  // !!ti || !!ri)
130   {
131     TRasterP raster;
132     // if(ti)
133     //  raster = ti->getRGBM(true);
134     // else
135     raster = ri->getRaster();
136 
137     TPoint point = getRasterPoint(pos);
138     if (!raster->getBounds().contains(point)) return TPixel32::Transparent;
139 
140     TRaster32P raster32 = raster;
141     if (raster32) return raster32->pixels(point.y)[point.x];
142 
143     TRasterGR8P rasterGR8 = raster;
144     if (rasterGR8) return toPixel32(rasterGR8->pixels(point.y)[point.x]);
145   } else if (vi) {
146     const TPalette *palette = m_palette.getPointer();
147     if (!palette) return TPixel32::Transparent;
148     int styleId = pickStyleId(pos, radius, scale2);
149     if (0 <= styleId && styleId < palette->getStyleCount())
150       return palette->getStyle(styleId)->getAverageColor();
151   } else if (ti) {
152     const TPalette *palette = m_palette.getPointer();
153     if (!palette) return TPixel32::Transparent;
154     int paintId = pickStyleId(pos, radius, scale2, 0);
155     int inkId   = pickStyleId(pos, radius, scale2, 1);
156     int tone    = pickTone(pos);
157     TPixel32 ink, paint;
158     if (0 <= inkId && inkId < palette->getStyleCount())
159       ink = palette->getStyle(inkId)->getAverageColor();
160     if (0 <= paintId && paintId < palette->getStyleCount())
161       paint = palette->getStyle(paintId)->getAverageColor();
162 
163     if (tone == 0)
164       return ink;
165     else if (tone == 255)
166       return paint;
167     else
168       return blend(ink, paint, tone, TPixelCM32::getMaxTone());
169   }
170   return TPixel32::Transparent;
171 }
172 
173 //---------------------------------------------------------
174 
pickAverageColor(const TRectD & rect) const175 TPixel32 StylePicker::pickAverageColor(const TRectD &rect) const {
176   TRasterImageP ri = m_image;
177   assert(ri);
178   if (!!ri) {
179     TRasterP raster;
180     raster = ri->getRaster();
181 
182     TPoint topLeft     = getRasterPoint(rect.getP00());
183     TPoint bottomRight = getRasterPoint(rect.getP11());
184 
185     if (!raster->getBounds().overlaps(TRect(topLeft, bottomRight)))
186       return TPixel32::Transparent;
187 
188     topLeft.x     = std::max(0, topLeft.x);
189     topLeft.y     = std::max(0, topLeft.y);
190     bottomRight.x = std::min(raster->getLx(), bottomRight.x);
191     bottomRight.y = std::min(raster->getLy(), bottomRight.y);
192 
193     TRaster32P raster32 = raster;
194     assert(raster32);
195     if (raster32) {
196       UINT r = 0, g = 0, b = 0, m = 0, size = 0;
197       for (int y = topLeft.y; y < bottomRight.y; y++) {
198         TPixel32 *p = &raster32->pixels(y)[topLeft.x];
199         for (int x = topLeft.x; x < bottomRight.x; x++, p++) {
200           r += p->r;
201           g += p->g;
202           b += p->b;
203           m += p->m;
204           size++;
205         }
206       }
207 
208       if (size)
209         return TPixel32(r / size, g / size, b / size, m / size);
210       else
211         return TPixel32::Transparent;
212     }
213   }
214   return TPixel32::Transparent;
215 }
216 
217 //---------------------------------------------------------
218 
219 namespace {
220 
getAverageColor(const TRect & rect)221 TPixel32 getAverageColor(const TRect &rect) {
222   GLenum fmt =
223 #if defined(TNZ_MACHINE_CHANNEL_ORDER_BGRM)
224       GL_RGBA;
225 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MBGR)
226       GL_ABGR_EXT;
227 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM)
228       GL_RGBA;
229 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MRGB)
230       GL_BGRA;
231 #else
232 //   Error  PLATFORM NOT SUPPORTED
233 #error "unknown channel order!"
234 #endif
235   UINT r = 0, g = 0, b = 0, m = 0;
236   std::vector<TPixel32> buffer(rect.getLx() * rect.getLy());
237   glReadPixels(rect.x0, rect.y0, rect.getLx(), rect.getLy(), fmt,
238                GL_UNSIGNED_BYTE, &buffer[0]);
239   int size = rect.getLx() * rect.getLy();
240   for (int i = 0; i < size; i++) {
241     r += buffer[i].r;
242     g += buffer[i].g;
243     b += buffer[i].b;
244   }
245 
246   return TPixel32(b / size, g / size, r / size, 255);
247 }
248 
249 //---------------------------------------------------------
250 
getAverageColor(TStroke * stroke)251 TPixel32 getAverageColor(TStroke *stroke) {
252   GLenum fmt =
253 #if defined(TNZ_MACHINE_CHANNEL_ORDER_BGRM)
254       GL_RGBA;
255 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MBGR)
256       GL_ABGR_EXT;
257 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM)
258       GL_RGBA;
259 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MRGB)
260       GL_BGRA;
261 #else
262 //   Error  PLATFORM NOT SUPPORTED
263 #error "unknown channel order"
264 #endif
265 
266   // leggo il buffer e mi prendo i pixels
267   UINT r = 0, g = 0, b = 0, m = 0;
268   TRect rect = convert(stroke->getBBox());
269   std::vector<TPixel32> buffer(rect.getLx() * rect.getLy());
270   glReadPixels(rect.x0, rect.y0, rect.getLx(), rect.getLy(), fmt,
271                GL_UNSIGNED_BYTE, &buffer[0]);
272 
273   // calcolo le regioni dello stroke
274   TVectorImage aux;
275   aux.addStroke(stroke);
276   aux.transform(TTranslation(convert(-rect.getP00())));
277   aux.findRegions();
278   int regionCount = aux.getRegionCount();
279   int size = 0, lx = rect.getLx();
280 
281   for (int j = 0; j < regionCount; j++) {
282     TRegion *reg  = aux.getRegion(j);
283     TRect regRect = convert(reg->getBBox());
284     for (int y = regRect.y0; y < regRect.y1; y++) {
285       std::vector<double> intersections;
286       reg->computeScanlineIntersections(y, intersections);
287       assert(!(intersections.size() & 0x1));
288       for (UINT i = 0; i < intersections.size(); i += 2) {
289         if (intersections[i] == intersections[i + 1]) continue;
290         int firstInters  = (int)intersections[i];
291         int secondInters = (int)intersections[i + 1];
292         for (int x = firstInters + 1; x < secondInters - 1; x++) {
293           r += buffer[y * lx + x].r;
294           g += buffer[y * lx + x].g;
295           b += buffer[y * lx + x].b;
296           size++;
297         }
298       }
299     }
300   }
301 
302   if (size != 0)
303     return TPixel32(b / size, g / size, r / size, 255);
304   else
305     return TPixel32(buffer[0].b, buffer[0].g, buffer[0].r, 255);
306 }
307 
308 }  // namespace
309 
310 //---------------------------------------------------------
311 
pickColor(const TRectD & area) const312 TPixel32 StylePicker::pickColor(const TRectD &area) const {
313   // TRectD rect=area.enlarge(-1,-1);
314   return getAverageColor(convert(area));
315 }
316 
317 //---------------------------------------------------------
318 
pickColor(TStroke * stroke) const319 TPixel32 StylePicker::pickColor(TStroke *stroke) const {
320   return getAverageColor(stroke);
321 }
322 
323 //---------------------------------------------------------
324