1 /*
2  * Copyright (C) 2004-2009 Andrew Mihal
3  * Copyright (C) 2009-2016 Christoph Spiel
4  *
5  * This file is part of Enblend.
6  *
7  * Enblend is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * Enblend is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Enblend; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #ifndef __COMMON_H__
22 #define __COMMON_H__
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <algorithm>
29 #include <cassert>
30 #include <fstream>
31 #include <iomanip>
32 #include <limits>
33 #include <locale>
34 #include <map>
35 #include <stdexcept>
36 #include <string>
37 #include <vector>
38 
39 #include <vigra/numerictraits.hxx>
40 
41 #include "error_message.h"
42 #include "filenameparse.h"
43 
44 #define NUMERIC_OPTION_DELIMITERS ";:/"    //< numeric-option-delimiters ;:/
45 #define PATH_OPTION_DELIMITERS ",;:"       //< path-option-delimiters ,;:
46 #define ASSIGNMENT_CHARACTERS "="          //< assignment-characters =
47 
48 #define MASK_COMPRESSION "DEFLATE"
49 
50 // IMPLEMENTATION NOTE: For 30 or more pyramid levels, the full width
51 // will just barely fit in a 32-bit integer.  When this range is added
52 // to a bounding box it will certainly overflow the vigra::Diff2D.
53 #define MAX_PYRAMID_LEVELS 29   //< maximum-pyramid-levels 29
54 
55 // Colors used in the optimizer visualization
56 #define VISUALIZE_RGB_COLOR_BLUE1    vigra::RGBValue<vigra::UInt8>(  0,   0, 255)
57 #define VISUALIZE_RGB_COLOR_BLUE2    vigra::RGBValue<vigra::UInt8>(  0,   0, 238)
58 #define VISUALIZE_RGB_COLOR_BLUE3    vigra::RGBValue<vigra::UInt8>(  0,   0, 205)
59 #define VISUALIZE_RGB_COLOR_BLUE4    vigra::RGBValue<vigra::UInt8>(  0,   0, 139)
60 
61 #define VISUALIZE_RGB_COLOR_CYAN1    vigra::RGBValue<vigra::UInt8>(  0, 255, 255)
62 #define VISUALIZE_RGB_COLOR_CYAN2    vigra::RGBValue<vigra::UInt8>(  0, 238, 238)
63 #define VISUALIZE_RGB_COLOR_CYAN3    vigra::RGBValue<vigra::UInt8>(  0, 205, 205)
64 #define VISUALIZE_RGB_COLOR_CYAN4    vigra::RGBValue<vigra::UInt8>(  0, 139, 139)
65 
66 #define VISUALIZE_RGB_COLOR_GRAY0    vigra::RGBValue<vigra::UInt8>(  0,   0,   0)
67 #define VISUALIZE_RGB_COLOR_GRAY63   vigra::RGBValue<vigra::UInt8>( 63,  63,  63)
68 #define VISUALIZE_RGB_COLOR_GRAY127  vigra::RGBValue<vigra::UInt8>(127, 127, 127)
69 #define VISUALIZE_RGB_COLOR_GRAY139  vigra::RGBValue<vigra::UInt8>(139, 139, 139)
70 #define VISUALIZE_RGB_COLOR_GRAY191  vigra::RGBValue<vigra::UInt8>(191, 191, 191)
71 #define VISUALIZE_RGB_COLOR_GRAY205  vigra::RGBValue<vigra::UInt8>(205, 205, 205)
72 #define VISUALIZE_RGB_COLOR_GRAY238  vigra::RGBValue<vigra::UInt8>(238, 238, 238)
73 #define VISUALIZE_RGB_COLOR_GRAY255  vigra::RGBValue<vigra::UInt8>(255, 255, 255)
74 
75 #define VISUALIZE_RGB_COLOR_GREEN1   vigra::RGBValue<vigra::UInt8>(  0, 255,   0)
76 #define VISUALIZE_RGB_COLOR_GREEN2   vigra::RGBValue<vigra::UInt8>(  0, 238,   0)
77 #define VISUALIZE_RGB_COLOR_GREEN3   vigra::RGBValue<vigra::UInt8>(  0, 205,   0)
78 #define VISUALIZE_RGB_COLOR_GREEN4   vigra::RGBValue<vigra::UInt8>(  0, 139,   0)
79 
80 #define VISUALIZE_RGB_COLOR_MAGENTA1 vigra::RGBValue<vigra::UInt8>(255,   0, 255)
81 #define VISUALIZE_RGB_COLOR_MAGENTA2 vigra::RGBValue<vigra::UInt8>(238,   0, 238)
82 #define VISUALIZE_RGB_COLOR_MAGENTA3 vigra::RGBValue<vigra::UInt8>(205,   0, 205)
83 #define VISUALIZE_RGB_COLOR_MAGENTA4 vigra::RGBValue<vigra::UInt8>(139,   0, 139)
84 
85 #define VISUALIZE_RGB_COLOR_ORANGE1  vigra::RGBValue<vigra::UInt8>(255, 165,   0)
86 #define VISUALIZE_RGB_COLOR_ORANGE2  vigra::RGBValue<vigra::UInt8>(238, 154,   0)
87 #define VISUALIZE_RGB_COLOR_ORANGE3  vigra::RGBValue<vigra::UInt8>(205, 133,   0)
88 #define VISUALIZE_RGB_COLOR_ORANGE4  vigra::RGBValue<vigra::UInt8>(139,  90,   0)
89 
90 #define VISUALIZE_RGB_COLOR_RED1     vigra::RGBValue<vigra::UInt8>(255,   0,   0)
91 #define VISUALIZE_RGB_COLOR_RED2     vigra::RGBValue<vigra::UInt8>(238,   0,   0)
92 #define VISUALIZE_RGB_COLOR_RED3     vigra::RGBValue<vigra::UInt8>(205,   0,   0)
93 #define VISUALIZE_RGB_COLOR_RED4     vigra::RGBValue<vigra::UInt8>(139,   0,   0)
94 
95 #define VISUALIZE_RGB_COLOR_YELLOW1  vigra::RGBValue<vigra::UInt8>(255, 255,   0)
96 #define VISUALIZE_RGB_COLOR_YELLOW2  vigra::RGBValue<vigra::UInt8>(238, 238,   0)
97 #define VISUALIZE_RGB_COLOR_YELLOW3  vigra::RGBValue<vigra::UInt8>(205, 205,   0)
98 #define VISUALIZE_RGB_COLOR_YELLOW4  vigra::RGBValue<vigra::UInt8>(139, 139,   0)
99 
100 
101 // Different marker types offered by visualizePoint()
102 typedef enum
103 {
104     NO_MARKER,
105     DOT_MARKER,
106     PLUS_MARKER,
107     CROSS_MARKER,
108     HOLLOW_SQUARE_MARKER,
109     HOLLOW_DIAMOND_MARKER,
110 } marker_t;
111 
112 
113 //< visualize-movable-point light orange
114 #define VISUALIZE_MOVABLE_POINT VISUALIZE_RGB_COLOR_ORANGE1
115 //< mark-movable-point diamond
116 #define MARK_MOVABLE_POINT HOLLOW_DIAMOND_MARKER
117 //< visualize-frozen-point bright white
118 #define VISUALIZE_FROZEN_POINT VISUALIZE_RGB_COLOR_GRAY255
119 //< mark-frozen-point cross
120 #define MARK_FROZEN_POINT CROSS_MARKER
121 //< visualize-initial-path-color dark yellow
122 #define VISUALIZE_INITIAL_PATH       VISUALIZE_RGB_COLOR_YELLOW4
123 //< visualize-short-path-value-color bright yellow
124 #define VISUALIZE_SHORT_PATH_VALUE   VISUALIZE_RGB_COLOR_YELLOW1
125 //< visualize-first-vertex-value-color medium green
126 #define VISUALIZE_FIRST_VERTEX_VALUE VISUALIZE_RGB_COLOR_GREEN3
127 //< visualize-next-vertex-value-color light green
128 #define VISUALIZE_NEXT_VERTEX_VALUE  VISUALIZE_RGB_COLOR_GREEN2
129 //< visualize-no-overlap-value-color dark red
130 #define VISUALIZE_NO_OVERLAP_VALUE   VISUALIZE_RGB_COLOR_RED4
131 //< visualize-state-space-color dark blue
132 #define VISUALIZE_STATE_SPACE        VISUALIZE_RGB_COLOR_BLUE3
133 //< visualize-state-space-inside-color bright cyan
134 #define VISUALIZE_STATE_SPACE_INSIDE VISUALIZE_RGB_COLOR_CYAN1
135 //< visualize-state-space-unconverged-color bright magenta
136 #define VISUALIZE_STATE_SPACE_UNCONVERGED VISUALIZE_RGB_COLOR_MAGENTA1
137 
138 
139 // For CIELAB, CIELUV, and CIECAM blending, Enblend and Enfuse
140 // transform the input images from their respective RGB color spaces
141 // to XYZ space (and for CIECAM then on to JCh).  The following two
142 // #defines control the color transformation from and to XYZ space.
143 #define RENDERING_INTENT_FOR_BLENDING INTENT_PERCEPTUAL
144 #define TRANSFORMATION_FLAGS_FOR_BLENDING cmsFLAGS_NOCACHE
145 
146 
147 // Select our preferred type of image depending on what ./configure
148 // tells us.
149 #ifdef CACHE_IMAGES
150 #error "The ImageCache feature has been withdrawn.  Reconfigure without ImageCache and re-build."
151 #define IMAGETYPE vigra_ext::CachedFileImage
152 #else
153 #define IMAGETYPE vigra::BasicImage
154 #endif
155 
156 
157 #ifdef WIN32
158 #define sleep(m_duration) Sleep(m_duration)
159 #endif
160 
161 #if defined __MINGW32__ || defined __MINGW64__
162 #undef rand_r
163 #undef strtok_r
164 #endif
165 
166 #define PENALIZE_DEPRECATED_OPTION(m_old_name, m_new_name) \
167     do { \
168         std::cerr << command <<                                         \
169             ": info: option \"" m_old_name "\" is deprecated; use \"" m_new_name "\" instead" << \
170             std::endl;                                                  \
171         sleep(1); \
172     } while (false)
173 
174 
175 #define lengthof(m_array) (sizeof(m_array) / sizeof(m_array[0]))
176 
177 
178 // Replacement for `assert(0)' and `assert(false)'.
179 class never_reached : public std::runtime_error
180 {
181 public:
182     never_reached() = delete;
never_reached(const std::string & a_message)183     explicit never_reached(const std::string& a_message) : std::runtime_error(a_message) {}
~never_reached()184     virtual ~never_reached() noexcept {}
185 };
186 
187 #ifdef __GNUC__
188 #define NEVER_REACHED(m_message) \
189     do {__builtin_unreachable();  throw ::never_reached(m_message);} while (false)
190 #else
191 #define NEVER_REACHED(m_message) throw ::never_reached(m_message)
192 #endif
193 
194 
195 namespace enblend {
196 
197 /** The different image overlap classifications. */
198 enum Overlap {NoOverlap, PartialOverlap, CompleteOverlap};
199 
200 
201 /** Symbolic expressions for the three different metrics that
202  *  vigra::distanceTransform understands. */
203 typedef enum
204 {
205     ChessboardDistance,         // 0
206     ManhattanDistance,          // 1, L1 norm
207     EuclideanDistance           // 2, L2 norm
208 } nearest_neighbor_metric_t;
209 
210 
211 /** Define our own reentrant, uniform pseudo-random number generator. */
212 inline int
rand_r(unsigned int * seed)213 rand_r(unsigned int* seed)
214 {
215     *seed = *seed * 1103515245U + 12345U;
216     return static_cast<int>(*seed % (static_cast<unsigned int>(RAND_MAX) + 1U));
217 }
218 
219 
220 /** Answer the square of the argument x. */
221 template <typename t>
222 inline t
square(t x)223 square(t x)
224 {
225     return x * x;
226 }
227 
228 
229 /** Test whether s starts with p. */
230 inline static bool
starts_with(const std::string & s,const std::string & p)231 starts_with(const std::string& s, const std::string& p)
232 {
233     return s.substr(0U, p.length()) == p;
234 }
235 
236 
237 /** Answer the string representation of the boolean b. */
238 std::string
stringOfBool(bool b)239 stringOfBool(bool b)
240 {
241     return b ? "true" : "false";
242 }
243 
244 
245 /** Answer whether we can open aFilename. */
246 bool
can_open_file(const std::string & aFilename)247 can_open_file(const std::string& aFilename)
248 {
249     errno = 0;
250     std::ifstream file(aFilename.c_str());
251     if (!file)
252     {
253         std::cerr << command <<
254             ": failed to open \"" << aFilename << "\": " <<
255             errorMessage(errno) << "\n";
256         return false;
257     }
258     else
259     {
260         errno = 0;
261         file.close();
262         if (file.fail())
263         {
264             std::cerr << command <<
265                 ": info: problems when closing \"" << aFilename << "\": " <<
266                 errorMessage(errno) << "\n";
267         }
268         return true;
269     }
270 }
271 
272 
273 /** Answer the VIGRA file type as determined by the extension of
274  *  aFileName. */
275 std::string
getFileType(const std::string & aFileName)276 getFileType(const std::string& aFileName)
277 {
278     const std::string ext(to_upper_copy(aFileName.substr(aFileName.rfind(".") + 1U)));
279 
280     if (ext == "JPG") return "JPEG";
281     else if (ext == "TIF") return "TIFF";
282     else if (ext == "VIF") return "VIFF";
283     else if (ext == "PBM" || ext == "PGM" || ext == "PPM") return "PNM";
284     else return ext;
285 }
286 
287 
288 /** Convert aWraparoundMode given as string to the internal
289  *  representation as enum. */
290 boundary_t
wraparoundOfString(const char * aWraparoundMode)291 wraparoundOfString(const char* aWraparoundMode)
292 {
293     const std::string mode(to_upper_copy(std::string(aWraparoundMode)));
294 
295     if (mode == "NONE" || mode == "OPEN") return OpenBoundaries;
296     else if (mode == "HORIZONTAL") return HorizontalStrip;
297     else if (mode == "VERTICAL") return VerticalStrip;
298     else if (mode == "BOTH" ||
299              mode == "HORIZONTAL+VERTICAL" ||
300              mode == "VERTICAL+HORIZONTAL") return DoubleStrip;
301     else return UnknownWrapAround;
302 }
303 
304 
305 /** Convert aBoundaryMode to its string representation. */
306 std::string
stringOfWraparound(boundary_t aBoundaryMode)307 stringOfWraparound(boundary_t aBoundaryMode)
308 {
309     switch (aBoundaryMode)
310     {
311     case OpenBoundaries:
312         return "none";
313     case HorizontalStrip:
314         return "horizontal";
315     case VerticalStrip:
316         return "vertical";
317     case DoubleStrip:
318         return "both";
319     default:
320         NEVER_REACHED("switch control expression \"aBoundaryMode\" out of range");
321     }
322 }
323 
324 
325 /** Convert a_string into a number.
326  *
327  * Perform two validating tests in the numerical result.  These are,
328  * for example, tests for lower and upper boundaries. */
329 template <class NumericType, class Validator1, class Validator2>
330 NumericType
numberOfString(const char * a_string,Validator1 is_valid1,const std::string & invalid_message1,NumericType replacement_value1,Validator2 is_valid2,const std::string & invalid_message2,NumericType replacement_value2)331 numberOfString(const char* a_string,                // string we want to convert into a number
332                Validator1 is_valid1,                // 1st validator function
333                const std::string& invalid_message1, // error message for failed 1st validation
334                NumericType replacement_value1,      // replacement return value on 1st failure
335                Validator2 is_valid2,                // 2nd validator function
336                const std::string& invalid_message2, // error message for failed 2nd validation
337                NumericType replacement_value2)      // replacement return value on 2nd failure
338 {
339     typedef std::numeric_limits<NumericType> traits;
340 
341     char* tail;
342     long int long_int_value;
343     double double_value;
344     NumericType value;
345 
346     errno = 0;
347     if (traits::is_exact)
348     {
349         long_int_value = strtol(a_string, &tail, 10);
350     }
351     else
352     {
353         double_value = strtod(a_string, &tail);
354     }
355 
356     if (errno != 0)
357     {
358         std::cerr << command << ": "
359                   << "illegal numeric format of \""
360                   << a_string
361                   << "\": "
362                   << errorMessage(errno)
363                   << std::endl;
364         exit(1);
365     }
366 
367     if (*tail != 0)
368     {
369         if (strcmp(a_string, tail) == 0)
370         {
371             std::cerr << command << ": "
372                       << "number is garbage; maybe the option before \"" << a_string
373                       << "\" needs an argument"
374                       << std::endl;
375         }
376         else
377         {
378             std::cerr << command << ": "
379                       << "trailing garbage \"" << tail << "\" in \"" << a_string << "\""
380                       << std::endl;
381         }
382         exit(1);
383     }
384 
385     if (traits::is_exact)
386     {
387         if (traits::is_signed)
388         {
389             if (long_int_value < traits::min() || long_int_value > traits::max())
390             {
391                 std::cerr << command << ": "
392                           << "signed number x = " << long_int_value
393                           << " out of range " << traits::min() << " <= x <= " << traits::max()
394                           << std::endl;
395                 exit(1);
396             }
397             else
398             {
399                 value = static_cast<NumericType>(long_int_value);
400             }
401         }
402         else
403         {
404             if (long_int_value < 0L || long_int_value > traits::max())
405             {
406                 std::cerr << command << ": "
407                           << "unsigned number x = " << long_int_value
408                           << " out of range 0 <= x <= " << traits::max()
409                           << std::endl;
410                 exit(1);
411             }
412             else
413             {
414                 value = static_cast<NumericType>(long_int_value);
415             }
416         }
417     }
418     else
419     {
420         value = static_cast<NumericType>(double_value);
421     }
422 
423     if (is_valid1(value))
424     {
425         if (is_valid2(value))
426         {
427             return value;
428         }
429         else
430         {
431             std::cerr << command << ": warning: " << invalid_message2 << std::endl;
432             return replacement_value2;
433         }
434     }
435     else
436     {
437         std::cerr << command << ": warning: " << invalid_message1 << std::endl;
438         return replacement_value1;
439     }
440 }
441 
442 
443 template <class NumericType, class Validator1, class Validator2>
444 NumericType
numberOfString(const std::string & a_string,Validator1 is_valid1,const std::string & invalid_message1,NumericType replacement_value1,Validator2 is_valid2,const std::string & invalid_message2,NumericType replacement_value2)445 numberOfString(const std::string& a_string,         // string we want to convert into a number
446                Validator1 is_valid1,                // 1st validator function
447                const std::string& invalid_message1, // error message for failed 1st validation
448                NumericType replacement_value1,      // replacement return value on 1st failure
449                Validator2 is_valid2,                // 2nd validator function
450                const std::string& invalid_message2, // error message for failed 2nd validation
451                NumericType replacement_value2)      // replacement return value on 2nd failure
452 {
453     numberOfString(&a_string[0],
454                    is_valid1,
455                    invalid_message1, replacement_value1,
456                    is_valid2, invalid_message2, replacement_value2);
457 }
458 
459 
460 /**  Convert a_string into a number.
461  */
462 template <class NumericType, class Validator>
463 NumericType
numberOfString(const char * a_string,Validator is_valid,const std::string & invalid_message,NumericType replacement_value)464 numberOfString(const char* a_string,               // string we want to convert into a number
465                Validator is_valid,                 // validator function
466                const std::string& invalid_message, // error message for failed validation
467                NumericType replacement_value)      // replacement return value on failure
468 {
469     return numberOfString(a_string,
470                           is_valid, invalid_message, replacement_value,
471                           [](NumericType) {return true;},
472                           "<never reached>", NumericType());
473 }
474 
475 
476 template <class NumericType, class Validator>
477 NumericType
numberOfString(const std::string & a_string,Validator is_valid,const std::string & invalid_message,NumericType replacement_value)478 numberOfString(const std::string& a_string,        // string we want to convert into a number
479                Validator is_valid,                 // validator function
480                const std::string& invalid_message, // error message for failed validation
481                NumericType replacement_value)      // replacement return value on failure
482 {
483     return numberOfString(&a_string[0], is_valid, invalid_message, replacement_value);
484 }
485 
486 
487 inline bool
isFloatingPoint(const std::string & aPixelType)488 isFloatingPoint(const std::string& aPixelType)
489 {
490     return  aPixelType == "FLOAT" || aPixelType == "DOUBLE";
491 }
492 
493 
494 /** Convert an anOutputDepth to a "pixel type" string understood by
495  * VIGRA. */
496 std::string
outputPixelTypeOfString(const char * anOutputDepth)497 outputPixelTypeOfString(const char* anOutputDepth)
498 {
499     typedef std::map<std::string, std::string> Str2StrMapType;
500 
501     Str2StrMapType depthMap = {
502         {"INT16", "INT16"},
503         {"INT32", "INT32"},
504 
505         {"8", "UINT8"},
506         {"16", "UINT16"},
507         {"32", "UINT32"},
508         {"UINT8", "UINT8"},
509         {"UINT16", "UINT16"},
510         {"UINT32", "UINT32"},
511 
512         {"DOUBLE", "DOUBLE"},
513         {"FLOAT", "FLOAT"},
514         {"R32", "FLOAT"},
515         {"R64", "DOUBLE"},
516         {"REAL32", "FLOAT"},
517         {"REAL64", "DOUBLE"}
518     };
519 
520     const std::string output_depth(to_upper_copy(std::string(anOutputDepth)));
521     Str2StrMapType::const_iterator p = depthMap.find(output_depth);
522     if (p == depthMap.end())
523     {
524         throw std::invalid_argument(std::string("unknown output depth \"") + anOutputDepth + "\"");
525     }
526     else
527     {
528         return p->second;
529     }
530 }
531 
532 
533 /** Answer the best pixel type of an image given aFileType with
534  * respect to aPixelType.  This is the type with the largest range. */
535 std::string
bestPixelType(const std::string & aFileType,const std::string & aPixelType)536 bestPixelType(const std::string& aFileType, const std::string& aPixelType)
537 {
538     if (aFileType == "BMP" || aFileType == "JPEG" || aFileType == "RAS")
539     {
540         return "UINT8";
541     }
542     else if (aFileType == "PNG" &&
543              (aPixelType == "INT32" || aPixelType == "UINT32" ||
544               aPixelType == "FLOAT" || aPixelType == "DOUBLE"))
545     {
546         return "UINT16";
547     }
548     else if (aFileType == "EXR")
549     {
550         return "FLOAT";
551     }
552     else
553     {
554         return aPixelType;
555     }
556 }
557 
558 
559 typedef std::pair<double, double> range_t;
560 
561 
562 /** Answer the maximum range of values aPixelType can represent. */
563 range_t
rangeOfPixelType(const std::string & aPixelType)564 rangeOfPixelType(const std::string& aPixelType)
565 {
566     typedef std::map<std::string, range_t> Str2PairMapType;
567 
568     Str2PairMapType rangeMap = {
569         {"INT8", std::make_pair(vigra::NumericTraits<vigra::Int8>::min(),
570                                 vigra::NumericTraits<vigra::Int8>::max())},
571         {"INT16", std::make_pair(vigra::NumericTraits<vigra::Int16>::min(),
572                                  vigra::NumericTraits<vigra::Int16>::max())},
573         {"INT32", std::make_pair(vigra::NumericTraits<vigra::Int32>::min(),
574                                  vigra::NumericTraits<vigra::Int32>::max())},
575 
576         {"UINT8", std::make_pair(0.0, vigra::NumericTraits<vigra::UInt8>::max())},
577         {"UINT16", std::make_pair(0.0, vigra::NumericTraits<vigra::UInt16>::max())},
578         {"UINT32", std::make_pair(0.0, vigra::NumericTraits<vigra::UInt32>::max())},
579 
580         {"FLOAT", std::make_pair(0.0, 1.0)},
581         {"DOUBLE", std::make_pair(0.0, 1.0)}
582     };
583 
584     assert(!aPixelType.empty());
585     Str2PairMapType::const_iterator r = rangeMap.find(aPixelType);
586     if (r == rangeMap.end())
587     {
588         throw std::invalid_argument(std::string("unknown pixel type \"") + aPixelType + "\"");
589     }
590     else
591     {
592         return r->second;
593     }
594 }
595 
596 
597 /** Answer whether aPixelType defines a range that is so larges that
598  *  it includes both aRange and anotherRange. */
599 bool
includesBothRanges(const std::string & aPixelType,const range_t & aRange,const range_t & anotherRange)600 includesBothRanges(const std::string& aPixelType,
601                    const range_t& aRange,
602                    const range_t& anotherRange)
603 {
604     const range_t range = rangeOfPixelType(aPixelType);
605 
606     return (aRange.first >= range.first && aRange.second <= range.second &&
607             anotherRange.first >= range.first && anotherRange.second <= range.second);
608 }
609 
610 
611 /** Answer the smallest pixel type that is larger or equal to both
612  *  aPixelType and anotherPixelType. */
613 std::string
maxPixelType(const std::string & aPixelType,const std::string & anotherPixelType)614 maxPixelType(const std::string& aPixelType, const std::string& anotherPixelType)
615 {
616     const range_t range1 = rangeOfPixelType(aPixelType);
617     const range_t range2 = rangeOfPixelType(anotherPixelType);
618 
619     if (aPixelType == "DOUBLE" || anotherPixelType == "DOUBLE") {
620         return "DOUBLE";
621     } else if (aPixelType == "FLOAT" || anotherPixelType == "FLOAT") {
622         return "FLOAT";
623     } else if (range1.first <= range2.first && range1.second >= range2.second) {
624         return aPixelType;      // first includes second
625     } else if (range2.first <= range1.first && range2.second >= range1.second) {
626         return anotherPixelType; // second includes first
627     } else {
628         // Types are different: look for the smallest containing type
629         typedef std::vector<std::string> string_array;
630         typedef string_array::const_iterator string_array_ci;
631 
632         if (range1.first < 0 || range2.first < 0) {
633             const string_array types = {"INT8", "INT16", "INT32"};
634             for (string_array_ci i = types.begin(); i != types.end(); ++i) {
635                 if (includesBothRanges(*i, range1, range2)) {
636                     return *i;
637                 }
638             }
639             return "INT32";
640         } else {
641             const string_array types = {"UINT8", "UINT16", "UINT32"};
642             for (string_array_ci i = types.begin(); i != types.end(); ++i) {
643                 if (includesBothRanges(*i, range1, range2)) {
644                     return *i;
645                 }
646             }
647             return "UINT32";
648         }
649     }
650 }
651 
652 
653 /** Answer the sign of x.
654  */
655 
656 template <typename T>
657 inline int
sign(T x)658 sign(T x)
659 {
660     return x > T() ? 1 : (x < T() ? -1 : 0);
661 }
662 
663 
664 /** Compute the integral logarithm of n to the base 10.  We do not
665  *  need to take special care of the case n == 0 for our purposes. */
666 inline unsigned
ilog10(unsigned n)667 ilog10(unsigned n)
668 {
669     return n <= 9 ? 0 : 1 + ilog10(n / 10);
670 }
671 
672 
673 /** Expand aTemplate filling the variable parts with anInputFilename,
674  *  anOutputFilename, and aNumber depending on the conversion
675  *  specifiers in aTemplate.
676  *
677  *  Conversion Specifiers - lowercase characters refer to
678  *  anInputFilename whereas uppercase ones refer to anOutputFilename:
679  *      %%        A single '%'-sign
680  *      %i        aNumber unaltered
681  *      %n        successor of aNumber
682  *      %p        aFilename unaltered
683  *      %d        directory part of aFilename
684  *      %b        non-directory part (aka basename) of aFilename
685  *      %f        basename of aFilename without extension
686  *      %e        extension of aFilename (including the leading dot)
687  *  All other characters in aTemplate are passed through literally.
688  *
689  *  The "%i" and "%n" conversions honor a flag which is either
690  *      '0'       pad with zeros (default) or
691  *      PUNCT     i.e. any punctuation character to pad with
692  *  and a width specification.  If no width is requested, the
693  *  width is computed based on aNumberOfImages.
694  *
695  *  For example
696  *          expandFilenameTemplate("mask-%04n.tif", 2, "foobar.jpg", 9)
697  *  evaluates to
698  *          mask-0009.tif
699  */
700 std::string
expandFilenameTemplate(const std::string & aTemplate,unsigned aNumberOfImages,const std::string & anInputFilename,const std::string & anOutputFilename,unsigned aNumber)701 expandFilenameTemplate(const std::string& aTemplate,
702                        unsigned aNumberOfImages,
703                        const std::string& anInputFilename,
704                        const std::string& anOutputFilename,
705                        unsigned aNumber)
706 {
707     std::string result;
708 
709     for (std::string::const_iterator c = aTemplate.begin();
710          c != aTemplate.end();
711          ++c)
712     {
713         if (*c == '%')
714         {
715             ++c;
716             if (c == aTemplate.end())
717             {
718                 result.push_back(*c);
719             }
720             else
721             {
722                 char pad = 0;
723                 while (c != aTemplate.end() && (*c == '0' || ispunct(*c)))
724                 {
725                     pad = *c;
726                     ++c;
727                 }
728 
729                 std::string width;
730                 while (c != aTemplate.end() && isdigit(*c))
731                 {
732                     width.push_back(*c);
733                     ++c;
734                 }
735 
736                 if (c != aTemplate.end())
737                 {
738                     switch (*c)
739                     {
740                     case '%':
741                         result.push_back(*c);
742                         break;
743                     case 'n':
744                         ++aNumber;
745                         ++aNumberOfImages;
746                         BOOST_FALLTHROUGH;
747                     case 'i':
748                     {
749                         std::ostringstream oss;
750                         oss <<
751                             std::setw(width.empty() ? 1U + ilog10(aNumberOfImages - 1U) : atoi(width.c_str())) <<
752                             std::setfill(pad == 0 ? '0' : pad) <<
753                             aNumber;
754                         result.append(oss.str());
755                         break;
756                     }
757                     case 'P':
758                         result.append(anOutputFilename);
759                         break;
760                     case 'p':
761                         result.append(anInputFilename);
762                         break;
763                     case 'D':
764                         result.append(extractDirname(anOutputFilename));
765                         break;
766                     case 'd':
767                         result.append(extractDirname(anInputFilename));
768                         break;
769                     case 'B':
770                         result.append(extractBasename(anOutputFilename));
771                         break;
772                     case 'b':
773                         result.append(extractBasename(anInputFilename));
774                         break;
775                     case 'F':
776                         result.append(extractFilename(anOutputFilename));
777                         break;
778                     case 'f':
779                         result.append(extractFilename(anInputFilename));
780                         break;
781                     case 'E':
782                         result.append(extractExtension(anOutputFilename));
783                         break;
784                     case 'e':
785                         result.append(extractExtension(anInputFilename));
786                         break;
787                     default:
788                         std::cerr <<
789                             command <<
790                             ": warning: ignoring unknown variable character ";
791                         if (isprint(*c))
792                         {
793                             std::cerr << "'" << *c << "'";
794                         }
795                         else
796                         {
797                             std::cerr << "0x" << std::hex << *c;
798                         }
799                         std::cerr << " in\n"
800                                   << command
801                                   << ": warning: filename template \""
802                                   << aTemplate
803                                   << "\""
804                                   << std::endl;
805                     } // switch (*c)
806                 }
807             }
808         }
809         else
810         {
811             result.push_back(*c);
812         }
813     }
814 
815     return result;
816 }
817 
818 
819 /** Answer a phrase that describes a layer in an image consisting of
820  *  multiple layers.  If the image has got only one layer, we avoid to
821  *  confuse the user and answer an empty string. */
822 inline std::string
optional_layer_name(unsigned layer_number,unsigned layer_total)823 optional_layer_name(unsigned layer_number, unsigned layer_total)
824 {
825     if (layer_total <= 1U)
826     {
827         return std::string();
828     }
829     else
830     {
831         std::ostringstream oss;
832         oss << ", layer " << layer_number << "/" << layer_total;
833         return oss.str();
834     }
835 }
836 
837 
838 template <class predicate>
839 inline static void
trim_if(std::string & a_string,predicate a_predicate)840 trim_if(std::string& a_string, predicate a_predicate)
841 {
842     auto negated_predicate =
843         std::bind(std::logical_not<bool>(), std::bind(a_predicate, std::placeholders::_1));
844     std::string::iterator begin = std::find_if(a_string.begin(), a_string.end(), negated_predicate);
845 
846     if (begin == a_string.end())
847     {
848         a_string.clear();
849     }
850     else
851     {
852         std::string::reverse_iterator reverse_end =
853             std::find_if(a_string.rbegin(), a_string.rend(), negated_predicate);
854 
855         a_string.assign(begin, reverse_end.base());
856     }
857 }
858 
859 
860 inline std::string
profileInfo(cmsHPROFILE profile,cmsInfoType info)861 profileInfo(cmsHPROFILE profile, cmsInfoType info)
862 {
863     const size_t size = cmsGetProfileInfoASCII(profile, info, cmsNoLanguage, cmsNoCountry, nullptr, 0);
864     std::string information(size, '\000');
865     cmsGetProfileInfoASCII(profile, info, cmsNoLanguage, cmsNoCountry, &information[0], size);
866     trim_if(information, std::bind(std::less_equal<char>(), std::placeholders::_1, '\040'));
867 
868     return information;
869 }
870 
871 
872 inline std::string
profileDescription(cmsHPROFILE profile)873 profileDescription(cmsHPROFILE profile)
874 {
875     return profileInfo(profile, cmsInfoDescription);
876 }
877 
878 
879 inline std::string
profileName(cmsHPROFILE profile)880 profileName(cmsHPROFILE profile)
881 {
882     return profileInfo(profile, cmsInfoModel);
883 }
884 
885 
886 inline unsigned
profileChannels(cmsHPROFILE profile)887 profileChannels(cmsHPROFILE profile)
888 {
889     const cmsColorSpaceSignature signature = cmsGetColorSpace(profile);
890     const unsigned number_of_channels = cmsChannelsOf(signature);
891     assert(number_of_channels == 1U || number_of_channels == 3U);
892     return number_of_channels;
893 }
894 } // namespace enblend
895 
896 
897 #ifndef HAVE_STRTOK_R
898 char*
strtok_r(char * str,const char * delim,char ** save_ptr)899 strtok_r(char* str, const char* delim, char** save_ptr)
900 {
901     char *s = str ? str : *save_ptr;
902 
903     if (s)
904     {
905         while (*s != 0 && strchr(delim, (int) *s))
906         {
907             s++;
908         }
909 
910         if (*s)
911         {
912             char *token = s;
913 
914             while (*s != 0 && !strchr(delim, (int) *s))
915             {
916                 s++;
917             }
918             if (*s)
919             {
920                 *s = 0;
921                 s++;
922             }
923             *save_ptr = s;
924 
925             return token;
926         }
927         else
928         {
929             return nullptr;
930         }
931     }
932     else
933     {
934         return nullptr;
935     }
936 }
937 #endif
938 
939 #endif /* __COMMON_H__ */
940 
941 // Local Variables:
942 // mode: c++
943 // End:
944