OpenImageIO
 All Classes Files Friends Macros Pages
oiiotool.h
1 /*
2  Copyright 2011 Larry Gritz and the other authors and contributors.
3  All Rights Reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8  * Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright
11  notice, this list of conditions and the following disclaimer in the
12  documentation and/or other materials provided with the distribution.
13  * Neither the name of the software's owners nor the names of its
14  contributors may be used to endorse or promote products derived from
15  this software without specific prior written permission.
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28  (This is the Modified BSD License)
29 */
30 
31 
32 #ifndef OIIOTOOL_H
33 
34 #include "imagebuf.h"
35 #include "refcnt.h"
36 #include "timer.h"
37 
38 
39 OIIO_NAMESPACE_ENTER {
40 namespace OiioTool {
41 
42 typedef int (*CallbackFunction)(int argc,const char*argv[]);
43 
44 class ImageRec;
45 typedef shared_ptr<ImageRec> ImageRecRef;
46 
47 
48 
49 class Oiiotool {
50 public:
51  // General options
52  bool verbose;
53  bool runstats;
54  bool noclobber;
55  bool allsubimages;
56  bool printinfo;
57  bool printstats;
58  bool hash;
59  bool updatemode;
60  int threads;
61  std::string full_command_line;
62  std::string printinfo_metamatch;
63  std::string printinfo_nometamatch;
64 
65  // Output options
66  TypeDesc output_dataformat;
67  std::map<std::string,std::string> output_channelformats;
68  int output_bitspersample;
69  bool output_scanline;
70  int output_tilewidth, output_tileheight;
71  std::string output_compression;
72  int output_quality;
73  std::string output_planarconfig;
74  bool output_adjust_time;
75  bool output_autocrop;
76  bool output_autotrim;
77 
78  // Options for --diff
79  float diff_warnthresh;
80  float diff_warnpercent;
81  float diff_hardwarn;
82  float diff_failthresh;
83  float diff_failpercent;
84  float diff_hardfail;
85 
86  // Internal state
87  ImageRecRef curimg; // current image
88  std::vector<ImageRecRef> image_stack; // stack of previous images
89  ImageCache *imagecache; // back ptr to ImageCache
90  int return_value; // oiiotool command return code
91  ColorConfig colorconfig; // OCIO color config
92  Timer total_readtime;
93  Timer total_writetime;
94  double total_imagecache_readtime;
95  typedef std::map<std::string, double> TimingMap;
96  TimingMap function_times;
97  bool enable_function_timing;
98 
99  Oiiotool ();
100 
101  void clear_options ();
102 
103  // Force img to be read at this point.
104  void read (ImageRecRef img);
105  // Read the current image
106  void read () { if (curimg) read (curimg); }
107 
108  // If required_images are not yet on the stack, then postpone this
109  // call by putting it on the 'pending' list and return true.
110  // Otherwise (if enough images are on the stack), return false.
111  bool postpone_callback (int required_images, CallbackFunction func,
112  int argc, const char *argv[]);
113 
114  // Process any pending commands.
115  void process_pending ();
116 
117  CallbackFunction pending_callback () const { return m_pending_callback; }
118  const char *pending_callback_name () const { return m_pending_argv[0]; }
119 
120  void push (const ImageRecRef &img) {
121  if (img) {
122  if (curimg)
123  image_stack.push_back (curimg);
124  curimg = img;
125  }
126  }
127 
128  void push (ImageRec *newir) { push (ImageRecRef(newir)); }
129 
130  ImageRecRef pop () {
131  ImageRecRef r = curimg;
132  if (image_stack.size()) {
133  // There are images on the full stack -- pop it
134  curimg = image_stack.back ();
135  image_stack.resize (image_stack.size()-1);
136  } else {
137  // Nothing on the stack, so get rid of the current image
138  curimg = ImageRecRef();
139  }
140  return r;
141  }
142 
143  ImageRecRef top () { return curimg; }
144 
145  void error (const std::string &command, const std::string &explanation="");
146 
147 private:
148  CallbackFunction m_pending_callback;
149  int m_pending_argc;
150  const char *m_pending_argv[4];
151 };
152 
153 
154 typedef shared_ptr<ImageBuf> ImageBufRef;
155 
156 
157 class SubimageRec {
158 public:
159  int miplevels() const { return (int) m_miplevels.size(); }
160  ImageBuf * operator() () {
161  return miplevels() ? m_miplevels[0].get() : NULL;
162  }
163  ImageBuf * operator[] (int i) {
164  return i < miplevels() ? m_miplevels[i].get() : NULL;
165  }
166  const ImageBuf * operator[] (int i) const {
167  return i < miplevels() ? m_miplevels[i].get() : NULL;
168  }
169  ImageSpec * spec (int i) {
170  return i < miplevels() ? &m_specs[i] : NULL;
171  }
172  const ImageSpec * spec (int i) const {
173  return i < miplevels() ? &m_specs[i] : NULL;
174  }
175 private:
176  std::vector<ImageBufRef> m_miplevels;
177  std::vector<ImageSpec> m_specs;
178  friend class ImageRec;
179 };
180 
181 
182 
183 class ImageRec {
184 public:
185  ImageRec (const std::string &name, ImageCache *imagecache)
186  : m_name(name), m_elaborated(false),
187  m_metadata_modified(false), m_pixels_modified(false),
188  m_imagecache(imagecache)
189  { }
190 
191  // Initialize an ImageRec with a collection of prepared ImageSpec's.
192  // The number of subimages is nsubimages, the number of MIP levels
193  // for each subimages is in miplevels[0..nsubimages-1] (if miplevels
194  // is NULL, allocate just one MIP level per subimage), and specs[]
195  // contains the specs for all the MIP levels of subimage 0, followed
196  // by all the specs for the MIP levels of subimage 1, and so on.
197  // If spec == NULL, the IB's will not be fully allocated/initialized.
198  ImageRec (const std::string &name, int nsubimages = 1,
199  const int *miplevels = NULL, const ImageSpec *specs=NULL);
200 
201  // Copy an existing ImageRec. Copy just the single subimage_to_copy
202  // if >= 0, or all subimages if <0. Copy just the single
203  // miplevel_to_copy if >= 0, or all MIP levels if <0. If writable
204  // is true, we expect to need to alter the pixels of the resulting
205  // ImageRec. If copy_pixels is false, just make the new image big
206  // enough, no need to initialize the pixel values.
207  ImageRec (ImageRec &img, int subimage_to_copy = -1,
208  int miplevel_to_copy = -1, bool writable = true,
209  bool copy_pixels = true);
210 
211  // Create an ImageRef that consists of the ImageBuf img. Copy img
212  // if copy_pixels==true, otherwise just take ownership of img (it's
213  // a shared pointer).
214  ImageRec (ImageBufRef img, bool copy_pixels = true);
215 
216  // Initialize an ImageRec with the given spec.
217  ImageRec (const std::string &name, const ImageSpec &spec,
218  ImageCache *imagecache);
219 
220  enum WinMerge { WinMergeUnion, WinMergeIntersection, WinMergeA, WinMergeB };
221 
222  // Initialize a new ImageRec based on two exemplars. Initialize
223  // just the single subimage_to_copy if >= 0, or all subimages if <0.
224  // The two WinMerge parameters pixwin and fullwin, dictate the
225  // policy for setting up the pixel data and full (display) windows,
226  // respectively. If pixeltype not UNKNOWN, use that rather than
227  // A's pixel type (the default behavior).
228  ImageRec (ImageRec &imgA, ImageRec &imgB, int subimage_to_copy = -1,
229  WinMerge pixwin = WinMergeUnion,
230  WinMerge fullwin = WinMergeUnion,
231  TypeDesc pixeltype = TypeDesc::UNKNOWN);
232 
233  // Number of subimages
234  int subimages() const { return (int) m_subimages.size(); }
235 
236  // Number of MIP levels of the given subimage
237  int miplevels (int subimage=0) const {
238  if (subimage >= subimages())
239  return 0;
240  return m_subimages[subimage].miplevels();
241  }
242 
243  // Subimage reference accessors.
244  SubimageRec& subimage (int i) {
245  return m_subimages[i];
246  }
247  const SubimageRec& subimage (int i) const {
248  return m_subimages[i];
249  }
250 
251  // Accessing it like an array returns a specific subimage
252  SubimageRec& operator[] (int i) {
253  return m_subimages[i];
254  }
255  const SubimageRec& operator[] (int i) const {
256  return m_subimages[i];
257  }
258 
259  std::string name () const { return m_name; }
260 
261  // Has the ImageRec been actually read or evaluated? (Until needed,
262  // it's lazily kept as name only, without reading the file.)
263  bool elaborated () const { return m_elaborated; }
264 
265  bool read ();
266 
267  // ir(subimg,mip) references a specific MIP level of a subimage
268  // ir(subimg) references the first MIP level of a subimage
269  // ir() references the first MIP level of the first subimage
270  ImageBuf& operator() (int subimg=0, int mip=0) {
271  return *m_subimages[subimg][mip];
272  }
273  const ImageBuf& operator() (int subimg=0, int mip=0) const {
274  return *m_subimages[subimg][mip];
275  }
276 
277  ImageSpec * spec (int subimg=0, int mip=0) {
278  return subimg < subimages() ? m_subimages[subimg].spec(mip) : NULL;
279  }
280  const ImageSpec * spec (int subimg=0, int mip=0) const {
281  return subimg < subimages() ? m_subimages[subimg].spec(mip) : NULL;
282  }
283 
284  bool metadata_modified () const { return m_metadata_modified; }
285  void metadata_modified (bool mod) { m_metadata_modified = mod; }
286  bool pixels_modified () const { return m_pixels_modified; }
287  void pixels_modified (bool mod) { m_pixels_modified = mod; }
288 
289  std::time_t time() const { return m_time; }
290 
291  // This should be called if for some reason the underlying
292  // ImageBuf's spec may have been modified in place. We need to
293  // update the outer copy held by the SubimageRec.
294  void update_spec_from_imagebuf (int subimg=0, int mip=0) {
295  *m_subimages[subimg].spec(mip) = m_subimages[subimg][mip]->spec();
296  metadata_modified();
297  }
298 
299 private:
300  std::string m_name;
301  bool m_elaborated;
302  bool m_metadata_modified;
303  bool m_pixels_modified;
304  std::vector<SubimageRec> m_subimages;
305  std::time_t m_time; //< Modification time of the input file
306  ImageCache *m_imagecache;
307 };
308 
309 
310 
311 
312 struct print_info_options {
313  bool verbose;
314  bool filenameprefix;
315  bool sum;
316  bool subimages;
317  bool compute_sha1;
318  bool compute_stats;
319  std::string metamatch;
320  std::string nometamatch;
321  size_t namefieldlength;
322 
323  print_info_options ()
324  : verbose(false), filenameprefix(false), sum(false), subimages(false),
325  compute_sha1(false), compute_stats(false), namefieldlength(20)
326  {}
327 };
328 
329 
330 // Print info about the named file to stdout, using print_info_options
331 // opt for guidance on what to print and how to do it. The total size
332 // of the uncompressed pixels in the file is returned in totalsize. The
333 // return value will be true if everything is ok, or false if there is
334 // an error (in which case the error message will be stored in 'error').
335 bool print_info (const std::string &filename,
336  const print_info_options &opt,
337  long long &totalsize, std::string &error);
338 
339 
340 // Modify the resolution and/or offset according to what's in geom.
341 // Valid geometries are WxH (resolution), +X+Y (offsets), WxH+X+Y
342 // (resolution and offset). If 'allow_scaling' is true, geometries of
343 // S% (e.g. "50%") or just S (e.g., "1.2") will be accepted to scale the
344 // existing width and height (rounding to the nearest whole number of
345 // pixels.
346 bool adjust_geometry (int &w, int &h, int &x, int &y, const char *geom,
347  bool allow_scaling=false);
348 
349 // Set an attribute of the given image. The type should be one of
350 // TypeDesc::INT (decode the value as an int), FLOAT, STRING, or UNKNOWN
351 // (look at the string and try to discern whether it's an int, float, or
352 // string). If the 'value' string is empty, it will delete the
353 // attribute.
354 bool set_attribute (ImageRecRef img, const std::string &attribname,
355  TypeDesc type, const std::string &value);
356 
357 inline bool same_size (const ImageBuf &A, const ImageBuf &B)
358 {
359  const ImageSpec &a (A.spec()), &b (B.spec());
360  return (a.width == b.width && a.height == b.height &&
361  a.depth == b.depth && a.nchannels == b.nchannels);
362 }
363 
364 
365 enum DiffErrors {
366  DiffErrOK = 0,
367  DiffErrWarn,
368  DiffErrFail,
369  DiffErrDifferentSize,
370  DiffErrFile,
371  DiffErrLast
372 };
373 
374 int do_action_diff (ImageRec &ir0, ImageRec &ir1, Oiiotool &options);
375 
376 
377 
378 // Helper template -- perform the action on each spec in the ImageRec.
379 // The action needs a signature like:
380 // bool action(ImageSpec &spec, const T& t))
381 template<class Action, class Type>
382 bool apply_spec_mod (ImageRec &img, Action act, const Type &t,
383  bool allsubimages)
384 {
385  bool ok = true;
386  img.read ();
387  img.metadata_modified (true);
388  for (int s = 0, send = img.subimages(); s < send; ++s) {
389  for (int m = 0, mend = img.miplevels(s); m < mend; ++m) {
390  ok &= act (*img.spec(s,m), t);
391  if (! allsubimages)
392  break;
393  }
394  if (! allsubimages)
395  break;
396  }
397  return ok;
398 }
399 
400 
401 } // OiioTool namespace
402 } OIIO_NAMESPACE_EXIT;
403 
404 
405 #endif // OIIOTOOL_H