1 
2 
3 // TnzCore includes
4 #include "tcommon.h"
5 
6 #include "timageinfo.h"
7 #include "timage_io.h"
8 #include "tlevel_io.h"
9 
10 #include "ttoonzimage.h"
11 #include "tvectorimage.h"
12 #include "trastercm.h"
13 #include "tvectorrenderdata.h"
14 #include "tpalette.h"
15 
16 #include "tgl.h"
17 #include "tvectorgl.h"
18 #include "tofflinegl.h"
19 
20 #include "timagecache.h"
21 
22 // TnzLib includes
23 #include "toonz/txshleveltypes.h"
24 #include "toonz/levelproperties.h"
25 #include "toonz/txshsimplelevel.h"
26 #include "toonz/fill.h"
27 
28 // Qt includes
29 #include <QImage>
30 #include <QThread>
31 #include <QOpenGLContext>
32 #include <QOffscreenSurface>
33 #include <QOpenGLFramebufferObject>
34 
35 #include "imagebuilders.h"
36 
37 //***************************************************************************************
38 //    Global stuff
39 //***************************************************************************************
40 
41 extern TOfflineGL *currentOfflineGL;
42 
43 //***************************************************************************************
44 //    ImageLoader  implementation
45 //***************************************************************************************
46 
ImageLoader(const TFilePath & path,const TFrameId & fid)47 ImageLoader::ImageLoader(const TFilePath &path, const TFrameId &fid)
48     : m_path(path), m_fid(fid), m_subsampling(0), m_64bitCompatible(false) {}
49 
50 //-------------------------------------------------------------------------
51 
getInfo(TImageInfo & info,int imFlags,void * extData)52 bool ImageLoader::getInfo(TImageInfo &info, int imFlags, void *extData) {
53   try {
54     TLevelReaderP lr(m_path);
55     TImageReaderP fr = lr->getFrameReader(m_fid);
56 
57     // NOTE: Currently not changing imageInfo's bpp stuff...
58     //       Ignoring subsampling too...
59 
60     return ImageBuilder::setImageInfo(info, fr.getPointer());
61   } catch (TException &e) {
62     QString msg = QString::fromStdWString(e.getMessage());
63     if (msg == QString("Old 4.1 Palette")) throw;
64 
65     return false;
66   }
67 }
68 
69 //-------------------------------------------------------------------------
70 
buildSubsampling(int imFlags,BuildExtData * data)71 inline int ImageLoader::buildSubsampling(int imFlags, BuildExtData *data) {
72   return (imFlags & ImageManager::toBeModified)
73              ? 1
74              : (data->m_subs > 0)
75                    ? data->m_subs
76                    : (m_subsampling > 0)
77                          ? m_subsampling
78                          : data->m_sl->getProperties()->getSubsampling();
79 }
80 
81 //-------------------------------------------------------------------------
82 
build(int imFlags,void * extData)83 TImageP ImageLoader::build(int imFlags, void *extData) {
84   assert(extData);
85 
86   // Extract external data
87   BuildExtData *data = static_cast<BuildExtData *>(extData);
88 
89   int subsampling = buildSubsampling(imFlags, data);
90 
91   try {
92     // Initialize level reader
93     TLevelReaderP lr(m_path);
94     if (!lr) return TImageP();
95 
96     // Load info in cases where it's required first
97     lr->doReadPalette(false);
98 
99     if ((m_path.getType() == "pli") || (m_path.getType() == "svg") ||
100         (m_path.getType() == "psd"))
101       lr->loadInfo();
102 
103     bool isTlvIcon = data->m_icon && m_path.getType() == "tlv";
104 
105     // for TLV icons, palettes will be applied in IconGenerator later
106     if (!isTlvIcon) lr->doReadPalette(true);  // Allow palette loading
107 
108     TImageReaderP ir = lr->getFrameReader(m_fid);
109 
110     bool enable64bit = (imFlags & ImageManager::is64bitEnabled);
111     ir->enable16BitRead(enable64bit);  // Set 64-bit loading if required
112 
113     // Load the image
114     TImageP img;
115 
116     if (isTlvIcon)
117       img = ir->loadIcon();  // TODO: Why just in the tlv case??
118     else {
119       ir->setShrink(subsampling);
120       img = ir->load();
121     }
122 
123     ir->enable16BitRead(false);
124 
125     if (!img) return img;  // There was an error loading the image.
126 
127     TPalette *palette = data->m_sl->getPalette();
128     if (palette) img->setPalette(palette);
129 
130     if (subsampling > 1) {
131       // Store the subsampling info in the image
132       if (TRasterImageP ri = img)
133         ri->setSubsampling(subsampling);
134       else if (TToonzImageP ti = img)
135         ti->setSubsampling(subsampling);
136     }
137 
138     // In case the image will be cached, store its subsampling and 64 bit
139     // compatibility
140     if (!(imFlags & ImageManager::dontPutInCache)) {
141       m_subsampling = subsampling;
142       m_64bitCompatible =
143           data->m_sl->is16BitChannelLevel() ? enable64bit : true;
144     }
145 
146     return img;
147   } catch (...) {
148     return TImageP();
149   }
150 }
151 
152 //-------------------------------------------------------------------------
153 
isImageCompatible(int imFlags,void * extData)154 bool ImageLoader::isImageCompatible(int imFlags, void *extData) {
155   assert(extData);
156 
157   BuildExtData *data        = static_cast<BuildExtData *>(extData);
158   const TXshSimpleLevel *sl = data->m_sl;
159 
160   // NOTE: Vector and Mesh dont care about sub sampling rate and bit depth
161   // compatibility.
162   //       They are property of Raster.
163   if (sl->getType() == PLI_XSHLEVEL || sl->getType() == MESH_XSHLEVEL)
164     return true;
165 
166   int subsampling = buildSubsampling(imFlags, data);
167 
168   if (m_subsampling <= 0 || subsampling != m_subsampling) return false;
169 
170   if (m_64bitCompatible || !(imFlags & ImageManager::is64bitEnabled)) {
171     return true;
172   } else {
173     return false;
174   }
175 }
176 
177 //-------------------------------------------------------------------------
178 
invalidate()179 void ImageLoader::invalidate() {
180   ImageBuilder::invalidate();
181   m_subsampling     = 0;
182   m_64bitCompatible = false;
183 }
184 
185 //-------------------------------------------------------------------------
186 /*--
187  * ImageBuilder仮想関数の実装。アイコン、画像をLoad時に全てキャッシュに格納する
188  * --*/
189 
buildAllIconsAndPutInCache(TXshSimpleLevel * level,std::vector<TFrameId> fids,std::vector<std::string> iconIds,bool cacheImagesAsWell)190 void ImageLoader::buildAllIconsAndPutInCache(TXshSimpleLevel *level,
191                                              std::vector<TFrameId> fids,
192                                              std::vector<std::string> iconIds,
193                                              bool cacheImagesAsWell) {
194   if (m_path.getType() != "tlv") return;
195   if (fids.empty() || iconIds.empty()) return;
196   /*- fidとアイコンidの数は同じはず -*/
197   if ((int)fids.size() != (int)iconIds.size()) return;
198 
199   try {
200     TLevelReaderP lr(m_path);
201     if (!lr) return;
202 
203     for (int i = 0; i < (int)fids.size(); i++) {
204       lr->doReadPalette(false);
205       TImageReaderP ir = lr->getFrameReader(fids[i]);
206       lr->doReadPalette(true);
207 
208       TImageInfo info;
209       TPalette *palette     = level->getPalette();
210       std::string fullImgId = level->getImageId(fids[i]);
211 
212       /*- 画像データも一緒にキャッシュする場合 -*/
213       if (cacheImagesAsWell) {
214         ir->enable16BitRead(m_64bitCompatible);
215         ir->setShrink(1);
216         TImageP fullImg = ir->load();
217         if (fullImg) {
218           if (palette) fullImg->setPalette(palette);
219           TImageCache::instance()->add(fullImgId, fullImg, true);
220           setImageInfo(info, fullImg.getPointer());
221         }
222       }
223 
224       /*- アイコンのロード -*/
225       TImageP img = ir->loadIcon();
226       ir->enable16BitRead(false);
227       if (img) {
228         if (palette) img->setPalette(palette);
229         TImageCache::instance()->add(iconIds[i], img, true);
230       }
231     }
232   } catch (...) {
233     return;
234   }
235 }
236 
setFid(const TFrameId & fid)237 void ImageLoader::setFid(const TFrameId &fid) { m_fid = fid; }
238 
239 //***************************************************************************************
240 //    ImageRasterizer  implementation
241 //***************************************************************************************
242 
getInfo(TImageInfo & info,int imFlags,void * extData)243 bool ImageRasterizer::getInfo(TImageInfo &info, int imFlags, void *extData) {
244   assert(false);  // None should get these... in case, TODO
245   return false;
246 }
247 
248 //-------------------------------------------------------------------------
249 
build(int imFlags,void * extData)250 TImageP ImageRasterizer::build(int imFlags, void *extData) {
251   assert(!(imFlags &
252            ~(ImageManager::dontPutInCache | ImageManager::forceRebuild)));
253 
254   TDimension d(10, 10);
255   TPoint off(0, 0);
256 
257   // Fetch image
258   assert(extData);
259   ImageLoader::BuildExtData *data = (ImageLoader::BuildExtData *)extData;
260 
261   const std::string &srcImgId = data->m_sl->getImageId(data->m_fid);
262 
263   TImageP img = ImageManager::instance()->getImage(srcImgId, imFlags, extData);
264   if (img) {
265     TVectorImageP vi = img;
266     if (vi) {
267       TRectD bbox = vi->getBBox();
268 
269       d   = TDimension(tceil(bbox.getLx()) + 1, tceil(bbox.getLy()) + 1);
270       off = TPoint((int)bbox.x0, (int)bbox.y0);
271 
272       TPalette *vpalette = vi->getPalette();
273       TVectorRenderData rd(TTranslation(-off.x, -off.y), TRect(TPoint(0, 0), d),
274                            vpalette, 0, true, true);
275 
276       // this is too slow.
277       {
278         QSurfaceFormat format;
279         format.setProfile(QSurfaceFormat::CompatibilityProfile);
280 
281         std::unique_ptr<QOffscreenSurface> surface(new QOffscreenSurface());
282         surface->setFormat(format);
283         surface->create();
284 
285         TRaster32P ras(d);
286 
287         glPushAttrib(GL_ALL_ATTRIB_BITS);
288         glMatrixMode(GL_MODELVIEW), glPushMatrix();
289         glMatrixMode(GL_PROJECTION), glPushMatrix();
290         {
291           std::unique_ptr<QOpenGLFramebufferObject> fb(
292               new QOpenGLFramebufferObject(d.lx, d.ly));
293 
294           fb->bind();
295 
296           glViewport(0, 0, d.lx, d.ly);
297           glClearColor(0, 0, 0, 0);
298           glClear(GL_COLOR_BUFFER_BIT);
299 
300           glMatrixMode(GL_PROJECTION);
301           glLoadIdentity();
302           gluOrtho2D(0, d.lx, 0, d.ly);
303 
304           glMatrixMode(GL_MODELVIEW);
305           glLoadIdentity();
306           glTranslatef(0.375, 0.375, 0.0);
307 
308           tglDraw(rd, vi.getPointer());
309 
310           glFlush();
311 
312           QImage img =
313               fb->toImage().scaled(QSize(d.lx, d.ly), Qt::IgnoreAspectRatio,
314                                    Qt::SmoothTransformation);
315 
316           int wrap      = ras->getLx() * sizeof(TPixel32);
317           uchar *srcPix = img.bits();
318           uchar *dstPix = ras->getRawData() + wrap * (d.ly - 1);
319           for (int y = 0; y < d.ly; y++) {
320             memcpy(dstPix, srcPix, wrap);
321             dstPix -= wrap;
322             srcPix += wrap;
323           }
324           fb->release();
325         }
326         glMatrixMode(GL_MODELVIEW), glPopMatrix();
327         glMatrixMode(GL_PROJECTION), glPopMatrix();
328 
329         glPopAttrib();
330 
331         TRasterImageP ri = TRasterImageP(ras);
332         ri->setOffset(off + ras->getCenter());
333 
334         assert(glGetError() == 0);
335 
336         return ri;
337       }
338     }
339   }
340 
341   // Error case: return a dummy image (is it really required?)
342 
343   TRaster32P ras(d);
344   ras->fill(TPixel32(127, 0, 127, 127));
345 
346   return TRasterImageP(ras);
347 }
348 
349 //***************************************************************************************
350 //    ImageFiller  implementation
351 //***************************************************************************************
352 
getInfo(TImageInfo & info,int imFlags,void * extData)353 bool ImageFiller::getInfo(TImageInfo &info, int imFlags, void *extData) {
354   assert(false);  // None should get these... in case, TODO
355   return false;
356 }
357 
358 //-------------------------------------------------------------------------
359 
build(int imFlags,void * extData)360 TImageP ImageFiller::build(int imFlags, void *extData) {
361   assert(imFlags == ImageManager::none);
362 
363   // Fetch image
364   assert(extData);
365 
366   ImageLoader::BuildExtData *data = (ImageLoader::BuildExtData *)extData;
367   assert(data->m_subs == 0);
368 
369   const std::string &srcImgId = data->m_sl->getImageId(data->m_fid);
370 
371   TImageP img = ImageManager::instance()->getImage(srcImgId, imFlags, extData);
372   if (img) {
373     TRasterImageP ri = img;
374     if (ri) {
375       TRaster32P ras = ri->getRaster();
376       if (ras) {
377         TRaster32P newRas = ras->clone();
378         FullColorAreaFiller filler(newRas);
379 
380         TPaletteP palette = new TPalette();
381         int styleId       = palette->getPage(0)->addStyle(TPixel32::White);
382 
383         FillParameters params;
384         params.m_palette      = palette.getPointer();
385         params.m_styleId      = styleId;
386         params.m_minFillDepth = 0;
387         params.m_maxFillDepth = 15;
388         filler.rectFill(newRas->getBounds(), params, false);
389 
390         TRasterImageP ri = TRasterImageP(newRas);
391         return ri;
392       }
393     }
394   }
395 
396   // Error case: return a dummy image (is it really required?)
397 
398   TRaster32P ras(10, 10);
399   ras->fill(TPixel32(127, 0, 127, 127));
400 
401   return TRasterImageP(ras);
402 }
403