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