libopenraw
neffile.cpp
1 /* -*- tab-width:4; c-basic-offset:4 -*- */
2 
3 /*
4  * libopenraw - neffile.cpp
5  *
6  * Copyright (C) 2006-2008 Hubert Figuiere
7  * Copyright (C) 2008 Novell, Inc.
8  *
9  * This library is free software: you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation, either version 3 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library. If not, see
21  * <http://www.gnu.org/licenses/>.
22  */
23 
24 
25 #include <iostream>
26 #include <vector>
27 #include <libopenraw++/thumbnail.h>
28 #include <libopenraw++/rawdata.h>
29 
30 #include "trace.h"
31 #include "ifd.h"
32 #include "ifdfilecontainer.h"
33 #include "ifddir.h"
34 #include "ifdentry.h"
35 #include "io/file.h"
36 #include "huffman.h"
37 #include "nefdiffiterator.h"
38 #include "nefcfaiterator.h"
39 #include "neffile.h"
40 
41 using namespace Debug;
42 
43 namespace OpenRaw {
44 
45 
46  namespace Internals {
47  const IFDFile::camera_ids_t NEFFile::s_def[] = {
48  { "NIKON D1 ", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
49  OR_TYPEID_NIKON_D1) },
50  { "NIKON D100 ", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
51  OR_TYPEID_NIKON_D100) },
52  { "NIKON D1X", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
53  OR_TYPEID_NIKON_D1X) },
54  { "NIKON D200", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
55  OR_TYPEID_NIKON_D200) },
56  { "NIKON D2H", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
57  OR_TYPEID_NIKON_D2H ) },
58  { "NIKON D2X", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
59  OR_TYPEID_NIKON_D2X ) },
60  { "NIKON D3", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
61  OR_TYPEID_NIKON_D3) },
62  { "NIKON D300", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
63  OR_TYPEID_NIKON_D300) },
64  { "NIKON D3000", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
65  OR_TYPEID_NIKON_D3000) },
66  { "NIKON D40", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
67  OR_TYPEID_NIKON_D40) },
68  { "NIKON D40X", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
69  OR_TYPEID_NIKON_D40X) },
70  { "NIKON D50", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
71  OR_TYPEID_NIKON_D50) },
72  { "NIKON D70", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
73  OR_TYPEID_NIKON_D70) },
74  { "NIKON D70s", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
75  OR_TYPEID_NIKON_D70S) },
76  { "NIKON D80", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_NIKON,
77  OR_TYPEID_NIKON_D80) },
78  { 0, 0 }
79  };
80 
81  RawFile *NEFFile::factory(IO::Stream* _filename)
82  {
83  return new NEFFile(_filename);
84  }
85 
86  NEFFile::NEFFile(IO::Stream* _filename)
87  : TiffEpFile(_filename, OR_RAWFILE_TYPE_NEF)
88  {
89  _setIdMap(s_def);
90  }
91 
92 
93  NEFFile::~NEFFile()
94  {
95  }
96 
97  bool NEFFile::isCompressed(RawContainer & container, uint32_t offset)
98  {
99  int i;
100  uint8_t buf[256];
101  size_t real_size = container.fetchData(buf, offset,
102  256);
103  if(real_size != 256) {
104  return true;
105  }
106  for(i = 15; i < 256; i+= 16) {
107  if(buf[i]) {
108  Trace(DEBUG1) << "isCompressed: true\n";
109  return true;
110  }
111  }
112  Trace(DEBUG1) << "isCompressed: false\n";
113  return false;
114  }
115 
116  ::or_error NEFFile::_decompressNikonQuantized(RawData & data)
117  {
118  NEFCompressionInfo c;
119  if (!_getCompressionCurve(data, c)) {
120  return OR_ERROR_NOT_FOUND;
121  }
122  const uint32_t rows = data.y();
123  const uint32_t raw_columns = data.x();
124 
125  //FIXME: not always true
126  const uint32_t columns = raw_columns - 1;
127 
128  NefDiffIterator
129  diffs(c.huffman, data.data());
130  NefCfaIterator iter(diffs, rows, raw_columns, c.vpred);
131 
132  RawData newData;
133  uint16_t *p = (uint16_t *) newData.allocData(rows * columns * 2);
134  newData.setDimensions(columns, rows);
135  newData.setDataType(OR_DATA_TYPE_CFA);
136  uint16_t bpc = data.bpc();
137  newData.setBpc(bpc);
138  newData.setMax((1 << bpc) - 1);
139  newData.setCfaPattern(data.cfaPattern());
140 
141  for (unsigned int i = 0; i < rows; i++) {
142  for (unsigned int j = 0; j < raw_columns; j++) {
143  uint16_t t = iter.get();
144  if (j < columns) {
145  unsigned shift = 16 - data.bpc();
146  p[i * columns + j] = c.curve[t & 0x3fff] << shift;
147  }
148  }
149  }
150 
151  data.swap(newData);
152  return OR_ERROR_NONE;
153  }
154 
155  ::or_error NEFFile::_decompressIfNeeded(RawData & data,
156  uint32_t options)
157  {
158  uint32_t compression = data.compression();
159  if((options & OR_OPTIONS_DONT_DECOMPRESS) ||
160  compression == IFD::COMPRESS_NONE) {
161  return OR_ERROR_NONE;
162  } else if(compression == IFD::COMPRESS_NIKON_QUANTIZED) {
163  return _decompressNikonQuantized(data);
164  } else {
165  return OR_ERROR_INVALID_FORMAT;
166  }
167  }
168 
169  int NEFFile::_getCompressionCurve(RawData & data, NEFFile::NEFCompressionInfo& c)
170  {
171  if(!m_exifIfd) {
172  m_exifIfd = _locateExifIfd();
173  }
174  if(!m_exifIfd) {
175  return 0;
176  }
177 
178  IFDEntry::Ref maker_ent =
179  m_exifIfd->getEntry(IFD::EXIF_TAG_MAKER_NOTE);
180  if(!maker_ent) {
181  return 0;
182  }
183 
184  uint32_t off = maker_ent->offset();
185  uint32_t base = off + 10;
186 
187  IFDDir::Ref ref(new IFDDir(base + 8, *m_container));
188  ref->load();
189  IFDEntry::Ref curveEntry = ref->getEntry(0x0096);
190  if(!curveEntry) {
191  return 0;
192  }
193 
194  size_t pos = base + curveEntry->offset();
195 
196  IO::Stream *file = m_container->file();
197  file->seek(pos, SEEK_SET);
198 
199  int16_t aux;
200 
201  uint16_t header;
202  bool read = m_container->readInt16(file, aux);
203  header = aux;
204  if(!read) {
205  return 0;
206  }
207 
208  if (header == 0x4410) {
209  c.huffman = NefDiffIterator::Lossy12Bit;
210  data.setBpc(12);
211  } else if (header == 0x4630) {
212  c.huffman = NefDiffIterator::LossLess14Bit;
213  data.setBpc(14);
214  } else {
215  return 0;
216  }
217 
218  for (int i = 0; i < 2; ++i) {
219  for (int j = 0; j < 2; ++j) {
220  read = m_container->readInt16(file, aux);
221  if(!read) {
222  return 0;
223  }
224  c.vpred[i][j] = aux;
225  }
226  }
227 
228  if (header == 0x4410) {
229  size_t nelems;
230  read = m_container->readInt16(file, aux);
231  nelems = aux;
232 
233  for (size_t i = 0; i < nelems; ++i) {
234  read = m_container->readInt16(file, aux);
235  if (!read)
236  return 0;
237  c.curve.push_back(aux);
238  }
239  } else if (header == 0x4630) {
240  for (size_t i = 0; i <= 0x3fff; ++i) {
241  c.curve.push_back(i);
242  }
243  }
244 
245  return 1;
246  }
247 
248  ::or_error NEFFile::_getRawData(RawData & data, uint32_t options)
249  {
250  ::or_error ret = OR_ERROR_NONE;
251  m_cfaIfd = _locateCfaIfd();
252  Trace(DEBUG1) << "_getRawData()\n";
253 
254  if(m_cfaIfd) {
255  ret = _getRawDataFromDir(data, m_cfaIfd);
256  if (ret != OR_ERROR_NONE) {
257  return ret;
258  }
259  ret = _decompressIfNeeded(data, options);
260  }
261  else {
262  ret = OR_ERROR_NOT_FOUND;
263  }
264  return ret;
265  }
266 
267  }
268 }
269 
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard. I guess it failed.
Definition: arwfile.cpp:33
IFDFileContainer * m_container
Definition: ifdfile.h:95
size_t fetchData(void *buf, const off_t offset, const size_t buf_size)
virtual void setDimensions(uint32_t x, uint32_t y)
Definition: rawdata.cpp:132
bool readInt16(IO::Stream *f, int16_t &v)
uint32_t bpc() const
Definition: bitmapdata.cpp:142
void swap(RawData &with)
Definition: rawdata.cpp:117
void setBpc(uint32_t _bpc)
Definition: bitmapdata.cpp:154
virtual int seek(off_t offset, int whence)=0
Definition: trace.cpp:28
void setDataType(DataType _type)
Definition: bitmapdata.cpp:92
boost::shared_ptr< IFDEntry > Ref
Definition: ifdentry.h:122
static bool isCompressed(RawContainer &container, uint32_t offset)
Definition: neffile.cpp:97
::or_error _getRawDataFromDir(RawData &data, IFDDir::Ref &dir)
Definition: ifdfile.cpp:477