| /*****************************************************************************/ |
| // 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<dng_image> & /* 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<dng_image> &image) |
| { |
| |
| dng_rect modifiedBounds = ModifiedBounds (image->Bounds ()); |
| |
| if (modifiedBounds.NotEmpty ()) |
| { |
| |
| // Allocate destination image. |
| |
| AutoPtr<dng_image> 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<dng_memory_block> 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<dng_image> &image) |
| { |
| |
| dng_rect modifiedBounds = ModifiedBounds (image->Bounds ()); |
| |
| if (modifiedBounds.NotEmpty ()) |
| { |
| |
| dng_inplace_opcode_task task (*this, |
| negative, |
| *image); |
| |
| host.PerformAreaTask (task, |
| modifiedBounds); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |