libopenraw
|
00001 /* 00002 * libopenraw - ciffcontainer.cpp 00003 * 00004 * Copyright (C) 2006-2008 Hubert Figuiere 00005 * 00006 * This library is free software: you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public License 00008 * as published by the Free Software Foundation, either version 3 of 00009 * the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library. If not, see 00018 * <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 #include <cstring> 00022 #include <iostream> 00023 #include <boost/shared_ptr.hpp> 00024 00025 #include <libopenraw/types.h> 00026 00027 #include "io/file.h" 00028 #include "ciffcontainer.h" 00029 #include "debug.h" 00030 00031 using namespace Debug; 00032 00033 namespace OpenRaw { 00034 namespace Internals { 00035 00036 namespace CIFF { 00037 00038 00039 bool ImageSpec::readFrom(off_t offset, CIFFContainer *container) 00040 { 00041 bool ret; 00042 IO::Stream *file = container->file(); 00043 file->seek(offset, SEEK_SET); 00044 ret = container->readUInt32(file, imageWidth); 00045 ret = container->readUInt32(file, imageHeight); 00046 ret = container->readUInt32(file, pixelAspectRatio); 00047 ret = container->readInt32(file, rotationAngle); 00048 ret = container->readUInt32(file, componentBitDepth); 00049 ret = container->readUInt32(file, colorBitDepth); 00050 ret = container->readUInt32(file, colorBW); 00051 return ret; 00052 } 00053 00054 int32_t ImageSpec::exifOrientation() const 00055 { 00056 int32_t orientation = 0; 00057 switch(rotationAngle) { 00058 case 0: 00059 orientation = 1; 00060 break; 00061 case 90: 00062 orientation = 6; 00063 break; 00064 case 180: 00065 orientation = 3; 00066 break; 00067 case 270: 00068 orientation = 8; 00069 break; 00070 } 00071 return orientation; 00072 } 00073 00074 RecordEntry::RecordEntry() 00075 : typeCode(0), length(0), offset(0) 00076 { 00077 } 00078 00079 bool RecordEntry::readFrom(CIFFContainer *container) 00080 { 00081 bool ret; 00082 IO::Stream *file = container->file(); 00083 ret = container->readUInt16(file, typeCode); 00084 ret = container->readUInt32(file, length); 00085 ret = container->readUInt32(file, offset); 00086 return ret; 00087 } 00088 00089 size_t RecordEntry::fetchData(Heap* heap, void* buf, size_t size) const 00090 { 00091 return heap->container()->fetchData(buf, 00092 offset + heap->offset(), size); 00093 } 00094 00095 00096 Heap::Heap(off_t start, off_t length, CIFFContainer * _container) 00097 : m_start(start), 00098 m_length(length), 00099 m_container(_container), 00100 m_records() 00101 { 00102 Debug::Trace(DEBUG2) << "Heap @ " << start << " length = " 00103 << m_length << "\n"; 00104 } 00105 00106 std::vector<RecordEntry> & Heap::records() 00107 { 00108 if (m_records.size() == 0) { 00109 _loadRecords(); 00110 } 00111 return m_records; 00112 } 00113 00114 00115 bool Heap::_loadRecords() 00116 { 00117 IO::Stream *file = m_container->file(); 00118 file->seek(m_start + m_length - 4, SEEK_SET); 00119 int32_t record_offset; 00120 bool ret = m_container->readInt32(file, record_offset); 00121 00122 if (ret) { 00123 int16_t numRecords; 00124 00125 m_records.clear(); 00126 file->seek(m_start + record_offset, SEEK_SET); 00127 ret = m_container->readInt16(file, numRecords); 00128 if (!ret) 00129 { 00130 Trace(DEBUG1) << "read failed: " << ret << "\n"; 00131 } 00132 Trace(DEBUG2) << "numRecords " << numRecords << "\n"; 00133 int16_t i; 00134 m_records.reserve(numRecords); 00135 for (i = 0; i < numRecords; i++) { 00136 m_records.push_back(RecordEntry()); 00137 m_records.back().readFrom(m_container); 00138 } 00139 } 00140 return ret; 00141 } 00142 00143 00144 #if 0 00145 class OffsetTable { 00146 uint16_t numRecords;/* the number tblArray elements */ 00147 RecordEntry tblArray[1];/* Array of the record entries */ 00148 }; 00149 #endif 00150 00151 00152 bool HeapFileHeader::readFrom(CIFFContainer *container) 00153 { 00154 endian = RawContainer::ENDIAN_NULL; 00155 bool ret = false; 00156 IO::Stream *file = container->file(); 00157 int s = file->read(byteOrder, 2); 00158 if (s == 2) { 00159 if((byteOrder[0] == 'I') && (byteOrder[1] == 'I')) { 00160 endian = RawContainer::ENDIAN_LITTLE; 00161 } 00162 else if((byteOrder[0] == 'M') && (byteOrder[1] == 'M')) { 00163 endian = RawContainer::ENDIAN_BIG; 00164 } 00165 container->setEndian(endian); 00166 ret = container->readUInt32(file, headerLength); 00167 if (ret) { 00168 ret = (file->read(type, 4) == 4); 00169 } 00170 if (ret) { 00171 ret = (file->read(subType, 4) == 4); 00172 } 00173 if (ret) { 00174 ret = container->readUInt32(file, version); 00175 } 00176 } 00177 return ret; 00178 } 00179 } 00180 00181 CIFFContainer::CIFFContainer(IO::Stream *_file) 00182 : RawContainer(_file, 0), 00183 m_hdr(), 00184 m_heap((CIFF::Heap*)NULL), 00185 m_hasImageSpec(false) 00186 { 00187 m_endian = _readHeader(); 00188 } 00189 00190 CIFFContainer::~CIFFContainer() 00191 { 00192 } 00193 00194 CIFF::Heap::Ref CIFFContainer::heap() 00195 { 00196 if (m_heap == NULL) { 00197 _loadHeap(); 00198 } 00199 return m_heap; 00200 } 00201 00202 bool CIFFContainer::_loadHeap() 00203 { 00204 bool ret = false; 00205 if (m_heap == NULL) { 00206 if(m_endian != ENDIAN_NULL) { 00207 off_t heapLength = m_file->filesize() - m_hdr.headerLength; 00208 00209 Trace(DEBUG1) << "heap len " << heapLength << "\n"; 00210 m_heap = CIFF::Heap::Ref(new CIFF::Heap(m_hdr.headerLength, 00211 heapLength, this)); 00212 00213 ret = true; 00214 } 00215 else { 00216 Trace(DEBUG1) << "Unknown endian\n"; 00217 } 00218 } 00219 return ret; 00220 } 00221 00222 00223 RawContainer::EndianType CIFFContainer::_readHeader() 00224 { 00225 EndianType _endian = ENDIAN_NULL; 00226 m_hdr.readFrom(this); 00227 if ((::strncmp(m_hdr.type, "HEAP", 4) == 0) 00228 && (::strncmp(m_hdr.subType, "CCDR", 4) == 0)) { 00229 _endian = m_hdr.endian; 00230 } 00231 return _endian; 00232 } 00233 00234 CIFF::Heap::Ref CIFFContainer::getImageProps() 00235 { 00236 if(!m_imageprops) { 00237 if(!heap()) { 00238 return CIFF::Heap::Ref(); 00239 } 00240 00241 const CIFF::RecordEntry::List & records = m_heap->records(); 00242 CIFF::RecordEntry::List::const_iterator iter; 00243 00244 // locate the properties 00245 iter = std::find_if(records.begin(), records.end(), boost::bind( 00246 &CIFF::RecordEntry::isA, _1, 00247 static_cast<uint16_t>(CIFF::TAG_IMAGEPROPS))); 00248 if (iter == records.end()) { 00249 Trace(ERROR) << "Couldn't find the image properties.\n"; 00250 return CIFF::Heap::Ref(); 00251 } 00252 00253 m_imageprops = CIFF::Heap::Ref(new CIFF::Heap(iter->offset + m_heap->offset(), iter->length, this)); 00254 } 00255 return m_imageprops; 00256 } 00257 00258 const CIFF::ImageSpec * CIFFContainer::getImageSpec() 00259 { 00260 if(!m_hasImageSpec) { 00261 CIFF::Heap::Ref props = getImageProps(); 00262 00263 if(!props) 00264 return NULL; 00265 const CIFF::RecordEntry::List & propsRecs = props->records(); 00266 CIFF::RecordEntry::List::const_iterator iter; 00267 iter = std::find_if(propsRecs.begin(), propsRecs.end(), 00268 boost::bind( 00269 &CIFF::RecordEntry::isA, _1, 00270 static_cast<uint16_t>(CIFF::TAG_IMAGEINFO))); 00271 if (iter == propsRecs.end()) { 00272 Trace(ERROR) << "Couldn't find the image info.\n"; 00273 return NULL; 00274 } 00275 m_imagespec.readFrom(iter->offset + props->offset(), this); 00276 m_hasImageSpec = true; 00277 } 00278 return &m_imagespec; 00279 } 00280 00281 00282 const CIFF::Heap::Ref CIFFContainer::getCameraProps() 00283 { 00284 if(!m_cameraprops) { 00285 CIFF::Heap::Ref props = getImageProps(); 00286 00287 if(!props) 00288 return CIFF::Heap::Ref(); 00289 const CIFF::RecordEntry::List & propsRecs = props->records(); 00290 CIFF::RecordEntry::List::const_iterator iter; 00291 iter = std::find_if(propsRecs.begin(), propsRecs.end(), 00292 boost::bind( 00293 &CIFF::RecordEntry::isA, _1, 00294 static_cast<uint16_t>(CIFF::TAG_CAMERAOBJECT))); 00295 if (iter == propsRecs.end()) { 00296 Trace(ERROR) << "Couldn't find the camera props.\n"; 00297 return CIFF::Heap::Ref(); 00298 } 00299 m_cameraprops = CIFF::Heap::Ref(new CIFF::Heap(iter->offset + props->offset(), 00300 iter->length, this)); 00301 } 00302 return m_cameraprops; 00303 } 00304 00305 const CIFF::RecordEntry * CIFFContainer::getRawDataRecord() const 00306 { 00307 if(!m_heap) { 00308 return NULL; 00309 } 00310 const CIFF::RecordEntry::List & records = m_heap->records(); 00311 CIFF::RecordEntry::List::const_iterator iter; 00312 // locate the RAW data 00313 iter = std::find_if(records.begin(), records.end(), boost::bind( 00314 &CIFF::RecordEntry::isA, _1, 00315 static_cast<uint16_t>(CIFF::TAG_RAWIMAGEDATA))); 00316 00317 if (iter != records.end()) { 00318 return &(*iter); 00319 } 00320 return NULL; 00321 } 00322 } 00323 }