You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
555 lines
10 KiB
555 lines
10 KiB
/*****************************************************************************/
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|