dng_basic_tag_set * dng_image_preview::AddTagSet (dng_tiff_directory &directory) const { fIFD.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage : sfAltPreviewImage; fIFD.fImageWidth = fImage->Width (); fIFD.fImageLength = fImage->Height (); fIFD.fSamplesPerPixel = fImage->Planes (); fIFD.fPhotometricInterpretation = fIFD.fSamplesPerPixel == 1 ? piBlackIsZero : piRGB; fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++) { fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0]; } fIFD.SetSingleStrip (); return new dng_preview_tag_set (directory, *this, fIFD); }
void dng_filter_task::Start (uint32 threadCount, const dng_point &tileSize, dng_memory_allocator *allocator, dng_abort_sniffer * /* sniffer */) { dng_point srcTileSize = SrcTileSize (tileSize); uint32 srcPixelSize = TagTypeSize (fSrcPixelType); uint32 srcBufferSize = srcTileSize.v * RoundUpForPixelSize (srcTileSize.h, srcPixelSize) * srcPixelSize * fSrcPlanes; uint32 dstPixelSize = TagTypeSize (fDstPixelType); uint32 dstBufferSize = tileSize.v * RoundUpForPixelSize (tileSize.h, dstPixelSize) * dstPixelSize * fDstPlanes; for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++) { fSrcBuffer [threadIndex] . Reset (allocator->Allocate (srcBufferSize)); fDstBuffer [threadIndex] . Reset (allocator->Allocate (dstBufferSize)); // Zero buffers so add pad bytes have defined values. DoZeroBytes (fSrcBuffer [threadIndex]->Buffer (), fSrcBuffer [threadIndex]->LogicalSize ()); DoZeroBytes (fDstBuffer [threadIndex]->Buffer (), fDstBuffer [threadIndex]->LogicalSize ()); } }
dng_basic_tag_set * dng_raw_preview::AddTagSet (dng_tiff_directory &directory) const { fIFD.fNewSubFileType = sfPreviewImage; fIFD.fImageWidth = fImage->Width (); fIFD.fImageLength = fImage->Height (); fIFD.fSamplesPerPixel = fImage->Planes (); fIFD.fPhotometricInterpretation = piLinearRaw; if (fImage->PixelType () == ttFloat) { fIFD.fCompression = ccDeflate; fIFD.fCompressionQuality = fCompressionQuality; fIFD.fPredictor = cpFloatingPoint; for (uint32 j = 0; j < fIFD.fSamplesPerPixel; j++) { fIFD.fBitsPerSample [j] = 16; fIFD.fSampleFormat [j] = sfFloatingPoint; } fIFD.FindTileSize (512 * 1024); } else { fIFD.fCompression = ccLossyJPEG; fIFD.fCompressionQuality = fCompressionQuality; fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++) { fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0]; } fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel); } return new dng_raw_preview_tag_set (directory, *this, fIFD); }
void dng_image::SetPixelType (uint32 pixelType) { if (TagTypeSize (pixelType) != PixelSize ()) { ThrowProgramError ("Cannot change pixel size for existing image"); } fPixelType = pixelType; }
dng_simple_image::dng_simple_image (const dng_rect &bounds, uint32 planes, uint32 pixelType, uint32 pixelRange, dng_memory_allocator &allocator) : dng_image (bounds, planes, pixelType, pixelRange) , fMemory () , fBuffer () { uint32 pixelSize = TagTypeSize (pixelType); uint32 bytes = bounds.H () * bounds.W () * planes * pixelSize; fMemory.Reset (allocator.Allocate (bytes)); fBuffer.fArea = bounds; fBuffer.fPlane = 0; fBuffer.fPlanes = planes; fBuffer.fRowStep = planes * bounds.W (); fBuffer.fColStep = planes; fBuffer.fPlaneStep = 1; fBuffer.fPixelType = pixelType; fBuffer.fPixelSize = pixelSize; fBuffer.fPixelRange = pixelRange; fBuffer.fData = fMemory->Buffer (); }
uint32 ComputeBufferSize(uint32 pixelType, const dng_point &tileSize, uint32 numPlanes, PaddingType paddingType) { // Convert tile size to uint32. if (tileSize.h < 0 || tileSize.v < 0) { ThrowMemoryFull("Negative tile size"); } const uint32 tileSizeH = static_cast<uint32>(tileSize.h); const uint32 tileSizeV = static_cast<uint32>(tileSize.v); const uint32 pixelSize = TagTypeSize(pixelType); // Add padding to width if necessary. uint32 paddedWidth = tileSizeH; if (paddingType == pad16Bytes) { if (!RoundUpForPixelSize(paddedWidth, pixelSize, &paddedWidth)) { ThrowMemoryFull("Arithmetic overflow computing buffer size"); } } // Compute buffer size. uint32 bufferSize; if (!SafeUint32Mult(paddedWidth, tileSizeV, &bufferSize) || !SafeUint32Mult(bufferSize, pixelSize, &bufferSize) || !SafeUint32Mult(bufferSize, numPlanes, &bufferSize)) { ThrowMemoryFull("Arithmetic overflow computing buffer size"); } return bufferSize; }
dng_basic_tag_set * dng_mask_preview::AddTagSet (dng_tiff_directory &directory) const { fIFD.fNewSubFileType = sfPreviewMask; fIFD.fImageWidth = fImage->Width (); fIFD.fImageLength = fImage->Height (); fIFD.fSamplesPerPixel = 1; fIFD.fPhotometricInterpretation = piTransparencyMask; fIFD.fCompression = ccDeflate; fIFD.fPredictor = cpHorizontalDifference; fIFD.fCompressionQuality = fCompressionQuality; fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel); return new dng_basic_tag_set (directory, fIFD); }
uint32 dng_image::PixelSize () const { return TagTypeSize (PixelType ()); }
bool dng_info::ParseMakerNoteIFD (dng_host &host, dng_stream &stream, uint64 ifdSize, uint64 ifdOffset, int64 offsetDelta, uint64 minOffset, uint64 maxOffset, uint32 parentCode) { uint32 tagIndex; uint32 tagCode; uint32 tagType; uint32 tagCount; // Assume there is no next IFD pointer. fMakerNoteNextIFD = 0; // If size is too small to hold a single entry IFD, abort. if (ifdSize < 14) { return false; } // Get entry count. stream.SetReadPosition (ifdOffset); uint32 ifdEntries = stream.Get_uint16 (); // Make the entry count if reasonable for the MakerNote size. if (ifdEntries < 1 || 2 + ifdEntries * 12 > ifdSize) { return false; } // Scan IFD to verify all the tag types are all valid. for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++) { stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12 + 2); tagType = stream.Get_uint16 (); // Kludge: Some Canon MakerNotes contain tagType = 0 tags, so we // need to ignore them. This was a "firmware 1.0.4" Canon 40D raw file. if (parentCode == tcCanonMakerNote && tagType == 0) { continue; } if (TagTypeSize (tagType) == 0) { return false; } } // OK, the IFD looks reasonable enough to parse. #if qDNGValidate if (gVerbose) { printf ("%s: Offset = %u, Entries = %u\n\n", LookupParentCode (parentCode), (unsigned) ifdOffset, (unsigned) ifdEntries); } #endif for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++) { stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12); tagCode = stream.Get_uint16 (); tagType = stream.Get_uint16 (); tagCount = stream.Get_uint32 (); if (tagType == 0) { continue; } uint32 tagSize = tagCount * TagTypeSize (tagType); uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8; if (tagSize > 4) { tagOffset = stream.Get_uint32 () + offsetDelta; if (tagOffset < minOffset || tagOffset + tagSize > maxOffset) { // Tag data is outside the valid offset range, // so ignore this tag. continue; } stream.SetReadPosition (tagOffset); } // Olympus switched to using IFDs in version 3 makernotes. if (parentCode == tcOlympusMakerNote && tagType == ttIFD && tagCount == 1) { uint32 olympusMakerParent = 0; switch (tagCode) { case 8208: olympusMakerParent = tcOlympusMakerNote8208; break; case 8224: olympusMakerParent = tcOlympusMakerNote8224; break; case 8240: olympusMakerParent = tcOlympusMakerNote8240; break; case 8256: olympusMakerParent = tcOlympusMakerNote8256; break; case 8272: olympusMakerParent = tcOlympusMakerNote8272; break; case 12288: olympusMakerParent = tcOlympusMakerNote12288; break; default: break; } if (olympusMakerParent) { stream.SetReadPosition (tagOffset); uint64 subMakerNoteOffset = stream.Get_uint32 () + offsetDelta; if (subMakerNoteOffset >= minOffset && subMakerNoteOffset < maxOffset) { if (ParseMakerNoteIFD (host, stream, maxOffset - subMakerNoteOffset, subMakerNoteOffset, offsetDelta, minOffset, maxOffset, olympusMakerParent)) { continue; } } } stream.SetReadPosition (tagOffset); } ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, parentCode, tagCode, tagType, tagCount, tagOffset, offsetDelta); } // Grab next IFD pointer, for possible use. if (ifdSize >= 2 + ifdEntries * 12 + 4) { stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12); fMakerNoteNextIFD = stream.Get_uint32 (); } #if qDNGValidate if (gVerbose) { printf ("\n"); } #endif return true; }
void dng_info::ParseIFD (dng_host &host, dng_stream &stream, dng_exif *exif, dng_shared *shared, dng_ifd *ifd, uint64 ifdOffset, int64 offsetDelta, uint32 parentCode) { #if qDNGValidate bool isMakerNote = (parentCode >= tcFirstMakerNoteIFD && parentCode <= tcLastMakerNoteIFD); #endif stream.SetReadPosition (ifdOffset); if (ifd) { ifd->fThisIFD = ifdOffset; } uint32 ifdEntries = stream.Get_uint16 (); #if qDNGValidate if (gVerbose) { printf ("%s: Offset = %u, Entries = %u\n\n", LookupParentCode (parentCode), (unsigned) ifdOffset, (unsigned) ifdEntries); } if ((ifdOffset & 1) && !isMakerNote) { char message [256]; sprintf (message, "%s has odd offset (%u)", LookupParentCode (parentCode), (unsigned) ifdOffset); ReportWarning (message); } #endif uint32 prev_tag_code = 0; for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++) { stream.SetReadPosition (ifdOffset + 2 + tag_index * 12); uint32 tagCode = stream.Get_uint16 (); uint32 tagType = stream.Get_uint16 (); // Minolta 7D files have a bug in the EXIF block where the count // is wrong, and we run off into next IFD link. So if abort parsing // if we get a zero code/type combinations. if (tagCode == 0 && tagType == 0) { #if qDNGValidate char message [256]; sprintf (message, "%s had zero/zero tag code/type entry", LookupParentCode (parentCode)); ReportWarning (message); #endif return; } uint32 tagCount = stream.Get_uint32 (); #if qDNGValidate { if (tag_index > 0 && tagCode <= prev_tag_code && !isMakerNote) { char message [256]; sprintf (message, "%s tags are not sorted in ascending numerical order", LookupParentCode (parentCode)); ReportWarning (message); } } #endif prev_tag_code = tagCode; uint32 tag_type_size = TagTypeSize (tagType); if (tag_type_size == 0) { #if qDNGValidate { char message [256]; sprintf (message, "%s %s has unknown type (%u)", LookupParentCode (parentCode), LookupTagCode (parentCode, tagCode), (unsigned) tagType); ReportWarning (message); } #endif continue; } uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8; if (tagCount * tag_type_size > 4) { tagOffset = stream.Get_uint32 (); #if qDNGValidate { if (!(ifdOffset & 1) && (tagOffset & 1) && !isMakerNote && parentCode != tcKodakDCRPrivateIFD && parentCode != tcKodakKDCPrivateIFD) { char message [256]; sprintf (message, "%s %s has odd data offset (%u)", LookupParentCode (parentCode), LookupTagCode (parentCode, tagCode), (unsigned) tagOffset); ReportWarning (message); } } #endif tagOffset += offsetDelta; stream.SetReadPosition (tagOffset); } ParseTag (host, stream, exif, shared, ifd, parentCode, tagCode, tagType, tagCount, tagOffset, offsetDelta); } stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12); uint32 nextIFD = stream.Get_uint32 (); #if qDNGValidate if (gVerbose) { printf ("NextIFD = %u\n", (unsigned) nextIFD); } #endif if (ifd) { ifd->fNextIFD = nextIFD; } #if qDNGValidate if (nextIFD) { if (parentCode != 0 && (parentCode < tcFirstChainedIFD || parentCode > tcLastChainedIFD )) { char message [256]; sprintf (message, "%s has an unexpected non-zero NextIFD (%u)", LookupParentCode (parentCode), (unsigned) nextIFD); ReportWarning (message); } } if (gVerbose) { printf ("\n"); } #endif }
bool dng_info::ValidateIFD (dng_stream &stream, uint64 ifdOffset, int64 offsetDelta) { // Make sure we have a count. if (ifdOffset + 2 > stream.Length ()) { return false; } // Get entry count. stream.SetReadPosition (ifdOffset); uint32 ifdEntries = stream.Get_uint16 (); if (ifdEntries < 1) { return false; } // Make sure we have room for all entries and next IFD link. if (ifdOffset + 2 + ifdEntries * 12 + 4 > stream.Length ()) { return false; } // Check each entry. for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++) { stream.SetReadPosition (ifdOffset + 2 + tag_index * 12); stream.Skip (2); // Ignore tag code. uint32 tagType = stream.Get_uint16 (); uint32 tagCount = stream.Get_uint32 (); uint32 tag_type_size = TagTypeSize (tagType); if (tag_type_size == 0) { return false; } uint32 tag_data_size = tagCount * tag_type_size; if (tag_data_size > 4) { uint64 tagOffset = stream.Get_uint32 (); tagOffset += offsetDelta; if (tagOffset + tag_data_size > stream.Length ()) { return false; } } } return true; }
void dng_info::ParseDNGPrivateData (dng_host &host, dng_stream &stream) { if (fShared->fDNGPrivateDataCount < 2) { return; } // DNG private data should always start with a null-terminated // company name, to define the format of the private data. dng_string privateName; { char buffer [64]; stream.SetReadPosition (fShared->fDNGPrivateDataOffset); uint32 readLength = Min_uint32 (fShared->fDNGPrivateDataCount, sizeof (buffer) - 1); stream.Get (buffer, readLength); buffer [readLength] = 0; privateName.Set (buffer); } // Pentax is storing their MakerNote in the DNGPrivateData data. if (privateName.StartsWith ("PENTAX" ) || privateName.StartsWith ("SAMSUNG")) { #if qDNGValidate if (gVerbose) { printf ("Parsing Pentax/Samsung DNGPrivateData\n\n"); } #endif stream.SetReadPosition (fShared->fDNGPrivateDataOffset + 8); bool bigEndian = stream.BigEndian (); uint16 endianMark = stream.Get_uint16 (); if (endianMark == byteOrderMM) { bigEndian = true; } else if (endianMark == byteOrderII) { bigEndian = false; } TempBigEndian temp_endian (stream, bigEndian); ParseMakerNoteIFD (host, stream, fShared->fDNGPrivateDataCount - 10, fShared->fDNGPrivateDataOffset + 10, fShared->fDNGPrivateDataOffset, fShared->fDNGPrivateDataOffset, fShared->fDNGPrivateDataOffset + fShared->fDNGPrivateDataCount, tcPentaxMakerNote); return; } // Stop parsing if this is not an Adobe format block. if (!privateName.Matches ("Adobe")) { return; } TempBigEndian temp_order (stream); uint32 section_offset = 6; while (section_offset + 8 < fShared->fDNGPrivateDataCount) { stream.SetReadPosition (fShared->fDNGPrivateDataOffset + section_offset); uint32 section_key = stream.Get_uint32 (); uint32 section_count = stream.Get_uint32 (); if (section_key == DNG_CHAR4 ('M','a','k','N') && section_count > 6) { #if qDNGValidate if (gVerbose) { printf ("Found MakerNote inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint64 old_offset = stream.Get_uint32 (); uint32 tempSize = section_count - 6; AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize)); uint64 positionInOriginalFile = stream.PositionInOriginalFile(); stream.Get (tempBlock->Buffer (), tempSize); dng_stream tempStream (tempBlock->Buffer (), tempSize, positionInOriginalFile); tempStream.SetBigEndian (order_mark == byteOrderMM); ParseMakerNote (host, tempStream, tempSize, 0, 0 - old_offset, 0, tempSize); } else if (section_key == DNG_CHAR4 ('S','R','2',' ') && section_count > 6) { #if qDNGValidate if (gVerbose) { printf ("Found Sony private data inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint64 old_offset = stream.Get_uint32 (); uint64 new_offset = fShared->fDNGPrivateDataOffset + section_offset + 14; TempBigEndian sr2_order (stream, order_mark == byteOrderMM); ParseSonyPrivateData (host, stream, section_count - 6, old_offset, new_offset); } else if (section_key == DNG_CHAR4 ('R','A','F',' ') && section_count > 4) { #if qDNGValidate if (gVerbose) { printf ("Found Fuji RAF tags inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint32 tagCount = stream.Get_uint32 (); uint64 tagOffset = stream.Position (); if (tagCount) { TempBigEndian raf_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcFujiRAF, tcFujiHeader, ttUndefined, tagCount, tagOffset, 0); stream.SetReadPosition (tagOffset + tagCount); } tagCount = stream.Get_uint32 (); tagOffset = stream.Position (); if (tagCount) { TempBigEndian raf_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcFujiRAF, tcFujiRawInfo1, ttUndefined, tagCount, tagOffset, 0); stream.SetReadPosition (tagOffset + tagCount); } tagCount = stream.Get_uint32 (); tagOffset = stream.Position (); if (tagCount) { TempBigEndian raf_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcFujiRAF, tcFujiRawInfo2, ttUndefined, tagCount, tagOffset, 0); stream.SetReadPosition (tagOffset + tagCount); } } else if (section_key == DNG_CHAR4 ('C','n','t','x') && section_count > 4) { #if qDNGValidate if (gVerbose) { printf ("Found Contax Raw header inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint32 tagCount = stream.Get_uint32 (); uint64 tagOffset = stream.Position (); if (tagCount) { TempBigEndian contax_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcContaxRAW, tcContaxHeader, ttUndefined, tagCount, tagOffset, 0); } } else if (section_key == DNG_CHAR4 ('C','R','W',' ') && section_count > 4) { #if qDNGValidate if (gVerbose) { printf ("Found Canon CRW tags inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint32 entries = stream.Get_uint16 (); uint64 crwTagStart = stream.Position (); for (uint32 parsePass = 1; parsePass <= 2; parsePass++) { stream.SetReadPosition (crwTagStart); for (uint32 index = 0; index < entries; index++) { uint32 tagCode = stream.Get_uint16 (); uint32 tagCount = stream.Get_uint32 (); uint64 tagOffset = stream.Position (); // We need to grab the model id tag first, and then all the // other tags. if ((parsePass == 1) == (tagCode == 0x5834)) { TempBigEndian tag_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcCanonCRW, tagCode, ttUndefined, tagCount, tagOffset, 0); } stream.SetReadPosition (tagOffset + tagCount); } } } else if (section_count > 4) { uint32 parentCode = 0; bool code32 = false; bool hasType = true; switch (section_key) { case DNG_CHAR4 ('M','R','W',' '): { parentCode = tcMinoltaMRW; code32 = true; hasType = false; break; } case DNG_CHAR4 ('P','a','n','o'): { parentCode = tcPanasonicRAW; break; } case DNG_CHAR4 ('L','e','a','f'): { parentCode = tcLeafMOS; break; } case DNG_CHAR4 ('K','o','d','a'): { parentCode = tcKodakDCRPrivateIFD; break; } case DNG_CHAR4 ('K','D','C',' '): { parentCode = tcKodakKDCPrivateIFD; break; } default: break; } if (parentCode) { #if qDNGValidate if (gVerbose) { printf ("Found %s tags inside DNGPrivateData\n\n", LookupParentCode (parentCode)); } #endif uint16 order_mark = stream.Get_uint16 (); uint32 entries = stream.Get_uint16 (); for (uint32 index = 0; index < entries; index++) { uint32 tagCode = code32 ? stream.Get_uint32 () : stream.Get_uint16 (); uint32 tagType = hasType ? stream.Get_uint16 () : ttUndefined; uint32 tagCount = stream.Get_uint32 (); uint32 tagSize = tagCount * TagTypeSize (tagType); uint64 tagOffset = stream.Position (); TempBigEndian tag_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, parentCode, tagCode, tagType, tagCount, tagOffset, 0); stream.SetReadPosition (tagOffset + tagSize); } } } section_offset += 8 + section_count; if (section_offset & 1) { section_offset++; } } }
void dng_filter_task::Process (uint32 threadIndex, const dng_rect &area, dng_abort_sniffer * /* sniffer */) { // Find source area for this destination area. dng_rect srcArea = SrcArea (area); // Setup srcBuffer. dng_pixel_buffer srcBuffer; srcBuffer.fArea = srcArea; srcBuffer.fPlane = fSrcPlane; srcBuffer.fPlanes = fSrcPlanes; srcBuffer.fPixelType = fSrcPixelType; srcBuffer.fPixelSize = TagTypeSize (fSrcPixelType); srcBuffer.fPlaneStep = RoundUpForPixelSize (srcArea.W (), srcBuffer.fPixelSize); srcBuffer.fRowStep = srcBuffer.fPlaneStep * srcBuffer.fPlanes; if (fSrcPixelType == fSrcImage.PixelType ()) { srcBuffer.fPixelRange = fSrcImage.PixelRange (); } else switch (fSrcPixelType) { case ttByte: case ttSByte: { srcBuffer.fPixelRange = 0x0FF; break; } case ttShort: case ttSShort: { srcBuffer.fPixelRange = 0x0FFFF; break; } case ttLong: case ttSLong: { srcBuffer.fPixelRange = 0xFFFFFFFF; break; } case ttFloat: break; default: ThrowProgramError (); } srcBuffer.fData = fSrcBuffer [threadIndex]->Buffer (); // Setup dstBuffer. dng_pixel_buffer dstBuffer; dstBuffer.fArea = area; dstBuffer.fPlane = fDstPlane; dstBuffer.fPlanes = fDstPlanes; dstBuffer.fPixelType = fDstPixelType; dstBuffer.fPixelSize = TagTypeSize (fDstPixelType); dstBuffer.fPlaneStep = RoundUpForPixelSize (area.W (), dstBuffer.fPixelSize); dstBuffer.fRowStep = dstBuffer.fPlaneStep * dstBuffer.fPlanes; if (fDstPixelType == fDstImage.PixelType ()) { dstBuffer.fPixelRange = fDstImage.PixelRange (); } else switch (fDstPixelType) { case ttByte: case ttSByte: { dstBuffer.fPixelRange = 0x0FF; break; } case ttShort: case ttSShort: { dstBuffer.fPixelRange = 0x0FFFF; break; } case ttLong: case ttSLong: { dstBuffer.fPixelRange = 0xFFFFFFFF; break; } case ttFloat: break; default: ThrowProgramError (); } dstBuffer.fData = fDstBuffer [threadIndex]->Buffer (); // Get source pixels. fSrcImage.Get (srcBuffer, dng_image::edge_repeat, fSrcRepeat.v, fSrcRepeat.h); // Process area. ProcessArea (threadIndex, srcBuffer, dstBuffer); // Save result pixels. fDstImage.Put (dstBuffer); }
void dng_filter_task::Process (uint32 threadIndex, const dng_rect &area, dng_abort_sniffer * /* sniffer */) { // Find source area for this destination area. dng_rect srcArea = SrcArea (area); // Setup srcBuffer. dng_pixel_buffer srcBuffer; srcBuffer.fArea = srcArea; srcBuffer.fPlane = fSrcPlane; srcBuffer.fPlanes = fSrcPlanes; srcBuffer.fPixelType = fSrcPixelType; srcBuffer.fPixelSize = TagTypeSize (fSrcPixelType); srcBuffer.fPlaneStep = RoundUpForPixelSize (srcArea.W (), srcBuffer.fPixelSize); srcBuffer.fRowStep = srcBuffer.fPlaneStep * srcBuffer.fPlanes; srcBuffer.fData = fSrcBuffer [threadIndex]->Buffer (); // Setup dstBuffer. dng_pixel_buffer dstBuffer; dstBuffer.fArea = area; dstBuffer.fPlane = fDstPlane; dstBuffer.fPlanes = fDstPlanes; dstBuffer.fPixelType = fDstPixelType; dstBuffer.fPixelSize = TagTypeSize (fDstPixelType); dstBuffer.fPlaneStep = RoundUpForPixelSize (area.W (), dstBuffer.fPixelSize); dstBuffer.fRowStep = dstBuffer.fPlaneStep * dstBuffer.fPlanes; dstBuffer.fData = fDstBuffer [threadIndex]->Buffer (); // Get source pixels. fSrcImage.Get (srcBuffer, dng_image::edge_repeat, fSrcRepeat.v, fSrcRepeat.h); // Process area. ProcessArea (threadIndex, srcBuffer, dstBuffer); // Save result pixels. fDstImage.Put (dstBuffer); }
bool dng_camera_profile_info::ParseExtended (dng_stream &stream) { try { // Offsets are relative to the start of this structure, not the entire file. uint64 startPosition = stream.Position (); // Read header. Like a TIFF header, but with different magic number // Plus all offsets are relative to the start of the IFD, not to the // stream or file. uint16 byteOrder = stream.Get_uint16 (); if (byteOrder == byteOrderMM) fBigEndian = true; else if (byteOrder == byteOrderII) fBigEndian = false; else return false; TempBigEndian setEndianness (stream, fBigEndian); uint16 magicNumber = stream.Get_uint16 (); if (magicNumber != magicExtendedProfile) { return false; } uint32 offset = stream.Get_uint32 (); stream.Skip (offset - 8); // Start on IFD entries. uint32 ifdEntries = stream.Get_uint16 (); if (ifdEntries < 1) { return false; } for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++) { stream.SetReadPosition (startPosition + 8 + 2 + tag_index * 12); uint16 tagCode = stream.Get_uint16 (); uint32 tagType = stream.Get_uint16 (); uint32 tagCount = stream.Get_uint32 (); uint64 tagOffset = stream.Position (); if (TagTypeSize (tagType) * tagCount > 4) { tagOffset = startPosition + stream.Get_uint32 (); stream.SetReadPosition (tagOffset); } if (!ParseTag (stream, 0, tagCode, tagType, tagCount, tagOffset)) { #if qDNGValidate if (gVerbose) { stream.SetReadPosition (tagOffset); printf ("*"); DumpTagValues (stream, LookupTagType (tagType), 0, tagCode, tagType, tagCount); } #endif } } return true; } catch (...) { // Eat parsing errors. } return false; }
bool dng_shared::Parse_ifd0 (dng_stream &stream, dng_exif & /* exif */, uint32 parentCode, uint32 tagCode, uint32 tagType, uint32 tagCount, uint64 tagOffset) { switch (tagCode) { case tcXMP: { CheckTagType (parentCode, tagCode, tagType, ttByte); fXMPCount = tagCount; fXMPOffset = fXMPCount ? tagOffset : 0; #if qDNGValidate if (gVerbose) { printf ("XMP: Count = %u, Offset = %u\n", (unsigned) fXMPCount, (unsigned) fXMPOffset); if (fXMPCount) { DumpXMP (stream, fXMPCount); } } #endif break; } case tcIPTC_NAA: { CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii); fIPTC_NAA_Count = tagCount * TagTypeSize (tagType); fIPTC_NAA_Offset = fIPTC_NAA_Count ? tagOffset : 0; #if qDNGValidate if (gVerbose) { printf ("IPTC/NAA: Count = %u, Offset = %u\n", (unsigned) fIPTC_NAA_Count, (unsigned) fIPTC_NAA_Offset); if (fIPTC_NAA_Count) { DumpHexAscii (stream, fIPTC_NAA_Count); } // Compute and output the digest. dng_memory_data buffer (fIPTC_NAA_Count); stream.SetReadPosition (fIPTC_NAA_Offset); stream.Get (buffer.Buffer (), fIPTC_NAA_Count); const uint8 *data = buffer.Buffer_uint8 (); uint32 count = fIPTC_NAA_Count; // Method 1: Counting all bytes (this is correct). { dng_md5_printer printer; printer.Process (data, count); printf ("IPTCDigest: "); DumpFingerprint (printer.Result ()); printf ("\n"); } // Method 2: Ignoring zero padding. { uint32 removed = 0; while ((removed < 3) && (count > 0) && (data [count - 1] == 0)) { removed++; count--; } if (removed != 0) { dng_md5_printer printer; printer.Process (data, count); printf ("IPTCDigest (ignoring zero padding): "); DumpFingerprint (printer.Result ()); printf ("\n"); } } } #endif break; } case tcExifIFD: { CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); CheckTagCount (parentCode, tagCode, tagCount, 1); fExifIFD = stream.TagValue_uint32 (tagType); #if qDNGValidate if (gVerbose) { printf ("ExifIFD: %u\n", (unsigned) fExifIFD); } #endif break; } case tcGPSInfo: { CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); CheckTagCount (parentCode, tagCode, tagCount, 1); fGPSInfo = stream.TagValue_uint32 (tagType); #if qDNGValidate if (gVerbose) { printf ("GPSInfo: %u\n", (unsigned) fGPSInfo); } #endif break; } case tcKodakDCRPrivateIFD: { CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); CheckTagCount (parentCode, tagCode, tagCount, 1); fKodakDCRPrivateIFD = stream.TagValue_uint32 (tagType); #if qDNGValidate if (gVerbose) { printf ("KodakDCRPrivateIFD: %u\n", (unsigned) fKodakDCRPrivateIFD); } #endif break; } case tcKodakKDCPrivateIFD: { CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); CheckTagCount (parentCode, tagCode, tagCount, 1); fKodakKDCPrivateIFD = stream.TagValue_uint32 (tagType); #if qDNGValidate if (gVerbose) { printf ("KodakKDCPrivateIFD: %u\n", (unsigned) fKodakKDCPrivateIFD); } #endif break; } case tcDNGVersion: { CheckTagType (parentCode, tagCode, tagType, ttByte); CheckTagCount (parentCode, tagCode, tagCount, 4); uint32 b0 = stream.Get_uint8 (); uint32 b1 = stream.Get_uint8 (); uint32 b2 = stream.Get_uint8 (); uint32 b3 = stream.Get_uint8 (); fDNGVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; #if qDNGValidate if (gVerbose) { printf ("DNGVersion: %u.%u.%u.%u\n", (unsigned) b0, (unsigned) b1, (unsigned) b2, (unsigned) b3); } #endif break; } case tcDNGBackwardVersion: { CheckTagType (parentCode, tagCode, tagType, ttByte); CheckTagCount (parentCode, tagCode, tagCount, 4); uint32 b0 = stream.Get_uint8 (); uint32 b1 = stream.Get_uint8 (); uint32 b2 = stream.Get_uint8 (); uint32 b3 = stream.Get_uint8 (); fDNGBackwardVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; #if qDNGValidate if (gVerbose) { printf ("DNGBackwardVersion: %u.%u.%u.%u\n", (unsigned) b0, (unsigned) b1, (unsigned) b2, (unsigned) b3); } #endif break; } case tcUniqueCameraModel: { CheckTagType (parentCode, tagCode, tagType, ttAscii); ParseStringTag (stream, parentCode, tagCode, tagCount, fUniqueCameraModel, false); bool didTrim = fUniqueCameraModel.TrimTrailingBlanks (); #if qDNGValidate if (didTrim) { ReportWarning ("UniqueCameraModel string has trailing blanks"); } if (gVerbose) { printf ("UniqueCameraModel: "); DumpString (fUniqueCameraModel); printf ("\n"); } #else (void) didTrim; // Unused #endif break; } case tcLocalizedCameraModel: { CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); ParseStringTag (stream, parentCode, tagCode, tagCount, fLocalizedCameraModel, false, false); bool didTrim = fLocalizedCameraModel.TrimTrailingBlanks (); #if qDNGValidate if (didTrim) { ReportWarning ("LocalizedCameraModel string has trailing blanks"); } if (gVerbose) { printf ("LocalizedCameraModel: "); DumpString (fLocalizedCameraModel); printf ("\n"); } #else (void) didTrim; // Unused #endif break; } case tcCameraCalibration1: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) return false; if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, fCameraProfile.fColorPlanes, fCameraProfile.fColorPlanes, fCameraCalibration1)) return false; #if qDNGValidate if (gVerbose) { printf ("CameraCalibration1:\n"); DumpMatrix (fCameraCalibration1); } #endif break; } case tcCameraCalibration2: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) return false; if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, fCameraProfile.fColorPlanes, fCameraProfile.fColorPlanes, fCameraCalibration2)) return false; #if qDNGValidate if (gVerbose) { printf ("CameraCalibration2:\n"); DumpMatrix (fCameraCalibration2); } #endif break; } case tcCameraCalibrationSignature: { CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); ParseStringTag (stream, parentCode, tagCode, tagCount, fCameraCalibrationSignature, false, false); #if qDNGValidate if (gVerbose) { printf ("CameraCalibrationSignature: "); DumpString (fCameraCalibrationSignature); printf ("\n"); } #endif break; } case tcAnalogBalance: { CheckTagType (parentCode, tagCode, tagType, ttRational); if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) return false; if (!ParseVectorTag (stream, parentCode, tagCode, tagType, tagCount, fCameraProfile.fColorPlanes, fAnalogBalance)) return false; #if qDNGValidate if (gVerbose) { printf ("AnalogBalance:"); DumpVector (fAnalogBalance); } #endif break; } case tcAsShotNeutral: { CheckTagType (parentCode, tagCode, tagType, ttRational); if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) return false; if (!ParseVectorTag (stream, parentCode, tagCode, tagType, tagCount, fCameraProfile.fColorPlanes, fAsShotNeutral)) return false; #if qDNGValidate if (gVerbose) { printf ("AsShotNeutral:"); DumpVector (fAsShotNeutral); } #endif break; } case tcAsShotWhiteXY: { CheckTagType (parentCode, tagCode, tagType, ttRational); if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) return false; if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) return false; fAsShotWhiteXY.x = stream.TagValue_real64 (tagType); fAsShotWhiteXY.y = stream.TagValue_real64 (tagType); #if qDNGValidate if (gVerbose) { printf ("AsShotWhiteXY: %0.4f %0.4f\n", fAsShotWhiteXY.x, fAsShotWhiteXY.y); } #endif break; } case tcBaselineExposure: { CheckTagType (parentCode, tagCode, tagType, ttSRational); CheckTagCount (parentCode, tagCode, tagCount, 1); fBaselineExposure = stream.TagValue_srational (tagType); #if qDNGValidate if (gVerbose) { printf ("BaselineExposure: %+0.2f\n", fBaselineExposure.As_real64 ()); } #endif break; } case tcBaselineNoise: { CheckTagType (parentCode, tagCode, tagType, ttRational); CheckTagCount (parentCode, tagCode, tagCount, 1); fBaselineNoise = stream.TagValue_urational (tagType); #if qDNGValidate if (gVerbose) { printf ("BaselineNoise: %0.2f\n", fBaselineNoise.As_real64 ()); } #endif break; } case tcNoiseReductionApplied: { if (!CheckTagType (parentCode, tagCode, tagType, ttRational)) return false; if (!CheckTagCount (parentCode, tagCode, tagCount, 1)) return false; fNoiseReductionApplied = stream.TagValue_urational (tagType); #if qDNGValidate if (gVerbose) { printf ("NoiseReductionApplied: %u/%u\n", (unsigned) fNoiseReductionApplied.n, (unsigned) fNoiseReductionApplied.d); } #endif break; } case tcNoiseProfile: { if (!CheckTagType (parentCode, tagCode, tagType, ttDouble)) return false; // Must be an even, positive number of doubles in a noise profile. if (!tagCount || (tagCount & 1)) return false; // Determine number of planes (i.e., half the number of doubles). const uint32 numPlanes = Pin_uint32 (0, tagCount >> 1, kMaxColorPlanes); // Parse the noise function parameters. std::vector<dng_noise_function> noiseFunctions; for (uint32 i = 0; i < numPlanes; i++) { const real64 scale = stream.TagValue_real64 (tagType); const real64 offset = stream.TagValue_real64 (tagType); noiseFunctions.push_back (dng_noise_function (scale, offset)); } // Store the noise profile. fNoiseProfile = dng_noise_profile (noiseFunctions); // Debug. #if qDNGValidate if (gVerbose) { printf ("NoiseProfile:\n"); printf (" Planes: %u\n", numPlanes); for (uint32 plane = 0; plane < numPlanes; plane++) { printf (" Noise function for plane %u: scale = %.8lf, offset = %.8lf\n", plane, noiseFunctions [plane].Scale (), noiseFunctions [plane].Offset ()); } } #endif break; } case tcBaselineSharpness: { CheckTagType (parentCode, tagCode, tagType, ttRational); CheckTagCount (parentCode, tagCode, tagCount, 1); fBaselineSharpness = stream.TagValue_urational (tagType); #if qDNGValidate if (gVerbose) { printf ("BaselineSharpness: %0.2f\n", fBaselineSharpness.As_real64 ()); } #endif break; } case tcLinearResponseLimit: { CheckTagType (parentCode, tagCode, tagType, ttRational); CheckTagCount (parentCode, tagCode, tagCount, 1); fLinearResponseLimit = stream.TagValue_urational (tagType); #if qDNGValidate if (gVerbose) { printf ("LinearResponseLimit: %0.2f\n", fLinearResponseLimit.As_real64 ()); } #endif break; } case tcShadowScale: { CheckTagType (parentCode, tagCode, tagType, ttRational); CheckTagCount (parentCode, tagCode, tagCount, 1); fShadowScale = stream.TagValue_urational (tagType); #if qDNGValidate if (gVerbose) { printf ("ShadowScale: %0.4f\n", fShadowScale.As_real64 ()); } #endif break; } case tcDNGPrivateData: { CheckTagType (parentCode, tagCode, tagType, ttByte); fDNGPrivateDataCount = tagCount; fDNGPrivateDataOffset = tagOffset; #if qDNGValidate if (gVerbose) { printf ("DNGPrivateData: Count = %u, Offset = %u\n", (unsigned) fDNGPrivateDataCount, (unsigned) fDNGPrivateDataOffset); DumpHexAscii (stream, tagCount); } #endif break; } case tcMakerNoteSafety: { CheckTagType (parentCode, tagCode, tagType, ttShort); CheckTagCount (parentCode, tagCode, tagCount, 1); fMakerNoteSafety = stream.TagValue_uint32 (tagType); #if qDNGValidate if (gVerbose) { printf ("MakerNoteSafety: %s\n", LookupMakerNoteSafety (fMakerNoteSafety)); } #endif break; } case tcRawImageDigest: { if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) return false; if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) return false; stream.Get (fRawImageDigest.data, 16); #if qDNGValidate if (gVerbose) { printf ("RawImageDigest: "); DumpFingerprint (fRawImageDigest); printf ("\n"); } #endif break; } case tcRawDataUniqueID: { if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) return false; if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) return false; stream.Get (fRawDataUniqueID.data, 16); #if qDNGValidate if (gVerbose) { printf ("RawDataUniqueID: "); DumpFingerprint (fRawDataUniqueID); printf ("\n"); } #endif break; } case tcOriginalRawFileName: { CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); ParseStringTag (stream, parentCode, tagCode, tagCount, fOriginalRawFileName, false, false); #if qDNGValidate if (gVerbose) { printf ("OriginalRawFileName: "); DumpString (fOriginalRawFileName); printf ("\n"); } #endif break; } case tcOriginalRawFileData: { CheckTagType (parentCode, tagCode, tagType, ttUndefined); fOriginalRawFileDataCount = tagCount; fOriginalRawFileDataOffset = tagOffset; #if qDNGValidate if (gVerbose) { printf ("OriginalRawFileData: Count = %u, Offset = %u\n", (unsigned) fOriginalRawFileDataCount, (unsigned) fOriginalRawFileDataOffset); DumpHexAscii (stream, tagCount); } #endif break; } case tcOriginalRawFileDigest: { if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) return false; if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) return false; stream.Get (fOriginalRawFileDigest.data, 16); #if qDNGValidate if (gVerbose) { printf ("OriginalRawFileDigest: "); DumpFingerprint (fOriginalRawFileDigest); printf ("\n"); } #endif break; } case tcAsShotICCProfile: { CheckTagType (parentCode, tagCode, tagType, ttUndefined); fAsShotICCProfileCount = tagCount; fAsShotICCProfileOffset = tagOffset; #if qDNGValidate if (gVerbose) { printf ("AsShotICCProfile: Count = %u, Offset = %u\n", (unsigned) fAsShotICCProfileCount, (unsigned) fAsShotICCProfileOffset); DumpHexAscii (stream, tagCount); } #endif break; } case tcAsShotPreProfileMatrix: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) return false; uint32 rows = fCameraProfile.fColorPlanes; if (tagCount == fCameraProfile.fColorPlanes * 3) { rows = 3; } if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, rows, fCameraProfile.fColorPlanes, fAsShotPreProfileMatrix)) return false; #if qDNGValidate if (gVerbose) { printf ("AsShotPreProfileMatrix:\n"); DumpMatrix (fAsShotPreProfileMatrix); } #endif break; } case tcCurrentICCProfile: { CheckTagType (parentCode, tagCode, tagType, ttUndefined); fCurrentICCProfileCount = tagCount; fCurrentICCProfileOffset = tagOffset; #if qDNGValidate if (gVerbose) { printf ("CurrentICCProfile: Count = %u, Offset = %u\n", (unsigned) fCurrentICCProfileCount, (unsigned) fCurrentICCProfileOffset); DumpHexAscii (stream, tagCount); } #endif break; } case tcCurrentPreProfileMatrix: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) return false; uint32 rows = fCameraProfile.fColorPlanes; if (tagCount == fCameraProfile.fColorPlanes * 3) { rows = 3; } if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, rows, fCameraProfile.fColorPlanes, fCurrentPreProfileMatrix)) return false; #if qDNGValidate if (gVerbose) { printf ("CurrentPreProfileMatrix:\n"); DumpMatrix (fCurrentPreProfileMatrix); } #endif break; } case tcColorimetricReference: { CheckTagType (parentCode, tagCode, tagType, ttShort); CheckTagCount (parentCode, tagCode, tagCount, 1); fColorimetricReference = stream.TagValue_uint32 (tagType); #if qDNGValidate if (gVerbose) { printf ("ColorimetricReference: %s\n", LookupColorimetricReference (fColorimetricReference)); } #endif break; } case tcExtraCameraProfiles: { CheckTagType (parentCode, tagCode, tagType, ttLong); CheckTagCount (parentCode, tagCode, tagCount, 1, tagCount); #if qDNGValidate if (gVerbose) { printf ("ExtraCameraProfiles: %u\n", (unsigned) tagCount); } #endif fExtraCameraProfiles.reserve (tagCount); for (uint32 index = 0; index < tagCount; index++) { #if qDNGValidate if (gVerbose) { printf ("\nExtraCameraProfile [%u]:\n\n", (unsigned) index); } #endif stream.SetReadPosition (tagOffset + index * 4); uint32 profileOffset = stream.TagValue_uint32 (tagType); dng_camera_profile_info profileInfo; stream.SetReadPosition (profileOffset); if (profileInfo.ParseExtended (stream)) { fExtraCameraProfiles.push_back (profileInfo); } else { #if qDNGValidate ReportWarning ("Unable to parse extra camera profile"); #endif } } #if qDNGValidate if (gVerbose) { printf ("\nDone with ExtraCameraProfiles\n\n"); } #endif break; } case tcAsShotProfileName: { CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); ParseStringTag (stream, parentCode, tagCode, tagCount, fAsShotProfileName, false, false); #if qDNGValidate if (gVerbose) { printf ("AsShotProfileName: "); DumpString (fAsShotProfileName); printf ("\n"); } #endif break; } default: { // The main camera profile tags also appear in IFD 0 return fCameraProfile.ParseTag (stream, parentCode, tagCode, tagType, tagCount, tagOffset); } } return true; }