Skip to content

Commit 5b8bc22

Browse files
authored
Refactor of metadata printing and Exif read/write (#1774)
"Maker notes" are extra camera manufacturer-specific metadata stored as opaque blobs inside Exif records. The manufacturers don't seem to publish the specs for these blobs, but they have been reverse engineered and with some hunting you can find tinkerer-prouced documentation (at a range of levels of completeness or correctness). With this patch, we do a substantial refactor of exif.cpp (and a bit of work in formatspec, rawinput, and other places) to incorporate full awareness of maker notes into our metadata processing. At this stage, we only read Canon makernotes, and quite incompletely. But we get a lot more of the metadata than we used to (previously we just ignored any makernotes we found), and the structure is now sound for adding more complete support for this and other cameras. This will be an ongoing project to support more cameras, but the foundation is now set for this work.
1 parent a346101 commit 5b8bc22

File tree

26 files changed

+2647
-870
lines changed

26 files changed

+2647
-870
lines changed

src/include/OpenImageIO/imageio.h

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,55 +1454,6 @@ OIIO_API bool copy_image (int nchannels, int width, int height, int depth,
14541454
void *dst, stride_t dst_xstride,
14551455
stride_t dst_ystride, stride_t dst_zstride);
14561456

1457-
/// Decode a raw Exif data block and save all the metadata in an
1458-
/// ImageSpec. Return true if all is ok, false if the exif block was
1459-
/// somehow malformed. The binary data pointed to by 'exif' should
1460-
/// start with a TIFF directory header.
1461-
OIIO_API bool decode_exif (string_view exif, ImageSpec &spec);
1462-
OIIO_API bool decode_exif (const void *exif, int length, ImageSpec &spec); // DEPRECATED (1.8)
1463-
1464-
/// Construct an Exif data block from the ImageSpec, appending the Exif
1465-
/// data as a big blob to the char vector.
1466-
OIIO_API void encode_exif (const ImageSpec &spec, std::vector<char> &blob);
1467-
1468-
/// Helper: For the given OIIO metadata attribute name, look up the Exif tag
1469-
/// ID, TIFFDataType (expressed as an int), and count. Return true and fill
1470-
/// in the fields if found, return false if not found.
1471-
OIIO_API bool exif_tag_lookup (string_view name, int &tag,
1472-
int &tifftype, int &count);
1473-
1474-
/// Add metadata to spec based on raw IPTC (International Press
1475-
/// Telecommunications Council) metadata in the form of an IIM
1476-
/// (Information Interchange Model). Return true if all is ok, false if
1477-
/// the iptc block was somehow malformed. This is a utility function to
1478-
/// make it easy for multiple format plugins to support embedding IPTC
1479-
/// metadata without having to duplicate functionality within each
1480-
/// plugin. Note that IIM is actually considered obsolete and is
1481-
/// replaced by an XML scheme called XMP.
1482-
OIIO_API bool decode_iptc_iim (const void *iptc, int length, ImageSpec &spec);
1483-
1484-
/// Find all the IPTC-amenable metadata in spec and assemble it into an
1485-
/// IIM data block in iptc. This is a utility function to make it easy
1486-
/// for multiple format plugins to support embedding IPTC metadata
1487-
/// without having to duplicate functionality within each plugin. Note
1488-
/// that IIM is actually considered obsolete and is replaced by an XML
1489-
/// scheme called XMP.
1490-
OIIO_API void encode_iptc_iim (const ImageSpec &spec, std::vector<char> &iptc);
1491-
1492-
/// Add metadata to spec based on XMP data in an XML block. Return true
1493-
/// if all is ok, false if the xml was somehow malformed. This is a
1494-
/// utility function to make it easy for multiple format plugins to
1495-
/// support embedding XMP metadata without having to duplicate
1496-
/// functionality within each plugin.
1497-
OIIO_API bool decode_xmp (const std::string &xml, ImageSpec &spec);
1498-
1499-
/// Find all the relavant metadata (IPTC, Exif, etc.) in spec and
1500-
/// assemble it into an XMP XML string. This is a utility function to
1501-
/// make it easy for multiple format plugins to support embedding XMP
1502-
/// metadata without having to duplicate functionality within each
1503-
/// plugin. If 'minimal' is true, then don't encode things that would
1504-
/// be part of ordinary TIFF or exif tags.
1505-
OIIO_API std::string encode_xmp (const ImageSpec &spec, bool minimal=false);
15061457

15071458
// All the wrap_foo functions implement a wrap mode, wherein coord is
15081459
// altered to be origin <= coord < origin+width. The return value

src/include/OpenImageIO/tiffutils.h

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
/*
2+
Copyright 2017 Larry Gritz et al. All Rights Reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are
6+
met:
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above copyright
10+
notice, this list of conditions and the following disclaimer in the
11+
documentation and/or other materials provided with the distribution.
12+
* Neither the name of the software's owners nor the names of its
13+
contributors may be used to endorse or promote products derived from
14+
this software without specific prior written permission.
15+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
(This is the Modified BSD License)
28+
*/
29+
30+
/////////////////////////////////////////////////////////////////////////////
31+
/// \file
32+
///
33+
/// Utilities for dealing with TIFF tags and data structures (common to
34+
/// plugins that have to deal with TIFF itself, Exif data blocks, and other
35+
/// miscellaneous stuff that piggy-backs off TIFF format).
36+
///
37+
/////////////////////////////////////////////////////////////////////////////
38+
39+
40+
#pragma once
41+
42+
#ifndef OIIO_TIFFUTILS_H
43+
#define OIIO_TIFFUTILS_H
44+
45+
extern "C" {
46+
#include "tiff.h"
47+
}
48+
49+
#include <OpenImageIO/imageio.h>
50+
51+
52+
#ifdef TIFF_VERSION_BIG
53+
// In old versions of TIFF, this was defined in tiff.h. It's gone from
54+
// "BIG TIFF" (libtiff 4.x), so we just define it here.
55+
56+
struct TIFFHeader {
57+
uint16_t tiff_magic; /* magic number (defines byte order) */
58+
uint16_t tiff_version;/* TIFF version number */
59+
uint32_t tiff_diroff; /* byte offset to first directory */
60+
};
61+
62+
struct TIFFDirEntry {
63+
uint16_t tdir_tag; /* tag ID */
64+
uint16_t tdir_type; /* data type -- see TIFFDataType enum */
65+
uint32_t tdir_count; /* number of items; length in spec */
66+
uint32_t tdir_offset; /* byte offset to field data */
67+
};
68+
#endif
69+
70+
71+
72+
73+
OIIO_NAMESPACE_BEGIN
74+
75+
// Define EXIF constants
76+
enum TIFFTAG {
77+
EXIF_EXPOSURETIME = 33434,
78+
EXIF_FNUMBER = 33437,
79+
EXIF_EXPOSUREPROGRAM = 34850,
80+
EXIF_SPECTRALSENSITIVITY = 34852,
81+
EXIF_PHOTOGRAPHICSENSITIVITY = 34855,
82+
EXIF_ISOSPEEDRATINGS = 34855, // old nme for PHOTOGRAPHICSENSITIVITY
83+
EXIF_OECF = 34856,
84+
EXIF_SENSITIVITYTYPE = 34864,
85+
EXIF_STANDARDOUTPUTSENSITIVITY = 34865,
86+
EXIF_RECOMMENDEDEXPOSUREINDEX = 34866,
87+
EXIF_ISOSPEED = 34867,
88+
EXIF_ISOSPEEDLATITUDEYYY = 34868,
89+
EXIF_ISOSPEEDLATITUDEZZZ = 34869,
90+
EXIF_EXIFVERSION = 36864,
91+
EXIF_DATETIMEORIGINAL = 36867,
92+
EXIF_DATETIMEDIGITIZED = 36868,
93+
EXIF_OFFSETTIME = 36880,
94+
EXIF_OFFSETTIMEORIGINAL = 36881,
95+
EXIF_OFFSETTIMEDIGITIZED = 36882,
96+
EXIF_COMPONENTSCONFIGURATION = 37121,
97+
EXIF_COMPRESSEDBITSPERPIXEL = 37122,
98+
EXIF_SHUTTERSPEEDVALUE = 37377,
99+
EXIF_APERTUREVALUE = 37378,
100+
EXIF_BRIGHTNESSVALUE = 37379,
101+
EXIF_EXPOSUREBIASVALUE = 37380,
102+
EXIF_MAXAPERTUREVALUE = 37381,
103+
EXIF_SUBJECTDISTANCE = 37382,
104+
EXIF_METERINGMODE = 37383,
105+
EXIF_LIGHTSOURCE = 37384,
106+
EXIF_FLASH = 37385,
107+
EXIF_FOCALLENGTH = 37386,
108+
EXIF_SECURITYCLASSIFICATION = 37394,
109+
EXIF_IMAGEHISTORY = 37395,
110+
EXIF_SUBJECTAREA = 37396,
111+
EXIF_MAKERNOTE = 37500,
112+
EXIF_USERCOMMENT = 37510,
113+
EXIF_SUBSECTIME = 37520,
114+
EXIF_SUBSECTIMEORIGINAL = 37521,
115+
EXIF_SUBSECTIMEDIGITIZED = 37522,
116+
EXIF_TEMPERATURE = 37888,
117+
EXIF_HUMIDITY = 37889,
118+
EXIF_PRESSURE = 37890,
119+
EXIF_WATERDEPTH = 37891,
120+
EXIF_ACCELERATION = 37892,
121+
EXIF_CAMERAELEVATIONANGLE = 37893,
122+
EXIF_FLASHPIXVERSION = 40960,
123+
EXIF_COLORSPACE = 40961,
124+
EXIF_PIXELXDIMENSION = 40962,
125+
EXIF_PIXELYDIMENSION = 40963,
126+
EXIF_RELATEDSOUNDFILE = 40964,
127+
EXIF_FLASHENERGY = 41483,
128+
EXIF_SPATIALFREQUENCYRESPONSE = 41484,
129+
EXIF_FOCALPLANEXRESOLUTION = 41486,
130+
EXIF_FOCALPLANEYRESOLUTION = 41487,
131+
EXIF_FOCALPLANERESOLUTIONUNIT = 41488,
132+
EXIF_SUBJECTLOCATION = 41492,
133+
EXIF_EXPOSUREINDEX = 41493,
134+
EXIF_SENSINGMETHOD = 41495,
135+
EXIF_FILESOURCE = 41728,
136+
EXIF_SCENETYPE = 41729,
137+
EXIF_CFAPATTERN = 41730,
138+
EXIF_CUSTOMRENDERED = 41985,
139+
EXIF_EXPOSUREMODE = 41986,
140+
EXIF_WHITEBALANCE = 41987,
141+
EXIF_DIGITALZOOMRATIO = 41988,
142+
EXIF_FOCALLENGTHIN35MMFILM = 41989,
143+
EXIF_SCENECAPTURETYPE = 41990,
144+
EXIF_GAINCONTROL = 41991,
145+
EXIF_CONTRAST = 41992,
146+
EXIF_SATURATION = 41993,
147+
EXIF_SHARPNESS = 41994,
148+
EXIF_DEVICESETTINGDESCRIPTION = 41995,
149+
EXIF_SUBJECTDISTANCERANGE = 41996,
150+
EXIF_IMAGEUNIQUEID = 42016,
151+
EXIF_CAMERAOWNERNAME = 42032,
152+
EXIF_BODYSERIALNUMBER = 42033,
153+
EXIF_LENSSPECIFICATION = 42034,
154+
EXIF_LENSMAKE = 42035,
155+
EXIF_LENSMODEL = 42036,
156+
EXIF_LENSSERIALNUMBER = 42037,
157+
EXIF_GAMMA = 42240,
158+
};
159+
160+
161+
162+
/// Given a TIFF data type code (defined in tiff.h) and a count, return the
163+
/// equivalent TypeDesc where one exists. .Return TypeUndefined if there
164+
/// is no obvious equivalent.
165+
OIIO_API TypeDesc tiff_datatype_to_typedesc (TIFFDataType tifftype, size_t tiffcount=1);
166+
167+
inline TypeDesc tiff_datatype_to_typedesc (const TIFFDirEntry& dir) {
168+
return tiff_datatype_to_typedesc (TIFFDataType(dir.tdir_type), dir.tdir_count);
169+
}
170+
171+
/// Return the data size (in bytes) of the TIFF type.
172+
OIIO_API size_t tiff_data_size (TIFFDataType tifftype);
173+
174+
/// Return the data size (in bytes) of the data for the given TIFFDirEntry.
175+
OIIO_API size_t tiff_data_size (const TIFFDirEntry &dir);
176+
177+
/// Given a TIFFDirEntry and a data arena (represented by an array view
178+
/// of unsigned bytes), return an array_view of where the values for the
179+
/// tiff dir lives. Return an empty array_view if there is an error, which
180+
/// could include a nonsensical situation where the TIFFDirEntry seems to
181+
/// point outside the data arena.
182+
OIIO_API array_view<const uint8_t>
183+
OIIO_API tiff_dir_data (const TIFFDirEntry &td, array_view<const uint8_t> data);
184+
185+
/// Decode a raw Exif data block and save all the metadata in an
186+
/// ImageSpec. Return true if all is ok, false if the exif block was
187+
/// somehow malformed. The binary data pointed to by 'exif' should
188+
/// start with a TIFF directory header.
189+
OIIO_API bool decode_exif (array_view<const uint8_t> exif, ImageSpec &spec);
190+
OIIO_API bool decode_exif (string_view exif, ImageSpec &spec);
191+
OIIO_API bool decode_exif (const void *exif, int length, ImageSpec &spec); // DEPRECATED (1.8)
192+
193+
/// Construct an Exif data block from the ImageSpec, appending the Exif
194+
/// data as a big blob to the char vector.
195+
OIIO_API void encode_exif (const ImageSpec &spec, std::vector<char> &blob);
196+
197+
/// Helper: For the given OIIO metadata attribute name, look up the Exif tag
198+
/// ID, TIFFDataType (expressed as an int), and count. Return true and fill
199+
/// in the fields if found, return false if not found.
200+
OIIO_API bool exif_tag_lookup (string_view name, int &tag,
201+
int &tifftype, int &count);
202+
203+
/// Add metadata to spec based on raw IPTC (International Press
204+
/// Telecommunications Council) metadata in the form of an IIM
205+
/// (Information Interchange Model). Return true if all is ok, false if
206+
/// the iptc block was somehow malformed. This is a utility function to
207+
/// make it easy for multiple format plugins to support embedding IPTC
208+
/// metadata without having to duplicate functionality within each
209+
/// plugin. Note that IIM is actually considered obsolete and is
210+
/// replaced by an XML scheme called XMP.
211+
OIIO_API bool decode_iptc_iim (const void *iptc, int length, ImageSpec &spec);
212+
213+
/// Find all the IPTC-amenable metadata in spec and assemble it into an
214+
/// IIM data block in iptc. This is a utility function to make it easy
215+
/// for multiple format plugins to support embedding IPTC metadata
216+
/// without having to duplicate functionality within each plugin. Note
217+
/// that IIM is actually considered obsolete and is replaced by an XML
218+
/// scheme called XMP.
219+
OIIO_API void encode_iptc_iim (const ImageSpec &spec, std::vector<char> &iptc);
220+
221+
/// Add metadata to spec based on XMP data in an XML block. Return true
222+
/// if all is ok, false if the xml was somehow malformed. This is a
223+
/// utility function to make it easy for multiple format plugins to
224+
/// support embedding XMP metadata without having to duplicate
225+
/// functionality within each plugin.
226+
OIIO_API bool decode_xmp (const std::string &xml, ImageSpec &spec);
227+
228+
/// Find all the relavant metadata (IPTC, Exif, etc.) in spec and
229+
/// assemble it into an XMP XML string. This is a utility function to
230+
/// make it easy for multiple format plugins to support embedding XMP
231+
/// metadata without having to duplicate functionality within each
232+
/// plugin. If 'minimal' is true, then don't encode things that would
233+
/// be part of ordinary TIFF or exif tags.
234+
OIIO_API std::string encode_xmp (const ImageSpec &spec, bool minimal=false);
235+
236+
237+
/// Handy structure to hold information mapping TIFF/EXIF tags to their
238+
/// names and actions.
239+
struct TagInfo {
240+
typedef void (*HandlerFunc)(const TagInfo& taginfo, const TIFFDirEntry& dir,
241+
array_view<const uint8_t> buf, ImageSpec& spec,
242+
bool swapendian, int offset_adjustment);
243+
244+
TagInfo (int tag, const char *name, TIFFDataType type,
245+
int count, HandlerFunc handler = nullptr)
246+
: tifftag(tag), name(name), tifftype(type), tiffcount(count),
247+
handler(handler) {}
248+
249+
int tifftag = -1; // TIFF tag used for this info
250+
const char *name = nullptr; // OIIO attribute name we use
251+
TIFFDataType tifftype = TIFF_NOTYPE; // Data type that TIFF wants
252+
int tiffcount = 0; // Number of items
253+
HandlerFunc handler = nullptr; // Special decoding handler
254+
};
255+
256+
/// Return an array_view of a TagInfo array for the corresponding table.
257+
/// Valid names are "Exif", "GPS", and "TIFF". This can be handy for
258+
/// iterating through all possible tags for each category.
259+
OIIO_API array_view<const TagInfo> tag_table (string_view tablename);
260+
261+
/// Look up the TagInfo of a numbered or named tag from a named domain
262+
/// ("TIFF", "Exif", or "GPS"). Return nullptr if it is not known.
263+
OIIO_API const TagInfo* tag_lookup (string_view domain, int tag);
264+
OIIO_API const TagInfo* tag_lookup (string_view domain, string_view tagname);
265+
266+
267+
268+
OIIO_NAMESPACE_END
269+
270+
#endif // OIIO_TIFFUTILS_H

src/jpeg.imageio/jpeginput.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <OpenImageIO/filesystem.h>
3838
#include <OpenImageIO/fmath.h>
3939
#include <OpenImageIO/color.h>
40+
#include <OpenImageIO/tiffutils.h>
4041
#include "jpeg_pvt.h"
4142

4243
OIIO_PLUGIN_NAMESPACE_BEGIN

src/jpeg.imageio/jpegoutput.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <OpenImageIO/imageio.h>
3737
#include <OpenImageIO/filesystem.h>
3838
#include <OpenImageIO/fmath.h>
39+
#include <OpenImageIO/tiffutils.h>
3940
#include "jpeg_pvt.h"
4041

4142
OIIO_PLUGIN_NAMESPACE_BEGIN

src/libOpenImageIO/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ if (NOT MSVC)
2929
endif()
3030

3131
list (APPEND libOpenImageIO_srcs
32-
deepdata.cpp exif.cpp formatspec.cpp imagebuf.cpp
32+
deepdata.cpp exif.cpp exif-canon.cpp
33+
formatspec.cpp imagebuf.cpp
3334
imageinput.cpp imageio.cpp imageioplugin.cpp
3435
imageoutput.cpp iptc.cpp xmp.cpp
3536
color_ocio.cpp

0 commit comments

Comments
 (0)