libopenraw
ifdfile.cpp
00001 /*
00002  * libopenraw - ifdfile.cpp
00003  *
00004  * Copyright (C) 2006-2008 Hubert Figuiere
00005  * Copyright (C) 2008 Novell, Inc.
00006  *
00007  * This library is free software: you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation, either version 3 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library.  If not, see
00019  * <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 #include <algorithm>
00023 #include <numeric>
00024 #include <boost/scoped_ptr.hpp>
00025 #include <boost/scoped_array.hpp>
00026 
00027 #include <libopenraw++/thumbnail.h>
00028 #include <libopenraw++/rawdata.h>
00029 
00030 #include "trace.h"
00031 #include "io/stream.h"
00032 #include "io/streamclone.h"
00033 #include "io/file.h"
00034 #include "ifd.h"
00035 #include "ifdfile.h"
00036 #include "ifdfilecontainer.h"
00037 #include "jfifcontainer.h"
00038 #include "neffile.h" // I wonder if this is smart as it break the abstraction.
00039 #include "metavalue.h"
00040 #include "unpack.h"
00041 
00042 using namespace Debug;
00043 using boost::scoped_ptr;
00044 
00045 
00046 namespace OpenRaw {
00047 namespace Internals {
00048 
00049 
00050 IFDFile::IFDFile(IO::Stream *s, Type _type, 
00051                  bool instantiateContainer)
00052     : RawFile(s, _type),
00053       m_thumbLocations(),
00054       m_io(s),
00055       m_container(NULL)
00056 {
00057     if(instantiateContainer) {
00058         m_container = new IFDFileContainer(m_io, 0);
00059     }
00060 }
00061 
00062 IFDFile::~IFDFile()
00063 {
00064     delete m_container;
00065     delete m_io;
00066 }
00067 
00068 // this one seems to be pretty much the same for all the
00069 // IFD based raw files
00070 IFDDir::Ref  IFDFile::_locateExifIfd()
00071 {
00072     m_mainIfd = _locateMainIfd();
00073     if (!m_mainIfd) {
00074         Trace(ERROR) << "IFDFile::_locateExifIfd() "
00075             "main IFD not found\n";
00076         return IFDDir::Ref();
00077     }
00078     return m_mainIfd->getExifIFD();
00079 }
00080 
00081 
00082 void IFDFile::_identifyId()
00083 {
00084     if(!m_mainIfd) {
00085         m_mainIfd = _locateMainIfd();
00086     }
00087     if(!m_mainIfd) {
00088         Trace(ERROR) << "Main IFD not found to identify the file.\n";
00089         return;
00090     }
00091     std::string model;
00092     if(m_mainIfd->getValue(IFD::EXIF_TAG_MODEL, model)) {
00093         _setTypeId(_typeIdFromModel(model));
00094     }
00095 }
00096 
00097 
00098 
00099 ::or_error IFDFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
00100 {
00101     ::or_error err = OR_ERROR_NONE;
00102 
00103     Trace(DEBUG1) << "_enumThumbnailSizes()\n";
00104     std::vector<IFDDir::Ref> & dirs = m_container->directories();
00105     std::vector<IFDDir::Ref>::iterator iter; 
00106             
00107     Trace(DEBUG1) << "num of dirs " << dirs.size() << "\n";
00108     for(iter = dirs.begin(); iter != dirs.end(); ++iter)
00109     {
00110         IFDDir::Ref & dir = *iter;
00111         dir->load();
00112         or_error ret = _locateThumbnail(dir, list);
00113         if (ret == OR_ERROR_NONE)
00114         {
00115             Trace(DEBUG1) << "Found " << list.back() << " pixels\n";
00116         }
00117         std::vector<IFDDir::Ref> subdirs;
00118         if(dir->getSubIFDs(subdirs)) {
00119             Trace(DEBUG1) << "Iterating subdirs\n";
00120             std::vector<IFDDir::Ref>::iterator iter2; 
00121             for(iter2 = subdirs.begin(); iter2 != subdirs.end(); 
00122                 ++iter2)
00123             {
00124                 IFDDir::Ref & dir2 = *iter2;
00125                 dir2->load();
00126                 ret = _locateThumbnail(dir2, list);
00127                 if (ret == OR_ERROR_NONE)
00128                 {
00129                     Trace(DEBUG1) << "Found " << list.back() << " pixels\n";
00130                 }
00131             }
00132         }
00133     }
00134     if (list.size() <= 0) {
00135         err = OR_ERROR_NOT_FOUND;
00136     }
00137     return err;
00138 }
00139 
00140 
00141 ::or_error IFDFile::_locateThumbnail(const IFDDir::Ref & dir,
00142                                      std::vector<uint32_t> &list)
00143 {
00144     ::or_error ret = OR_ERROR_NOT_FOUND;
00145     bool got_it;
00146     uint32_t x = 0;
00147     uint32_t y = 0;
00148     ::or_data_type _type = OR_DATA_TYPE_NONE;
00149     uint32_t subtype = 0;
00150 
00151     Trace(DEBUG1) << "_locateThumbnail\n";
00152 
00153     got_it = dir->getValue(IFD::EXIF_TAG_NEW_SUBFILE_TYPE, subtype);
00154     Trace(DEBUG1) << "subtype " << subtype  << "\n";
00155     if(!got_it) {
00156         if(!m_cfaIfd) {
00157             m_cfaIfd = _locateCfaIfd();
00158         }
00159         if(m_cfaIfd == dir) {
00160             return OR_ERROR_NOT_FOUND;
00161         }
00162         else {
00163             subtype = 1;
00164         }
00165     }
00166     if (subtype == 1) {
00167 
00168         uint16_t photom_int = 0;
00169         got_it = dir->getValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION, 
00170                                photom_int);
00171 
00172         if (got_it) {
00173             Trace(DEBUG1) << "photometric int " << photom_int  << "\n";
00174         }
00175         // photometric interpretation is RGB by default
00176         else {
00177             photom_int = 2;
00178             Trace(DEBUG1) << "assume photometric int is RGB\n";
00179         }
00180 
00181         got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
00182         got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
00183 
00184         uint16_t compression = 0;
00185         got_it = dir->getValue(IFD::EXIF_TAG_COMPRESSION, compression);
00186                 
00187         uint32_t offset = 0;
00188         got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
00189         if (!got_it || (compression == 6) || (compression == 7)) {
00190             if(!got_it) {
00191                 got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
00192                                        offset);
00193             }
00194             if (got_it) {
00195                 // workaround for CR2 files where 8RGB data is marked
00196                 // as JPEG. Check the real data size.
00197                 uint32_t byte_count = 0;
00198                 if(x && y && dir->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_count)) {
00199                     if(byte_count >= (x * y * 3)) {
00200                         _type = OR_DATA_TYPE_PIXMAP_8RGB;
00201                     }
00202                     else {
00203                         _type = OR_DATA_TYPE_JPEG;
00204                     }
00205                 }
00206                 else {
00207                     _type = OR_DATA_TYPE_JPEG;
00208                     Trace(DEBUG1) << "looking for JPEG at " << offset << "\n";
00209                     if (x == 0 || y == 0) {
00210                         scoped_ptr<IO::StreamClone> s(new IO::StreamClone(m_io, offset));
00211                         scoped_ptr<JFIFContainer> jfif(new JFIFContainer(s.get(), 0));
00212                         if (jfif->getDimensions(x,y)) {
00213                             Trace(DEBUG1) << "JPEG dimensions x=" << x 
00214                                           << " y=" << y << "\n";
00215                         }
00216                         else {
00217                             _type = OR_DATA_TYPE_NONE;
00218                             Trace(WARNING) << "Couldn't get JPEG "
00219                                 "dimensions.\n";
00220                         }
00221                     }
00222                     else {
00223                         Trace(DEBUG1) << "JPEG (supposed) dimensions x=" << x 
00224                                       << " y=" << y << "\n";
00225                     }
00226                 }
00227 
00228             }
00229         }
00230         else if (photom_int == 6) {
00231             Trace(WARNING) << "Unsupported YCbCr photometric "
00232                 "interpretation in non JPEG.\n";
00233             ret = OR_ERROR_INVALID_FORMAT;
00234         }
00235         else {
00236             Trace(DEBUG1) << "found strip offsets\n";
00237             if (x != 0 && y != 0) {
00238                 _type = OR_DATA_TYPE_PIXMAP_8RGB;
00239             }
00240         }
00241         if(_type != OR_DATA_TYPE_NONE) {
00242             uint32_t dim = std::max(x, y);
00243             m_thumbLocations[dim] = IFDThumbDesc(x, y, _type, dir);
00244             list.push_back(dim);
00245             ret = OR_ERROR_NONE;
00246         }
00247     }
00248 
00249     return ret;
00250 }
00251 
00252 
00253 ::or_error IFDFile::_getThumbnail(uint32_t size, Thumbnail & thumbnail)
00254 {
00255     ::or_error ret = OR_ERROR_NOT_FOUND;
00256     ThumbLocations::iterator iter = m_thumbLocations.find(size);
00257     if(iter != m_thumbLocations.end()) 
00258     {
00259         bool got_it;
00260 
00261         IFDThumbDesc & desc = iter->second;
00262         thumbnail.setDataType(desc.type);
00263         uint32_t byte_length= 0; 
00264         uint32_t offset = 0;
00265         uint32_t x = desc.x;
00266         uint32_t y = desc.y;
00267 
00268         switch(desc.type)
00269         {
00270         case OR_DATA_TYPE_JPEG:
00271             got_it = desc.ifddir
00272                 ->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
00273                            byte_length);
00274             if(got_it) {
00275                 got_it = desc.ifddir
00276                     ->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
00277                                offset);
00278             }
00279             else {
00280                 // some case it is STRIP_OFFSETS for JPEG
00281                 got_it = desc.ifddir
00282                     ->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
00283                 got_it = desc.ifddir
00284                     ->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_length);
00285             }
00286             break;
00287         case OR_DATA_TYPE_PIXMAP_8RGB:
00288             got_it = desc.ifddir
00289                 ->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
00290             got_it = desc.ifddir
00291                 ->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_length);
00292 
00293             got_it = desc.ifddir
00294                 ->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
00295             got_it = desc.ifddir
00296                 ->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
00297             break;
00298         default:
00299             break;
00300         }
00301         if (byte_length != 0) {
00302             void *p = thumbnail.allocData(byte_length);
00303             size_t real_size = m_container->fetchData(p, offset, 
00304                                                       byte_length);
00305             if (real_size < byte_length) {
00306                 Trace(WARNING) << "Size mismatch for data: ignoring.\n";
00307             }
00308 
00309             thumbnail.setDimensions(x, y);
00310             ret = OR_ERROR_NONE;
00311         }
00312     }
00313 
00314     return ret;
00315 }
00316 
00317 
00318 MetaValue *IFDFile::_getMetaValue(int32_t meta_index)
00319 {
00320     MetaValue * val = NULL;
00321     IFDDir::Ref ifd;
00322     if(META_INDEX_MASKOUT(meta_index) == META_NS_TIFF) {
00323         if(!m_mainIfd) {
00324             m_mainIfd = _locateMainIfd();
00325         }
00326         ifd = m_mainIfd;
00327     }
00328     else if(META_INDEX_MASKOUT(meta_index) == META_NS_EXIF) {
00329         if(!m_exifIfd) {
00330             m_exifIfd = _locateExifIfd();
00331         }
00332         ifd = m_exifIfd;
00333     }
00334     else {
00335         Trace(ERROR) << "Unknown Meta Namespace\n";
00336     }
00337     if(ifd) {
00338         Trace(DEBUG1) << "Meta value for " 
00339                       << META_NS_MASKOUT(meta_index) << "\n";
00340 
00341         IFDEntry::Ref e = ifd->getEntry(META_NS_MASKOUT(meta_index));
00342         if(e) {
00343             val = new MetaValue(e);
00344         }
00345     }
00346     return val;
00347 }
00348 
00349 
00350 namespace {
00351 
00352 RawData::CfaPattern 
00353 _convertArrayToCfaPattern(const std::vector<uint8_t> &cfaPattern)
00354 {
00355     RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
00356     if(cfaPattern.size() != 4) {
00357         Trace(WARNING) << "Unsupported bayer pattern\n";
00358     }
00359     else {
00360         Trace(DEBUG2) << "patter is = " << cfaPattern[0] << ", "
00361                       << cfaPattern[1] << ", " << cfaPattern[2] 
00362                       << ", " << cfaPattern[3] << "\n";
00363         switch(cfaPattern[0]) {
00364         case IFD::CFA_RED:
00365             switch(cfaPattern[1]) {
00366             case IFD::CFA_GREEN:
00367                 if((cfaPattern[2] == IFD::CFA_GREEN) 
00368                    && (cfaPattern[3] == IFD::CFA_BLUE)) 
00369                 {
00370                     cfa_pattern = OR_CFA_PATTERN_RGGB;
00371                 }
00372                 break;
00373             }
00374             break;
00375         case IFD::CFA_GREEN:
00376             switch(cfaPattern[1]) {
00377             case IFD::CFA_RED:
00378                 if((cfaPattern[2] == 2) 
00379                    && (cfaPattern[3] == IFD::CFA_GREEN)) 
00380                 {
00381                     cfa_pattern = OR_CFA_PATTERN_GRBG;
00382                 }
00383                 break;
00384             case 2:
00385                 if((cfaPattern[2] == IFD::CFA_RED) 
00386                    && (cfaPattern[3] == IFD::CFA_GREEN)) 
00387                 {
00388                     cfa_pattern = OR_CFA_PATTERN_GBRG;
00389                 }
00390                 break;
00391             }
00392             break;
00393         case IFD::CFA_BLUE:
00394             switch(cfaPattern[1]) {
00395             case IFD::CFA_GREEN:
00396                 if((cfaPattern[2] == IFD::CFA_GREEN) 
00397                    && (cfaPattern[3] == IFD::CFA_RED)) 
00398                 {
00399                     cfa_pattern = OR_CFA_PATTERN_BGGR;
00400                 }
00401                 break;
00402             }
00403             break;
00404         }
00405         //
00406     }
00407     return cfa_pattern;
00408 }
00409 
00410 RawData::CfaPattern _convertNewCfaPattern(const IFDEntry::Ref & e)
00411 {
00412     RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NONE;
00413     if(!e || (e->count() < 4)) {
00414         return cfa_pattern;
00415     }
00416 
00417     uint16_t hdim = IFDTypeTrait<uint16_t>::get(*e, 0, true);
00418     uint16_t vdim = IFDTypeTrait<uint16_t>::get(*e, 1, true);
00419     if(hdim != 2 && vdim != 2) {
00420         cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
00421     }
00422     else {
00423         std::vector<uint8_t> cfaPattern;
00424         cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 4, true));
00425         cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 5, true));
00426         cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 6, true));
00427         cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 7, true));
00428         cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
00429     }
00430     return cfa_pattern;
00431 }
00432 
00433 
00435 RawData::CfaPattern _convertCfaPattern(const IFDEntry::Ref & e)
00436 {
00437     std::vector<uint8_t> cfaPattern;
00438     RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NONE;
00439             
00440     e->getArray(cfaPattern);
00441     if(!cfaPattern.empty()) {
00442         cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
00443     }
00444     return cfa_pattern;
00445 }
00446 
00452 static RawData::CfaPattern _getCfaPattern(const IFDDir::Ref & dir)
00453 {
00454     Trace(DEBUG1) << __FUNCTION__ << "\n";
00455     RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NONE;
00456     try {
00457         IFDEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_CFA_PATTERN);
00458         if(e) {
00459             cfa_pattern = _convertCfaPattern(e);
00460         }
00461         else {
00462             e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
00463             if(e)  {
00464                 cfa_pattern = _convertNewCfaPattern(e);
00465             }
00466         }
00467     }
00468     catch(...)
00469     {
00470         Trace(ERROR) << "Exception in _getCfaPattern().\n";
00471     }
00472     return cfa_pattern;
00473 }
00474 
00475 } // end anon namespace
00476 
00477 ::or_error IFDFile::_getRawDataFromDir(RawData & data, IFDDir::Ref & dir)
00478 {
00479     ::or_error ret = OR_ERROR_NONE;
00480             
00481     uint16_t bpc = 0;
00482     uint32_t offset = 0;
00483     uint32_t byte_length = 0;
00484     bool got_it;
00485     uint32_t x, y;
00486     x = 0;
00487     y = 0;
00488 
00489     if(!dir) {
00490         Trace(ERROR) << "dir is NULL\n";
00491         return OR_ERROR_NOT_FOUND;
00492     }
00493     got_it = dir->getValue(IFD::EXIF_TAG_BITS_PER_SAMPLE, bpc);
00494     if(!got_it) {
00495         Trace(ERROR) << "unable to guess Bits per sample\n";
00496     }
00497 
00498     got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
00499     if(got_it) {
00500         IFDEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
00501         if(e) {
00502             std::vector<uint32_t> counts;
00503             e->getArray(counts);
00504             Trace(DEBUG1) << "counting tiles\n";
00505             byte_length = std::accumulate(counts.begin(), counts.end(), 0);
00506         }
00507         else {
00508             Trace(DEBUG1) << "byte len not found\n";
00509             return OR_ERROR_NOT_FOUND;
00510         }
00511     }
00512     else {
00513         // the tile are individual JPEGS....
00514         // TODO extract all of them.
00515         IFDEntry::Ref e = dir->getEntry(IFD::TIFF_TAG_TILE_OFFSETS);
00516         if(e) {
00517             std::vector<uint32_t> offsets;
00518             e->getArray(offsets);
00519             if(offsets.size() > 1) {
00520                 offset = offsets[0];
00521             }
00522             else {
00523                 Trace(DEBUG1) << "tile offsets empty\n";
00524                 return OR_ERROR_NOT_FOUND;                      
00525             }
00526         }
00527         else {
00528             Trace(DEBUG1) << "tile offsets not found\n";
00529             return OR_ERROR_NOT_FOUND;                      
00530         }
00531         e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
00532         if(e) {
00533             std::vector<uint32_t> counts;
00534             e->getArray(counts);
00535             Trace(DEBUG1) << "counting tiles\n";
00536             byte_length = std::accumulate(counts.begin(), counts.end(), 0);
00537         }
00538         else {
00539             Trace(DEBUG1) << "tile byte counts not found\n";
00540             return OR_ERROR_NOT_FOUND;                      
00541         }
00542     }
00543     got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
00544     if(!got_it) {
00545         Trace(DEBUG1) << "X not found\n";
00546         return OR_ERROR_NOT_FOUND;
00547     }
00548     got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
00549     if(!got_it) {
00550         Trace(DEBUG1) << "Y not found\n";
00551         return OR_ERROR_NOT_FOUND;
00552     }
00553 
00554     uint32_t compression = 0;
00555     got_it = dir->getIntegerValue(IFD::EXIF_TAG_COMPRESSION, compression);
00556     if(!got_it)
00557     {
00558         Trace(DEBUG1) << "Compression type not found\n";
00559     }
00560     BitmapData::DataType data_type = OR_DATA_TYPE_NONE;
00561 
00562     switch(compression) 
00563     {
00564     case IFD::COMPRESS_NONE:
00565         data_type = OR_DATA_TYPE_CFA;
00566         break;
00567     case IFD::COMPRESS_NIKON_PACK:
00568         data_type = OR_DATA_TYPE_CFA;
00569         break;
00570     case IFD::COMPRESS_NIKON_QUANTIZED:
00571         // must check whether it is really compressed
00572         // only for D100
00573         if( !NEFFile::isCompressed(*m_container, offset) ) {
00574             compression = IFD::COMPRESS_NIKON_PACK;
00575             data_type = OR_DATA_TYPE_CFA;
00576             // this is a hack. we should check if 
00577             // we have a D100 instead, but that case is already
00578             // a D100 corner case. WILL BREAK on compressed files.
00579             // according to dcraw we must increase the size by 6.
00580             x += 6;
00581             break;
00582         }
00583     default:
00584         data_type = OR_DATA_TYPE_COMPRESSED_CFA;
00585         break;
00586     }
00587 
00588     Trace(DEBUG1) << "RAW Compression is " << compression << "\n";
00589             
00590     RawData::CfaPattern cfa_pattern = _getCfaPattern(dir);
00591     if(cfa_pattern == OR_CFA_PATTERN_NONE) {
00592         // some file have it in the exif IFD instead.
00593         if(!m_exifIfd) {
00594             m_exifIfd = _locateExifIfd();
00595         }
00596         cfa_pattern = _getCfaPattern(m_exifIfd);
00597     }
00598 
00599 
00600     if((bpc == 12 || bpc == 14) && (compression == 1) 
00601        && (byte_length == (x * y * 2))) 
00602     {
00603         Trace(DEBUG1) << "setting bpc from " << bpc 
00604                       << " to 16\n";
00605         bpc = 16;
00606     }
00607     if((bpc == 16) || (data_type == OR_DATA_TYPE_COMPRESSED_CFA)) {
00608         void *p = data.allocData(byte_length);
00609         size_t real_size = m_container->fetchData(p, offset, 
00610                                                   byte_length);
00611         if (real_size < byte_length) {
00612             Trace(WARNING) << "Size mismatch for data: ignoring.\n";
00613         }
00614     }
00615     else if((bpc == 12) || (bpc == 8)) {
00616         size_t fetched = 0;
00617         Unpack unpack(x, compression);
00618         const size_t blocksize = (bpc == 8 ? x : unpack.block_size());
00619         Trace(DEBUG1) << "Block size = " << blocksize << "\n";
00620         Trace(DEBUG1) << "dimensions (x, y) " << x << ", "
00621                       << y << "\n";
00622         boost::scoped_array<uint8_t> block(new uint8_t[blocksize]);
00623         uint8_t * outdata = (uint8_t*)data.allocData(x * y * 2);
00624         size_t got;
00625         Trace(DEBUG1) << "offset of RAW data = " << offset << "\n";
00626         do {
00627             got = m_container->fetchData (block.get(), 
00628                                           offset, blocksize);
00629             fetched += got;
00630             offset += got;
00631             if(got) {
00632                 if(bpc == 12) {
00633                     size_t out = unpack.unpack_be12to16(outdata, 
00634                                                         block.get(), 
00635                                                         got);
00636                     outdata += out;
00637                 }
00638                 else {
00639                     // outdata point to uint16_t
00640                     std::copy(block.get(), block.get()+got,
00641                               (uint16_t*)outdata);
00642                     outdata += (got << 1);
00643                 }
00644             }
00645         } while((got != 0) && (fetched < byte_length));
00646     }
00647     else {
00648         Trace(ERROR) << "Unsupported bpc " << bpc << "\n";
00649         return OR_ERROR_INVALID_FORMAT;                     
00650     }
00651     data.setCfaPattern(cfa_pattern);
00652     data.setDataType(data_type);
00653     data.setCompression(data_type == OR_DATA_TYPE_COMPRESSED_CFA 
00654                         ? compression : 1);
00655     if((data_type == OR_DATA_TYPE_CFA) && (data.max() == 0)) {
00656         data.setMax((1 << bpc) - 1);
00657     }
00658     data.setDimensions(x, y);
00659             
00660     return ret;
00661 }
00662 
00663 }
00664 }
00665 
00666 /*
00667   Local Variables:
00668   mode:c++
00669   c-file-style:"stroustrup"
00670   c-file-offsets:((innamespace . 0))
00671   indent-tabs-mode:nil
00672   fill-column:80
00673   End:
00674 */