1 
2 
3 // TnzCore includes
4 #include "tsystem.h"
5 #include "timage_io.h"
6 #include "trop.h"
7 #include "tconvert.h"
8 #include "tvectorimage.h"
9 #include "ttoonzimage.h"
10 #include "tproperty.h"
11 #include "trasterimage.h"
12 #include "tiio.h"
13 #include "tfilepath_io.h"
14 #include "tpixelutils.h"
15 
16 // boost includes
17 #include <boost/range.hpp>
18 
19 #ifdef _MSC_VER
20 #pragma warning(disable : 4996)
21 #endif
22 
23 // OS-specific includes
24 #ifdef _WIN32
25 #include <io.h>
26 #endif
27 #if defined(LINUX) || defined(FREEBSD)
28 #include <unistd.h>
29 #endif
30 
31 // System V includes
32 #include <fcntl.h>     // didn't even know Windows had them  :D
33 #include <sys/stat.h>  // btw, why are they here?
34 
35 DEFINE_CLASS_CODE(TImageReader, 5)
36 DEFINE_CLASS_CODE(TImageWriter, 6)
37 
38 //-----------------------------------------------------------
39 
40 std::map<QString, TImageReaderCreateProc *> ImageReaderTable;
41 std::map<QString, std::pair<TImageWriterCreateProc *, bool>> ImageWriterTable;
42 
43 //-----------------------------------------------------------
44 
45 bool TImageReader::m_safeMode = false;
46 
47 //-----------------------------------------------------------
48 
TImageReader(const TFilePath & path)49 TImageReader::TImageReader(const TFilePath &path)
50     : TSmartObject(m_classCode)
51     , m_path(path)
52     , m_reader(0)
53     , m_vectorReader(0)
54     , m_readGreytones(true)
55     , m_file(NULL)
56     , m_is64BitEnabled(false)
57     , m_shrink(1)
58     , m_region(TRect()) {}
59 
60 //-----------------------------------------------------------
61 
doReadGraytones(bool readThem)62 void TImageReader::doReadGraytones(bool readThem) {
63   m_readGreytones = readThem;
64 }
65 
66 //-----------------------------------------------------------
67 
~TImageReader()68 TImageReader::~TImageReader() { close(); }
69 
70 //-----------------------------------------------------------
71 
isOpen() const72 bool TImageReader::isOpen() const { return m_file != NULL; }
73 
74 //-----------------------------------------------------------
75 
close()76 void TImageReader::close() {
77   delete m_reader;
78   delete m_vectorReader;
79 
80   if (m_file != NULL) {
81     int err = 0;
82     err     = fclose(m_file);
83 
84     assert(err == 0);  // il file e' stato chiuso senza errori
85   }
86 
87   m_file         = NULL;
88   m_reader       = 0;
89   m_vectorReader = 0;
90 }
91 
92 //-----------------------------------------------------------
93 
94 /*!
95   Opens for reading using \b fopen().
96 */
getTzpPaletteColorNames(std::map<int,std::pair<std::string,std::string>> & pltColorNames)97 void TImageReader::getTzpPaletteColorNames(
98     std::map<int, std::pair<std::string, std::string>> &pltColorNames) {
99   if (!m_file) open();
100 
101   if (!m_file) return;
102 
103   assert(m_reader);
104   m_reader->getTzpPaletteColorNames(pltColorNames);
105 }
106 
107 //-----------------------------------------------------------
108 
open()109 void TImageReader::open() {
110   assert(m_file == NULL);
111 
112   std::string type = toLower(m_path.getType());
113   m_file = fopen(m_path, "rb");  // Opens for reading. If the file does not
114                                  // exist or cannot be found, the fopen_s call
115                                  // fails
116 
117   if (m_file == NULL)  // Non dovrebbe mai andarci!
118     close();  // close() chiude il file se e' aperto e setta m_file a NULL.
119   else {
120     try {
121       m_reader = Tiio::makeReader(type);
122       if (m_reader)
123         m_reader->open(m_file);
124       else {
125         m_vectorReader = Tiio::makeVectorReader(type);
126         if (m_vectorReader)
127           m_vectorReader->open(m_file);
128         else
129           throw TImageException(m_path, "Image format not supported");
130       }
131     } catch (TException &e) {
132       close();  // close() chiude il file e setta m_file a NULL.
133       QString msg = QString::fromStdWString(e.getMessage());
134       if (msg == QString("Old 4.1 Palette")) throw e;
135     } catch (std::string str) {
136       if (str == "Tiff file closed") m_file = NULL;
137     }
138   }
139 }
140 
141 //===========================================================
142 
setShrink(int shrink)143 void TImageReader::setShrink(int shrink) { m_shrink = shrink; }
144 
145 //-----------------------------------------------------------
146 
TImageReaderP(const TFilePath & path)147 TImageReaderP::TImageReaderP(const TFilePath &path) {
148   m_pointer = new TImageReader(path);
149   m_pointer->addRef();
150   m_pointer->open();
151 }
152 
153 //-----------------------------------------------------------
154 
load()155 TImageP TImageReader::load() {
156   TImageP image = load0();
157   if (!image) return TImageP();
158 
159   TImageInfo info = m_reader->getImageInfo();
160   if (info.m_lx <= 0 || info.m_ly <= 0) return TImageP();
161 
162   return image;
163 }
164 
165 //============================================================
166 
167 template <typename Pix>
168 struct pixel_traits {};
169 
170 template <>
171 struct pixel_traits<TPixel32> {
172   typedef TPixel32 rgbm_pixel_type;
173   typedef char buffer_type;
174 };
175 
176 template <>
177 struct pixel_traits<TPixel64> {
178   typedef TPixel64 rgbm_pixel_type;
179   typedef short buffer_type;
180 };
181 
182 template <>
183 struct pixel_traits<TPixelGR8> {
184   typedef TPixel32 rgbm_pixel_type;
185   typedef char buffer_type;
186 };
187 
188 template <>
189 struct pixel_traits<TPixelGR16> {
190   typedef TPixel64 rgbm_pixel_type;
191   typedef short buffer_type;
192 };
193 
194 template <>
195 struct pixel_traits<TPixelCM32> {
196   typedef TPixel32 rgbm_pixel_type;
197   typedef char buffer_type;
198 };
199 
200 //------------------------------------------------------------------------------------
201 
202 template <typename Pix>
copyLine(typename pixel_traits<Pix>::rgbm_pixel_type * lineIn,Pix * lineOut,int x0,int length,int shrink)203 void copyLine(typename pixel_traits<Pix>::rgbm_pixel_type *lineIn, Pix *lineOut,
204               int x0, int length, int shrink) {
205   lineIn += x0;
206 
207   for (int i = 0; i < length; ++i, lineIn += shrink, ++lineOut)
208     memcpy(lineOut, lineIn, sizeof(Pix));
209 }
210 
211 template <>
copyLine(TPixel32 * lineIn,TPixelGR8 * lineOut,int x0,int length,int shrink)212 void copyLine<TPixelGR8>(TPixel32 *lineIn, TPixelGR8 *lineOut, int x0,
213                          int length, int shrink) {
214   lineIn += x0;
215 
216   for (int i = 0; i < length; ++i, lineIn += shrink, ++lineOut)
217     lineOut->value = lineIn->r;
218 }
219 
220 template <>
copyLine(TPixel64 * lineIn,TPixelGR16 * lineOut,int x0,int length,int shrink)221 void copyLine<TPixelGR16>(TPixel64 *lineIn, TPixelGR16 *lineOut, int x0,
222                           int length, int shrink) {
223   lineIn += x0;
224 
225   for (int i = 0; i < length; ++i, lineIn += shrink, ++lineOut)
226     lineOut->value = lineIn->r;
227 }
228 
229 //------------------------------------------------------------------------------------
230 
231 template <typename Pix>
readRaster_copyLines(const TRasterPT<Pix> & ras,Tiio::Reader * reader,int x0,int y0,int x1,int y1,int inLx,int inLy,int shrink)232 void readRaster_copyLines(const TRasterPT<Pix> &ras, Tiio::Reader *reader,
233                           int x0, int y0, int x1, int y1, int inLx, int inLy,
234                           int shrink) {
235   typedef typename pixel_traits<Pix>::buffer_type buffer_type;
236   typedef typename pixel_traits<Pix>::rgbm_pixel_type rgbm_pixel_type;
237 
238   int linesToSkip = shrink - 1;
239 
240   buffer_type *lineBuffer =
241       (buffer_type *)malloc(inLx * sizeof(rgbm_pixel_type));
242   if (!lineBuffer) return;
243 
244   rgbm_pixel_type *lineIn = (rgbm_pixel_type *)lineBuffer;
245 
246   if (reader->getRowOrder() == Tiio::BOTTOM2TOP) {
247     int start = reader->skipLines(y0);
248     int stop  = y1 + 1;
249 
250     for (int y = start; y < stop; ++y) {
251       reader->readLine(lineBuffer, x0, x1, shrink);
252 
253       if (y >= y0 && y <= y1 && (y - y0) % shrink == 0) {
254         Pix *line = (Pix *)ras->getRawData(0, (y - y0) / shrink);
255         copyLine<Pix>(lineIn, line, x0, ras->getLx(), shrink);
256       }
257 
258       if (linesToSkip > 0 && y + linesToSkip < inLy)
259         y += reader->skipLines(linesToSkip);
260     }
261   } else  // TOP2BOTTOM
262   {
263     reader->skipLines(inLy - y1 - 1);
264 
265     for (int y = y1; y >= y0; --y) {
266       reader->readLine(lineBuffer, x0, x1, shrink);
267 
268       if ((y - y0) % shrink == 0) {
269         Pix *line = (Pix *)ras->getRawData(0, (y - y0) / shrink);
270         copyLine<Pix>(lineIn, line, x0, ras->getLx(), shrink);
271       }
272 
273       if (linesToSkip > 0 && y - linesToSkip > 0)
274         y -= reader->skipLines(linesToSkip);
275     }
276   }
277 
278   free(lineBuffer);
279 }
280 
281 //------------------------------------------------------------------------------------
282 
283 template <typename Pix>
readRaster(const TRasterPT<Pix> & ras,Tiio::Reader * reader,int x0,int y0,int x1,int y1,int inLx,int inLy,int shrink)284 void readRaster(const TRasterPT<Pix> &ras, Tiio::Reader *reader, int x0, int y0,
285                 int x1, int y1, int inLx, int inLy, int shrink) {
286   typedef typename pixel_traits<Pix>::buffer_type buffer_type;
287 
288   if (shrink == 1) {
289     // Direct read
290     ras->lock();
291 
292     ptrdiff_t linePad = -x0 * ras->getPixelSize();
293 
294     if (reader->getRowOrder() == Tiio::BOTTOM2TOP) {
295       int start = reader->skipLines(y0);
296       int stop  = y1 + 1;
297 
298       for (int y = start; y < stop; ++y)
299         if (y >= y0 && y <= y1) {
300           buffer_type *line =
301               (buffer_type *)(ras->getRawData(0, y - y0) + linePad);
302           reader->readLine(line, x0, x1, 1);
303         }
304     } else  // TOP2BOTTOM
305     {
306       reader->skipLines(inLy - y1 - 1);
307 
308       for (int y = y1; y >= y0; --y) {
309         buffer_type *line =
310             (buffer_type *)(ras->getRawData(0, y - y0) + linePad);
311         reader->readLine(line, x0, x1, 1);
312       }
313     }
314 
315     ras->unlock();
316   } else
317     readRaster_copyLines(ras, reader, x0, y0, x1, y1, inLx, inLy, shrink);
318 }
319 
320 //------------------------------------------------------------------------------------
321 
load0()322 TImageP TImageReader::load0() {
323   if (!m_reader && !m_vectorReader) open();
324 
325   if (m_reader) {
326     TImageInfo info = m_reader->getImageInfo();
327     if (info.m_lx <= 0 || info.m_ly <= 0) return TImageP();
328 
329     // Initialize raster info
330     assert(m_shrink > 0);
331 
332     // Build loading rect
333     int x0 = 0;
334     int x1 = info.m_lx - 1;
335     int y0 = 0;
336     int y1 = info.m_ly - 1;
337 
338     if (!m_region.isEmpty()) {
339       // Intersect with the externally specified loading region
340 
341       x0 = std::max(x0, m_region.x0);
342       y0 = std::max(y0, m_region.y0);
343       x1 = std::min(x1, m_region.x1);
344       y1 = std::min(y1, m_region.y1);
345 
346       if (x0 >= x1 || y0 >= y1) return TImageP();
347     }
348 
349     if (m_shrink > 1) {
350       // Crop to shrink multiples
351       x1 -= (x1 - x0) % m_shrink;
352       y1 -= (y1 - y0) % m_shrink;
353     }
354 
355     assert(x0 <= x1 && y0 <= y1);
356 
357     TDimension imageDimension =
358         TDimension((x1 - x0) / m_shrink + 1, (y1 - y0) / m_shrink + 1);
359 
360     if (m_path.getType() == "tzp" || m_path.getType() == "tzu") {
361       // Colormap case
362 
363       TRasterCM32P ras(imageDimension);
364       readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly, m_shrink);
365 
366       // Build the savebox
367       TRect saveBox(info.m_x0, info.m_y0, info.m_x1, info.m_y1);
368       if (!m_region.isEmpty()) {
369         // Intersect with the loading rect
370         if (m_region.overlaps(saveBox)) {
371           saveBox *= m_region;
372 
373           int sbx0 = saveBox.x0 - m_region.x0;
374           int sby0 = saveBox.y0 - m_region.y0;
375           int sbx1 = sbx0 + saveBox.getLx() - 1;
376           int sby1 = sby0 + saveBox.getLy() - 1;
377           assert(sbx0 >= 0);
378           assert(sby0 >= 0);
379           assert(sbx1 >= 0);
380           assert(sby1 >= 0);
381 
382           saveBox = TRect(sbx0, sby0, sbx1, sby1);
383         } else
384           saveBox = TRect(0, 0, 1, 1);
385       }
386 
387       if (m_shrink > 1) {
388         saveBox.x0 = saveBox.x0 / m_shrink;
389         saveBox.y0 = saveBox.y0 / m_shrink;
390         saveBox.x1 = saveBox.x1 / m_shrink;
391         saveBox.y1 = saveBox.y1 / m_shrink;
392       }
393 
394       TToonzImageP ti(ras, ras->getBounds() * saveBox);
395       ti->setDpi(info.m_dpix, info.m_dpiy);
396 
397       return ti;
398     } else if (info.m_bitsPerSample >= 8) {
399       // Common byte-based rasters (see below, we have black-and-white bit-based
400       // images too)
401 
402       if (info.m_samplePerPixel == 1 && m_readGreytones) {
403         //  Greymap case
404         // NOTE: Uses a full 32-bit raster first, and then copies down to the
405         // GR8
406 
407         // Observe that GR16 file images get immediately down-cast to GR8...
408         // Should we implement that too?
409 
410         TRasterGR8P ras(imageDimension);
411         readRaster_copyLines(ras, m_reader, x0, y0, x1, y1, info.m_lx,
412                              info.m_ly, m_shrink);
413 
414         TRasterImageP ri(ras);
415         ri->setDpi(info.m_dpix, info.m_dpiy);
416 
417         return ri;
418       }
419 
420       // assert(info.m_samplePerPixel == 3 || info.m_samplePerPixel == 4);
421 
422       TRasterP _ras;
423       if (info.m_bitsPerSample == 16) {
424         if (m_is64BitEnabled || m_path.getType() != "tif") {
425           //  Standard 64-bit case.
426 
427           // Also covers down-casting to 32-bit from a 64-bit image file
428           // whenever
429           // not a tif file (see below).
430 
431           TRaster64P ras(imageDimension);
432           readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly,
433                      m_shrink);
434 
435           _ras = ras;
436         } else {
437           // The Tif reader has got an automatically down-casting
438           // readLine(char*, ...)
439           // in case the input file is 64-bit. The advantage is that no
440           // intermediate
441           // 64-bit raster is required in this case.
442 
443           TRaster32P ras(imageDimension);
444           readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly,
445                      m_shrink);
446 
447           _ras = ras;
448         }
449       } else if (info.m_bitsPerSample == 8) {
450         //  Standard 32-bit case
451         TRaster32P ras(imageDimension);
452         readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly,
453                    m_shrink);
454 
455         _ras = ras;
456       } else
457         throw TImageException(m_path, "Image format not supported");
458 
459       // 64-bit to 32-bit conversions if necessary  (64 bit images not allowed)
460       if (!m_is64BitEnabled && (TRaster64P)_ras) {
461         TRaster32P raux(_ras->getLx(), _ras->getLy());
462         TRop::convert(raux, _ras);
463         _ras = raux;
464       }
465 
466       // Return the image
467       TRasterImageP ri(_ras);
468       ri->setDpi(info.m_dpix, info.m_dpiy);
469 
470       return ri;
471     } else if (info.m_samplePerPixel == 1 && info.m_valid == true) {
472       //  Previously dubbed as 'Palette cases'. No clue about what is this... :|
473 
474       TRaster32P ras(imageDimension);
475       readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly, m_shrink);
476 
477       TRasterImageP ri(ras);
478       ri->setDpi(info.m_dpix, info.m_dpiy);
479 
480       return ri;
481     } else if (info.m_samplePerPixel == 1 && m_readGreytones) {
482       //  Black-and-White case, I guess. Standard greymaps were considered
483       //  above...
484 
485       TRasterGR8P ras(imageDimension);
486       readRaster_copyLines(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly,
487                            m_shrink);
488 
489       TRasterImageP ri(ras);
490       ri->setDpi(info.m_dpix, info.m_dpiy);
491 
492       if (info.m_bitsPerSample == 1)  // I suspect this always evaluates true...
493         ri->setScanBWFlag(true);
494 
495       return ri;
496     } else
497       return TImageP();
498   } else if (m_vectorReader) {
499     TVectorImage *vi = m_vectorReader->read();
500     return TVectorImageP(vi);
501   } else
502     return TImageP();
503 }
504 
505 //-----------------------------------------------------------
506 
TImageWriter(const TFilePath & path)507 TImageWriter::TImageWriter(const TFilePath &path)
508     : TSmartObject(m_classCode)
509     , m_path(path)
510     , m_writer(0)
511     , m_vectorWriter(0)
512     , m_properties(0) {}
513 
514 //-----------------------------------------------------------
515 
~TImageWriter()516 TImageWriter::~TImageWriter() {
517   delete m_writer;
518   delete m_vectorWriter;
519   delete m_properties;
520 }
521 
522 //-----------------------------------------------------------
523 
setProperties(const TPropertyGroup * g)524 void TImageWriter::setProperties(const TPropertyGroup *g) {
525   if (m_properties) {
526     assert(m_properties != g);
527     delete m_properties;
528   }
529   m_properties = g ? g->clone() : 0;
530 }
531 
532 //-----------------------------------------------------------
533 
convertForWriting(TRasterP & ras,const TRasterP & rin,int bpp)534 static void convertForWriting(TRasterP &ras, const TRasterP &rin, int bpp) {
535   switch (bpp) {
536   case 1:
537   case 8:
538     ras = TRasterGR8P(rin->getSize());
539     TRop::convert(ras, rin);
540     break;
541   case 24:
542   case 32:
543     ras = TRaster32P(rin->getSize());
544     TRop::convert(ras, rin);
545     break;
546   case 48:
547   case 64:
548     ras = TRaster64P(rin->getSize());
549     TRop::convert(ras, rin);
550     break;
551   default:
552     assert(false);
553   }
554 }
555 
556 //-----------------------------------------------------------
557 
save(const TImageP & img)558 void TImageWriter::save(const TImageP &img) {
559   const std::string &type = toLower(m_path.getType());
560 
561   Tiio::Writer *writer = Tiio::makeWriter(type);
562   if (!writer)
563     throw TImageException(m_path, "unsupported format for raster images");
564 
565   writer->setProperties(m_properties);
566 
567   FILE *file = fopen(m_path, "wb");
568   if (file == NULL) throw TImageException(m_path, "Can't write file");
569 
570   if (TRasterImageP ri = img) {
571     TImageInfo info;
572     TRasterP ras;
573 
574     TRasterGR8P rasGr = ri->getRaster();
575     TRaster32P ras32  = ri->getRaster();
576     TRaster64P ras64  = ri->getRaster();
577 
578     TEnumProperty *p =
579         m_properties
580             ? (TEnumProperty *)m_properties->getProperty("Bits Per Pixel")
581             : 0;
582 
583     if (p && ri->isScanBW()) {
584       const std::vector<std::wstring> &range = p->getRange();
585       p->setValue(range[2]);  // Horrible. See tiio_tif.cpp (732 or near) -.-'
586     }
587 
588     int bpp = p ? std::stoi(p->getValue()) : 32;
589 
590     //  bpp       1  8  16 24 32 40  48 56  64
591     int spp[] = {
592         1, 1, 1, 4, 4,
593         0, 4, 0, 4};  // 0s are for pixel sizes which are normally unsupported
594     int bps[] = {
595         1, 8,  16, 8, 8,
596         0, 16, 0,  16};  // by image formats, let alone by Toonz raster ones.
597     // The 24 and 48 cases get automatically promoted to 32 and 64.
598     int bypp = bpp / 8;
599     assert(bypp < boost::size(spp) && spp[bypp] && bps[bypp]);
600 
601     info.m_samplePerPixel = spp[bypp];
602     info.m_bitsPerSample  = bps[bypp];
603 
604     if (rasGr) {
605       if (bypp < 2)   // Seems 16 bit greymaps are not handled... why?
606         ras = rasGr;  // we do have a Toonz raster for those...    >:|
607       else
608         convertForWriting(ras, rasGr, bpp);
609     } else if (ras32) {
610       if (bpp == 32 || bpp == 24)
611         ras = ras32;
612       else
613         convertForWriting(ras, ras32, bpp);
614     } else if (ras64) {
615       if (bpp == 64 || bpp == 48)
616         ras = ras64;
617       else
618         convertForWriting(ras, ras64, bpp);
619     } else {
620       fclose(file);
621       throw TImageException(m_path, "unsupported raster type");
622     }
623 
624     info.m_lx = ras->getLx();
625     info.m_ly = ras->getLy();
626 
627     ri->getDpi(info.m_dpix, info.m_dpiy);
628 
629     if (writer->getProperties() && m_properties)
630       writer->getProperties()->setProperties(m_properties);
631 
632     writer->open(file, info);
633 
634     // add background colors for non alpha-enabled image types
635     if ((ras32 || ras64) && !writer->writeAlphaSupported() &&
636         TImageWriter::getBackgroundColor() != TPixel::Black) {
637       if (bpp == 32 || bpp == 24)
638         TRop::addBackground(ras, TImageWriter::getBackgroundColor());
639       else if (bpp == 64 || bpp == 48) {
640         TRaster64P bgRas(ras->getSize());
641         bgRas->fill(toPixel64(TImageWriter::getBackgroundColor()));
642         TRop::over(bgRas, ras);
643         ras = bgRas;
644       }  // for other bpp values, do nothing for now
645     }
646 
647     ras->lock();
648 
649     if (writer->getRowOrder() == Tiio::BOTTOM2TOP) {
650       if (bpp == 1 || bpp == 8 || bpp == 24 || bpp == 32 || bpp == 16)
651         for (int i = 0; i < ras->getLy(); i++)
652           writer->writeLine((char *)ras->getRawData(0, i));
653       else
654         for (int i = 0; i < ras->getLy(); i++)
655           writer->writeLine((short *)ras->getRawData(0, i));
656     } else {
657       if (bpp == 1 || bpp == 8 || bpp == 24 || bpp == 32 || bpp == 16)
658         for (int i = ras->getLy() - 1; i >= 0; i--)
659           writer->writeLine((char *)ras->getRawData(0, i));
660       else
661         for (int i = ras->getLy() - 1; i >= 0; i--)
662           writer->writeLine((short *)ras->getRawData(0, i));
663     }
664 
665     ras->unlock();
666 
667     writer->flush();
668     delete writer;
669   } else if (TVectorImageP vi = img) {
670     Tiio::VectorWriter *writer = Tiio::makeVectorWriter(type);
671     if (!writer) {
672       fclose(file);
673       throw TImageException(m_path, "unsupported format for vector images");
674     }
675 
676     writer->open(file);
677     writer->write(vi.getPointer());
678 
679     delete writer;
680   } else {
681     fclose(file);
682     throw TImageException(m_path, "Can't write file");
683   }
684 
685   fclose(file);
686 }
687 
688 //-----------------------------------------------------------
689 
TImageWriterP(const TFilePath & path)690 TImageWriterP::TImageWriterP(const TFilePath &path) {
691   m_pointer = new TImageWriter(path);
692   m_pointer->addRef();
693 }
694 
695 //============================================================
696 //
697 // Helper functions statiche
698 //
699 //============================================================
700 
load(const TFilePath & path,TRasterP & raster)701 bool TImageReader::load(const TFilePath &path, TRasterP &raster) {
702   raster = TRasterP();
703   TImageReaderP ir(path);
704   if (!ir) return false;
705   TImageP img = ir->load();
706   if (!img) return false;
707 
708   TRasterImageP ri(img);
709   if (!ri) return false;
710 
711   raster = ri->getRaster();
712   return true;
713 }
714 
715 //-----------------------------------------------------------
716 
717 //-----------------------------------------------------------
718 
load(const TRasterP & ras,const TPoint & pos,int shrinkX,int shrinkY)719 void TImageReader::load(const TRasterP &ras, const TPoint &pos, int shrinkX,
720                         int shrinkY) {
721   TImageP srcImage          = load();
722   TRasterImageP srcRasImage = srcImage;
723   TRaster32P srcRaster      = srcRasImage->getRaster();
724   /*
725 TRaster32P clippedRas = srcRaster->extractT
726   (shrinkX*pos.x, shrinkY*pos.y,
727   (pos.x + ras->getLx()) * shrinkX - 1, (pos.y + ras->getLy()) * shrinkY - 1);
728 
729 if (shrinkX != 1 || shrinkY != 1)
730 {
731 TRaster32P ras32 = ras;
732 if (ras32)
733 ras32->fill(TPixel32::Transparent);
734 TRop::resample(ras, clippedRas, TScale(1./shrinkX, 1./shrinkY),
735 TRop::ClosestPixel);
736 }
737 else*/
738   ras->copy(srcRaster);
739 }
740 
741 //-----------------------------------------------------------
742 
load(const TFilePath & path,TImageP & image)743 bool TImageReader::load(const TFilePath &path, TImageP &image) {
744   image = TImageReaderP(path)->load();
745   return image;
746 }
747 
748 //-----------------------------------------------------------
749 
save(const TFilePath & path,TRasterP raster)750 void TImageWriter::save(const TFilePath &path, TRasterP raster) {
751   TRasterImageP rasImage(raster);
752   TImageWriterP(path)->save(TImageP(rasImage));
753 }
754 
755 //-----------------------------------------------------------
756 
save(const TFilePath & path,const TImageP & image)757 void TImageWriter::save(const TFilePath &path, const TImageP &image) {
758   TImageWriterP(path)->save(image);
759 }
760 
761 //===========================================================
762 // Background color for saving ransparent pixel to the format not
763 // supporting alpha channel. Specified in the preferences.
764 
765 TPixel32 TImageWriter::m_backgroundColor;
766 
setBackgroundColor(TPixel32 color)767 void TImageWriter::setBackgroundColor(TPixel32 color) {
768   m_backgroundColor = color;
769 }
770 
getBackgroundColor()771 TPixel32 TImageWriter::getBackgroundColor() { return m_backgroundColor; }
772 
773 //===========================================================
774 //
775 // funzioni per la registrazione dei formati (chiamate dal Plugin)
776 //
777 //===========================================================
778 
define(QString extension,TImageReaderCreateProc * proc)779 void TImageReader::define(QString extension, TImageReaderCreateProc *proc) {
780   ImageReaderTable[extension] = proc;
781 }
782 
783 //-----------------------------------------------------------
784 
define(QString extension,TImageWriterCreateProc * proc,bool isRenderFormat)785 void TImageWriter::define(QString extension, TImageWriterCreateProc *proc,
786                           bool isRenderFormat) {
787   ImageWriterTable[extension] =
788       std::pair<TImageWriterCreateProc *, bool>(proc, isRenderFormat);
789 }
790 
791 //-----------------------------------------------------------
792 
getSupportedFormats(QStringList & names)793 void TImageReader::getSupportedFormats(QStringList &names) {
794   for (std::map<QString, TImageReaderCreateProc *>::iterator it =
795            ImageReaderTable.begin();
796        it != ImageReaderTable.end(); ++it) {
797     names.push_back(it->first);
798   }
799 }
800 
801 //-----------------------------------------------------------
802 
getSupportedFormats(QStringList & names,bool onlyRenderFormat)803 void TImageWriter::getSupportedFormats(QStringList &names,
804                                        bool onlyRenderFormat) {
805   for (std::map<QString, std::pair<TImageWriterCreateProc *, bool>>::iterator
806            it = ImageWriterTable.begin();
807        it != ImageWriterTable.end(); ++it) {
808     if (!onlyRenderFormat || it->second.second) names.push_back(it->first);
809   }
810 }
811 
812 //-----------------------------------------------------------
813 
getImageInfo() const814 const TImageInfo *TImageReader::getImageInfo() const {
815   if (m_reader)
816     return &(m_reader->getImageInfo());
817   else
818     return 0;
819 }
820 
821 //-----------------------------------------------------------
822 
823 //===========================================================
824 //
825 // Eccezioni
826 //
827 //===========================================================
828 
TImageException(const TFilePath & fp,const std::string & msg)829 TImageException::TImageException(const TFilePath &fp, const std::string &msg)
830     : TException(msg), m_fp(fp) {}
831 
832 //-----------------------------------------------------------
833 
getMessage() const834 TString TImageException::getMessage() const {
835   return m_fp.getWideString() + L": " + TException::getMessage();
836 }
837 
838 //===========================================================
839 
TImageVersionException(const TFilePath & fp,int major,int minor)840 TImageVersionException::TImageVersionException(const TFilePath &fp, int major,
841                                                int minor)
842     : TException(L"The file " + fp.getWideString() +
843                  L" was generated by a newer version of OpenToonz and cannot "
844                  L"be loaded.")
845     , m_fp(fp)
846     , m_major(major)
847     , m_minor(minor) {}
848