1
2
3 #pragma warning(disable : 4533)
4
5 #include "tiio_std.h"
6
7 #include "tlevel.h"
8 #include "trasterimage.h"
9 #include "ttoonzimage.h"
10 #include "trastercm.h"
11 #include "tnzimage.h"
12 #include "tsystem.h"
13 #include "trop.h"
14 #include "toonz/fill.h"
15 #include "toonz/autoclose.h"
16 #include "tenv.h"
17 #include "convert2tlv.h"
18 #include "tstream.h"
19
20 #include <map>
21
22 #include "toonz/toonzfolders.h"
23
24 // gmt, 14/11/2013 removed a commented out blocks of code (void buildInks1(),
25 // void buildPalette() )
26
27 extern TEnv::DoubleVar AutocloseDistance;
28 extern TEnv::DoubleVar AutocloseAngle;
29 extern TEnv::IntVar AutocloseOpacity;
30
31 namespace {
32 //----------------------------------------------
33
unmultiply(const TPixel & in)34 inline TPixel unmultiply(const TPixel &in) {
35 if (in.r == 255) return in;
36 TPixel out;
37 int val = in.r * 255 / in.m;
38 out.r = tcrop(val, 0, 255);
39 val = in.g * 255 / in.m;
40 out.g = tcrop(val, 0, 255);
41 val = in.b * 255 / in.m;
42 out.b = tcrop(val, 0, 255);
43 out.m = 255;
44 return out;
45 }
46
47 //----------------------------------------------
48
distance(const TPixel & c1,const TPixel & c2)49 inline int distance(const TPixel &c1, const TPixel &c2) {
50 return (c1.r - c2.r) * (c1.r - c2.r) + (c1.g - c2.g) * (c1.g - c2.g) +
51 (c1.b - c2.b) * (c1.b - c2.b);
52 }
53
54 //----------------------------------------------
55
findClosest(const std::map<TPixel,int> & colorMap,TPixel & curPixColor)56 int findClosest(const std::map<TPixel, int> &colorMap, TPixel &curPixColor) {
57 std::map<TPixel, int>::const_iterator it = colorMap.begin();
58 int minDistance = 1000000000;
59 int index = -1;
60 for (; it != colorMap.end(); ++it) {
61 int dist = distance(it->first, curPixColor);
62 if (dist < minDistance) {
63 minDistance = dist;
64 index = it->second;
65 }
66 }
67 assert(index != -1);
68 return index;
69 }
70
71 //----------------------------------------------
72
73 #define CHECKCOLOR(r, x, y, tone) \
74 { \
75 TPixelCM32 color = *((TPixelCM32 *)r->pixels(y) + (x)); \
76 if (color.getTone() == tone /*&& color.getPaint()!=0*/) \
77 return TPoint(x, y); \
78 }
79
80 // cerca in quadrati concentrici di raggio rad intorno al pixel in (x, y)
81 // il primo pixel di paint puro e ritorna il suo indice di paint
82
getClosestToneValue(const TRasterCM32P & r,int y,int x,int tone)83 TPoint getClosestToneValue(const TRasterCM32P &r, int y, int x, int tone) {
84 int maxRad = std::min({x, r->getLx() - x - 1, y, r->getLy() - y - 1});
85
86 for (int rad = 1; rad < maxRad; rad++) {
87 CHECKCOLOR(r, x, y - rad, tone)
88 CHECKCOLOR(r, x, y + rad, tone)
89 CHECKCOLOR(r, x - rad, y, tone)
90 CHECKCOLOR(r, x + rad, y, tone)
91 for (int j = 1; j <= rad; j++) {
92 CHECKCOLOR(r, x - j, y - rad, tone)
93 CHECKCOLOR(r, x + j, y - rad, tone)
94 CHECKCOLOR(r, x - j, y + rad, tone)
95 CHECKCOLOR(r, x + j, y + rad, tone)
96
97 CHECKCOLOR(r, x - rad, y - j, tone)
98 CHECKCOLOR(r, x - rad, y + j, tone)
99 CHECKCOLOR(r, x + rad, y - j, tone)
100 CHECKCOLOR(r, x + rad, y + j, tone)
101 }
102 }
103 return TPoint(-1, -1);
104 }
105
106 //--------------------------------------------------
107
getClosestPurePaint(const TRasterCM32P & r,int y,int x)108 TPoint getClosestPurePaint(const TRasterCM32P &r, int y, int x) {
109 return getClosestToneValue(r, y, x, 255);
110 }
111
112 //----------------------------------------------------
113
getClosestPureInk(const TRasterCM32P & r,int y,int x)114 TPoint getClosestPureInk(const TRasterCM32P &r, int y, int x) {
115 return getClosestToneValue(r, y, x, 0);
116 }
117
118 //----------------------------------------------------
119
firstIsUnpainted(const TRaster32P & r1,const TRaster32P & r2)120 bool firstIsUnpainted(const TRaster32P &r1, const TRaster32P &r2) {
121 for (int i = 0; i < r1->getLy(); i++) {
122 TPixel32 *pix1 = r1->pixels(i);
123 TPixel32 *pix2 = r2->pixels(i);
124 for (int j = 0; j < r1->getLx(); j++, pix1++, pix2++) {
125 if (pix1->m == 255 && pix2->m == 0)
126 return false;
127 else if (pix1->m == 0 && pix2->m == 255)
128 return true;
129 }
130 }
131 return true;
132 }
133
134 //----------------------------------------------
135 // ritorna -1 se non ha il canale di matte (tutti i pixel a 255)
136
getMaxMatte(const TRaster32P & r)137 int getMaxMatte(const TRaster32P &r) {
138 int maxMatte = -1;
139 bool withMatte = false;
140 for (int i = 0; i < r->getLy(); i++) {
141 TPixel32 *pix = r->pixels(i);
142 for (int j = 0; j < r->getLx(); j++, pix++) {
143 maxMatte = std::max(maxMatte, (int)pix->m);
144 if (pix->m != 255) withMatte = true;
145 }
146 }
147 return withMatte ? maxMatte : -1;
148 }
149
150 //----------------------------------------------
151
normalize(const TRaster32P & r,int maxMatte)152 void normalize(const TRaster32P &r, int maxMatte) {
153 int val;
154
155 for (int i = 0; i < r->getLy(); i++) {
156 TPixel32 *pix = r->pixels(i);
157 for (int j = 0; j < r->getLx(); j++, pix++) {
158 val = pix->r * 255 / maxMatte;
159 pix->r = tcrop(val, 0, 255);
160 val = pix->g * 255 / maxMatte;
161 pix->g = tcrop(val, 0, 255);
162 val = pix->b * 255 / maxMatte;
163 pix->b = tcrop(val, 0, 255);
164 val = pix->m * 255 / maxMatte;
165 pix->m = tcrop(val, 0, 255);
166 }
167 }
168 }
169
170 //----------------------------------------------------
171
getFramesCount(const TLevelP & l,int from,int to)172 int getFramesCount(const TLevelP &l, int from, int to) {
173 if (from == -1) return l->getFrameCount();
174
175 int count = 0;
176 TLevel::Iterator it = l->begin();
177 while (it != l->end() && it->first.getNumber() < from) it++;
178 while (it != l->end() && it->first.getNumber() <= to) it++, count++;
179 return count;
180 }
181 } // namespace
182 // namespace
183
findNearestColor(const TPixel & color)184 std::map<TPixel, int>::const_iterator Convert2Tlv::findNearestColor(
185 const TPixel &color) {
186 // assert((int)colorMap.size()>toIndex);
187 // assert((int)colorMap.size()>fromIndex);
188 std::map<TPixel, int>::const_iterator ret = m_colorMap.end(),
189 it = m_colorMap.begin();
190 // std::advance(it, fromIndex);
191
192 int mindist = 1000;
193 for (; it != m_colorMap.end(); ++it) {
194 const TPixel &curr = it->first;
195 int dr = abs(curr.r - color.r);
196 if (dr > m_colorTolerance) continue;
197 int dg = abs(curr.g - color.g);
198 if (dg > m_colorTolerance) continue;
199 int db = abs(curr.b - color.b);
200 if (db > m_colorTolerance) continue;
201 int dist = dr + dg + db;
202 if (dist < mindist) {
203 mindist = dist;
204 ret = it;
205 }
206 }
207 return ret;
208 }
209
210 //-------------------------------------------------------------------
211
buildInks(TRasterCM32P & rout,const TRaster32P & rin)212 void Convert2Tlv::buildInks(TRasterCM32P &rout, const TRaster32P &rin) {
213 std::map<TPixel, int>::const_iterator it;
214 TPixel curColor = TPixel::Transparent;
215 int i, j;
216 int curIndex;
217
218 // prima passata: identifico i colori di inchiostro e metto in rout i pixel di
219 // inchiostro puro
220 for (i = 0; i < rin->getLy(); i++) {
221 TPixel *pixin = rin->pixels(i);
222 TPixelCM32 *pixout = rout->pixels(i);
223 for (j = 0; j < rin->getLx(); j++, pixin++, pixout++) {
224 TPixel colorIn;
225
226 if (pixin->m != 255) continue;
227
228 if (curColor != *pixin) {
229 curColor = *pixin;
230 if ((it = m_colorMap.find(curColor)) == m_colorMap.end()) {
231 if (m_colorTolerance > 0) it = findNearestColor(curColor);
232 // if (it==colorMap.end() && (int)colorMap.size()>origColorCount)
233 // it = findNearestColor(curColor, colorMap, colorTolerance,
234 // origColorCount, colorMap.size()-1);
235 if (it == m_colorMap.end() && m_lastIndex < 4095) {
236 m_colorMap[curColor] = ++m_lastIndex;
237 curIndex = m_lastIndex;
238 } else if (it != m_colorMap.end()) {
239 m_colorMap[curColor] = it->second;
240 curIndex = it->second;
241 }
242 } else
243 curIndex = it->second;
244 }
245 *pixout = TPixelCM32(curIndex, 0, 0);
246 }
247 }
248
249 // seconda passata: metto gli inchiostri di antialiasing
250 curColor = TPixel::Transparent;
251
252 for (i = 0; i < rin->getLy(); i++) {
253 TPixel *pixin = rin->pixels(i);
254 TPixelCM32 *pixout = rout->pixels(i);
255 for (j = 0; j < rin->getLx(); j++, pixin++, pixout++) {
256 TPixel colorIn;
257 if (pixin->m == 255) // gia' messo nel ciclo precedente
258 continue;
259 if (pixin->m == 0) continue;
260
261 colorIn = unmultiply(*pixin); // findClosestOpaque(rin, i, j);
262
263 if (curColor != colorIn) {
264 curColor = colorIn;
265 if ((it = m_colorMap.find(curColor)) != m_colorMap.end())
266 curIndex = it->second;
267 else
268 curIndex = findClosest(m_colorMap, curColor);
269 }
270 *pixout = TPixelCM32(curIndex, 0, 255 - pixin->m);
271 }
272 }
273 }
274
275 //----------------------------------------------
276
removeAntialias(TRasterCM32P & r)277 void Convert2Tlv::removeAntialias(TRasterCM32P &r) {
278 int threshold = (int)(m_antialiasValue * 255.0 / 100.0);
279 int tone;
280 for (int i = 0; i < r->getLy(); i++) {
281 TPixelCM32 *pix = r->pixels(i);
282 for (int j = 0; j < r->getLx(); j++, pix++)
283 if ((tone = pix->getTone()) !=
284 0xff) // tone==ff e tone==0 non vanno toccati mai
285 pix->setTone(tone > threshold ? 0xff : 0);
286 }
287 }
288
289 //------------------------------------------------------------------
290
buildInksFromGrayTones(TRasterCM32P & rout,const TRasterP & rin)291 void Convert2Tlv::buildInksFromGrayTones(TRasterCM32P &rout,
292 const TRasterP &rin) {
293 int i, j;
294
295 TRasterGR8P r8 = (TRasterGR8P)rin;
296 TRaster32P r32 = (TRaster32P)rin;
297 if (r8)
298 for (i = 0; i < rin->getLy(); i++) {
299 TPixelGR8 *pixin = r8->pixels(i);
300 TPixelCM32 *pixout = rout->pixels(i);
301 for (j = 0; j < rin->getLx(); j++, pixin++, pixout++)
302 *pixout = TPixelCM32(1, 0, pixin->value);
303 }
304 else
305 for (i = 0; i < rin->getLy(); i++) {
306 TPixel *pixin = r32->pixels(i);
307 TPixelCM32 *pixout = rout->pixels(i);
308 for (j = 0; j < rin->getLx(); j++, pixin++, pixout++)
309 *pixout = TPixelCM32(1, 0, TPixelGR8::from(*pixin).value);
310 }
311 }
312
313 //----------------------------------------------------------------------
314
buildInksForNAAImage(TRasterCM32P & rout,const TRaster32P & rin)315 void Convert2Tlv::buildInksForNAAImage(TRasterCM32P &rout,
316 const TRaster32P &rin) {
317 std::map<TPixel, int>::iterator it;
318 TPixel curColor = TPixel::Transparent;
319 int i, j;
320 int curIndex;
321
322 // prima passata: identifico i colori di inchiostro e metto in rout i pixel di
323 // inchiostro puro
324 for (i = 0; i < rin->getLy(); i++) {
325 TPixel *pixin = rin->pixels(i);
326 TPixelCM32 *pixout = rout->pixels(i);
327 for (j = 0; j < rin->getLx(); j++, pixin++, pixout++) {
328 TPixel colorIn;
329
330 /*- treat white/transparent pixels as transparent -*/
331 if (*pixin == TPixel(255, 255, 255) || *pixin == TPixel::Transparent) {
332 *pixout = TPixelCM32(0, 0, 255);
333 continue;
334 }
335
336 if (curColor != *pixin) {
337 curColor = *pixin;
338 if ((it = m_colorMap.find(curColor)) == m_colorMap.end()) {
339 if (m_lastIndex < 4095) m_colorMap[curColor] = ++m_lastIndex;
340 curIndex = m_lastIndex;
341 } else
342 curIndex = it->second;
343 }
344 *pixout = TPixelCM32(curIndex, 0, 0);
345 }
346 }
347
348 if (m_colorMap.empty()) m_colorMap[TPixel::Black] = ++m_lastIndex;
349 }
350
351 //----------------------------------------------
352
doFill(TRasterCM32P & rout,const TRaster32P & rin)353 void Convert2Tlv::doFill(TRasterCM32P &rout, const TRaster32P &rin) {
354 // prima passata: si filla solo partendo da pixel senza inchiostro, senza
355 // antialiasing(tone==255)
356 for (int i = 0; i < rin->getLy(); i++) {
357 TPixel *pixin = rin->pixels(i);
358 TPixelCM32 *pixout = rout->pixels(i);
359 for (int j = 0; j < rin->getLx(); j++, pixin++, pixout++) {
360 if (!(pixout->getTone() == 255 && pixout->getPaint() == 0 &&
361 pixin->m == 255))
362 continue;
363
364 std::map<TPixel, int>::const_iterator it;
365 int paintIndex;
366 if ((it = m_colorMap.find(*pixin)) == m_colorMap.end()) {
367 if (m_colorTolerance > 0) it = findNearestColor(*pixin);
368 // if (it==colorMap.end() && (int)colorMap.size()>origColorCount) //se
369 // non l'ho trovato tra i colori origari, lo cerco in quelli nuovi, ma
370 // in questo caso deve essere esattamente uguale(tolerance = 0)
371 // it = findNearestColor(*pixin, colorMap, colorTolerance,
372 // origColorCount, colorMap.size()-1);
373
374 if (it == m_colorMap.end() && m_lastIndex < 4096) {
375 m_colorMap[*pixin] = ++m_lastIndex;
376 paintIndex = m_lastIndex;
377 } else if (it != m_colorMap.end()) {
378 m_colorMap[*pixin] = it->second;
379 paintIndex = it->second;
380 }
381 } else
382 paintIndex = it->second;
383 FillParameters params;
384 params.m_p = TPoint(j, i);
385 params.m_styleId = paintIndex;
386 params.m_emptyOnly = true;
387 fill(rout, params);
388 // if (*((ULONG *)rout->getRawData())!=0xff)
389 // {
390 // int cavolo=0;
391 // }
392 }
393 }
394
395 // seconda passata: se son rimasti pixel antialiasati non fillati, si fillano,
396 // cercando nelle vicinanze un pixel di paint puro per capire il colore da
397 // usare
398 for (int i = 0; i < rin->getLy(); i++) {
399 TPixel *pixin = rin->pixels(i);
400 TPixelCM32 *pixout = rout->pixels(i);
401 for (int j = 0; j < rin->getLx(); j++, pixin++, pixout++) {
402 if (!(pixout->getTone() > 0 && pixout->getTone() < 255 &&
403 pixout->getPaint() == 0 && pixin->m == 255))
404 continue;
405
406 TPoint p = getClosestPurePaint(rout, i, j);
407 if (p.x == -1) continue;
408
409 // pixout->setPaint( paintIndex);
410 FillParameters params;
411 params.m_p = TPoint(j, i);
412 params.m_styleId = (rout->pixels(p.y) + p.x)->getPaint();
413 params.m_emptyOnly = true;
414
415 fill(rout, params);
416 }
417 }
418
419 // infine, si filla di trasparente lo sfondo, percorrendo il bordo, nel caso
420 // di trasbordamenti di colore
421 TPixelCM32 *pixCm;
422 TPixel *pix;
423
424 pixCm = rout->pixels(0);
425 pix = rin->pixels(0);
426 FillParameters params;
427 params.m_styleId = 0;
428
429 for (int i = 0; i < rout->getLx(); i++, pixCm++, pix++)
430 if (pixCm->getTone() == 255 && pixCm->getPaint() != 0 && pix->m == 0) {
431 params.m_p = TPoint(i, 0);
432 fill(rout, params);
433 }
434
435 pixCm = rout->pixels(rout->getLy() - 1);
436 pix = rin->pixels(rout->getLy() - 1);
437 for (int i = 0; i < rout->getLx(); i++, pixCm++, pix++)
438 if (pixCm->getTone() == 255 && pixCm->getPaint() != 0 && pix->m == 0) {
439 params.m_p = TPoint(i, rout->getLy() - 1);
440 fill(rout, params);
441 }
442 int wrapCM = rout->getWrap();
443 int wrap = rin->getWrap();
444
445 pixCm = rout->pixels(0);
446 pix = rin->pixels(0);
447 for (int i = 0; i < rin->getLy(); i++, pixCm += wrapCM, pix += wrap)
448 if (pixCm->getTone() == 255 && pixCm->getPaint() != 0 && pix->m == 0) {
449 params.m_p = TPoint(0, i);
450 fill(rout, params);
451 }
452 pixCm = rout->pixels(0) + rout->getLx() - 1;
453 pix = rin->pixels(0) + rin->getLx() - 1;
454 for (int i = 0; i < rin->getLy(); i++, pixCm += wrapCM, pix += wrap)
455 if (pixCm->getTone() == 255 && pixCm->getPaint() != 0 && pix->m == 0) {
456 params.m_p = TPoint(rout->getLx() - 1, i);
457 fill(rout, params);
458 }
459 }
460
461 //----------------------------------------------
462
buildToonzRaster(TRasterCM32P & rout,const TRasterP & rin1,const TRasterP & rin2)463 void Convert2Tlv::buildToonzRaster(TRasterCM32P &rout, const TRasterP &rin1,
464 const TRasterP &rin2) {
465 if (rin2) assert(rin1->getSize() == rin2->getSize());
466
467 rout->clear();
468
469 std::cout << " computing inks...\n";
470 TRaster32P r1 = (TRaster32P)rin1;
471 TRasterGR8P r1gr = (TRasterGR8P)rin1;
472 TRaster32P r2 = (TRaster32P)rin2;
473 TRasterGR8P r2gr = (TRasterGR8P)rin2;
474 TRasterP rU, rP;
475
476 if (r1gr) {
477 rU = r1gr;
478 rP = r2;
479 } else if (r2gr) {
480 rU = r2gr;
481 rP = r1;
482 } else if (!r1)
483 rU = r2;
484 else if (!r2)
485 rU = r1;
486 else if (firstIsUnpainted(r1, r2)) {
487 rU = r1;
488 rP = r2;
489 } else {
490 rU = r2;
491 rP = r1;
492 }
493
494 TRasterCM32P r;
495 if (rout->getSize() != rU->getSize()) {
496 int dx = rout->getLx() - rU->getLx();
497 int dy = rout->getLy() - rU->getLy();
498 assert(dx >= 0 && dy >= 0);
499
500 r = rout->extract(dx / 2, dy / 2, dx / 2 + rU->getLx() - 1,
501 dy / 2 + rU->getLy() - 1);
502 } else
503 r = rout;
504
505 if ((TRasterGR8P)rU)
506 buildInksFromGrayTones(r, rU);
507 else if (m_isUnpaintedFromNAA)
508 buildInksForNAAImage(r, (TRaster32P)rU);
509 else {
510 int maxMatte = getMaxMatte((TRaster32P)rU);
511 if (maxMatte == -1)
512 buildInksFromGrayTones(r, rU);
513 else if (maxMatte == 0) // empty frame doesn't need further computation
514 return;
515 else {
516 if (maxMatte < 255) normalize(rU, maxMatte);
517 buildInks(r, (TRaster32P)rU /*rP,*/);
518 }
519 }
520
521 if (m_autoclose)
522 TAutocloser(r, AutocloseDistance, AutocloseAngle, 1, AutocloseOpacity)
523 .exec();
524
525 if (rP) {
526 std::cout << " computing paints...\n";
527 doFill(r, rP);
528 }
529 if (m_antialiasType == 2) // remove antialias
530 removeAntialias(r);
531 else if (m_antialiasType == 1) // add antialias
532 {
533 TRasterCM32P raux(r->getSize());
534 TRop::antialias(r, raux, 10, m_antialiasValue);
535 rout = raux;
536 }
537 }
538
539 //----------------------------------------------
540
buildPalette()541 TPalette *Convert2Tlv::buildPalette() {
542 std::map<TPixel, int>::const_iterator it = m_colorMap.begin();
543 TPalette::Page *page = m_palette->getPage(0);
544
545 QList<int> stylesToBeAddedToPage;
546
547 for (; it != m_colorMap.end(); ++it) {
548 if (it->second >
549 m_maxPaletteIndex) // colore nuovo da aggiungere alla paletta)
550 {
551 if (m_palette->getStyleCount() > it->second)
552 m_palette->setStyle(it->second, it->first);
553 else {
554 while (m_palette->getStyleCount() < it->second)
555 m_palette->addStyle(TPixel::Transparent);
556 int id = m_palette->addStyle(it->first);
557 assert(id == it->second);
558 }
559 }
560 if (!m_palette->getStylePage(it->second))
561 stylesToBeAddedToPage.push_back(it->second);
562 }
563
564 /*- インデックス順にページに格納する -*/
565 if (!stylesToBeAddedToPage.isEmpty()) {
566 std::sort(stylesToBeAddedToPage.begin(), stylesToBeAddedToPage.end());
567 for (int s = 0; s < stylesToBeAddedToPage.size(); s++)
568 page->addStyle(stylesToBeAddedToPage.at(s));
569 }
570
571 /*
572 If the palette path is empty, an initial palette with four colors are set in
573 the palette here.
574 ( see Convert2Tlv::init() ) So here I make the latter three styles in the
575 initial palette to set
576 "AutoPaint" options.
577 */
578 if (m_palettePath.isEmpty()) {
579 assert(m_palette->getStyleCount() >= 5);
580 for (int id = 2; id <= 4; id++) m_palette->getStyle(id)->setFlags(1);
581 }
582
583 if (!m_appendDefaultPalette) return m_palette;
584
585 /*-- Adding styles in the default palette to the result palette, starts here
586 * --*/
587 TFilePath palettePath =
588 ToonzFolder::getStudioPaletteFolder() + "cleanup_default.tpl";
589 TFileStatus pfs(palettePath);
590
591 if (!pfs.doesExist() || !pfs.isReadable()) return m_palette;
592
593 TIStream is(palettePath);
594 if (!is) return m_palette;
595
596 std::string tagName;
597 if (!is.matchTag(tagName) || tagName != "palette") return m_palette;
598
599 std::string gname;
600 is.getTagParam("name", gname);
601 TPalette *defaultPalette = new TPalette();
602 defaultPalette->loadData(is);
603
604 m_palette->setIsCleanupPalette(false);
605
606 TPalette::Page *dstPage = m_palette->getPage(0);
607 TPalette::Page *srcPage = defaultPalette->getPage(0);
608
609 for (int srcIndexInPage = 0; srcIndexInPage < srcPage->getStyleCount();
610 srcIndexInPage++) {
611 int id = srcPage->getStyleId(srcIndexInPage);
612
613 bool isUsedInDstPalette = false;
614
615 for (int dstIndexInPage = 0; dstIndexInPage < dstPage->getStyleCount();
616 dstIndexInPage++) {
617 if (dstPage->getStyleId(dstIndexInPage) == id) {
618 isUsedInDstPalette = true;
619 break;
620 }
621 }
622
623 if (isUsedInDstPalette)
624 continue;
625 else {
626 int addedId =
627 m_palette->addStyle(srcPage->getStyle(srcIndexInPage)->clone());
628 dstPage->addStyle(addedId);
629 /*-- StudioPalette由来のDefaultPaletteの場合、GrobalNameを消去する --*/
630 m_palette->getStyle(addedId)->setGlobalName(L"");
631 m_palette->getStyle(addedId)->setOriginalName(L"");
632 }
633 }
634 delete defaultPalette;
635 /*-- Adding styles in the default palette to the result palette, ends here
636 * --*/
637
638 return m_palette;
639 }
640
641 //------------------------------------------------------------------------------
642
Convert2Tlv(const TFilePath & filepath1,const TFilePath & filepath2,const TFilePath & outFolder,const QString & outName,int from,int to,bool doAutoclose,const TFilePath & palettePath,int colorTolerance,int antialiasType,int antialiasValue,bool isUnpaintedFromNAA,bool appendDefaultPalette,double dpi)643 Convert2Tlv::Convert2Tlv(const TFilePath &filepath1, const TFilePath &filepath2,
644 const TFilePath &outFolder, const QString &outName,
645 int from, int to, bool doAutoclose,
646 const TFilePath &palettePath, int colorTolerance,
647 int antialiasType, int antialiasValue,
648 bool isUnpaintedFromNAA, bool appendDefaultPalette,
649 double dpi)
650 : m_size(0, 0)
651 , m_level1()
652 , m_levelIn1()
653 , m_levelIn2()
654 , m_levelOut()
655 , m_autoclose(doAutoclose)
656 , m_premultiply(false)
657 , m_count(0)
658 , m_from(from)
659 , m_to(to)
660 , m_palettePath(palettePath)
661 , m_colorTolerance(colorTolerance)
662 , m_palette(0)
663 , m_antialiasType(antialiasType)
664 , m_antialiasValue(antialiasValue)
665 , m_isUnpaintedFromNAA(isUnpaintedFromNAA)
666 , m_appendDefaultPalette(appendDefaultPalette)
667 , m_dpi(dpi) {
668 if (filepath1 != TFilePath()) {
669 m_levelIn1 = filepath1.getParentDir() + filepath1.getLevelName();
670 if (outFolder != TFilePath())
671 m_levelOut =
672 m_levelIn1.withParentDir(outFolder).withNoFrame().withType("tlv");
673 else
674 m_levelOut = m_levelIn1.withNoFrame().withType(
675 "tlv"); // filePaths[0].getParentDir() +
676 // TFilePath(filePaths[0].getWideName() + L".tlv");
677
678 if (outName != "") m_levelOut = m_levelOut.withName(outName.toStdString());
679 }
680
681 if (filepath2 != TFilePath())
682 m_levelIn2 = filepath2.getParentDir() + filepath2.getLevelName();
683 }
684
685 //-------------------------------------------------------------------------------------
686
getFramesToConvertCount()687 int Convert2Tlv::getFramesToConvertCount() {
688 if (m_level1 && m_level1->getFrameCount() > 0)
689 return getFramesCount(m_level1, m_from,
690 m_to); // m_level1->getFrameCount();
691 else {
692 try {
693 TLevelReaderP lr = TLevelReaderP(m_levelIn1);
694 if (lr) {
695 TLevelP l = lr->loadInfo();
696 if (l) {
697 return getFramesCount(l, m_from, m_to);
698 }
699 }
700 } catch (...) {
701 return 0;
702 }
703 }
704 return 0;
705 }
706
707 //---------------------------------------------
708
init(std::string & errorMessage)709 bool Convert2Tlv::init(std::string &errorMessage) {
710 m_lastIndex = m_maxPaletteIndex = 0;
711 m_colorMap.clear();
712
713 try {
714 m_lr1 = TLevelReaderP(m_levelIn1);
715 if (m_lr1) m_level1 = m_lr1->loadInfo();
716 } catch (...) {
717 errorMessage =
718 "Error: can't read level " + ::to_string(m_levelIn1.getWideString());
719 return false;
720 }
721
722 if (m_level1->getFrameCount() == 0) {
723 errorMessage =
724 "Error: can't find level " + ::to_string(m_levelIn1.getWideString());
725 return false;
726 }
727
728 TLevelP level2;
729
730 if (m_levelIn2 != TFilePath()) {
731 try {
732 m_lr2 = TLevelReaderP(m_levelIn2);
733 if (m_lr2) level2 = m_lr2->loadInfo();
734 } catch (...) {
735 errorMessage =
736 "Error: can't read level " + ::to_string(m_levelIn2.getWideString());
737 return false;
738 }
739
740 if (level2->getFrameCount() == 0) {
741 errorMessage =
742 "Error: can't find level " + ::to_string(m_levelIn2.getWideString());
743 return false;
744 }
745
746 if (m_level1->getFrameCount() != level2->getFrameCount()) {
747 errorMessage = "Error: the two input levels must have same frame number";
748 return false;
749 }
750 }
751
752 m_size = TDimension();
753
754 m_lw = TLevelWriterP(m_levelOut);
755 m_it = m_level1->begin();
756
757 TLevel::Iterator it2;
758
759 if (level2->getFrameCount() > 0) it2 = level2->begin();
760
761 for (; m_it != m_level1->end(); ++m_it) {
762 TImageReaderP ir1 = m_lr1->getFrameReader(m_it->first);
763 const TImageInfo *info1 = ir1->getImageInfo();
764 if (!info1) {
765 errorMessage = "Error: can't read frame " +
766 std::to_string(m_it->first.getNumber()) + " of level " +
767 ::to_string(m_levelIn1.getWideString());
768 return false;
769 }
770
771 if (info1->m_bitsPerSample != 8) {
772 errorMessage = "Error: all frames must have 8 bits per channel!\n";
773 return false;
774 }
775 m_size.lx = std::max(m_size.lx, info1->m_lx);
776 m_size.ly = std::max(m_size.ly, info1->m_ly);
777
778 if (m_lr2 != TLevelReaderP()) {
779 TImageReaderP ir2 = m_lr2->getFrameReader(it2->first);
780
781 if (ir2) {
782 const TImageInfo *info2 = ir2->getImageInfo();
783 if (!info1) {
784 errorMessage = "Error: can't read frame " +
785 std::to_string(it2->first.getNumber()) +
786 " of level " +
787 ::to_string(m_levelIn2.getWideString());
788 ;
789 return false;
790 }
791
792 if (info1->m_lx != info2->m_lx || info1->m_ly != info2->m_ly) {
793 errorMessage =
794 "Error: painted frames must have same resolution of matching "
795 "unpainted frames!\n";
796 return false;
797 }
798 if (info2->m_bitsPerSample != 8) {
799 errorMessage = "Error: all frames must have 8 bits per channel!\n";
800 return false;
801 }
802 }
803 ++it2;
804 }
805 }
806
807 m_palette = new TPalette();
808
809 if (m_palettePath != TFilePath()) {
810 TIStream is(m_palettePath);
811 is >> m_palette;
812 if (m_palette->getStyleInPagesCount() == 0) {
813 errorMessage = "Error: invalid palette!\n";
814
815 return false;
816 }
817 for (int i = 0; i < m_palette->getStyleCount(); i++)
818 if (m_palette->getStylePage(i)) {
819 m_colorMap[m_palette->getStyle(i)->getMainColor()] = i;
820 if (i > m_lastIndex) m_lastIndex = i;
821 }
822 assert(m_colorMap.size() == m_palette->getStyleInPagesCount());
823 }
824
825 m_maxPaletteIndex = m_lastIndex;
826
827 m_it = m_level1->begin();
828
829 /*-
830 If the palette is empty, make an initial palette with black, red, blue and
831 green styles.
832 For the latter three styles the "autopaint" option should be set.
833 -*/
834 if (m_lastIndex == 0) {
835 m_colorMap[TPixel::Black] = ++m_lastIndex;
836 m_colorMap[TPixel::Red] = ++m_lastIndex;
837 m_colorMap[TPixel::Blue] = ++m_lastIndex;
838 m_colorMap[TPixel::Green] = ++m_lastIndex;
839 }
840
841 return true;
842 }
843
844 //----------------------------------------------------------------------------------------
845
convertNext(std::string & errorMessage)846 bool Convert2Tlv::convertNext(std::string &errorMessage) {
847 if (m_count == 0 && m_from != -1)
848 while (m_it != m_level1->end() && m_it->first.getNumber() < m_from) m_it++;
849
850 std::cout << "Processing image " << ++m_count << " of "
851 << getFramesCount(m_level1, m_from, m_to) << "...\n";
852 std::cout << " Loading frame " << m_it->first.getNumber() << "...\n";
853 TImageReaderP ir1 = m_lr1->getFrameReader(m_it->first);
854 TRasterImageP imgIn1 = (TRasterImageP)ir1->load();
855 if (!imgIn1) {
856 errorMessage = "Error: cannot read frame" +
857 std::to_string(m_it->first.getNumber()) + " of " +
858 ::to_string(m_levelIn1.getWideString()) + "!";
859 return false;
860 }
861 TRasterP rin1 = imgIn1->getRaster();
862
863 assert((TRaster32P)rin1 || (TRasterGR8P)rin1);
864
865 TRasterP rin2;
866 TRasterImageP imgIn2;
867
868 if (m_lr2) {
869 TImageReaderP ir2 = m_lr2->getFrameReader(m_it->first);
870 imgIn2 = (TRasterImageP)ir2->load();
871 if (!imgIn2) {
872 errorMessage = "Error: cannot read frame " +
873 std::to_string(m_it->first.getNumber()) + " of " +
874 ::to_string(m_levelIn2.getWideString()) + "!";
875 return false;
876 }
877 rin2 = imgIn2->getRaster();
878 assert((TRaster32P)rin2 || (TRasterGR8P)rin2);
879 }
880
881 TRasterCM32P rout(m_size);
882 buildToonzRaster(rout, rin1, rin2);
883
884 std::cout << " saving frame in level \'" << m_levelOut.getLevelName()
885 << "\'...\n\n";
886 TImageWriterP iw = m_lw->getFrameWriter(m_it->first);
887 TToonzImageP timg = TToonzImageP(rout, rout->getBounds());
888
889 TRect bbox;
890 TRop::computeBBox(rout, bbox);
891 timg->setSavebox(bbox);
892
893 if (m_dpi > 0.0) // specify dpi in the convert popup
894 timg->setDpi(m_dpi, m_dpi);
895 else {
896 double dpix, dpiy;
897 imgIn1->getDpi(dpix, dpiy);
898 timg->setDpi(dpix, dpiy);
899 }
900
901 TLevel::Iterator itaux = m_it;
902 itaux++;
903 if (itaux == m_level1->end() ||
904 (m_to != -1 &&
905 itaux->first.getNumber() > m_to)) // ultimo frame da scrivere.
906 timg->setPalette(buildPalette());
907
908 iw->save(timg);
909
910 ++m_it;
911 return true;
912 }
913
914 //----------------------------------------------------------------------------------------------
915
abort()916 bool Convert2Tlv::abort() {
917 try {
918 m_lr1 = TLevelReaderP();
919 m_lr2 = TLevelReaderP();
920 m_lw = TLevelWriterP();
921 m_level1 = TLevelP();
922
923 std::cout << "No output generated\n";
924 TSystem::deleteFile(m_levelOut);
925 TSystem::deleteFile(m_levelOut.withType("tpl"));
926 return false;
927 } catch (...) {
928 return false;
929 }
930 }
931
932 //==============================================================================================
933 //
934 // RasterToToonzRasterConverter
935 //
936 //----------------------------------------------------------------------------------------------
937
RasterToToonzRasterConverter()938 RasterToToonzRasterConverter::RasterToToonzRasterConverter() {
939 m_palette = new TPalette();
940 }
941
~RasterToToonzRasterConverter()942 RasterToToonzRasterConverter::~RasterToToonzRasterConverter() {}
943
setPalette(const TPaletteP & palette)944 void RasterToToonzRasterConverter::setPalette(const TPaletteP &palette) {
945 m_palette = palette;
946 }
947
convert(const TRasterP & inputRaster)948 TRasterCM32P RasterToToonzRasterConverter::convert(
949 const TRasterP &inputRaster) {
950 int lx = inputRaster->getLx();
951 int ly = inputRaster->getLy();
952
953 TRaster32P r = inputRaster;
954 /*
955 TRasterGR8P r1gr = (TRasterGR8P)inputRaster;
956 TRasterP rU, rP;
957 */
958
959 TRasterCM32P rout(lx, ly);
960
961 for (int y = 0; y < ly; y++) {
962 TPixel32 *pixin = r->pixels(y);
963 TPixel32 *pixinEnd = pixin + lx;
964 TPixelCM32 *pixout = rout->pixels(y);
965 while (pixin < pixinEnd) {
966 int v = (pixin->r + pixin->g + pixin->b) / 3;
967 ++pixin;
968 *pixout++ = TPixelCM32(1, 0, v);
969 }
970 }
971 return rout;
972 }
973
convert(const TRasterP & inksInputRaster,const TRasterP & paintInputRaster)974 TRasterCM32P RasterToToonzRasterConverter::convert(
975 const TRasterP &inksInputRaster, const TRasterP &paintInputRaster) {
976 return TRasterCM32P();
977 }
978
convert(const TRasterImageP & ri)979 TToonzImageP RasterToToonzRasterConverter::convert(const TRasterImageP &ri) {
980 TRasterCM32P ras = convert(ri->getRaster());
981 if (ras)
982 return TToonzImageP(ras, TRect(ras->getBounds()));
983 else
984 return TToonzImageP();
985 }
986