1 
2 
3 #include "toonz/cleanupparameters.h"
4 #include "tstream.h"
5 #include "texception.h"
6 #include "toonz/toonzscene.h"
7 #include "toonz/sceneproperties.h"
8 #include "toonz/txshleveltypes.h"
9 #include "tsystem.h"
10 #include "tenv.h"
11 #include "tconvert.h"
12 #include "cleanuppalette.h"
13 #include "tpalette.h"
14 
15 #ifdef _MSC_VER
16 #pragma warning(disable : 4996)
17 #endif
18 
19 using namespace CleanupTypes;
20 
21 #define FDG_VERSION_FILE "VERSION_1.0"
22 
23 CleanupParameters CleanupParameters::GlobalParameters;
24 CleanupParameters CleanupParameters::LastSavedParameters;
25 //=========================================================
26 
27 namespace {
28 
29 //=========================================================
30 
31 class FdgManager {  // singleton
32 
33   std::map<std::string, FDG_INFO> m_infos;
34 
35   void loadFieldGuideInfo();
FdgManager()36   FdgManager() { loadFieldGuideInfo(); }
37 
38 public:
instance()39   static FdgManager *instance() {
40     static FdgManager _instance;
41     return &_instance;
42   }
43 
getFdg(std::string name) const44   const FDG_INFO *getFdg(std::string name) const {
45     std::map<std::string, FDG_INFO>::const_iterator it;
46     it = m_infos.find(name);
47     if (it == m_infos.end())
48       return 0;
49     else
50       return &it->second;
51   }
52 
getFdgNames(std::vector<std::string> & names) const53   void getFdgNames(std::vector<std::string> &names) const {
54     std::map<std::string, FDG_INFO>::const_iterator it;
55     for (it = m_infos.begin(); it != m_infos.end(); ++it)
56       names.push_back(it->first);
57   }
58 };
59 
60 //---------------------------------------------------------
61 
62 #define REMOVE_CR(s)                                                           \
63   {                                                                            \
64     while (*(s) && *(s) != '\n' && *(s) != '\r') (s)++;                        \
65     *(s) = '\0';                                                               \
66   }
67 
68 #define SKIP_BLANKS(s)                                                         \
69   {                                                                            \
70     while (*(s) && (*(s) == ' ' || *(s) == '\t')) (s)++;                       \
71   }
72 
73 #define STR_EQ(s1, s2) (!strcmp((s1), (s2)))
74 
75 //---------------------------------------------------------
76 
loadFieldGuideInfo()77 void FdgManager::loadFieldGuideInfo() {
78   FILE *fp;
79   char *s, buffer[256], label[100], arg[100];
80   int i, version = 0, cnt;
81 
82   try {
83     TFilePathSet fps =
84         TSystem::readDirectory(TEnv::getConfigDir() + "fdg", false);
85     for (TFilePathSet::iterator it = fps.begin(); it != fps.end(); ++it) {
86       TFilePath fname = *it;
87       if (fname.getType() != "fdg") continue;
88       fp = fopen(::to_string(fname.getWideString()).c_str(), "r");
89       if (!fp) continue;
90       FDG_INFO fdg_info;
91 
92       // memset(&fdg_info,0, sizeof(FDG_INFO));
93 
94       fdg_info.dots.resize(3);
95 
96       cnt = 0;
97       while (fgets(buffer, 256, fp)) {
98         s = buffer;
99         if (*s == '#' || *s == '*') continue;
100         REMOVE_CR(s)
101         s = buffer;
102         SKIP_BLANKS(s)
103         if (!*s) continue;
104         for (i = 0; *s && *s != ' ' && *s != '\t'; i++, s++) label[i] = *s;
105         label[i] = '\0';
106         SKIP_BLANKS(s)
107         for (i = 0; *s && *s != ' ' && *s != '\t'; i++, s++) arg[i] = *s;
108         arg[i] = '\0';
109 
110         /* suppongo ci siano sempre 3 dots */
111 
112         if (STR_EQ(label, FDG_VERSION_FILE))
113           version = 1;
114         else if (STR_EQ(label, "CTRX"))
115           sscanf(arg, "%lf", &fdg_info.ctr_x), fdg_info.ctr_type = 1;
116         else if (STR_EQ(label, "CTRY"))
117           sscanf(arg, "%lf", &fdg_info.ctr_y), fdg_info.ctr_type = 1;
118         else if (STR_EQ(label, "ANGLE"))
119           sscanf(arg, "%lf", &fdg_info.ctr_angle), fdg_info.ctr_type = 1;
120         else if (STR_EQ(label, "SKEW"))
121           sscanf(arg, "%lf", &fdg_info.ctr_skew), fdg_info.ctr_type = 1;
122         else if (STR_EQ(label, "HOLE")) {
123           sscanf(arg, "%d", &cnt);
124           if (cnt >= (int)fdg_info.dots.size()) {
125             fdg_info.dots.push_back(CleanupTypes::DOT());
126           }
127         } else if (STR_EQ(label, "X0"))
128           sscanf(arg, "%d", &fdg_info.dots[cnt].x1);
129         else if (STR_EQ(label, "Y0"))
130           sscanf(arg, "%d", &fdg_info.dots[cnt].y1);
131         else if (STR_EQ(label, "X1"))
132           sscanf(arg, "%d", &fdg_info.dots[cnt].x2);
133         else if (STR_EQ(label, "Y1"))
134           sscanf(arg, "%d", &fdg_info.dots[cnt].y2);
135         else if (STR_EQ(label, "X"))
136           sscanf(arg, "%f", &fdg_info.dots[cnt].x);
137         else if (STR_EQ(label, "Y"))
138           sscanf(arg, "%f", &fdg_info.dots[cnt].y);
139         else if (STR_EQ(label, "XSIZE"))
140           sscanf(arg, "%d", &fdg_info.dots[cnt].lx);
141         else if (STR_EQ(label, "YSIZE"))
142           sscanf(arg, "%d", &fdg_info.dots[cnt].ly);
143         else if (STR_EQ(label, "AREA"))
144           sscanf(arg, "%d", &fdg_info.dots[cnt].area);
145         else if (STR_EQ(label, "END")) {
146         } else if (STR_EQ(label, "DIST_CTR_TO_CTR_HOLE"))
147           sscanf(arg, "%lf", &fdg_info.dist_ctr_to_ctr_hole);
148         else if (STR_EQ(label, "DIST_CTR_HOLE_TO_EDGE"))
149           sscanf(arg, "%lf", &fdg_info.dist_ctr_hole_to_edge);
150       }
151 
152       fclose(fp);
153       if (!fdg_info.ctr_type && version != 1) {
154         // tmsg_error("load field guide info: bad file or old version");
155         // return FALSE;
156       } else {
157         fdg_info.m_name          = fname.getName();
158         m_infos[fdg_info.m_name] = fdg_info;
159       }
160     }
161   } catch (...) {
162   }
163   // return TRUE;
164 }
165 
166 }  // namespace
167 
168 //=========================================================
169 
CleanupParameters()170 CleanupParameters::CleanupParameters()
171     : m_autocenterType(AUTOCENTER_NONE)
172     , m_pegSide(PEGS_BOTTOM)
173     , m_fdgInfo()
174     , m_rotate(0)
175     , m_flipx(false)
176     , m_flipy(false)
177     , m_offx(0)
178     , m_offy(0)
179     //, m_scale(1)
180     , m_lineProcessingMode(lpGrey)
181     , m_noAntialias(false)
182     , m_postAntialias(false)
183     , m_despeckling(2)
184     , m_aaValue(70)
185     , m_closestField(999.)
186     , m_sharpness(90.)
187     , m_autoAdjustMode(AUTO_ADJ_NONE)
188     , m_transparencyCheckEnabled(false)
189     , m_colors()
190     , m_path()
191     , m_cleanupPalette(createStandardCleanupPalette())
192     , m_camera()
193     , m_dirtyFlag(false)
194     //, m_resName("")
195     , m_offx_lock(false)
196     , m_offy_lock(false) {}
197 
198 //---------------------------------------------------------
199 
setFdgByName(std::string name)200 bool CleanupParameters::setFdgByName(std::string name) {
201   const FDG_INFO *info = FdgManager::instance()->getFdg(name);
202   if (info) {
203     m_fdgInfo = *info;
204     return true;
205   } else {
206     m_fdgInfo = FDG_INFO();
207     return false;
208   }
209 }
210 
211 //---------------------------------------------------------
212 
getFdgNames(std::vector<std::string> & names)213 void CleanupParameters::getFdgNames(std::vector<std::string> &names) {
214   FdgManager::instance()->getFdgNames(names);
215 }
216 
217 //---------------------------------------------------------
218 
getPath(ToonzScene * scene) const219 TFilePath CleanupParameters::getPath(ToonzScene *scene) const {
220   if (m_path == TFilePath()) {
221     int levelType =
222         (m_lineProcessingMode != lpNone) ? TZP_XSHLEVEL : OVL_XSHLEVEL;
223     TFilePath fp = scene->getDefaultLevelPath(levelType);
224     return fp.getParentDir();
225   } else
226     return scene->decodeSavePath(m_path);
227 }
228 
229 //---------------------------------------------------------
230 
setPath(ToonzScene * scene,TFilePath fp)231 void CleanupParameters::setPath(ToonzScene *scene, TFilePath fp) {
232   if (fp == scene->getDefaultLevelPath(TZP_XSHLEVEL).getParentDir())
233     m_path = TFilePath();
234   else
235     m_path = scene->codeSavePath(fp);
236 }
237 
238 //------------------------------------------------------------------------------
239 
getOutputImageInfo(TDimension & outDim,double & outDpiX,double & outDpiY) const240 void CleanupParameters::getOutputImageInfo(TDimension &outDim, double &outDpiX,
241                                            double &outDpiY) const {
242   double lq_nozoom, lp_nozoom;
243   double zoom_factor;
244 
245   // Retrieve camera infos
246   const TDimensionD &cameraSize = m_camera.getSize();
247   const TDimension &cameraRes   = m_camera.getRes();
248 
249   // Camera resolution
250   lp_nozoom = cameraRes.lx;
251   lq_nozoom = cameraRes.ly;
252 
253   // Zoom factor due to the 'closest field' parameter
254   if (m_closestField < cameraSize.lx)
255     zoom_factor = cameraSize.lx / m_closestField;
256   else
257     zoom_factor = 1.0;
258 
259   // Output image resolution (considering the closest field)
260   // apart from any rotation (eg m_parameters.m_rotate == 90 or 270)
261   outDim.lx = troundp(zoom_factor * lp_nozoom);
262   outDim.ly = troundp(zoom_factor * lq_nozoom);
263 
264   // output image dpi
265   outDpiX = zoom_factor * cameraRes.lx / cameraSize.lx;
266   outDpiY = zoom_factor * cameraRes.ly / cameraSize.ly;
267 }
268 
269 //------------------------------------------------------------------------------------
270 
assign(const CleanupParameters * param,bool clonePalette)271 void CleanupParameters::assign(const CleanupParameters *param,
272                                bool clonePalette) {
273   // m_resName        = param->m_resName;
274   m_camera         = param->m_camera;
275   m_autocenterType = param->m_autocenterType;
276   m_pegSide        = param->m_pegSide;
277   m_fdgInfo        = param->m_fdgInfo;
278   m_rotate         = param->m_rotate;
279   m_flipx          = param->m_flipx;
280   m_flipy          = param->m_flipy;
281   // m_scale          = param->m_scale;
282   m_offx                     = param->m_offx;
283   m_offy                     = param->m_offy;
284   m_closestField             = param->m_closestField;
285   m_autoAdjustMode           = param->m_autoAdjustMode;
286   m_sharpness                = param->m_sharpness;
287   m_path                     = param->m_path;
288   m_colors                   = param->m_colors;
289   m_dirtyFlag                = param->m_dirtyFlag;
290   m_transparencyCheckEnabled = param->m_transparencyCheckEnabled;
291   m_lineProcessingMode       = param->m_lineProcessingMode;
292   m_noAntialias              = param->m_noAntialias;
293   m_postAntialias            = param->m_postAntialias;
294   m_despeckling              = param->m_despeckling;
295   m_aaValue                  = param->m_aaValue;
296 
297   // In modern Toonz scenes, there always is a cleanup palette.
298   // In older Toonz scenes, it may be missing. In this case, leave the current
299   // one.
300   if (clonePalette && param->m_cleanupPalette)
301     m_cleanupPalette = param->m_cleanupPalette->clone();
302 
303   m_offx_lock = param->m_offx_lock;
304   m_offy_lock = param->m_offy_lock;
305 }
306 
307 //---------------------------------------------------------
308 
saveData(TOStream & os) const309 void CleanupParameters::saveData(TOStream &os) const {
310   CleanupParameters::LastSavedParameters.assign(this);
311 
312   os.openChild("cleanupCamera");
313   m_camera.saveData(os);
314   os.closeChild();
315 
316   os.openChild("cleanupPalette");
317   m_cleanupPalette->saveData(os);
318   os.closeChild();
319 
320   std::map<std::string, std::string> attr;
321   if (m_autocenterType != AUTOCENTER_NONE) {
322     attr.clear();
323     attr["type"]     = std::to_string(m_autocenterType);
324     attr["pegHoles"] = std::to_string(m_pegSide);
325     os.openCloseChild("autoCenter", attr);
326   }
327 
328   if (m_flipx || m_flipy || m_rotate != 0  //|| m_scale!=1
329       || m_offx != 0 || m_offy != 0) {
330     attr.clear();
331     std::string flip =
332         std::string(m_flipx ? "x" : "") + std::string(m_flipy ? "y" : "");
333     if (flip != "") attr["flip"]      = flip;
334     if (m_rotate != 0) attr["rotate"] = std::to_string(m_rotate);
335     if (m_offx != 0.0) attr["xoff"]   = std::to_string(m_offx);
336     if (m_offy != 0.0) attr["yoff"]   = std::to_string(m_offy);
337     os.openCloseChild("transform", attr);
338   }
339 
340   if (m_lineProcessingMode != lpNone) {
341     attr.clear();
342     attr["sharpness"]  = std::to_string(m_sharpness);
343     attr["autoAdjust"] = std::to_string(m_autoAdjustMode);
344     attr["mode"]       = (m_lineProcessingMode == lpGrey ? "grey" : "color");
345     os.openCloseChild("lineProcessing", attr);
346   }
347   if (m_noAntialias) {
348     attr.clear();
349     os.openCloseChild("noAntialias", attr);
350   }
351   if (m_postAntialias) {
352     attr.clear();
353     os.openCloseChild("MLAA", attr);
354   }
355   attr.clear();
356   attr["value"] = std::to_string(m_despeckling);
357   os.openCloseChild("despeckling", attr);
358   attr.clear();
359   attr["value"] = std::to_string(m_aaValue);
360   os.openCloseChild("aaValue", attr);
361   attr.clear();
362   attr["value"] = std::to_string(m_closestField);
363   os.openCloseChild("closestField", attr);
364   attr.clear();
365   attr["name"] = m_fdgInfo.m_name;
366   os.openCloseChild("fdg", attr);
367   attr.clear();
368   if (m_path != TFilePath()) os.child("path") << m_path;
369 }
370 
371 //---------------------------------------------------------
372 
loadData(TIStream & is,bool globalParams)373 void CleanupParameters::loadData(TIStream &is, bool globalParams) {
374   if (globalParams) {
375     CleanupParameters cp;
376     assign(&cp);
377   }
378 
379   std::string tagName;
380   m_lineProcessingMode = lpNone;
381   m_noAntialias        = false;
382   m_postAntialias      = false;
383 
384   while (is.matchTag(tagName)) {
385     if (tagName == "cleanupPalette") {
386       m_cleanupPalette->loadData(is);
387       m_cleanupPalette->setIsCleanupPalette(true);
388       is.closeChild();
389     } else if (tagName == "cleanupCamera") {
390       m_camera.loadData(is);
391       is.closeChild();
392     } else if (tagName == "autoCenter") {
393       m_autocenterType                          = AUTOCENTER_FDG;
394       std::string s                             = is.getTagAttribute("type");
395       if (s != "" && isInt(s)) m_autocenterType = (AUTOCENTER_TYPE)std::stoi(s);
396       s                                  = is.getTagAttribute("pegHoles");
397       if (s != "" && isInt(s)) m_pegSide = (PEGS_SIDE)std::stoi(s);
398     } else if (tagName == "transform") {
399       std::string s                      = is.getTagAttribute("flip");
400       m_flipx                            = (s.find("x") != std::string::npos);
401       m_flipy                            = (s.find("y") != std::string::npos);
402       s                                  = is.getTagAttribute("rotate");
403       if (s != "" && isInt(s)) m_rotate  = std::stoi(s);
404       s                                  = is.getTagAttribute("xoff");
405       if (s != "" && isDouble(s)) m_offx = std::stod(s);
406       s                                  = is.getTagAttribute("yoff");
407       if (s != "" && isDouble(s)) m_offy = std::stod(s);
408     } else if (tagName == "lineProcessing") {
409       m_lineProcessingMode                    = lpGrey;
410       std::string s                           = is.getTagAttribute("sharpness");
411       if (s != "" && isDouble(s)) m_sharpness = std::stod(s);
412       s = is.getTagAttribute("autoAdjust");
413       if (s != "" && isDouble(s))
414         m_autoAdjustMode = (CleanupTypes::AUTO_ADJ_MODE)std::stoi(s);
415       s                  = is.getTagAttribute("mode");
416       if (s != "" && s == "color") m_lineProcessingMode = lpColor;
417     } else if (tagName == "despeckling") {
418       std::string s                          = is.getTagAttribute("value");
419       if (s != "" && isInt(s)) m_despeckling = std::stoi(s);
420     } else if (tagName == "aaValue") {
421       std::string s                      = is.getTagAttribute("value");
422       if (s != "" && isInt(s)) m_aaValue = std::stoi(s);
423     } else if (tagName == "noAntialias")
424       m_noAntialias = true;
425     else if (tagName == "MLAA")
426       m_postAntialias = true;
427     else if (tagName == "closestField") {
428       std::string s                              = is.getTagAttribute("value");
429       if (s != "" && isDouble(s)) m_closestField = std::stod(s);
430     } else if (tagName == "fdg") {
431       std::string s = is.getTagAttribute("name");
432       if (s != "") setFdgByName(s);
433     } else if (tagName == "path") {
434       is >> m_path;
435       is.closeChild();
436     } else
437       is.skipCurrentTag();
438   }
439 
440   CleanupParameters::LastSavedParameters.assign(this);
441   if (globalParams) CleanupParameters::GlobalParameters.assign(this);
442 }
443 
444 //---------------------------------------------------------
445 
getFdgInfo()446 const CleanupTypes::FDG_INFO &CleanupParameters::getFdgInfo() {
447   if (m_fdgInfo.m_name == "") {
448     std::vector<std::string> names;
449     FdgManager::instance()->getFdgNames(names);
450     if (names.size() > 1) {
451       const CleanupTypes::FDG_INFO *info =
452           FdgManager::instance()->getFdg(names[0]);
453       if (info) m_fdgInfo = *info;
454     }
455   }
456   return m_fdgInfo;
457 }
458