CC Localization
tiff.cc
Go to the documentation of this file.
1 #include "tiff.hh"
3 #include "utils.hh"
4 #include <functional>
5 #include <iostream>
6 
7 using namespace std;
8 
9 namespace {union T {unsigned i;char c;};}
10 constexpr bool is_little() {return T({1}).c == '\1';}
11 
13 inline void tcheck(Tiff::DEntry const & e, uint16_t t)
14 {
15  if (e.type!=t) throw Error("Entry type error");
16 }
18 
19 uint16_t Tiff::read16()
20 {
21  union {
22  uint16_t v;
23  char c[2];
24  } b;
25  sp->read(b.c,2);
26  if (efix) {
27  char t = b.c[1];
28  b.c[1] = b.c[0];
29  b.c[0] = t;
30  }
31  return b.v;
32 }
33 
34 uint32_t Tiff::read32()
35 {
36  union {
37  uint32_t v;
38  char c[4];
39  } b;
40  sp->read(b.c,4);
41  if (efix) {
42  char t = b.c[3];
43  b.c[3] = b.c[0];
44  b.c[0] = t;
45  t = b.c[2];
46  b.c[2] = b.c[1];
47  b.c[1] = t;
48  }
49  return b.v;
50 }
51 
52 Tiff::DEntry Tiff::read_dentry()
53 {
54  DEntry e;
55  e.tag = read16();
56  e.type = read16();
57  e.count = read32();
58  e.data = read32();
59  return e;
60 }
61 
62 uint32_t Tiff::to32(DEntry const & e)
63 {
64  if (e.type==4) return e.data;
65  tcheck(e,3);
66  return get16(e);
67 }
68 
69 std::string Tiff::get_str(DEntry const & e)
70 {
71  tcheck(e,2);
72  std::vector<char> b(e.count);
73  sp->seekg(e.data);
74  sp->read(b.data(),e.count);
75  if (b[e.count-1]!='\0') warn << "String does not end with '\\0'";
76  return std::string(b.data(),e.count);
77 }
78 
79 std::vector<uint16_t> Tiff::get16s(DEntry const & e)
80 {
81  std::vector<uint16_t> r;
82  tcheck(e,3);
83  if (e.count<=2) {
84  r.push_back(get16(e));
85  if (e.count==2) r.push_back(next16(e));
86  }
87  else {
88  sp->seekg(e.data);
89  for (unsigned i = 0; i<e.count; i++) r.push_back(read16());
90  }
91  return r;
92 }
93 
94 std::vector<uint32_t> Tiff::get32s(DEntry const & e)
95 {
96  std::vector<uint32_t> r;
97  tcheck(e,4);
98  if (e.count<=1) r.push_back(e.data);
99  else {
100  sp->seekg(e.data);
101  for (unsigned i = 0; i<e.count; i++) r.push_back(read32());
102  }
103  return r;
104 }
105 
106 std::tuple<uint32_t,uint32_t> Tiff::get_ratio(DEntry const & e)
107 {
108  tcheck(e,5);
109  sp->seekg(e.data);
110  return {read32(),read32()};
111 }
112 
114 {
115  sp->seekg(0);
116  char b[3];
117  sp->read(b,2);
118  b[2] = 0;
119  le = string(b) == "II"; // little endian?
120  efix = le^is_little();
121  auto check = read16();
122  debug << '[' << b << "]:" << check << '\n';
123  ifd = read32();
124  debug << "IFD at " << ifd << '\n';
125 }
126 
127 uint32_t Tiff::parse_ifd(uint32_t i)
128 {
129  sp->seekg(i?i:ifd);
130  auto nde = read16();
131  debug << "# dentry = " << nde << '\n';
132  vector<DEntry> delist;
133  for (unsigned i = 0; i < nde; i ++) {
134  auto e = read_dentry();
135  delist.push_back(e);
136  }
137  uint32_t ni = read32();
138  static map<Tag,function<void(DEntry&)> > ptag = {
139  {Tag_ImageWidth,[this](DEntry& e){image_width = to32(e);}},
140  {Tag_ImageLength,[this](DEntry& e){image_length = to32(e);}},
141  {Tag_BitsPerSample,[this](DEntry& e){bits_per_sample = get16s(e);}},
142  {Tag_Compression,[this](DEntry& e){compression = (Compression)get16(e);}},
143  {Tag_PhotometricInterpretation,[this](DEntry& e){photometric = (Photometric)get16(e);}},
144  {Tag_FillOrder,[this](DEntry& e){fill_order = get16(e);}},
145  {Tag_ImageDescription,[this](DEntry& e){image_description = get_str(e);}},
146  {Tag_StripOffsets,[this](DEntry& e){strip_offsets = get32s(e);}},
147  {Tag_Orientation,[this](DEntry& e){orientation = get16(e);}},
148  {Tag_SamplesPerPixel,[this](DEntry& e){samples_per_pixel = to32(e);}},
149  {Tag_RowsPerStrip,[this](DEntry& e){rows_per_strip = to32(e);}},
150  {Tag_StripByteCounts,[this](DEntry& e){strip_byte_counts = get32s(e);}},
151  {Tag_XResolution,[this](DEntry& e){xresolution = get_ratio(e);}},
152  {Tag_YResolution,[this](DEntry& e){yresolution = get_ratio(e);}},
153  {Tag_PlanarConfiguration,[this](DEntry& e){planar_configuration = get16(e);}},
154  {Tag_ResolutionUnit,[this](DEntry& e){resolution_unit = (Unit)get16(e);}},
155  {Tag_Software,[this](DEntry& e){software = get_str(e);}},
156  {Tag_SampleFormat,[this](DEntry& e){for (auto i:get16s(e)) sample_formats.push_back((SampleFormat)i);}},
157  {Tag_ImageID,[this](DEntry& e){image_id = get_str(e);}}
158  };
159  for (auto e: delist) {
160  auto i = ptag.find((Tag)e.tag);
161  if (i!=ptag.end()) i->second(e);
162  else info << "unprocessed tag:" << e.tag << '\n';
163  }
164  debug << " next IFD: " << ni << '\n';
165  return ni;
166 }
167 
168 std::vector<char> Tiff::read_image()
169 {
170  if (samples_per_pixel!=1 || bits_per_sample[0]!=16) {
171  error("Unprocessed samples_per_pixel or bits_per_sample");
172  }
173  size_t isz = image_width*image_length*2;
174  // std::cout << "isz = " << isz << '\n';
175  std::vector<char> b(isz);
176  size_t ns = (image_length+rows_per_strip-1)/rows_per_strip; // number of strips
177  if (ns!=strip_offsets.size()) error("mismatch number of strip_offsets");
178  size_t tsz = 0;
179  for (unsigned i = 0; i<ns; i++) {
180  size_t z = strip_byte_counts[i];
181  sp->seekg(strip_offsets[i]);
182  sp->read(b.data()+tsz, z);
183  tsz += z;
184  }
185  if (tsz!=isz) error("Image byte size mismatch");
186  if (efix) for (size_t i = 0; i<isz; i += 2) {
187  char t = b[i];
188  b[i] = b[i+1];
189  b[i+1] = t;
190  }
191  return b;
192 }
uint16_t tag
entry name
Definition: tiff.hh:26
std::vector< char > read_image()
Definition: tiff.cc:168
std::ostream & warn
stream for warning messages
Definition: utils.cc:55
std::ostream & info
stream for informative messages
Definition: utils.cc:54
Unit
Units for image.
Definition: tiff.hh:100
Error exception.
Definition: utils.hh:14
SampleFormat
Sample formats.
Definition: tiff.hh:112
Photometric
Photometric formats.
Definition: tiff.hh:84
Tag
Directory entry ID tags.
Definition: tiff.hh:50
void error(std::string const &m)
throw an Error with given message string
Definition: utils.cc:58
void start()
Definition: tiff.cc:113
constexpr bool is_little()
is little endian
Definition: tiff.cc:10
uint16_t type
entry data type
Definition: tiff.hh:27
Directory Entry.
Definition: tiff.hh:24
Compression
Compression methods.
Definition: tiff.hh:72
std::ostream & debug
stream for debug messages
Definition: utils.cc:53
Miscellaneous utilities.
uint32_t parse_ifd(uint32_t i=0)
Parse image file directory (IFD)
Definition: tiff.cc:127
Class for processing TIFF file.