void PefDecoder::decodeMetaDataInternal(const CameraMetaData* meta) { int iso = 0; mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN, CFA_BLUE); if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS)) iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32(); setMetaData(meta, "", iso); // Read black level if (mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0x200))) { TiffEntry* black = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x200)); if (black->count == 4) { for (int i = 0; i < 4; i++) mRaw->blackLevelSeparate[i] = black->getU32(i); } } // Set the whitebalance if (mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0x0201))) { TiffEntry* wb = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x0201)); if (wb->count == 4) { mRaw->metadata.wbCoeffs[0] = wb->getU32(0); mRaw->metadata.wbCoeffs[1] = wb->getU32(1); mRaw->metadata.wbCoeffs[2] = wb->getU32(3); } } }
RawImage CrwDecoder::decodeRawInternal() { CiffEntry *sensorInfo = mRootIFD->getEntryRecursive(CIFF_SENSORINFO); if (!sensorInfo || sensorInfo->count < 6 || sensorInfo->type != CIFF_SHORT) ThrowRDE("CRW: Couldn't find image sensor info"); uint32 width = sensorInfo->getShort(1); uint32 height = sensorInfo->getShort(2); CiffEntry *decTable = mRootIFD->getEntryRecursive(CIFF_DECODERTABLE); if (!decTable || decTable->type != CIFF_LONG) ThrowRDE("CRW: Couldn't find decoder table"); uint32 dec_table = decTable->getInt(); if (dec_table > 2) ThrowRDE("CRW: Unknown decoder table %d", dec_table); mRaw->dim = iPoint2D(width, height); mRaw->createData(); bool lowbits = hints.find("no_decompressed_lowbits") == hints.end(); decodeRaw(lowbits, dec_table, width, height); return mRaw; }
RawImage KdcDecoder::decodeRawInternal() { int compression = mRootIFD->getEntryRecursive(COMPRESSION)->getInt(); if (7 != compression) ThrowRDE("KDC Decoder: Unsupported compression %d", compression); TiffEntry *ex = mRootIFD->getEntryRecursive(PIXELXDIMENSION); TiffEntry *ey = mRootIFD->getEntryRecursive(PIXELYDIMENSION); if (NULL == ex || NULL == ey) ThrowRDE("KDC Decoder: Unable to retrieve image size"); uint32 width = ex->getInt(); uint32 height = ey->getInt(); TiffEntry *offset = mRootIFD->getEntryRecursive(KODAK_KDC_OFFSET); if (!offset || offset->count < 13) ThrowRDE("KDC Decoder: Couldn't find the KDC offset"); const uint32 *offsetarray = offset->getIntArray(); uint32 off = offsetarray[4] + offsetarray[12]; mRaw->dim = iPoint2D(width, height); mRaw->createData(); ByteStream input(mFile->getData(off), mFile->getSize()-off); Decode12BitRawBE(input, width, height); return mRaw; }
RawImage MrwDecoder::decodeRawInternal() { uint32 imgsize; mRaw->dim = iPoint2D(raw_width, raw_height); mRaw->createData(); if (packed) imgsize = raw_width * raw_height * 3 / 2; else imgsize = raw_width * raw_height * 2; if (!mFile->isValid(data_offset)) ThrowRDE("MRW decoder: Data offset after EOF, file probably truncated"); if (!mFile->isValid(data_offset+imgsize-1)) ThrowRDE("MRW decoder: Image end after EOF, file probably truncated"); ByteStream input(mFile->getData(data_offset), imgsize); try { if (packed) Decode12BitRawBE(input, raw_width, raw_height); else Decode12BitRawBEunpacked(input, raw_width, raw_height); } catch (IOException &e) { mRaw->setError(e.what()); // Let's ignore it, it may have delivered somewhat useful data. } return mRaw; }
RawImage AriDecoder::decodeRawInternal() { mRaw->dim = iPoint2D(mWidth, mHeight); mRaw->createData(); startThreads(); mRaw->whitePoint = 4095; return mRaw; }
RawImage MosDecoder::decodeRawInternal() { vector<TiffIFD*> data; TiffIFD* raw = NULL; uint32 off = 0; uint32 base = 8; // We get a pointer up to the end of the file as we check offset bounds later const uchar8 *insideTiff = mFile->getData(base, mFile->getSize()-base); if (get4LE(insideTiff, 0) == 0x49494949) { uint32 offset = get4LE(insideTiff, 8); if (offset+base+4 > mFile->getSize()) ThrowRDE("MOS: PhaseOneC offset out of bounds"); uint32 entries = get4LE(insideTiff, offset); uint32 pos = 8; // Skip another 4 bytes uint32 width=0, height=0, strip_offset=0, data_offset=0, wb_offset=0; while (entries--) { if (offset+base+pos+16 > mFile->getSize()) ThrowRDE("MOS: PhaseOneC offset out of bounds"); uint32 tag = get4LE(insideTiff, offset+pos); //uint32 type = get4LE(insideTiff, offset+pos+4); //uint32 len = get4LE(insideTiff, offset+pos+8); uint32 data = get4LE(insideTiff, offset+pos+12); pos += 16; switch(tag) { case 0x107: wb_offset = data+base; break; case 0x108: width = data; break; case 0x109: height = data; break; case 0x10f: data_offset = data+base; break; case 0x21c: strip_offset = data+base; break; case 0x21d: black_level = data>>2; break; } } if (width <= 0 || height <= 0) ThrowRDE("MOS: PhaseOneC couldn't find width and height"); if (strip_offset+height*4 > mFile->getSize()) ThrowRDE("MOS: PhaseOneC strip offsets out of bounds"); if (data_offset > mFile->getSize()) ThrowRDE("MOS: PhaseOneC data offset out of bounds"); mRaw->dim = iPoint2D(width, height); mRaw->createData(); DecodePhaseOneC(data_offset, strip_offset, width, height); const uchar8 *data = mFile->getData(wb_offset, 12); for(int i=0; i<3; i++) { // Use get4LE instead of going straight to float so this is endian clean uint32 value = get4LE(data, i*4); mRaw->metadata.wbCoeffs[i] = *((float *) &value); } return mRaw; } else {
RawImage NakedDecoder::decodeRawInternal() { mRaw->dim = iPoint2D(width, height); mRaw->createData(); ByteStream input(mFile->getData(offset), mFile->getSize()-offset); iPoint2D pos(0, 0); readUncompressedRaw(input, mRaw->dim, pos, width*bits/8, bits, BitOrder_Jpeg16); return mRaw; }
void AriDecoder::decodeMetaDataInternal(CameraMetaData *meta) { mRaw->cfa.setCFA(iPoint2D(2,2), CFA_GREEN, CFA_RED, CFA_BLUE, CFA_GREEN2); mRaw->metadata.wbCoeffs[0] = mWB[0]; mRaw->metadata.wbCoeffs[1] = mWB[1]; mRaw->metadata.wbCoeffs[2] = mWB[2]; if (meta->hasCamera("ARRI", mModel, mEncoder)) { setMetaData(meta, "ARRI", mModel, mEncoder, mIso); } else { setMetaData(meta, "ARRI", mModel, "", mIso); } }
RawImage NakedDecoder::decodeRawInternal() { uint32 width=0, height=0, filesize=0, bits=0, offset=0; if(cam->hints.find("full_width") != cam->hints.end()) { string tmp = cam->hints.find(string("full_width"))->second; width = (uint32) atoi(tmp.c_str()); } else ThrowRDE("Naked: couldn't find width"); if(cam->hints.find("full_height") != cam->hints.end()) { string tmp = cam->hints.find(string("full_height"))->second; height = (uint32) atoi(tmp.c_str()); } else ThrowRDE("Naked: couldn't find height"); if(cam->hints.find("filesize") != cam->hints.end()) { string tmp = cam->hints.find(string("filesize"))->second; filesize = (uint32) atoi(tmp.c_str()); } else ThrowRDE("Naked: couldn't find filesize"); if(cam->hints.find("offset") != cam->hints.end()) { string tmp = cam->hints.find(string("offset"))->second; offset = (uint32) atoi(tmp.c_str()); } if(cam->hints.find("bits") != cam->hints.end()) { string tmp = cam->hints.find(string("bits"))->second; bits = (uint32) atoi(tmp.c_str()); } else bits = (filesize-offset)*8/width/height; BitOrder bo = BitOrder_Jpeg16; // Default if(cam->hints.find("order") != cam->hints.end()) { string tmp = cam->hints.find(string("order"))->second; if (tmp.compare("plain") == 0) { bo = BitOrder_Plain; } else if (tmp.compare("jpeg") == 0) { bo = BitOrder_Jpeg; } else if (tmp.compare("jpeg16") == 0) { bo = BitOrder_Jpeg16; } else if (tmp.compare("jpeg32") == 0) { bo = BitOrder_Jpeg32; } } mRaw->dim = iPoint2D(width, height); mRaw->createData(); ByteStream input(mFile->getData(offset), mFile->getSize()-offset); iPoint2D pos(0, 0); readUncompressedRaw(input, mRaw->dim, pos, width*bits/8, bits, bo); return mRaw; }
void CrwDecoder::decodeMetaDataInternal(CameraMetaData *meta) { int iso = 0; mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN2, CFA_BLUE); vector<CiffIFD*> data = mRootIFD->getIFDsWithTag(CIFF_MAKEMODEL); if (data.empty()) ThrowRDE("CRW Support check: Model name not found"); vector<string> makemodel = data[0]->getEntry(CIFF_MAKEMODEL)->getStrings(); if (makemodel.size() < 2) ThrowRDE("CRW Support check: wrong number of strings for make/model"); string make = makemodel[0]; string model = makemodel[1]; string mode = ""; if (mRootIFD->hasEntryRecursive(CIFF_SHOTINFO)) { CiffEntry *shot_info = mRootIFD->getEntryRecursive(CIFF_SHOTINFO); if (shot_info->type == CIFF_SHORT && shot_info->count >= 2) { // os << exp(canonEv(value.toLong()) * log(2.0)) * 100.0 / 32.0; ushort16 iso_index = shot_info->getShort(2); iso = expf(canonEv((long)iso_index) * logf(2.0)) * 100.0f / 32.0f; } } // Fetch the white balance try { if(mRootIFD->hasEntryRecursive((CiffTag)0x0032)) { CiffEntry *wb = mRootIFD->getEntryRecursive((CiffTag)0x0032); if (wb->type == CIFF_BYTE && wb->count == 768) { // We're in a D30 file, values are RGGB // This will probably not get used anyway as a 0x102c tag should exist mRaw->metadata.wbCoeffs[0] = (float) (1024.0 /wb->getByte(72)); mRaw->metadata.wbCoeffs[1] = (float) ((1024.0/wb->getByte(73))+(1024.0/wb->getByte(74)))/2.0f; mRaw->metadata.wbCoeffs[2] = (float) (1024.0 /wb->getByte(75)); } else if (wb->type == CIFF_BYTE && wb->count > 768) { // Other G series and S series cameras // correct offset for most cameras int offset = 120; // check for the hint that we need to use other offset if (hints.find("wb_offset") != hints.end()) { stringstream wb_offset(hints.find("wb_offset")->second); wb_offset >> offset; } ushort16 key[] = { 0x410, 0x45f3 }; if (hints.find("wb_mangle") == hints.end()) key[0] = key[1] = 0; offset /= 2; mRaw->metadata.wbCoeffs[0] = (float) (wb->getShort(offset+1) ^ key[1]); mRaw->metadata.wbCoeffs[1] = (float) (wb->getShort(offset+0) ^ key[0]); mRaw->metadata.wbCoeffs[2] = (float) (wb->getShort(offset+2) ^ key[0]); }
void Camera::parseCFA(xmlDocPtr doc, xmlNodePtr cur) { xmlChar *key; if (!xmlStrcmp(cur->name, (const xmlChar *) "Color")) { int x = getAttributeAsInt(cur, cur->name, "x"); if (x < 0 || x > 1) { ThrowCME("Invalid x coordinate in CFA array of in camera %s %s", make.c_str(), model.c_str()); } int y = getAttributeAsInt(cur, cur->name, "y"); if (y < 0 || y > 1) { ThrowCME("Invalid y coordinate in CFA array of in camera %s %s", make.c_str(), model.c_str()); } key = xmlNodeListGetString(doc, cur->children, 1); if (!xmlStrcmp(key, (const xmlChar *) "GREEN")) cfa.setColorAt(iPoint2D(x, y), CFA_GREEN); else if (!xmlStrcmp(key, (const xmlChar *) "RED")) cfa.setColorAt(iPoint2D(x, y), CFA_RED); else if (!xmlStrcmp(key, (const xmlChar *) "BLUE")) cfa.setColorAt(iPoint2D(x, y), CFA_BLUE); xmlFree(key); } }
void SrwDecoder::decodeMetaDataInternal(CameraMetaData *meta) { mRaw->cfa.setCFA(CFA_RED, CFA_GREEN, CFA_GREEN2, CFA_BLUE); vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL); if (data.empty()) ThrowRDE("SRW Meta Decoder: Model name found"); string make = data[0]->getEntry(MAKE)->getString(); string model = data[0]->getEntry(MODEL)->getString(); data = mRootIFD->getIFDsWithTag(CFAPATTERN); if (!this->checkCameraSupported(meta, make, model, "") && !data.empty() && data[0]->hasEntry(CFAREPEATPATTERNDIM)) { const unsigned short* pDim = data[0]->getEntry(CFAREPEATPATTERNDIM)->getShortArray(); iPoint2D cfaSize(pDim[1], pDim[0]); if (cfaSize.x != 2 && cfaSize.y != 2) ThrowRDE("SRW Decoder: Unsupported CFA pattern size"); const uchar8* cPat = data[0]->getEntry(CFAPATTERN)->getData(); if (cfaSize.area() != data[0]->getEntry(CFAPATTERN)->count) ThrowRDE("SRW Decoder: CFA pattern dimension and pattern count does not match: %d."); for (int y = 0; y < cfaSize.y; y++) { for (int x = 0; x < cfaSize.x; x++) { uint32 c1 = cPat[x+y*cfaSize.x]; CFAColor c2; switch (c1) { case 0: c2 = CFA_RED; break; case 1: c2 = CFA_GREEN; break; case 2: c2 = CFA_BLUE; break; default: c2 = CFA_UNKNOWN; ThrowRDE("SRW Decoder: Unsupported CFA Color."); } mRaw->cfa.setColorAt(iPoint2D(x, y), c2); } } printf("Camera CFA: %s\n", mRaw->cfa.asString().c_str()); } int iso = 0; if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS)) iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getInt(); setMetaData(meta, make, model, "", iso); }
RawImage PefDecoder::decodeRawInternal() { vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(STRIPOFFSETS); if (data.empty()) ThrowRDE("PEF Decoder: No image data found"); TiffIFD* raw = data[0]; int compression = raw->getEntry(COMPRESSION)->getInt(); if (1 == compression) { decodeUncompressed(raw, true); return mRaw; } if (65535 != compression) ThrowRDE("PEF Decoder: Unsupported compression"); TiffEntry *offsets = raw->getEntry(STRIPOFFSETS); TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS); if (offsets->count != 1) { ThrowRDE("PEF Decoder: Multiple Strips found: %u", offsets->count); } if (counts->count != offsets->count) { ThrowRDE("PEF 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("PEF Decoder: Truncated file."); uint32 width = raw->getEntry(IMAGEWIDTH)->getInt(); uint32 height = raw->getEntry(IMAGELENGTH)->getInt(); mRaw->dim = iPoint2D(width, height); mRaw->createData(); try { PentaxDecompressor l(mFile, mRaw); l.decodePentax(mRootIFD, offsets->getInt(), counts->getInt()); } catch (IOException &e) { errors.push_back(_strdup(e.what())); // Let's ignore it, it may have delivered somewhat useful data. } return mRaw; }
RawImage PefDecoder::decodeRawInternal() { auto raw = mRootIFD->getIFDWithTag(STRIPOFFSETS); int compression = raw->getEntry(COMPRESSION)->getU32(); if (1 == compression || compression == 32773) { decodeUncompressed(raw, BitOrder_MSB); return mRaw; } if (65535 != compression) ThrowRDE("Unsupported compression"); TiffEntry *offsets = raw->getEntry(STRIPOFFSETS); TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS); if (offsets->count != 1) { ThrowRDE("Multiple Strips found: %u", offsets->count); } if (counts->count != offsets->count) { ThrowRDE( "Byte count number does not match strip size: count:%u, strips:%u ", counts->count, offsets->count); } if (!mFile->isValid(offsets->getU32(), counts->getU32())) ThrowRDE("Truncated file."); uint32 width = raw->getEntry(IMAGEWIDTH)->getU32(); uint32 height = raw->getEntry(IMAGELENGTH)->getU32(); mRaw->dim = iPoint2D(width, height); mRaw->createData(); try { PentaxDecompressor::decompress( mRaw, ByteStream(mFile, offsets->getU32(), counts->getU32()), getRootIFD()); } catch (IOException &e) { mRaw->setError(e.what()); // Let's ignore it, it may have delivered somewhat useful data. } return mRaw; }
void NefDecoder::DecodeUncompressed() { vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(CFAPATTERN); TiffIFD* raw = FindBestImage(&data); uint32 nslices = raw->getEntry(STRIPOFFSETS)->count; const uint32 *offsets = raw->getEntry(STRIPOFFSETS)->getIntArray(); const uint32 *counts = raw->getEntry(STRIPBYTECOUNTS)->getIntArray(); uint32 yPerSlice = raw->getEntry(ROWSPERSTRIP)->getInt(); uint32 width = raw->getEntry(IMAGEWIDTH)->getInt(); uint32 height = raw->getEntry(IMAGELENGTH)->getInt(); uint32 bitPerPixel = raw->getEntry(BITSPERSAMPLE)->getInt(); vector<NefSlice> slices; uint32 offY = 0; for (uint32 s = 0; s < nslices; s++) { NefSlice slice; slice.offset = offsets[s]; slice.count = counts[s]; if (offY + yPerSlice > height) slice.h = height - offY; else slice.h = yPerSlice; offY = MIN(height, offY + yPerSlice); if (mFile->isValid(slice.offset, slice.count)) // Only decode if size is valid slices.push_back(slice); } if (0 == slices.size()) ThrowRDE("NEF Decoder: No valid slices found. File probably truncated."); mRaw->dim = iPoint2D(width, offY); mRaw->createData(); if (bitPerPixel == 14 && width*slices[0].h*2 == slices[0].count) bitPerPixel = 16; // D3 & D810 if(hints.find("real_bpp") != hints.end()) { stringstream convert(hints.find("real_bpp")->second); convert >> bitPerPixel; }
RawImage ThreefrDecoder::decodeRawInternal() { vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(STRIPOFFSETS); if (data.size() < 2) ThrowRDE("3FR Decoder: No image data found"); TiffIFD* raw = data[1]; uint32 width = raw->getEntry(IMAGEWIDTH)->getInt(); uint32 height = raw->getEntry(IMAGELENGTH)->getInt(); uint32 off = raw->getEntry(STRIPOFFSETS)->getInt(); mRaw->dim = iPoint2D(width, height); mRaw->createData(); ByteStream input(mFile->getData(off), mFile->getSize() - off); HasselbladDecompressor l(mFile, mRaw); map<string,string>::iterator pixelOffset = hints.find("pixelBaseOffset"); if (pixelOffset != hints.end()) { stringstream convert((*pixelOffset).second); convert >> l.pixelBaseOffset; }
void Cr2Decoder::decodeMetaDataInternal(CameraMetaData *meta) { int iso = 0; mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN2, CFA_BLUE); vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL); if (data.empty()) ThrowRDE("CR2 Meta Decoder: Model name not found"); string make = data[0]->getEntry(MAKE)->getString(); string model = data[0]->getEntry(MODEL)->getString(); string mode = ""; if (mRaw->metadata.subsampling.y == 2 && mRaw->metadata.subsampling.x == 2) mode = "sRaw1"; if (mRaw->metadata.subsampling.y == 1 && mRaw->metadata.subsampling.x == 2) mode = "sRaw2"; if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS)) iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getInt(); // Fetch the white balance try{ if (mRootIFD->hasEntryRecursive(CANONCOLORDATA)) { TiffEntry *wb = mRootIFD->getEntryRecursive(CANONCOLORDATA); // this entry is a big table, and different cameras store used WB in // different parts, so find the offset, starting with the most common one int offset = 126; // replace it with a hint if it exists if (hints.find("wb_offset") != hints.end()) { stringstream wb_offset(hints.find("wb_offset")->second); wb_offset >> offset; } offset /= 2; mRaw->metadata.wbCoeffs[0] = (float) wb->getShort(offset + 0); mRaw->metadata.wbCoeffs[1] = (float) wb->getShort(offset + 1); mRaw->metadata.wbCoeffs[2] = (float) wb->getShort(offset + 3); } else {
RawImage KdcDecoder::decodeRawInternal() { if (!mRootIFD->hasEntryRecursive(COMPRESSION)) ThrowRDE("KDC Decoder: Couldn't find compression setting"); int compression = mRootIFD->getEntryRecursive(COMPRESSION)->getInt(); if (7 != compression) ThrowRDE("KDC Decoder: Unsupported compression %d", compression); uint32 width = 0; uint32 height = 0; TiffEntry *ew = mRootIFD->getEntryRecursive(KODAK_KDC_WIDTH); TiffEntry *eh = mRootIFD->getEntryRecursive(KODAK_KDC_HEIGHT); if (ew && eh) { width = ew->getInt()+80; height = eh->getInt()+70; } else ThrowRDE("KDC Decoder: Unable to retrieve image size"); TiffEntry *offset = mRootIFD->getEntryRecursive(KODAK_KDC_OFFSET); if (!offset || offset->count < 13) ThrowRDE("KDC Decoder: Couldn't find the KDC offset"); const uint32 *offsetarray = offset->getIntArray(); uint32 off = offsetarray[4] + offsetarray[12]; // Offset hardcoding gotten from dcraw if (hints.find("easyshare_offset_hack") != hints.end()) off = off < 0x15000 ? 0x15000 : 0x17000; if (off > mFile->getSize()) ThrowRDE("KDC Decoder: offset is out of bounds"); mRaw->dim = iPoint2D(width, height); mRaw->createData(); ByteStream input(mFile, off); Decode12BitRawBE(input, width, height); return mRaw; }
void PefDecoder::decodeMetaDataInternal(CameraMetaData *meta) { int iso = 0; mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN2, CFA_BLUE); vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL); if (data.empty()) ThrowRDE("PEF Meta Decoder: Model name found"); TiffIFD* raw = data[0]; string make = raw->getEntry(MAKE)->getString(); string model = raw->getEntry(MODEL)->getString(); if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS)) iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getInt(); setMetaData(meta, make, model, "", iso); // Read black level if (mRootIFD->hasEntryRecursive((TiffTag)0x200)) { TiffEntry *black = mRootIFD->getEntryRecursive((TiffTag)0x200); const ushort16 *levels = black->getShortArray(); for (int i = 0; i < 4; i++) mRaw->blackLevelSeparate[i] = levels[i]; } // Set the whitebalance if (mRootIFD->hasEntryRecursive((TiffTag) 0x0201)) { TiffEntry *wb = mRootIFD->getEntryRecursive((TiffTag) 0x0201); if (wb->count == 4) { const ushort16 *tmp = wb->getShortArray(); mRaw->metadata.wbCoeffs[0] = tmp[0]; mRaw->metadata.wbCoeffs[1] = tmp[1]; mRaw->metadata.wbCoeffs[2] = tmp[3]; } } }
void Cr2Decoder::decodeMetaDataInternal(CameraMetaData *meta) { int iso = 0; mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN2, CFA_BLUE); vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL); if (data.empty()) ThrowRDE("CR2 Meta Decoder: Model name not found"); string make = data[0]->getEntry(MAKE)->getString(); string model = data[0]->getEntry(MODEL)->getString(); string mode = ""; if (mRaw->metadata.subsampling.y == 2 && mRaw->metadata.subsampling.x == 2) mode = "sRaw1"; if (mRaw->metadata.subsampling.y == 1 && mRaw->metadata.subsampling.x == 2) mode = "sRaw2"; if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS)) iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getInt(); // Fetch the white balance if (mRootIFD->hasEntryRecursive(CANONCOLORDATA)) { TiffEntry *color_data = mRootIFD->getEntryRecursive(CANONCOLORDATA); // this entry is a big table, and different cameras store used WB in // different parts, so find the offset // correct offset for most cameras int offset = 126; // check for the hint that we need to use other offset if (hints.find("wb_offset") != hints.end()) { stringstream wb_offset(hints.find("wb_offset")->second); wb_offset >> offset; }
void LJpegPlain::decodeScanLeft4Comps() { // First line HuffmanTable *dctbl1 = &huff[frame.compInfo[0].dcTblNo]; HuffmanTable *dctbl2 = &huff[frame.compInfo[1].dcTblNo]; HuffmanTable *dctbl3 = &huff[frame.compInfo[2].dcTblNo]; HuffmanTable *dctbl4 = &huff[frame.compInfo[3].dcTblNo]; if (mCanonDoubleHeight) { frame.h *= 2; mRaw->dim = iPoint2D(frame.w * 2, frame.h); mRaw->destroyData(); mRaw->createData(); } uchar8 *draw = mRaw->getData(); //Prepare slices (for CR2) uint32 slices = (uint32)slicesW.size() * (frame.h - skipY); offset = new uint32[slices+1]; uint32 t_y = 0; uint32 t_x = 0; uint32 t_s = 0; uint32 slice = 0; for (slice = 0; slice < slices; slice++) { offset[slice] = ((t_x + offX) * mRaw->getBpp() + ((offY + t_y) * mRaw->pitch)) | (t_s << 28); _ASSERTE((offset[slice]&0x0fffffff) < mRaw->pitch*mRaw->dim.y); t_y++; if (t_y == (frame.h - skipY)) { t_y = 0; t_x += slicesW[t_s++]; } } // We check the final position. If bad slice sizes are given we risk writing outside the image if ((offset[slices-1]&0x0fffffff) >= mRaw->pitch*mRaw->dim.y) { ThrowRDE("LJpegPlain::decodeScanLeft: Last slice out of bounds"); } offset[slices] = offset[slices-1]; // Extra offset to avoid branch in loop. slice_width = new int[slices]; // This is divided by comps, since comps pixels are processed at the time for (uint32 i = 0 ; i < slicesW.size(); i++) slice_width[i] = slicesW[i] / COMPS; if (skipX) slice_width[slicesW.size()-1] -= skipX; // First pixels are obviously not predicted int p1; int p2; int p3; int p4; ushort16 *dest = (ushort16*) & draw[offset[0] & 0x0fffffff]; ushort16 *predict = dest; *dest++ = p1 = (1 << (frame.prec - Pt - 1)) + HuffDecode(dctbl1); *dest++ = p2 = (1 << (frame.prec - Pt - 1)) + HuffDecode(dctbl2); *dest++ = p3 = (1 << (frame.prec - Pt - 1)) + HuffDecode(dctbl3); *dest++ = p4 = (1 << (frame.prec - Pt - 1)) + HuffDecode(dctbl4); slice = 1; uint32 pixInSlice = slice_width[0] - 1; uint32 cw = (frame.w - skipX); uint32 x = 1; // Skip first pixels on first line. if (mCanonDoubleHeight) skipY = frame.h >> 1; uint32 ch = (frame.h - skipY); // Fix for Canon 80D mraw format. // In that format, `frame` is 4032x3402, while `mRaw` is 4536x3024. // Consequently, the slices in `frame` wrap around (this is taken care of by // `offset`) and must be decoded fully (without skipY) to fill the image if (mWrappedCr2Slices) ch = frame.h; for (uint32 y = 0;y < ch;y++) { for (; x < cw ; x++) { p1 += HuffDecode(dctbl1); *dest++ = (ushort16)p1; p2 += HuffDecode(dctbl2); *dest++ = (ushort16)p2; p3 += HuffDecode(dctbl3); *dest++ = (ushort16)p3; p4 += HuffDecode(dctbl4); *dest++ = (ushort16)p4; if (0 == --pixInSlice) { // Next slice if (slice > slices) ThrowRDE("LJpegPlain::decodeScanLeft: Ran out of slices"); uint32 o = offset[slice++]; dest = (ushort16*) & draw[o&0x0fffffff]; // Adjust destination for next pixel if((o&0x0fffffff) > mRaw->pitch*mRaw->dim.y) ThrowRDE("LJpegPlain::decodeScanLeft: Offset out of bounds"); pixInSlice = slice_width[o>>28]; } } if (skipX) { for (uint32 i = 0; i < skipX; i++) { HuffDecode(dctbl1); HuffDecode(dctbl2); HuffDecode(dctbl3); HuffDecode(dctbl4); } } bits->checkPos(); p1 = predict[0]; // Predictors for next row p2 = predict[1]; p3 = predict[2]; // Predictors for next row p4 = predict[3]; predict = dest; // Adjust destination for next prediction x = 0; } }
RawImage Rw2Decoder::decodeRawInternal() { vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(PANASONIC_STRIPOFFSET); bool isOldPanasonic = FALSE; if (data.empty()) { if (!mRootIFD->hasEntryRecursive(STRIPOFFSETS)) ThrowRDE("RW2 Decoder: No image data found"); isOldPanasonic = TRUE; data = mRootIFD->getIFDsWithTag(STRIPOFFSETS); } TiffIFD* raw = data[0]; uint32 height = raw->getEntry((TiffTag)3)->getShort(); uint32 width = raw->getEntry((TiffTag)2)->getShort(); if (isOldPanasonic) { ThrowRDE("Cannot decode old-style Panasonic RAW files"); TiffEntry *offsets = raw->getEntry(STRIPOFFSETS); TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS); if (offsets->count != 1) { ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count); } int off = offsets->getInt(); if (!mFile->isValid(off)) ThrowRDE("Panasonic RAW Decoder: Invalid image data offset, cannot decode."); int count = counts->getInt(); if (count != (int)(width*height*2)) ThrowRDE("Panasonic RAW Decoder: Byte count is wrong."); if (!mFile->isValid(off+count)) ThrowRDE("Panasonic RAW Decoder: Invalid image data offset, cannot decode."); mRaw->dim = iPoint2D(width, height); mRaw->createData(); ByteStream input_start(mFile->getData(off), mFile->getSize() - off); iPoint2D pos(0, 0); readUncompressedRaw(input_start, mRaw->dim,pos, width*2, 16, BitOrder_Plain); } else { mRaw->dim = iPoint2D(width, height); mRaw->createData(); TiffEntry *offsets = raw->getEntry(PANASONIC_STRIPOFFSET); if (offsets->count != 1) { ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count); } load_flags = 0x2008; int off = offsets->getInt(); if (!mFile->isValid(off)) ThrowRDE("RW2 Decoder: Invalid image data offset, cannot decode."); input_start = new ByteStream(mFile->getData(off), mFile->getSize() - off); DecodeRw2(); } // Read blacklevels if (raw->hasEntry((TiffTag)0x1c) && raw->hasEntry((TiffTag)0x1d) && raw->hasEntry((TiffTag)0x1e)) { mRaw->blackLevelSeparate[0] = raw->getEntry((TiffTag)0x1c)->getInt() + 15; mRaw->blackLevelSeparate[1] = mRaw->blackLevelSeparate[2] = raw->getEntry((TiffTag)0x1d)->getInt() + 15; mRaw->blackLevelSeparate[3] = raw->getEntry((TiffTag)0x1e)->getInt() + 15; } 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 || (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; }
void NefDecoder::DecodeUncompressed() { vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(CFAPATTERN); TiffIFD* raw = FindBestImage(&data); uint32 nslices = raw->getEntry(STRIPOFFSETS)->count; const uint32 *offsets = raw->getEntry(STRIPOFFSETS)->getIntArray(); const uint32 *counts = raw->getEntry(STRIPBYTECOUNTS)->getIntArray(); uint32 yPerSlice = raw->getEntry(ROWSPERSTRIP)->getInt(); uint32 width = raw->getEntry(IMAGEWIDTH)->getInt(); uint32 height = raw->getEntry(IMAGELENGTH)->getInt(); uint32 bitPerPixel = raw->getEntry(BITSPERSAMPLE)->getInt(); vector<NefSlice> slices; uint32 offY = 0; for (uint32 s = 0; s < nslices; s++) { NefSlice slice; slice.offset = offsets[s]; slice.count = counts[s]; if (offY + yPerSlice > height) slice.h = height - offY; else slice.h = yPerSlice; offY += yPerSlice; if (mFile->isValid(slice.offset + slice.count)) // Only decode if size is valid slices.push_back(slice); } if (0 == slices.size()) ThrowRDE("NEF Decoder: No valid slices found. File probably truncated."); mRaw->dim = iPoint2D(width, offY); mRaw->createData(); if (bitPerPixel == 14 && width*slices[0].h*2 == slices[0].count) bitPerPixel = 16; // D3 offY = 0; for (uint32 i = 0; i < slices.size(); i++) { NefSlice slice = slices[i]; ByteStream in(mFile->getData(slice.offset), slice.count); iPoint2D size(width, slice.h); iPoint2D pos(0, offY); try { if (hints.find(string("coolpixmangled")) != hints.end()) readCoolpixMangledRaw(in, size, pos, width*bitPerPixel / 8); else if (hints.find(string("coolpixsplit")) != hints.end()) readCoolpixSplitRaw(in, size, pos, width*bitPerPixel / 8); else readUncompressedRaw(in, size, pos, width*bitPerPixel / 8, bitPerPixel, true); } catch (RawDecoderException e) { if (i>0) mRaw->setError(e.what()); else throw; } catch (IOException e) { if (i>0) mRaw->setError(e.what()); else ThrowRDE("NEF decoder: IO error occurred in first slice, unable to decode more. Error is: %s", e.what()); } offY += slice.h; } }
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; }
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 Cr2Decoder::decodeRawInternal() { 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; 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(mFile, mRaw); l.getSOF(&sof, slice.offset, slice.count); slice.w = sof.w * sof.cps; slice.h = sof.h; 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."); } if (slices.empty()) { ThrowRDE("CR2 Decoder: No Slices found."); } mRaw->dim = iPoint2D(slices[0].w, completeH); 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; } } mRaw->createData(); vector<int> s_width; if (raw->hasEntry(CANONCR2SLICE)) { const ushort16 *ss = raw->getEntry(CANONCR2SLICE)->getShortArray(); for (int i = 0; i < ss[0]; i++) { s_width.push_back(ss[1]); } s_width.push_back(ss[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(mFile, mRaw); l.addSlices(s_width); l.mUseBigtable = true; l.startDecoder(slice.offset, slice.count, 0, offY); } catch (RawDecoderException &e) { if (i == 0) throw; // These may just be single slice error - store the error and move on errors.push_back(_strdup(e.what())); } catch (IOException &e) { // Let's try to ignore this - it might be truncated data, so something might be useful. errors.push_back(_strdup(e.what())); } offY += slice.w; } if (mRaw->subsampling.x > 1 || mRaw->subsampling.y > 1) sRawInterpolate(); return mRaw; }