X3fDecoder::X3fDecoder(FileMap* file) : RawDecoder(file), bytes(NULL) { decoderVersion = 1; huge_table = NULL; line_offsets = NULL; if (getHostEndianness() == little) bytes = new ByteStream(file->getData(0), file->getSize()); else bytes = new ByteStreamSwap(file->getData(0), file->getSize()); }
void KdcDecoder::decodeMetaDataInternal(CameraMetaData *meta) { vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL); if (data.empty()) ThrowRDE("KDC Decoder: Model name found"); if (!data[0]->hasEntry(MAKE)) ThrowRDE("KDC Decoder: Make name not found"); string make = data[0]->getEntry(MAKE)->getString(); string model = data[0]->getEntry(MODEL)->getString(); setMetaData(meta, make, model, "", 0); // Try the kodak hidden IFD for WB if (mRootIFD->hasEntryRecursive(KODAK_IFD2)) { TiffEntry *ifdoffset = mRootIFD->getEntryRecursive(KODAK_IFD2); TiffIFD *kodakifd = NULL; try { if (mRootIFD->endian == getHostEndianness()) kodakifd = new TiffIFD(mFile, ifdoffset->getInt()); else kodakifd = new TiffIFDBE(mFile, ifdoffset->getInt()); if (kodakifd && kodakifd->hasEntryRecursive(KODAK_KDC_WB)) { TiffEntry *wb = kodakifd->getEntryRecursive(KODAK_KDC_WB); if (wb->count == 3) { const uint32 *tmp = wb->getIntArray(); mRaw->metadata.wbCoeffs[0] = (float)tmp[0]; mRaw->metadata.wbCoeffs[1] = (float)tmp[1]; mRaw->metadata.wbCoeffs[2] = (float)tmp[2]; } } } catch(TiffParserException e) { mRaw->setError(e.what()); } if (kodakifd) delete kodakifd; } // Use the normal WB if available if (mRootIFD->hasEntryRecursive(KODAKWB)) { TiffEntry *wb = mRootIFD->getEntryRecursive(KODAKWB); if (wb->count == 734 || wb->count == 1502) { const uchar8 *tmp = wb->getData(); mRaw->metadata.wbCoeffs[0] = (float)((((ushort16) tmp[148])<<8)|tmp[149])/256.0f; mRaw->metadata.wbCoeffs[1] = 1.0f; mRaw->metadata.wbCoeffs[2] = (float)((((ushort16) tmp[150])<<8)|tmp[151])/256.0f; } } }
void MrwDecoder::parseHeader() { const unsigned char* data = mFile->getData(0); if (mFile->getSize() < 30) ThrowRDE("Not a valid MRW file (size too small)"); if (!isMRW(mFile)) ThrowRDE("This isn't actually a MRW file, why are you calling me?"); data_offset = get4BE(data,4)+8; if (!mFile->isValid(data_offset)) ThrowRDE("MRW: Data offset is invalid"); // Make sure all values have at least been initialized raw_width = raw_height = packed = 0; wb_coeffs[0] = wb_coeffs[1] = wb_coeffs[2] = wb_coeffs[3] = NAN; uint32 currpos = 8; while (currpos < data_offset) { uint32 tag = get4BE(data,currpos); uint32 len = get4BE(data,currpos+4); switch(tag) { case 0x505244: // PRD raw_height = get2BE(data,currpos+16); raw_width = get2BE(data,currpos+18); packed = (data[currpos+24] == 12); case 0x574247: // WBG for(uint32 i=0; i<4; i++) wb_coeffs[i] = (float)get2BE(data, currpos+12+i*2); break; case 0x545457: // TTW // Base value for offsets needs to be at the beginning of the TIFF block, not the file FileMap *f = new FileMap(mFile->getDataWrt(currpos+8), mFile->getSize()-currpos-8); if (little == getHostEndianness()) tiff_meta = new TiffIFDBE(f, 8); else tiff_meta = new TiffIFD(f, 8); delete f; break; } currpos += MAX(len+8,1); // MAX(,1) to make sure we make progress } }
AriDecoder::AriDecoder(FileMap* file) : RawDecoder(file) { if (mFile->getSize() < 4096) { ThrowRDE("ARRI: File too small (no header)"); } try { ByteStream *s; if (getHostEndianness() == little) { s = new ByteStream(mFile->getData(8), mFile->getSize()- 8); } else { s = new ByteStreamSwap(mFile->getData(8), mFile->getSize()- 8); } mDataOffset = s->getInt(); uint32 someNumber = s->getInt(); // Value: 3? uint32 segmentLength = s->getInt(); // Value: 0x3c = length if (someNumber != 3 || segmentLength != 0x3c) { ThrowRDE("Unknown values in ARRIRAW header, %d, %d", someNumber, segmentLength); } mWidth = s->getInt(); mHeight = s->getInt(); s->setAbsoluteOffset(0x40); mDataSize = s->getInt(); // Smells like whitebalance s->setAbsoluteOffset(0x5c); mWB[0] = s->getFloat(); // 1.3667001 in sample mWB[1] = s->getFloat(); // 1.0000000 in sample mWB[2] = s->getFloat(); // 1.6450000 in sample // Smells like iso s->setAbsoluteOffset(0xb8); mIso = s->getInt(); // 100 in sample s->setAbsoluteOffset(0x29c-8); mModel = s->getString(); s->setAbsoluteOffset(0x2a4-8); mEncoder = s->getString(); } catch (IOException &e) { ThrowRDE("ARRI: IO Exception:%s", e.what()); } }
X3fParser::X3fParser(FileMap* file) { decoder = NULL; bytes = NULL; mFile = file; uint32 size = file->getSize(); if (size<104+128) ThrowRDE("X3F file too small"); if (getHostEndianness() == little) bytes = new ByteStream(file->getData(0), size); else bytes = new ByteStreamSwap(file->getData(0), size); try { try { // Read signature if (bytes->getUInt() != 0x62564f46) ThrowRDE("X3F Decoder: Not an X3f file (Signature)"); uint32 version = bytes->getUInt(); if (version < 0x00020000) ThrowRDE("X3F Decoder: File version too old"); // Skip identifier + mark bits bytes->skipBytes(16+4); bytes->setAbsoluteOffset(0); decoder = new X3fDecoder(file); readDirectory(); } catch (IOException e) { ThrowRDE("X3F Decoder: IO Error while reading header: %s", e.what()); } } catch (RawDecoderException e) { freeObjects(); throw e; } }
RawImage NefDecoder::decodeRawInternal() { vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(CFAPATTERN); if (data.empty()) ThrowRDE("NEF Decoder: No image data found"); TiffIFD* raw = data[0]; int compression = raw->getEntry(COMPRESSION)->getInt(); data = mRootIFD->getIFDsWithTag(MODEL); if (data.empty()) ThrowRDE("NEF Decoder: No model data found"); TiffEntry *offsets = raw->getEntry(STRIPOFFSETS); TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS); if (!data[0]->getEntry(MODEL)->getString().compare("NIKON D100 ")) { /**Sigh**/ if (!mFile->isValid(offsets->getInt())) ThrowRDE("NEF Decoder: Image data outside of file."); if (!D100IsCompressed(offsets->getInt())) { DecodeD100Uncompressed(); return mRaw; } } if (compression == 1 || (hints.find(string("force_uncompressed")) != hints.end()) || NEFIsUncompressed(raw)) { DecodeUncompressed(); return mRaw; } if (NEFIsUncompressedRGB(raw)) { DecodeSNefUncompressed(); return mRaw; } if (offsets->count != 1) { ThrowRDE("NEF Decoder: Multiple Strips found: %u", offsets->count); } if (counts->count != offsets->count) { ThrowRDE("NEF Decoder: Byte count number does not match strip size: count:%u, strips:%u ", counts->count, offsets->count); } if (!mFile->isValid(offsets->getInt(), counts->getInt())) ThrowRDE("NEF Decoder: Invalid strip byte count. File probably truncated."); if (34713 != compression) ThrowRDE("NEF Decoder: Unsupported compression"); uint32 width = raw->getEntry(IMAGEWIDTH)->getInt(); uint32 height = raw->getEntry(IMAGELENGTH)->getInt(); uint32 bitPerPixel = raw->getEntry(BITSPERSAMPLE)->getInt(); mRaw->dim = iPoint2D(width, height); mRaw->createData(); data = mRootIFD->getIFDsWithTag((TiffTag)0x8c); if (data.empty()) ThrowRDE("NEF Decoder: Decompression info tag not found"); TiffEntry *meta; if (data[0]->hasEntry((TiffTag)0x96)) { meta = data[0]->getEntry((TiffTag)0x96); } else { meta = data[0]->getEntry((TiffTag)0x8c); // Fall back } try { NikonDecompressor decompressor(mFile, mRaw); decompressor.uncorrectedRawValues = uncorrectedRawValues; ByteStream* metastream; if (getHostEndianness() == data[0]->endian) metastream = new ByteStream(meta->getData(), meta->count); else metastream = new ByteStreamSwap(meta->getData(), meta->count); decompressor.DecompressNikon(metastream, width, height, bitPerPixel, offsets->getInt(), counts->getInt()); delete metastream; } catch (IOException &e) { mRaw->setError(e.what()); // Let's ignore it, it may have delivered somewhat useful data. } return mRaw; }
TiffParser::TiffParser(FileMap* inputData): mInput(inputData), mRootIFD(0) { host_endian = getHostEndianness(); }
RawImage Cr2Decoder::decodeRawInternal() { if(hints.find("old_format") != hints.end()) { uint32 off = 0; if (mRootIFD->getEntryRecursive((TiffTag)0x81)) off = mRootIFD->getEntryRecursive((TiffTag)0x81)->getInt(); else { vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(CFAPATTERN); if (data.empty()) ThrowRDE("CR2 Decoder: Couldn't find offset"); else { if (data[0]->hasEntry(STRIPOFFSETS)) off = data[0]->getEntry(STRIPOFFSETS)->getInt(); else ThrowRDE("CR2 Decoder: Couldn't find offset"); } } ByteStream *b; if (getHostEndianness() == big) b = new ByteStream(mFile, off+41); else b = new ByteStreamSwap(mFile, off+41); uint32 height = b->getShort(); uint32 width = b->getShort(); // Every two lines can be encoded as a single line, probably to try and get // better compression by getting the same RGBG sequence in every line if(hints.find("double_line_ljpeg") != hints.end()) { height *= 2; mRaw->dim = iPoint2D(width*2, height/2); } else { width *= 2; mRaw->dim = iPoint2D(width, height); } mRaw->createData(); LJpegPlain *l = new LJpegPlain(mFile, mRaw); try { l->startDecoder(off, mFile->getSize()-off, 0, 0); } catch (IOException& e) { mRaw->setError(e.what()); } delete l; if(hints.find("double_line_ljpeg") != hints.end()) { // We now have a double width half height image we need to convert to the // normal format iPoint2D final_size(width, height); RawImage procRaw = RawImage::create(final_size, TYPE_USHORT16, 1); procRaw->metadata = mRaw->metadata; procRaw->copyErrorsFrom(mRaw); for (uint32 y = 0; y < height; y++) { ushort16 *dst = (ushort16*)procRaw->getData(0,y); ushort16 *src = (ushort16*)mRaw->getData(y%2 == 0 ? 0 : width, y/2); for (uint32 x = 0; x < width; x++) dst[x] = src[x]; } mRaw = procRaw; } if (mRootIFD->getEntryRecursive((TiffTag)0x123)) { TiffEntry *curve = mRootIFD->getEntryRecursive((TiffTag)0x123); if (curve->type == TIFF_SHORT && curve->count == 4096) { TiffEntry *linearization = mRootIFD->getEntryRecursive((TiffTag)0x123); uint32 len = linearization->count; ushort16 *table = new ushort16[len]; linearization->getShortArray(table, len); if (!uncorrectedRawValues) { mRaw->setTable(table, 4096, true); // Apply table mRaw->sixteenBitLookup(); // Delete table mRaw->setTable(NULL); } else { // We want uncorrected, but we store the table. mRaw->setTable(table, 4096, false); } } } return mRaw; } vector<TiffIFD*> data = mRootIFD->getIFDsWithTag((TiffTag)0xc5d8); if (data.empty()) ThrowRDE("CR2 Decoder: No image data found"); TiffIFD* raw = data[0]; mRaw = RawImage::create(); mRaw->isCFA = true; vector<Cr2Slice> slices; int completeH = 0; bool doubleHeight = false; try { TiffEntry *offsets = raw->getEntry(STRIPOFFSETS); TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS); // Iterate through all slices for (uint32 s = 0; s < offsets->count; s++) { Cr2Slice slice; slice.offset = offsets[0].getInt(); slice.count = counts[0].getInt(); SOFInfo sof; LJpegPlain *l = new LJpegPlain(mFile, mRaw); l->getSOF(&sof, slice.offset, slice.count); delete l; slice.w = sof.w * sof.cps; slice.h = sof.h; if (sof.cps == 4 && slice.w > slice.h * 4) { doubleHeight = true; } if (!slices.empty()) if (slices[0].w != slice.w) ThrowRDE("CR2 Decoder: Slice width does not match."); if (mFile->isValid(slice.offset, slice.count)) // Only decode if size is valid slices.push_back(slice); completeH += slice.h; } } catch (TiffParserException) { ThrowRDE("CR2 Decoder: Unsupported format."); } // Override with canon_double_height if set. map<string,string>::iterator msb_hint = hints.find("canon_double_height"); if (msb_hint != hints.end()) doubleHeight = (0 == (msb_hint->second).compare("true")); if (slices.empty()) { ThrowRDE("CR2 Decoder: No Slices found."); } mRaw->dim = iPoint2D(slices[0].w, completeH); // Fix for Canon 6D mRaw, which has flipped width & height for some part of the image // In that case, we swap width and height, since this is the correct dimension bool flipDims = false; bool wrappedCr2Slices = false; if (raw->hasEntry((TiffTag)0xc6c5)) { ushort16 ss = raw->getEntry((TiffTag)0xc6c5)->getInt(); // sRaw if (ss == 4) { mRaw->dim.x /= 3; mRaw->setCpp(3); mRaw->isCFA = false; // Fix for Canon 80D mraw format. // In that format, the frame (as read by getSOF()) is 4032x3402, while the // real image should be 4536x3024 (where the full vertical slices in // the frame "wrap around" the image. if (hints.find("wrapped_cr2_slices") != hints.end() && raw->hasEntry(IMAGEWIDTH) && raw->hasEntry(IMAGELENGTH)) { wrappedCr2Slices = true; int w = raw->getEntry(IMAGEWIDTH)->getInt(); int h = raw->getEntry(IMAGELENGTH)->getInt(); if (w * h != mRaw->dim.x * mRaw->dim.y) { ThrowRDE("CR2 Decoder: Wrapped slices don't match image size"); } mRaw->dim = iPoint2D(w, h); } } flipDims = mRaw->dim.x < mRaw->dim.y; if (flipDims) { int w = mRaw->dim.x; mRaw->dim.x = mRaw->dim.y; mRaw->dim.y = w; } } mRaw->createData(); vector<int> s_width; if (raw->hasEntry(CANONCR2SLICE)) { TiffEntry *ss = raw->getEntry(CANONCR2SLICE); for (int i = 0; i < ss->getShort(0); i++) { s_width.push_back(ss->getShort(1)); } s_width.push_back(ss->getShort(2)); } else { s_width.push_back(slices[0].w); } uint32 offY = 0; if (s_width.size() > 15) ThrowRDE("CR2 Decoder: No more than 15 slices supported"); _RPT1(0,"Org slices:%d\n", s_width.size()); for (uint32 i = 0; i < slices.size(); i++) { Cr2Slice slice = slices[i]; try { LJpegPlain *l = new LJpegPlain(mFile, mRaw); l->addSlices(s_width); l->mUseBigtable = true; l->mCanonFlipDim = flipDims; l->mCanonDoubleHeight = doubleHeight; l->mWrappedCr2Slices = wrappedCr2Slices; l->startDecoder(slice.offset, slice.count, 0, offY); delete l; } catch (RawDecoderException &e) { if (i == 0) throw; // These may just be single slice error - store the error and move on mRaw->setError(e.what()); } catch (IOException &e) { // Let's try to ignore this - it might be truncated data, so something might be useful. mRaw->setError(e.what()); } offY += slice.w; } if (mRaw->metadata.subsampling.x > 1 || mRaw->metadata.subsampling.y > 1) sRawInterpolate(); return mRaw; }
RawImage NefDecoder::decodeRawInternal() { vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(CFAPATTERN); if (data.empty()) ThrowRDE("NEF Decoder: No image data found"); TiffIFD* raw = data[0]; int compression = raw->getEntry(COMPRESSION)->getInt(); data = mRootIFD->getIFDsWithTag(MODEL); if (data.empty()) ThrowRDE("NEF Decoder: No model data found"); TiffEntry *offsets = raw->getEntry(STRIPOFFSETS); TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS); if (!data[0]->getEntry(MODEL)->getString().compare("NIKON D100 ")) { /**Sigh**/ if (!mFile->isValid(offsets->getInt())) ThrowRDE("NEF Decoder: Image data outside of file."); if (!D100IsCompressed(offsets->getInt())) { DecodeD100Uncompressed(); return mRaw; } } if (compression == 1) { DecodeUncompressed(); return mRaw; } if (offsets->count != 1) { ThrowRDE("NEF Decoder: Multiple Strips found: %u", offsets->count); } if (counts->count != offsets->count) { ThrowRDE("NEF Decoder: Byte count number does not match strip size: count:%u, strips:%u ", counts->count, offsets->count); } if (!mFile->isValid(offsets->getInt() + counts->getInt())) ThrowRDE("NEF Decoder: Invalid strip byte count. File probably truncated."); if (34713 != compression) ThrowRDE("NEF Decoder: Unsupported compression"); uint32 width = raw->getEntry(IMAGEWIDTH)->getInt(); uint32 height = raw->getEntry(IMAGELENGTH)->getInt(); uint32 bitPerPixel = raw->getEntry(BITSPERSAMPLE)->getInt(); mRaw->dim = iPoint2D(width, height); mRaw->createData(); data = mRootIFD->getIFDsWithTag(MAKERNOTE); if (data.empty()) ThrowRDE("NEF Decoder: No EXIF data found"); TiffIFD* exif = data[0]; TiffEntry *makernoteEntry = exif->getEntry(MAKERNOTE); const uchar8* makernote = makernoteEntry->getData(); FileMap makermap((uchar8*)&makernote[10], mFile->getSize() - makernoteEntry->getDataOffset() - 10); TiffParser makertiff(&makermap); makertiff.parseData(); data = makertiff.RootIFD()->getIFDsWithTag((TiffTag)0x8c); if (data.empty()) ThrowRDE("NEF Decoder: Decompression info tag not found"); TiffEntry *meta; try { meta = data[0]->getEntry((TiffTag)0x96); } catch (TiffParserException) { meta = data[0]->getEntry((TiffTag)0x8c); // Fall back } try { NikonDecompressor decompressor(mFile, mRaw); ByteStream* metastream; if (getHostEndianness() == data[0]->endian) metastream = new ByteStream(meta->getData(), meta->count); else metastream = new ByteStreamSwap(meta->getData(), meta->count); decompressor.DecompressNikon(metastream, width, height, bitPerPixel, offsets->getInt(), counts->getInt()); delete metastream; } catch (IOException &e) { mRaw->setError(e.what()); // Let's ignore it, it may have delivered somewhat useful data. } return mRaw; }