/*****************************************************************************/ // Copyright 2008 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in // accordance with the terms of the Adobe license agreement accompanying it. /*****************************************************************************/ /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_opcodes.cpp#1 $ */ /* $DateTime: 2012/05/30 13:28:51 $ */ /* $Change: 832332 $ */ /* $Author: tknoll $ */ /*****************************************************************************/ #include "dng_opcodes.h" #include "dng_bottlenecks.h" #include "dng_exceptions.h" #include "dng_filter_task.h" #include "dng_globals.h" #include "dng_host.h" #include "dng_image.h" #include "dng_negative.h" #include "dng_parse_utils.h" #include "dng_stream.h" #include "dng_tag_values.h" /*****************************************************************************/ dng_opcode::dng_opcode (uint32 opcodeID, uint32 minVersion, uint32 flags) : fOpcodeID (opcodeID) , fMinVersion (minVersion) , fFlags (flags) , fWasReadFromStream (false) , fStage (0) { } /*****************************************************************************/ dng_opcode::dng_opcode (uint32 opcodeID, dng_stream &stream, const char *name) : fOpcodeID (opcodeID) , fMinVersion (0) , fFlags (0) , fWasReadFromStream (true) , fStage (0) { fMinVersion = stream.Get_uint32 (); fFlags = stream.Get_uint32 (); #if qDNGValidate if (gVerbose) { printf ("\nOpcode: "); if (name) { printf ("%s", name); } else { printf ("Unknown (%u)", (unsigned) opcodeID); } printf (", minVersion = %u.%u.%u.%u", (unsigned) ((fMinVersion >> 24) & 0x0FF), (unsigned) ((fMinVersion >> 16) & 0x0FF), (unsigned) ((fMinVersion >> 8) & 0x0FF), (unsigned) ((fMinVersion ) & 0x0FF)); printf (", flags = %u\n", (unsigned) fFlags); } #else (void) name; #endif } /*****************************************************************************/ dng_opcode::~dng_opcode () { } /*****************************************************************************/ void dng_opcode::PutData (dng_stream &stream) const { // No data by default stream.Put_uint32 (0); } /*****************************************************************************/ bool dng_opcode::AboutToApply (dng_host &host, dng_negative &negative) { if (SkipIfPreview () && host.ForPreview ()) { negative.SetIsPreview (true); } else if (MinVersion () > dngVersion_Current && WasReadFromStream ()) { if (!Optional ()) { // Somebody screwed up computing the DNGBackwardVersion... ThrowBadFormat (); } } else if (!IsValidForNegative (negative)) { ThrowBadFormat (); } else if (!IsNOP ()) { return true; } return false; } /*****************************************************************************/ dng_opcode_Unknown::dng_opcode_Unknown (dng_host &host, uint32 opcodeID, dng_stream &stream) : dng_opcode (opcodeID, stream, NULL) , fData () { uint32 size = stream.Get_uint32 (); if (size) { fData.Reset (host.Allocate (size)); stream.Get (fData->Buffer (), fData->LogicalSize ()); #if qDNGValidate if (gVerbose) { DumpHexAscii (fData->Buffer_uint8 (), fData->LogicalSize ()); } #endif } } /*****************************************************************************/ void dng_opcode_Unknown::PutData (dng_stream &stream) const { if (fData.Get ()) { stream.Put_uint32 (fData->LogicalSize ()); stream.Put (fData->Buffer (), fData->LogicalSize ()); } else { stream.Put_uint32 (0); } } /*****************************************************************************/ void dng_opcode_Unknown::Apply (dng_host & /* host */, dng_negative & /* negative */, AutoPtr & /* image */) { // We should never need to apply an unknown opcode. if (!Optional ()) { ThrowBadFormat (); } } /*****************************************************************************/ class dng_filter_opcode_task: public dng_filter_task { private: dng_filter_opcode &fOpcode; dng_negative &fNegative; public: dng_filter_opcode_task (dng_filter_opcode &opcode, dng_negative &negative, const dng_image &srcImage, dng_image &dstImage) : dng_filter_task (srcImage, dstImage) , fOpcode (opcode) , fNegative (negative) { fSrcPixelType = fOpcode.BufferPixelType (srcImage.PixelType ()); fDstPixelType = fSrcPixelType; fSrcRepeat = opcode.SrcRepeat (); } virtual dng_rect SrcArea (const dng_rect &dstArea) { return fOpcode.SrcArea (dstArea, fDstImage.Bounds ()); } virtual dng_point SrcTileSize (const dng_point &dstTileSize) { return fOpcode.SrcTileSize (dstTileSize, fDstImage.Bounds ()); } virtual void ProcessArea (uint32 threadIndex, dng_pixel_buffer &srcBuffer, dng_pixel_buffer &dstBuffer) { fOpcode.ProcessArea (fNegative, threadIndex, srcBuffer, dstBuffer, dstBuffer.Area (), fDstImage.Bounds ()); } virtual void Start (uint32 threadCount, const dng_point &tileSize, dng_memory_allocator *allocator, dng_abort_sniffer *sniffer) { dng_filter_task::Start (threadCount, tileSize, allocator, sniffer); fOpcode.Prepare (fNegative, threadCount, tileSize, fDstImage.Bounds (), fDstImage.Planes (), fDstPixelType, *allocator); } }; /*****************************************************************************/ dng_filter_opcode::dng_filter_opcode (uint32 opcodeID, uint32 minVersion, uint32 flags) : dng_opcode (opcodeID, minVersion, flags) { } /*****************************************************************************/ dng_filter_opcode::dng_filter_opcode (uint32 opcodeID, dng_stream &stream, const char *name) : dng_opcode (opcodeID, stream, name) { } /*****************************************************************************/ void dng_filter_opcode::Apply (dng_host &host, dng_negative &negative, AutoPtr &image) { dng_rect modifiedBounds = ModifiedBounds (image->Bounds ()); if (modifiedBounds.NotEmpty ()) { // Allocate destination image. AutoPtr dstImage; // If we are processing the entire image, allocate an // undefined image. if (modifiedBounds == image->Bounds ()) { dstImage.Reset (host.Make_dng_image (image->Bounds (), image->Planes (), image->PixelType ())); } // Else start with a clone of the existing image. else { dstImage.Reset (image->Clone ()); } // Filter the image. dng_filter_opcode_task task (*this, negative, *image, *dstImage); host.PerformAreaTask (task, modifiedBounds); // Return the new image. image.Reset (dstImage.Release ()); } } /*****************************************************************************/ class dng_inplace_opcode_task: public dng_area_task { private: dng_inplace_opcode &fOpcode; dng_negative &fNegative; dng_image &fImage; uint32 fPixelType; AutoPtr fBuffer [kMaxMPThreads]; public: dng_inplace_opcode_task (dng_inplace_opcode &opcode, dng_negative &negative, dng_image &image) : dng_area_task () , fOpcode (opcode) , fNegative (negative) , fImage (image) , fPixelType (opcode.BufferPixelType (image.PixelType ())) { } virtual void Start (uint32 threadCount, const dng_point &tileSize, dng_memory_allocator *allocator, dng_abort_sniffer * /* sniffer */) { uint32 bufferSize = ComputeBufferSize(fPixelType, tileSize, fImage.Planes(), pad16Bytes); for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++) { fBuffer [threadIndex] . Reset (allocator->Allocate (bufferSize)); } fOpcode.Prepare (fNegative, threadCount, tileSize, fImage.Bounds (), fImage.Planes (), fPixelType, *allocator); } virtual void Process (uint32 threadIndex, const dng_rect &tile, dng_abort_sniffer * /* sniffer */) { // Setup buffer. dng_pixel_buffer buffer(tile, 0, fImage.Planes (), fPixelType, pcRowInterleavedAlign16, fBuffer [threadIndex]->Buffer ()); // Get source pixels. fImage.Get (buffer); // Process area. fOpcode.ProcessArea (fNegative, threadIndex, buffer, tile, fImage.Bounds ()); // Save result pixels. fImage.Put (buffer); } }; /*****************************************************************************/ dng_inplace_opcode::dng_inplace_opcode (uint32 opcodeID, uint32 minVersion, uint32 flags) : dng_opcode (opcodeID, minVersion, flags) { } /*****************************************************************************/ dng_inplace_opcode::dng_inplace_opcode (uint32 opcodeID, dng_stream &stream, const char *name) : dng_opcode (opcodeID, stream, name) { } /*****************************************************************************/ void dng_inplace_opcode::Apply (dng_host &host, dng_negative &negative, AutoPtr &image) { dng_rect modifiedBounds = ModifiedBounds (image->Bounds ()); if (modifiedBounds.NotEmpty ()) { dng_inplace_opcode_task task (*this, negative, *image); host.PerformAreaTask (task, modifiedBounds); } } /*****************************************************************************/