added DNG

master
Herwig Birke 6 years ago
parent cf3639fbff
commit 4ddadbb600

@ -0,0 +1,12 @@
#include "cdcp.h"
cDCP::cDCP(QObject* parent) :
QObject(parent)
{
}
void cDCPList::load(const QString& fileName)
{
m_fileName = fileName;
}

@ -0,0 +1,34 @@
#ifndef CDCP_H
#define CDCP_H
#include <QObject>
#include <QMetaObject>
#include <QList>
class cDCP : public QObject
{
Q_OBJECT
public:
explicit cDCP(QObject *parent = nullptr);
signals:
public slots:
private:
};
Q_DECLARE_METATYPE(cDCP*)
class cDCPList : public QList<cDCP*>
{
public:
void load(const QString& fileName);
private:
QString m_fileName;
};
#endif // CDCP_H

@ -10,6 +10,8 @@
#include <QTransform>
#include <QFileInfo>
#include <QDebug>
cImage::cImage() :
QImage()
@ -76,75 +78,181 @@ bool cImage::load(const QString &fileName, const char *format)
return(loadRAW(fileName));
}
bool cImage::loadRAW(const QString &fileName)
{
LibRaw rawProcessor;
libraw_processed_image_t* lpOutput;
if(rawProcessor.open_file(fileName.toUtf8()) != LIBRAW_SUCCESS)
return(false);
#include <math.h>
rawProcessor.imgdata.params.use_camera_wb = 0;
rawProcessor.imgdata.params.use_auto_wb = 0;
if(rawProcessor.unpack() != LIBRAW_SUCCESS)
return(false);
rawProcessor.dcraw_process();
lpOutput = rawProcessor.dcraw_make_mem_image();
QImage LibRawImageToQImage(const uchar *data, const int width, const int height, const int nCols, const int colorBits)
{
int colorSize = (colorBits % 8) == 0 ? colorBits / 8 : static_cast<int>(ceil(static_cast<double>(colorBits) / 8.0));
int numPixels = width * height;
int pixelSize = nCols * colorSize;
uchar* pixels = new uchar[numPixels * 3];
const libraw_data_t& imgdata = rawProcessor.imgdata;
uchar* pixels = nullptr;
for(int i = 0; i < numPixels; i++, data += pixelSize)
{
if(nCols == 3)
{
// this ordering produces correct RGB results - don't ask why
// tested with .CR2 (Canon)
pixels[i * 3] = data[3*colorSize];
pixels[i * 3 + 1] = data[colorSize];
pixels[i * 3 + 2] = data[2*colorSize];
}
else
{
pixels[i * 3] = data[0];
pixels[i * 3 + 1] = data[0];
pixels[i * 3 + 2] = data[0];
}
}
// immediately create a copy since otherwise we'd have to
// 'delete[] pixels' somewhere else, ourselves
// see http://doc.qt.io/qt-5.5/qimage.html#QImage-6
QImage out = QImage(pixels, width, height, width * 3, QImage::Format_RGB888).copy();
// QImage out = QImage(pixels, width, height, width * 3, QImage::Format_RGB32).copy();
delete[] pixels;
return out;
}
if(lpOutput->type == LIBRAW_IMAGE_JPEG)
void LibRawImagePerformFlip(const int flip, QImage& image)
{
if(flip != 0)
{
loadFromData(lpOutput->data, static_cast<int>(lpOutput->data_size), "JPEG");
QTransform rotation;
int angle = 0;
if(flip == 3)
angle = 180;
else if(flip == 5)
angle = -90;
else if(flip == 6)
angle = 90;
if(imgdata.sizes.flip != 0)
if (angle != 0)
{
QTransform rotation;
int angle = 0;
if(imgdata.sizes.flip == 3)
angle = 180;
else if(imgdata.sizes.flip == 5)
angle = -90;
else if(imgdata.sizes.flip == 6)
angle = 90;
if(angle != 0)
{
rotation.rotate(angle);
*this = transformed(rotation);
}
rotation.rotate(angle);
image = image.transformed(rotation);
}
}
else
{
int numPixels = lpOutput->width * lpOutput->height;
int colorSize = lpOutput->bits / 8;
int pixelSize = lpOutput->colors * colorSize;
pixels = new uchar[numPixels * 4];
uchar* data = lpOutput->data;
}
for(int i = 0; i < numPixels; i++, data += pixelSize)
bool cImage::loadRAW(const QString &fileName)
{
LibRaw RawProcessor;
QImage image;
// RawProcessor.imgdata.params.gamm[0] = 1.00;
// RawProcessor.imgdata.params.gamm[1] = 0.00;
// RawProcessor.imgdata.params.gamm[0] = 0.45;
// RawProcessor.imgdata.params.gamm[1] = 4.50;
RawProcessor.imgdata.params.gamm[0] = 1/2.4;
RawProcessor.imgdata.params.gamm[1] = 12.92;
// RawProcessor.imgdata.params.user_qual = 0; // fastest interpolation (linear)
RawProcessor.imgdata.params.use_camera_wb = 1;
if(LIBRAW_SUCCESS == RawProcessor.open_file(fileName.toUtf8()))
{
if(LIBRAW_SUCCESS == RawProcessor.unpack())
{
if(lpOutput->colors == 3)
if(LIBRAW_SUCCESS == RawProcessor.dcraw_process())
{
pixels[i * 4] = data[2 * colorSize];
pixels[i * 4 + 1] = data[1 * colorSize];
pixels[i * 4 + 2] = data[0];
}
else
{
pixels[i * 4] = data[0];
pixels[i * 4 + 1] = data[0];
pixels[i * 4 + 2] = data[0];
libraw_processed_image_t* output = RawProcessor.dcraw_make_mem_image();
if(LIBRAW_IMAGE_JPEG == output->type)
{
image.loadFromData(static_cast<uchar*>(output->data), static_cast<int>(output->data_size), "JPEG");
LibRawImagePerformFlip(RawProcessor.imgdata.sizes.flip, image);
}
else if(LIBRAW_IMAGE_BITMAP == output->type)
{
image = LibRawImageToQImage(static_cast<uchar*>(output->data), output->width, output->height, output->colors, output->bits);
} // else: could not read
LibRaw::dcraw_clear_mem(output);
}
RawProcessor.recycle();
}
*this = QImage(pixels, lpOutput->width, lpOutput->height, QImage::Format_RGB32);
}
rawProcessor.recycle();
*this = image;
return(true);
}
//bool cImage::loadRAW(const QString &fileName)
//{
// LibRaw rawProcessor;
// libraw_processed_image_t* lpOutput;
// rawProcessor.imgdata.params.use_camera_wb = 1;
// rawProcessor.imgdata.params.use_auto_wb = 1;
// rawProcessor.imgdata.params.use_camera_matrix = 0;
//// rawProcessor.imgdata.params.gamm[0] = 1/2.22;
//// rawProcessor.imgdata.params.gamm[1] = 4.50;
// rawProcessor.imgdata.params.gamm[0] = 1/2.40;
// rawProcessor.imgdata.params.gamm[1] = 12.92;
// if(rawProcessor.open_file(fileName.toUtf8()) != LIBRAW_SUCCESS)
// return(false);
// if(rawProcessor.unpack() != LIBRAW_SUCCESS)
// return(false);
// rawProcessor.raw2image();
// rawProcessor.dcraw_process();
// lpOutput = rawProcessor.dcraw_make_mem_image();
// const libraw_data_t& imgdata = rawProcessor.imgdata;
// uchar* pixels = nullptr;
// if(lpOutput->type == LIBRAW_IMAGE_JPEG)
// {
// loadFromData(lpOutput->data, static_cast<int>(lpOutput->data_size), "JPEG");
// if(imgdata.sizes.flip != 0)
// {
// QTransform rotation;
// int angle = 0;
// if(imgdata.sizes.flip == 3)
// angle = 180;
// else if(imgdata.sizes.flip == 5)
// angle = -90;
// else if(imgdata.sizes.flip == 6)
// angle = 90;
// if(angle != 0)
// {
// rotation.rotate(angle);
// *this = transformed(rotation);
// }
// }
// }
// else
// {
// int numPixels = lpOutput->width * lpOutput->height;
// int colorSize = lpOutput->bits / 8;
// int pixelSize = lpOutput->colors * colorSize;
// pixels = new uchar[numPixels * 4];
// uchar* data = lpOutput->data;
// for(int i = 0; i < numPixels; i++, data += pixelSize)
// {
// if(lpOutput->colors == 3)
// {
// pixels[i * 4] = data[2 * colorSize];
// pixels[i * 4 + 1] = data[1 * colorSize];
// pixels[i * 4 + 2] = data[0];
// }
// else
// {
// pixels[i * 4] = data[0];
// pixels[i * 4 + 1] = data[0];
// pixels[i * 4 + 2] = data[0];
// }
// }
// *this = QImage(pixels, lpOutput->width, lpOutput->height, QImage::Format_RGB32);
// }
// rawProcessor.recycle();
// return(true);
//}

@ -0,0 +1,19 @@
#ifndef __dng_RawEnvironment__
#define __dng_RawEnvironment__
// Define preprocessor constants that control platform-specific conditional
// compilation. The constants qMacOS and qWinOS must be defined on all
// platforms. Other constants, such as qLinux, only need to be defined if we're
// actually compiling for that platform.
#if defined(__linux__)
#define qMacOS 0
#define qWinOS 0
#define qLinux 1
#elif defined(__APPLE__)
#define qMacOS 1
#define qWinOS 0
#elif defined(_WIN32)
#define qMacOS 0
#define qWinOS 1
#endif
#define qDNGXMPDocOps 0
#endif // __dng_RawEnvironment__

@ -0,0 +1,188 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_1d_function.h"
#include "dng_utils.h"
/*****************************************************************************/
dng_1d_function::~dng_1d_function ()
{
}
/*****************************************************************************/
bool dng_1d_function::IsIdentity () const
{
return false;
}
/*****************************************************************************/
real64 dng_1d_function::EvaluateInverse (real64 y) const
{
const uint32 kMaxIterations = 30;
const real64 kNearZero = 1.0e-10;
real64 x0 = 0.0;
real64 y0 = Evaluate (x0);
real64 x1 = 1.0;
real64 y1 = Evaluate (x1);
for (uint32 iteration = 0; iteration < kMaxIterations; iteration++)
{
if (Abs_real64 (y1 - y0) < kNearZero)
{
break;
}
real64 x2 = Pin_real64 (0.0,
x1 + (y - y1) * (x1 - x0) / (y1 - y0),
1.0);
real64 y2 = Evaluate (x2);
x0 = x1;
y0 = y1;
x1 = x2;
y1 = y2;
}
return x1;
}
/*****************************************************************************/
bool dng_1d_identity::IsIdentity () const
{
return true;
}
/*****************************************************************************/
real64 dng_1d_identity::Evaluate (real64 x) const
{
return x;
}
/*****************************************************************************/
real64 dng_1d_identity::EvaluateInverse (real64 x) const
{
return x;
}
/*****************************************************************************/
const dng_1d_function & dng_1d_identity::Get ()
{
static dng_1d_identity static_function;
return static_function;
}
/*****************************************************************************/
dng_1d_concatenate::dng_1d_concatenate (const dng_1d_function &function1,
const dng_1d_function &function2)
: fFunction1 (function1)
, fFunction2 (function2)
{
}
/*****************************************************************************/
bool dng_1d_concatenate::IsIdentity () const
{
return fFunction1.IsIdentity () &&
fFunction2.IsIdentity ();
}
/*****************************************************************************/
real64 dng_1d_concatenate::Evaluate (real64 x) const
{
real64 y = Pin_real64 (0.0, fFunction1.Evaluate (x), 1.0);
return fFunction2.Evaluate (y);
}
/*****************************************************************************/
real64 dng_1d_concatenate::EvaluateInverse (real64 x) const
{
real64 y = fFunction2.EvaluateInverse (x);
return fFunction1.EvaluateInverse (y);
}
/*****************************************************************************/
dng_1d_inverse::dng_1d_inverse (const dng_1d_function &f)
: fFunction (f)
{
}
/*****************************************************************************/
bool dng_1d_inverse::IsIdentity () const
{
return fFunction.IsIdentity ();
}
/*****************************************************************************/
real64 dng_1d_inverse::Evaluate (real64 x) const
{
return fFunction.EvaluateInverse (x);
}
/*****************************************************************************/
real64 dng_1d_inverse::EvaluateInverse (real64 y) const
{
return fFunction.Evaluate (y);
}
/*****************************************************************************/

@ -0,0 +1,154 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Classes for a 1D floating-point to floating-point function abstraction.
*/
/*****************************************************************************/
#ifndef __dng_1d_function__
#define __dng_1d_function__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_types.h"
/*****************************************************************************/
/// \brief A 1D floating-point function.
///
/// The domain (input) is always from 0.0 to 1.0, while the range (output) can be an arbitrary interval.
class dng_1d_function
{
public:
virtual ~dng_1d_function ();
/// Returns true if this function is the map x -> y such that x == y for all x . That is if Evaluate(x) == x for all x.
virtual bool IsIdentity () const;
/// Return the mapping for value x.
/// This method must be implemented by a derived class of dng_1d_function and the derived class determines the
/// lookup method and function used.
/// \param x A value between 0.0 and 1.0 (inclusive).
/// \retval Mapped value for x
virtual real64 Evaluate (real64 x) const = 0;
/// Return the reverse mapped value for y.
/// This method can be implemented by derived classes. The default implementation uses Newton's method to solve
/// for x such that Evaluate(x) == y.
/// \param y A value to reverse map. Should be within the range of the function implemented by this dng_1d_function .
/// \retval A value x such that Evaluate(x) == y (to very close approximation).
virtual real64 EvaluateInverse (real64 y) const;
};
/*****************************************************************************/
/// An identity (x -> y such that x == y for all x) mapping function.
class dng_1d_identity: public dng_1d_function
{
public:
/// Always returns true for this class.
virtual bool IsIdentity () const;
/// Always returns x for this class.
virtual real64 Evaluate (real64 x) const;
/// Always returns y for this class.
virtual real64 EvaluateInverse (real64 y) const;
/// This class is a singleton, and is entirely threadsafe. Use this method to get an instance of the class.
static const dng_1d_function & Get ();
};
/*****************************************************************************/
/// A dng_1d_function that represents the composition (curry) of two other dng_1d_functions.
class dng_1d_concatenate: public dng_1d_function
{
protected:
const dng_1d_function &fFunction1;
const dng_1d_function &fFunction2;
public:
/// Create a dng_1d_function which computes y = function2.Evaluate(function1.Evaluate(x)).
/// Compose function1 and function2 to compute y = function2.Evaluate(function1.Evaluate(x)). The range of function1.Evaluate must be a subset of 0.0 to 1.0 inclusive,
/// otherwise the result of function1(x) will be pinned (clipped) to 0.0 if <0.0 and to 1.0 if > 1.0 .
/// \param function1 Inner function of composition.
/// \param function2 Outer function of composition.
dng_1d_concatenate (const dng_1d_function &function1,
const dng_1d_function &function2);
/// Only true if both function1 and function2 have IsIdentity equal to true.
virtual bool IsIdentity () const;
/// Return the composed mapping for value x.
/// \param x A value between 0.0 and 1.0 (inclusive).
/// \retval function2.Evaluate(function1.Evaluate(x)).
virtual real64 Evaluate (real64 x) const;
/// Return the reverse mapped value for y.
/// Be careful using this method with compositions where the inner function does not have a range 0.0 to 1.0 . (Or better yet, do not use such functions.)
/// \param y A value to reverse map. Should be within the range of function2.Evaluate.
/// \retval A value x such that function2.Evaluate(function1.Evaluate(x)) == y (to very close approximation).
virtual real64 EvaluateInverse (real64 y) const;
};
/*****************************************************************************/
/// A dng_1d_function that represents the inverse of another dng_1d_function.
class dng_1d_inverse: public dng_1d_function
{
protected:
const dng_1d_function &fFunction;
public:
dng_1d_inverse (const dng_1d_function &f);
virtual bool IsIdentity () const;
virtual real64 Evaluate (real64 x) const;
virtual real64 EvaluateInverse (real64 y) const;
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,196 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_1d_table.h"
#include "dng_1d_function.h"
#include "dng_assertions.h"
#include "dng_memory.h"
#include "dng_utils.h"
/*****************************************************************************/
dng_1d_table::dng_1d_table (uint32 count)
: fBuffer ()
, fTable (NULL)
, fTableCount (count)
{
DNG_REQUIRE (count >= kMinTableSize,
"count must be at least kMinTableSize");
DNG_REQUIRE ((count & (count - 1)) == 0,
"count must be power of 2");
}
/*****************************************************************************/
dng_1d_table::~dng_1d_table ()
{
}
/*****************************************************************************/
void dng_1d_table::SubDivide (const dng_1d_function &function,
uint32 lower,
uint32 upper,
real32 maxDelta)
{
uint32 range = upper - lower;
bool subDivide = (range > (fTableCount >> 8));
if (!subDivide)
{
real32 delta = Abs_real32 (fTable [upper] -
fTable [lower]);
if (delta > maxDelta)
{
subDivide = true;
}
}
if (subDivide)
{
uint32 middle = (lower + upper) >> 1;
fTable [middle] = (real32) function.Evaluate (middle * (1.0 / (real64) fTableCount));
if (range > 2)
{
SubDivide (function, lower, middle, maxDelta);
SubDivide (function, middle, upper, maxDelta);
}
}
else
{
real64 y0 = fTable [lower];
real64 y1 = fTable [upper];
real64 delta = (y1 - y0) / (real64) range;
for (uint32 j = lower + 1; j < upper; j++)
{
y0 += delta;
fTable [j] = (real32) y0;
}
}
}
/*****************************************************************************/
void dng_1d_table::Initialize (dng_memory_allocator &allocator,
const dng_1d_function &function,
bool subSample)
{
fBuffer.Reset (allocator.Allocate ((fTableCount + 2) * sizeof (real32)));
fTable = fBuffer->Buffer_real32 ();
if (subSample)
{
fTable [0 ] = (real32) function.Evaluate (0.0);
fTable [fTableCount] = (real32) function.Evaluate (1.0);
real32 maxDelta = Max_real32 (Abs_real32 (fTable [fTableCount] -
fTable [0 ]), 1.0f) *
(1.0f / 256.0f);
SubDivide (function,
0,
fTableCount,
maxDelta);
}
else
{
for (uint32 j = 0; j <= fTableCount; j++)
{
real64 x = j * (1.0 / (real64) fTableCount);
real64 y = function.Evaluate (x);
fTable [j] = (real32) y;
}
}
fTable [fTableCount + 1] = fTable [fTableCount];
}
/*****************************************************************************/
void dng_1d_table::Expand16 (uint16 *table16) const
{
real64 step = (real64) fTableCount / 65535.0;
real64 y0 = fTable [0];
real64 y1 = fTable [1];
real64 base = y0 * 65535.0 + 0.5;
real64 slope = (y1 - y0) * 65535.0;
uint32 index = 1;
real64 fract = 0.0;
for (uint32 j = 0; j < 0x10000; j++)
{
table16 [j] = (uint16) (base + slope * fract);
fract += step;
if (fract > 1.0)
{
index += 1;
fract -= 1.0;
y0 = y1;
y1 = fTable [index];
base = y0 * 65535.0 + 0.5;
slope = (y1 - y0) * 65535.0;
}
}
}
/*****************************************************************************/

@ -0,0 +1,126 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Definition of a lookup table based 1D floating-point to floating-point function abstraction using linear interpolation.
*/
/*****************************************************************************/
#ifndef __dng_1d_table__
#define __dng_1d_table__
/*****************************************************************************/
#include "dng_assertions.h"
#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_types.h"
#include "dng_uncopyable.h"
/*****************************************************************************/
/// \brief A 1D floating-point lookup table using linear interpolation.
class dng_1d_table: private dng_uncopyable
{
public:
/// Constant denoting minimum size of table.
static const uint32 kMinTableSize = 512;
private:
/// Constant denoting default size of table.
static const uint32 kDefaultTableSize = 4096;
protected:
AutoPtr<dng_memory_block> fBuffer;
real32 *fTable;
const uint32 fTableCount;
public:
/// Table constructor. count must be a power of two
/// and at least kMinTableSize.
explicit dng_1d_table (uint32 count = kDefaultTableSize);
virtual ~dng_1d_table ();
/// Number of table entries.
uint32 Count () const
{
return fTableCount;
}
/// Set up table, initialize entries using functiion.
/// This method can throw an exception, e.g. if there is not enough memory.
/// \param allocator Memory allocator from which table memory is allocated.
/// \param function Table is initialized with values of finction.Evalluate(0.0) to function.Evaluate(1.0).
/// \param subSample If true, only sample the function a limited number of times and interpolate.
void Initialize (dng_memory_allocator &allocator,
const dng_1d_function &function,
bool subSample = false);
/// Lookup and interpolate mapping for an input.
/// \param x value from 0.0 to 1.0 used as input for mapping
/// \retval Approximation of function.Evaluate(x)
real32 Interpolate (real32 x) const
{
real32 y = x * (real32) fTableCount;
int32 index = (int32) y;
// Enable vectorization by using DNG_ASSERT instead of DNG_REQUIRE
DNG_ASSERT(!(index < 0 || index >(int32) fTableCount), "dng_1d_table::Interpolate parameter out of range");
real32 z = (real32) index;
real32 fract = y - z;
return fTable [index ] * (1.0f - fract) +
fTable [index + 1] * ( fract);
}
/// Direct access function for table data.
const real32 * Table () const
{
return fTable;
}
/// Expand the table to a 16-bit to 16-bit table.
void Expand16 (uint16 *table16) const;
private:
void SubDivide (const dng_1d_function &function,
uint32 lower,
uint32 upper,
real32 maxDelta);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,316 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_abort_sniffer.h"
#include "dng_assertions.h"
#include "dng_mutex.h"
/*****************************************************************************/
#if qDNGThreadSafe
/*****************************************************************************/
// TO DO: This priority-based wait mechanism is not compatible with thread
// pools. Putting worker threads to sleep may result in deadlock because
// higher priority work may not make progress (the pool may not be able to
// spin up any new threads).
class dng_priority_manager
{
private:
// Use lower-level mutex and condition_variable for priority manager
// since we don't want to include these in our priority tracking.
dng_mutex fMutex;
dng_condition fCondition;
uint32 fCounter [dng_priority_count];
public:
dng_priority_manager ();
void Increment (dng_priority priority,
const char *name);
void Decrement (dng_priority priority,
const char *name);
void Wait (dng_abort_sniffer *sniffer);
private:
dng_priority MinPriority ()
{
// Assumes mutex is locked.
for (uint32 level = dng_priority_maximum;
level > dng_priority_minimum;
level--)
{
if (fCounter [level])
{
return (dng_priority) level;
}
}
return dng_priority_minimum;
}
};
/*****************************************************************************/
dng_priority_manager::dng_priority_manager ()
: fMutex ("dng_priority_manager::fMutex")
, fCondition ()
{
for (uint32 level = dng_priority_minimum;
level <= dng_priority_maximum;
level++)
{
fCounter [level] = 0;
}
}
/*****************************************************************************/
void dng_priority_manager::Increment (dng_priority priority,
const char *name)
{
dng_lock_mutex lock (&fMutex);
fCounter [priority] += 1;
#if 0
printf ("increment priority %d (%s) (%d, %d, %d)\n",
(int) priority,
name,
fCounter [dng_priority_low],
fCounter [dng_priority_medium],
fCounter [dng_priority_high]);
#else
(void) name;
#endif
}
/*****************************************************************************/
void dng_priority_manager::Decrement (dng_priority priority,
const char *name)
{
dng_priority oldMin = dng_priority_minimum;
dng_priority newMin = dng_priority_minimum;
{
dng_lock_mutex lock (&fMutex);
oldMin = MinPriority ();
fCounter [priority] -= 1;
newMin = MinPriority ();
#if 0
printf ("decrement priority %d (%s) (%d, %d, %d)\n",
(int) priority,
name,
fCounter [dng_priority_low],
fCounter [dng_priority_medium],
fCounter [dng_priority_high]);
#else
(void) name;
#endif
}
if (newMin < oldMin)
{
fCondition.Broadcast ();
}
}
/*****************************************************************************/
void dng_priority_manager::Wait (dng_abort_sniffer *sniffer)
{
if (!sniffer)
{
return;
}
const dng_priority priority = sniffer->Priority ();
if (priority < dng_priority_maximum)
{
dng_lock_mutex lock (&fMutex);
while (priority < MinPriority ())
{
fCondition.Wait (fMutex);
}
}
}
/*****************************************************************************/
static dng_priority_manager gPriorityManager;
/*****************************************************************************/
#endif // qDNGThreadSafe
/*****************************************************************************/
dng_set_minimum_priority::dng_set_minimum_priority (dng_priority priority,
const char *name)
: fPriority (priority)
{
#if qDNGThreadSafe
gPriorityManager.Increment (fPriority, name);
#endif
fName.Set (name);
}
/*****************************************************************************/
dng_set_minimum_priority::~dng_set_minimum_priority ()
{
#if qDNGThreadSafe
gPriorityManager.Decrement (fPriority, fName.Get ());
#endif
}
/*****************************************************************************/
dng_abort_sniffer::dng_abort_sniffer ()
: fPriority (dng_priority_maximum)
{
}
/*****************************************************************************/
dng_abort_sniffer::~dng_abort_sniffer ()
{
}
/*****************************************************************************/
void dng_abort_sniffer::SetPriority (dng_priority priority)
{
fPriority = priority;
}
/*****************************************************************************/
bool dng_abort_sniffer::SupportsPriorityWait () const
{
return false;
}
/*****************************************************************************/
void dng_abort_sniffer::SniffForAbort (dng_abort_sniffer *sniffer)
{
if (sniffer)
{
#if qDNGThreadSafe
if (sniffer->SupportsPriorityWait ())
{
gPriorityManager.Wait (sniffer);
}
#endif
sniffer->Sniff ();
}
}
/*****************************************************************************/
void dng_abort_sniffer::StartTask (const char * /* name */,
real64 /* fract */)
{
}
/*****************************************************************************/
void dng_abort_sniffer::EndTask ()
{
}
/*****************************************************************************/
void dng_abort_sniffer::UpdateProgress (real64 /* fract */)
{
}
/*****************************************************************************/

@ -0,0 +1,241 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Classes supporting user cancellation and progress tracking.
*/
/*****************************************************************************/
#ifndef __dng_abort_sniffer__
#define __dng_abort_sniffer__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_flags.h"
#include "dng_string.h"
#include "dng_types.h"
#include "dng_uncopyable.h"
/*****************************************************************************/
/// \brief Thread priority level.
enum dng_priority
{
dng_priority_low,
dng_priority_medium,
dng_priority_high,
dng_priority_count,
dng_priority_minimum = dng_priority_low,
dng_priority_maximum = dng_priority_high
};
/*****************************************************************************/
/// \brief Convenience class for setting thread priority level to minimum.
class dng_set_minimum_priority
{
private:
dng_priority fPriority;
dng_string fName;
public:
dng_set_minimum_priority (dng_priority priority,
const char *name);
~dng_set_minimum_priority ();
};
/*****************************************************************************/
/** \brief Class for signaling user cancellation and receiving progress updates.
*
* DNG SDK clients should derive a host application specific implementation
* from this class.
*/
class dng_abort_sniffer
{
friend class dng_sniffer_task;
private:
dng_priority fPriority;
public:
dng_abort_sniffer ();
virtual ~dng_abort_sniffer ();
/// Getter for priority level.
dng_priority Priority () const
{
return fPriority;
}
/// Setter for priority level.
void SetPriority (dng_priority priority);
/// Check for pending user cancellation or other abort. ThrowUserCanceled
/// will be called if one is pending. This static method is provided as a
/// convenience for quickly testing for an abort and throwing an exception
/// if one is pending.
/// \param sniffer The dng_sniffer to test for a pending abort. Can be NULL,
/// in which case there an abort is never signalled.
static void SniffForAbort (dng_abort_sniffer *sniffer);
// A way to call Sniff while bypassing the priority wait.
void SniffNoPriorityWait ()
{
Sniff ();
}
// Specifies whether or not the sniffer may be called by multiple threads
// in parallel. Default result is false. Subclass must override to return
// true.
virtual bool ThreadSafe () const
{
return false;
}
// Specifies whether or not this sniffer may participate in
// priority-based waiting (sleep the current thread on which
// SniffForAbort is called, if another thread has higher priority).
// Default result is false. Subclass must override to return true.
virtual bool SupportsPriorityWait () const;
protected:
/// Should be implemented by derived classes to check for an user
/// cancellation.
virtual void Sniff () = 0;
/// Signals the start of a named task withn processing in the DNG SDK.
/// Tasks may be nested.
/// \param name of the task
/// \param fract Percentage of total processing this task is expected to
/// take. From 0.0 to 1.0 .
virtual void StartTask (const char *name,
real64 fract);
/// Signals the end of the innermost task that has been started.
virtual void EndTask ();
/// Signals progress made on current task.
/// \param fract percentage of processing completed on current task.
/// From 0.0 to 1.0 .
virtual void UpdateProgress (real64 fract);
};
/******************************************************************************/
/// \brief Class to establish scope of a named subtask in DNG processing.
///
/// Instances of this class are intended to be stack allocated.
class dng_sniffer_task: private dng_uncopyable
{
private:
dng_abort_sniffer *fSniffer;
public:
/// Inform a sniffer of a subtask in DNG processing.
/// \param sniffer The sniffer associated with the host on which this
/// processing is occurring.
/// \param name The name of this subtask as a NUL terminated string.
/// \param fract Percentage of total processing this task is expected
/// to take, from 0.0 to 1.0 .
dng_sniffer_task (dng_abort_sniffer *sniffer,
const char *name = NULL,
real64 fract = 0.0)
: fSniffer (sniffer)
{
if (fSniffer)
fSniffer->StartTask (name, fract);
}
~dng_sniffer_task ()
{
if (fSniffer)
fSniffer->EndTask ();
}
/// Check for pending user cancellation or other abort. ThrowUserCanceled
/// will be called if one is pending.
void Sniff ()
{
dng_abort_sniffer::SniffForAbort (fSniffer);
}
/// Update progress on this subtask.
/// \param fract Percentage of processing completed on current task,
/// from 0.0 to 1.0 .
void UpdateProgress (real64 fract)
{
if (fSniffer)
fSniffer->UpdateProgress (fract);
}
/// Update progress on this subtask.
/// \param done Amount of task completed in arbitrary integer units.
/// \param total Total size of task in same arbitrary integer units as done.
void UpdateProgress (uint32 done,
uint32 total)
{
UpdateProgress ((real64) done /
(real64) total);
}
/// Signal task completed for progress purposes.
void Finish ()
{
UpdateProgress (1.0);
}
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,324 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_area_task.h"
#include "dng_abort_sniffer.h"
#include "dng_auto_ptr.h"
#include "dng_flags.h"
#include "dng_globals.h"
#include "dng_sdk_limits.h"
#include "dng_tile_iterator.h"
#include "dng_utils.h"
/*****************************************************************************/
dng_area_task::dng_area_task (const char *name)
: fMaxThreads (kMaxMPThreads)
, fMinTaskArea (256 * 256)
, fUnitCell (1, 1)
, fMaxTileSize (256, 256)
, fName ()
{
if (!name)
{
name = "dng_area_task";
}
fName.Set (name);
}
/*****************************************************************************/
dng_area_task::~dng_area_task ()
{
}
/*****************************************************************************/
dng_rect dng_area_task::RepeatingTile1 () const
{
return dng_rect ();
}
/*****************************************************************************/
dng_rect dng_area_task::RepeatingTile2 () const
{
return dng_rect ();
}
/*****************************************************************************/
dng_rect dng_area_task::RepeatingTile3 () const
{
return dng_rect ();
}
/*****************************************************************************/
void dng_area_task::Start (uint32 /* threadCount */,
const dng_rect & /* dstArea */,
const dng_point & /* tileSize */,
dng_memory_allocator * /* allocator */,
dng_abort_sniffer * /* sniffer */)
{
}
/*****************************************************************************/
void dng_area_task::Finish (uint32 /* threadCount */)
{
}
/*****************************************************************************/
dng_point dng_area_task::FindTileSize (const dng_rect &area) const
{
dng_rect repeatingTile1 = RepeatingTile1 ();
dng_rect repeatingTile2 = RepeatingTile2 ();
dng_rect repeatingTile3 = RepeatingTile3 ();
if (repeatingTile1.IsEmpty ())
{
repeatingTile1 = area;
}
if (repeatingTile2.IsEmpty ())
{
repeatingTile2 = area;
}
if (repeatingTile3.IsEmpty ())
{
repeatingTile3 = area;
}
uint32 repeatV = Min_uint32 (Min_uint32 (repeatingTile1.H (),
repeatingTile2.H ()),
repeatingTile3.H ());
uint32 repeatH = Min_uint32 (Min_uint32 (repeatingTile1.W (),
repeatingTile2.W ()),
repeatingTile3.W ());
dng_point maxTileSize = MaxTileSize ();
dng_point tileSize;
tileSize.v = Min_int32 (repeatV, maxTileSize.v);
tileSize.h = Min_int32 (repeatH, maxTileSize.h);
// Make Xcode happy (div by zero).
tileSize.v = Max_int32 (tileSize.v, 1);
tileSize.h = Max_int32 (tileSize.h, 1);
// What this is doing is, if the smallest repeating image tile is larger than the
// maximum tile size, adjusting the tile size down so that the tiles are as small
// as possible while still having the same number of tiles covering the
// repeat area. This makes the areas more equal in size, making MP
// algorithms work better.
// The image core team did not understand this code, and disabled it.
// Really stupid idea to turn off code you don't understand!
// I'm undoing this removal, because I think the code is correct and useful.
uint32 countV = (repeatV + tileSize.v - 1) / tileSize.v;
uint32 countH = (repeatH + tileSize.h - 1) / tileSize.h;
// Make Xcode happy (div by zero).
countV = Max_uint32 (countV, 1);
countH = Max_uint32 (countH, 1);
tileSize.v = (repeatV + countV - 1) / countV;
tileSize.h = (repeatH + countH - 1) / countH;
// Round up to unit cell size.
dng_point unitCell = UnitCell ();
if (unitCell.h != 1 || unitCell.v != 1)
{
tileSize.v = ((tileSize.v + unitCell.v - 1) / unitCell.v) * unitCell.v;
tileSize.h = ((tileSize.h + unitCell.h - 1) / unitCell.h) * unitCell.h;
}
// But if that is larger than maximum tile size, round down to unit cell size.
if (tileSize.v > maxTileSize.v)
{
tileSize.v = (maxTileSize.v / unitCell.v) * unitCell.v;
}
if (tileSize.h > maxTileSize.h)
{
tileSize.h = (maxTileSize.h / unitCell.h) * unitCell.h;
}
if (gPrintTimings)
{
fprintf (stdout,
"\nRender tile for below: %d x %d\n",
(int32) tileSize.h,
(int32) tileSize.v);
}
return tileSize;
}
/*****************************************************************************/
void dng_area_task::ProcessOnThread (uint32 threadIndex,
const dng_rect &area,
const dng_point &tileSize,
dng_abort_sniffer *sniffer,
dng_area_task_progress *progress)
{
dng_rect repeatingTile1 = RepeatingTile1 ();
dng_rect repeatingTile2 = RepeatingTile2 ();
dng_rect repeatingTile3 = RepeatingTile3 ();
if (repeatingTile1.IsEmpty ())
{
repeatingTile1 = area;
}
if (repeatingTile2.IsEmpty ())
{
repeatingTile2 = area;
}
if (repeatingTile3.IsEmpty ())
{
repeatingTile3 = area;
}
dng_rect tile1;
// TODO_EP: Review & document case where these dynamic allocations appeared to have significant overhead
AutoPtr<dng_base_tile_iterator> iter1
(MakeTileIterator (threadIndex,
repeatingTile3,
area));
while (iter1->GetOneTile (tile1))
{
dng_rect tile2;
AutoPtr<dng_base_tile_iterator> iter2
(MakeTileIterator (threadIndex,
repeatingTile2,
tile1));
while (iter2->GetOneTile (tile2))
{
dng_rect tile3;
AutoPtr<dng_base_tile_iterator> iter3
(MakeTileIterator (threadIndex,
repeatingTile1,
tile2));
while (iter3->GetOneTile (tile3))
{
dng_rect tile4;
AutoPtr<dng_base_tile_iterator> iter4
(MakeTileIterator (threadIndex,
tileSize,
tile3));
while (iter4->GetOneTile (tile4))
{
dng_abort_sniffer::SniffForAbort (sniffer);
Process (threadIndex, tile4, sniffer);
if (progress)
{
progress->FinishedTile (tile4);
}
}
}
}
}
}
/*****************************************************************************/
dng_base_tile_iterator * dng_area_task::MakeTileIterator (uint32 /* threadIndex */,
const dng_rect &tile,
const dng_rect &area) const
{
return new dng_tile_forward_iterator (tile, area);
}
/*****************************************************************************/
dng_base_tile_iterator * dng_area_task::MakeTileIterator (uint32 /* threadIndex */,
const dng_point &tileSize,
const dng_rect &area) const
{
return new dng_tile_forward_iterator (tileSize, area);
}
/*****************************************************************************/
void dng_area_task::Perform (dng_area_task &task,
const dng_rect &area,
dng_memory_allocator *allocator,
dng_abort_sniffer *sniffer,
dng_area_task_progress *progress)
{
dng_point tileSize (task.FindTileSize (area));
task.Start (1, area, tileSize, allocator, sniffer);
task.ProcessOnThread (0, area, tileSize, sniffer, progress);
task.Finish (1);
}
/*****************************************************************************/

@ -0,0 +1,286 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Class to handle partitioning a rectangular image processing operation taking
* into account multiple processing resources and memory constraints.
*/
/*****************************************************************************/
#ifndef __dng_area_task__
#define __dng_area_task__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_point.h"
#include "dng_string.h"
#include "dng_types.h"
#include "dng_uncopyable.h"
/*****************************************************************************/
class dng_area_task_progress: private dng_uncopyable
{
public:
virtual ~dng_area_task_progress ()
{
}
virtual void FinishedTile (const dng_rect & /* tile */) = 0;
};
/*****************************************************************************/
/// \brief Abstract class for rectangular processing operations with support
/// for partitioning across multiple processing resources and observing memory
/// constraints.
class dng_area_task
{
protected:
uint32 fMaxThreads;
uint32 fMinTaskArea;
dng_point fUnitCell;
dng_point fMaxTileSize;
dng_string fName;
public:
explicit dng_area_task (const char *name = "unnamed dng_area_task");
virtual ~dng_area_task ();
const char * Name () const
{
return fName.Get ();
}
/// Getter for the maximum number of threads (resources) that can be
/// used for processing
///
/// \retval Number of threads, minimum of 1, that can be used for this task.
virtual uint32 MaxThreads () const
{
return fMaxThreads;
}
/// Getter for minimum area of a partitioned rectangle.
/// Often it is not profitable to use more resources if it requires
/// partitioning the input into chunks that are too small, as the
/// overhead increases more than the speedup. This method can be
/// ovreridden for a specific task to indicate the smallest area for
/// partitioning. Default is 256x256 pixels.
///
/// \retval Minimum area for a partitoned tile in order to give performant
/// operation. (Partitions can be smaller due to small inputs and edge cases.)
virtual uint32 MinTaskArea () const
{
return fMinTaskArea;
}
/// Getter for dimensions of which partitioned tiles should be a multiple.
/// Various methods of processing prefer certain alignments. The
/// partitioning attempts to construct tiles such that the sizes are a
/// multiple of the dimensions of this point.
///
/// \retval a point giving preferred alignment in x and y
virtual dng_point UnitCell () const
{
return fUnitCell;
}
/// Getter for maximum size of a tile for processing.
/// Often processing will need to allocate temporary buffers or use
/// other resources that are either fixed or in limited supply. The
/// maximum tile size forces further partitioning if the tile is bigger
/// than this size.
///
/// \retval Maximum tile size allowed for this area task.
virtual dng_point MaxTileSize () const
{
return fMaxTileSize;
}
/// Getter for RepeatingTile1.
/// RepeatingTile1, RepeatingTile2, and RepeatingTile3 are used to
/// establish a set of 0 to 3 tile patterns for which the resulting
/// partitions that the final Process method is called on will not cross
/// tile boundaries in any of the tile patterns. This can be used for a
/// processing routine that needs to read from two tiles and write to a
/// third such that all the tiles are aligned and sized in a certain
/// way. A RepeatingTile value is valid if it is non-empty. Higher
/// numbered RepeatingTile patterns are only used if all lower ones are
/// non-empty. A RepeatingTile pattern must be a multiple of UnitCell in
/// size for all constraints of the partitionerr to be met.
virtual dng_rect RepeatingTile1 () const;
/// Getter for RepeatingTile2.
/// RepeatingTile1, RepeatingTile2, and RepeatingTile3 are used to
/// establish a set of 0 to 3 tile patterns for which the resulting
/// partitions that the final Process method is called on will not cross
/// tile boundaries in any of the tile patterns. This can be used for a
/// processing routine that needs to read from two tiles and write to a
/// third such that all the tiles are aligned and sized in a certain
/// way. A RepeatingTile value is valid if it is non-empty. Higher
/// numbered RepeatingTile patterns are only used if all lower ones are
/// non-empty. A RepeatingTile pattern must be a multiple of UnitCell in
/// size for all constraints of the partitionerr to be met.
virtual dng_rect RepeatingTile2 () const;
/// Getter for RepeatingTile3.
/// RepeatingTile1, RepeatingTile2, and RepeatingTile3 are used to
/// establish a set of 0 to 3 tile patterns for which the resulting
/// partitions that the final Process method is called on will not cross
/// tile boundaries in any of the tile patterns. This can be used for a
/// processing routine that needs to read from two tiles and write to a
/// third such that all the tiles are aligned and sized in a certain
/// way. A RepeatingTile value is valid if it is non-empty. Higher
/// numbered RepeatingTile patterns are only used if all lower ones are
/// non-empty. A RepeatingTile pattern must be a multiple of UnitCell in
/// size for all constraints of the partitionerr to be met.
virtual dng_rect RepeatingTile3 () const;
/// Task startup method called before any processing is done on partitions.
/// The Start method is called before any processing is done and can be
/// overridden to allocate temporary buffers, etc.
///
/// \param threadCount Total number of threads that will be used for processing.
/// Less than or equal to MaxThreads.
/// \param dstArea Area to be processed in the current run of the task.
/// \param tileSize Size of source tiles which will be processed.
/// (Not all tiles will be this size due to edge conditions.)
/// \param allocator dng_memory_allocator to use for allocating temporary buffers, etc.
/// \param sniffer Sniffer to test for user cancellation and to set up progress.
virtual void Start (uint32 threadCount,
const dng_rect &dstArea,
const dng_point &tileSize,
dng_memory_allocator *allocator,
dng_abort_sniffer *sniffer);
/// Process one tile or fully partitioned area. This method is
/// overridden by derived classes to implement the actual image
/// processing. Note that the sniffer can be ignored if it is certain
/// that a processing task will complete very quickly. This method
/// should never be called directly but rather accessed via Process.
/// There is no allocator parameter as all allocation should be done in
/// Start.
///
/// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
/// (Can be used to get a thread-specific buffer allocated in the Start method.)
/// \param tile Area to process.
/// \param sniffer dng_abort_sniffer to use to check for user cancellation
/// and progress updates.
virtual void Process (uint32 threadIndex,
const dng_rect &tile,
dng_abort_sniffer *sniffer) = 0;
/// Task computation finalization and teardown method. Called after all
/// resources have completed processing. Can be overridden to accumulate
/// results and free resources allocated in Start.
///
/// \param threadCount Number of threads used for processing. Same as value passed to Start.
virtual void Finish (uint32 threadCount);
/// Find tile size taking into account repeating tiles, unit cell, and maximum tile size.
/// \param area Computation area for which to find tile size.
/// \retval Tile size as height and width in point.
dng_point FindTileSize (const dng_rect &area) const;
/// Handle one resource's worth of partitioned tiles. Called after
/// thread partitioning has already been done. Area may be further
/// subdivided to handle maximum tile size, etc. It will be rare to
/// override this method.
///
/// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
/// \param area Tile area partitioned to this resource.
/// \param tileSize size of tiles to use for processing.
/// \param sniffer dng_abort_sniffer to use to check for user cancellation and progress updates.
/// \param progress optional pointer to progress reporting object.
void ProcessOnThread (uint32 threadIndex,
const dng_rect &area,
const dng_point &tileSize,
dng_abort_sniffer *sniffer,
dng_area_task_progress *progress);
/// Factory method to make a tile iterator. This iterator will be used
/// by a thread to process tiles in an area in a specific order. The
/// default implementation uses a forward iterator that visits tiles
/// from left to right (inner), top down (outer). Subclasses can
/// override this method to produce tile iterators that visit tiles in
/// different orders.
///
/// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
/// \param tile The tile to be traversed within the tile area.
/// \param area Tile area partitioned to this resource.
virtual dng_base_tile_iterator * MakeTileIterator (uint32 threadIndex,
const dng_rect &tile,
const dng_rect &area) const;
/// Factory method to make a tile iterator. This iterator will be used
/// by a thread to process tiles in an area in a specific order. The
/// default implementation uses a forward iterator that visits tiles
/// from left to right (inner), top down (outer). Subclasses can
/// override this method to produce tile iterators that visit tiles in
/// different orders.
///
/// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
/// \param tileSize The tile size to be traversed within the tile area.
/// \param area Tile area partitioned to this resource.
virtual dng_base_tile_iterator * MakeTileIterator (uint32 threadIndex,
const dng_point &tileSize,
const dng_rect &area) const;
/// Default resource partitioner that assumes a single resource to be
/// used for processing. Implementations that are aware of multiple
/// processing resources should override (replace) this method. This is
/// usually done in dng_host::PerformAreaTask.
///
/// \param task The task to perform.
/// \param area The area on which mage processing should be performed.
/// \param allocator dng_memory_allocator to use for allocating temporary buffers, etc.
/// \param sniffer dng_abort_sniffer to use to check for user cancellation and progress updates.
/// \param progress optional pointer to progress reporting object.
static void Perform (dng_area_task &task,
const dng_rect &area,
dng_memory_allocator *allocator,
dng_abort_sniffer *sniffer,
dng_area_task_progress *progress);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,128 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Conditionally compiled assertion check support.
*/
/*****************************************************************************/
#ifndef __dng_assertions__
#define __dng_assertions__
/*****************************************************************************/
#include "dng_exceptions.h"
#include "dng_flags.h"
/*****************************************************************************/
#if qDNGDebug
/// Platform-specific function to display an assert.
void dng_show_message (const char *s);
/// Show a formatted error message.
void dng_show_message_f (const char *fmt, ...);
#endif
/*****************************************************************************/
#ifndef DNG_ASSERT
#if qDNGDebug
/// Conditionally compiled macro to check an assertion and display a message if
/// it fails and assertions are compiled in via qDNGDebug
/// \param x Predicate which must be true.
/// \param y String to display if x is not true.
#define DNG_ASSERT(x,y) { if (!(x)) dng_show_message (y); }
#else
/// Conditionally compiled macro to check an assertion and display a message if
/// it fails and assertions are compiled in via qDNGDebug
/// \param x Predicate which must be true.
/// \param y String to display if x is not true.
#define DNG_ASSERT(x,y)
#endif
#endif
/*****************************************************************************/
#ifndef DNG_REQUIRE
#if qDNGDebug
/// Conditionally compiled macro to check an assertion, display a message, and throw
/// an exception if it fails and assertions are compiled in via qDNGDebug
/// \param condition Predicate which must be true.
/// \param msg String to display if condition is not true.
#define DNG_REQUIRE(condition,msg) \
do \
{ \
\
if (!(condition)) \
{ \
\
DNG_ASSERT(condition, msg); \
\
ThrowProgramError (msg); \
\
} \
\
} \
while (0)
#else
/// Conditionally compiled macro to check an assertion, display a message, and throw
/// an exception if it fails and assertions are compiled in via qDNGDebug
/// \param condition Predicate which must be true.
/// \param msg String to display if condition is not true.
#define DNG_REQUIRE(condition,msg) \
do \
{ \
\
if (!(condition)) \
{ \
\
ThrowProgramError (msg); \
\
} \
\
} \
while (0)
#endif
#endif
/*****************************************************************************/
#ifndef DNG_REPORT
/// Macro to display an informational message
/// \param x String to display.
#define DNG_REPORT(x) DNG_ASSERT (false, x)
#endif
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,239 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Class to implement std::auto_ptr like functionality even on platforms which do not
* have a full Standard C++ library.
*/
/*****************************************************************************/
#ifndef __dng_auto_ptr__
#define __dng_auto_ptr__
#include <stddef.h>
#include "dng_uncopyable.h"
/*****************************************************************************/
// The following template has similar functionality to the STL auto_ptr, without
// requiring all the weight of STL.
/*****************************************************************************/
/// \brief A class intended to be used in stack scope to hold a pointer from new. The
/// held pointer will be deleted automatically if the scope is left without calling
/// Release on the AutoPtr first.
template<class T>
class AutoPtr: private dng_uncopyable
{
private:
T *p_;
public:
/// Construct an AutoPtr with no referent.
AutoPtr () : p_ (0) { }
/// Construct an AutoPtr which owns the argument pointer.
/// \param p pointer which constructed AutoPtr takes ownership of. p will be
/// deleted on destruction or Reset unless Release is called first.
explicit AutoPtr (T *p) : p_( p ) { }
/// Reset is called on destruction.
~AutoPtr ();
/// Call Reset with a pointer from new. Uses T's default constructor.
void Alloc ();
/// Return the owned pointer of this AutoPtr, NULL if none. No change in
/// ownership or other effects occur.
T *Get () const { return p_; }
/// Return the owned pointer of this AutoPtr, NULL if none. The AutoPtr gives
/// up ownership and takes NULL as its value.
T *Release ();
/// If a pointer is owned, it is deleted. Ownership is taken of passed in
/// pointer.
/// \param p pointer which constructed AutoPtr takes ownership of. p will be
/// deleted on destruction or Reset unless Release is called first.
void Reset (T *p);
/// If a pointer is owned, it is deleted and the AutoPtr takes NULL as its
/// value.
void Reset ();
/// Allows members of the owned pointer to be accessed directly. It is an
/// error to call this if the AutoPtr has NULL as its value.
T *operator-> () const { return p_; }
/// Returns a reference to the object that the owned pointer points to. It is
/// an error to call this if the AutoPtr has NULL as its value.
T &operator* () const { return *p_; }
/// Swap with another auto ptr.
friend inline void Swap (AutoPtr< T > &x, AutoPtr< T > &y)
{
T* temp = x.p_;
x.p_ = y.p_;
y.p_ = temp;
}
};
/*****************************************************************************/
template<class T>
AutoPtr<T>::~AutoPtr ()
{
delete p_;
p_ = 0;
}
/*****************************************************************************/
template<class T>
T *AutoPtr<T>::Release ()
{
T *result = p_;
p_ = 0;
return result;
}
/*****************************************************************************/
template<class T>
void AutoPtr<T>::Reset (T *p)
{
if (p_ != p)
{
if (p_ != 0)
delete p_;
p_ = p;
}
}
/*****************************************************************************/
template<class T>
void AutoPtr<T>::Reset ()
{
if (p_ != 0)
{
delete p_;
p_ = 0;
}
}
/*****************************************************************************/
template<class T>
void AutoPtr<T>::Alloc ()
{
this->Reset (new T);
}
/*****************************************************************************/
/// \brief A class intended to be used similarly to AutoPtr but for arrays.
template<typename T>
class AutoArray: private dng_uncopyable
{
public:
/// Construct an AutoArray which owns the argument pointer.
/// \param p_ array pointer which constructed AutoArray takes ownership of. p_
/// will be deleted on destruction or Reset unless Release is called first.
explicit AutoArray (T *p_ = 0) : p (p_) { }
/// Reset is called on destruction.
~AutoArray ()
{
delete [] p;
p = 0;
}
/// Return the owned array pointer of this AutoArray, NULL if none. The
/// AutoArray gives up ownership and takes NULL as its value.
T *Release ()
{
T *p_ = p;
p = 0;
return p_;
}
/// If an array pointer is owned, it is deleted. Ownership is
/// taken of the passed in pointer p_.
/// \param p_ array pointer which constructed AutoArray takes ownership of. p_
/// will be deleted on destruction or Reset unless Release is called first.
void Reset (T *p_ = 0)
{
if (p != p_)
{
delete [] p;
p = p_;
}
}
/// Allows indexing into the AutoArray. It is an error to call this if the
/// AutoArray has NULL as its value.
T &operator[] (ptrdiff_t i) const
{
return p [i];
}
/// Return the owned pointer of this AutoArray, NULL if none. No change in
/// ownership or other effects occur.
T *Get () const
{
return p;
}
private:
// Owned pointer or NULL.
T *p;
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,303 @@
/*****************************************************************************/
// Copyright 2008-2019 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.
/*****************************************************************************/
/** \file
* Opcodes to fix defective pixels, including individual pixels and regions (such as
* defective rows and columns).
*/
/*****************************************************************************/
#ifndef __dng_bad_pixels__
#define __dng_bad_pixels__
/*****************************************************************************/
#include "dng_memory.h"
#include "dng_opcodes.h"
#include <vector>
/*****************************************************************************/
/// \brief An opcode to fix individual bad pixels that are marked with a constant
/// value (e.g., 0) in a Bayer image.
class dng_opcode_FixBadPixelsConstant: public dng_filter_opcode
{
private:
uint32 fConstant;
uint32 fBayerPhase;
public:
/// Construct an opcode to fix an individual bad pixels that are marked with
/// a constant value in a Bayer image.
/// \param constant The constant value that indicates a bad pixel.
/// \param bayerPhase The phase of the Bayer mosaic pattern (0, 1, 2, 3).
dng_opcode_FixBadPixelsConstant (uint32 constant,
uint32 bayerPhase);
dng_opcode_FixBadPixelsConstant (dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual dng_point SrcRepeat ();
virtual dng_rect SrcArea (const dng_rect &dstArea,
const dng_rect &imageBounds);
virtual void Prepare (dng_negative &negative,
uint32 threadCount,
const dng_point &tileSize,
const dng_rect &imageBounds,
uint32 imagePlanes,
uint32 bufferPixelType,
dng_memory_allocator &allocator);
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &srcBuffer,
dng_pixel_buffer &dstBuffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
protected:
bool IsGreen (int32 row, int32 col) const
{
return (((uint32) row + (uint32) col + fBayerPhase + (fBayerPhase >> 1)) & 1) == 0;
}
};
/*****************************************************************************/
/// \brief A list of bad pixels and rectangles (usually single rows or columns).
class dng_bad_pixel_list
{
public:
enum
{
kNoIndex = 0xFFFFFFFF
};
private:
// List of bad single pixels.
dng_std_vector<dng_point> fBadPoints;
// List of bad rectangles (usually single rows or columns).
dng_std_vector<dng_rect> fBadRects;
public:
/// Create an empty bad pixel list.
dng_bad_pixel_list ();
/// Returns the number of bad single pixels.
uint32 PointCount () const
{
return (uint32) fBadPoints.size ();
}
/// Retrieves the bad single pixel coordinate via the specified list index.
///
/// \param index The list index from which to retrieve the bad single pixel
/// coordinate.
const dng_point & Point (uint32 index) const
{
return fBadPoints [index];
}
/// Returns the number of bad rectangles.
uint32 RectCount () const
{
return (uint32) fBadRects.size ();
}
/// Retrieves the bad rectangle via the specified list index.
///
/// \param index The list index from which to retrieve the bad rectangle
/// coordinates.
const dng_rect & Rect (uint32 index) const
{
return fBadRects [index];
}
/// Returns true iff there are zero bad single pixels and zero bad
/// rectangles.
bool IsEmpty () const
{
return PointCount () == 0 &&
RectCount () == 0;
}
/// Returns true iff there is at least one bad single pixel or at least one
/// bad rectangle.
bool NotEmpty () const
{
return !IsEmpty ();
}
/// Add the specified coordinate to the list of bad single pixels.
///
/// \param pt The bad single pixel to add.
void AddPoint (const dng_point &pt);
/// Add the specified rectangle to the list of bad rectangles.
///
/// \param r The bad rectangle to add.
void AddRect (const dng_rect &r);
/// Sort the bad single pixels and bad rectangles by coordinates (top to
/// bottom, then left to right).
void Sort ();
/// Returns true iff the specified bad single pixel is isolated, i.e., there
/// is no other bad single pixel or bad rectangle that lies within radius
/// pixels of this bad single pixel.
///
/// \param index The index of the bad single pixel to test.
/// \param radius The pixel radius to test for isolation.
bool IsPointIsolated (uint32 index,
uint32 radius) const;
/// Returns true iff the specified bad rectangle is isolated, i.e., there
/// is no other bad single pixel or bad rectangle that lies within radius
/// pixels of this bad rectangle.
///
/// \param index The index of the bad rectangle to test.
/// \param radius The pixel radius to test for isolation.
bool IsRectIsolated (uint32 index,
uint32 radius) const;
/// Returns true iff the specified point is valid, i.e., lies within the
/// specified image bounds, is different from all other bad single pixels,
/// and is not contained in any bad rectangle. The second and third
/// conditions are only checked if provided with a starting search index.
///
/// \param pt The point to test for validity.
/// \param imageBounds The pt must lie within imageBounds to be valid.
/// \index The search index to use (or kNoIndex, to avoid a search) for
/// checking for validity.
bool IsPointValid (const dng_point &pt,
const dng_rect &imageBounds,
uint32 index = kNoIndex) const;
};
/*****************************************************************************/
/// \brief An opcode to fix lists of bad pixels (indicated by position) in a Bayer
/// image.
class dng_opcode_FixBadPixelsList: public dng_filter_opcode
{
protected:
enum
{
kBadPointPadding = 2,
kBadRectPadding = 4
};
private:
AutoPtr<dng_bad_pixel_list> fList;
uint32 fBayerPhase;
public:
/// Construct an opcode to fix lists of bad pixels (indicated by position) in
/// a Bayer image.
/// \param list The list of bad pixels to fix.
/// \param bayerPhase The phase of the Bayer mosaic pattern (0, 1, 2, 3).
dng_opcode_FixBadPixelsList (AutoPtr<dng_bad_pixel_list> &list,
uint32 bayerPhase);
dng_opcode_FixBadPixelsList (dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual dng_point SrcRepeat ();
virtual dng_rect SrcArea (const dng_rect &dstArea,
const dng_rect &imageBounds);
virtual void Prepare (dng_negative &negative,
uint32 threadCount,
const dng_point &tileSize,
const dng_rect &imageBounds,
uint32 imagePlanes,
uint32 bufferPixelType,
dng_memory_allocator &allocator);
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &srcBuffer,
dng_pixel_buffer &dstBuffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
protected:
bool IsGreen (int32 row, int32 col) const
{
return ((row + col + fBayerPhase + (fBayerPhase >> 1)) & 1) == 0;
}
virtual void FixIsolatedPixel (dng_pixel_buffer &buffer,
dng_point &badPoint);
virtual void FixClusteredPixel (dng_pixel_buffer &buffer,
uint32 pointIndex,
const dng_rect &imageBounds);
virtual void FixSingleColumn (dng_pixel_buffer &buffer,
const dng_rect &badRect);
virtual void FixSingleRow (dng_pixel_buffer &buffer,
const dng_rect &badRect);
virtual void FixClusteredRect (dng_pixel_buffer &buffer,
const dng_rect &badRect,
const dng_rect &imageBounds);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,670 @@
/*****************************************************************************/
// Copyright 2015-2019 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.
/*****************************************************************************/
#ifndef __dng_big_table__
#define __dng_big_table__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_camera_profile.h"
/*****************************************************************************/
class dng_big_table_cache;
class dng_big_table_storage;
/*****************************************************************************/
void dng_big_table_cache_flush ();
/*****************************************************************************/
class dng_big_table
{
protected:
enum BigTableTypeEnum
{
btt_LookTable = 0,
btt_RGBTable = 1
};
private:
dng_fingerprint fFingerprint;
dng_big_table_cache * fCache;
bool fIsMissing;
protected:
dng_big_table (dng_big_table_cache *cache);
dng_big_table (const dng_big_table &table);
dng_big_table & operator= (const dng_big_table &table);
public:
virtual ~dng_big_table ();
bool IsMissing () const
{
return fIsMissing;
}
void SetMissing ()
{
fIsMissing = true;
}
virtual bool IsValid () const = 0;
const dng_fingerprint & Fingerprint () const;
bool DecodeFromBinary (const uint8 * compressedData,
uint32 compressedSize,
dng_memory_allocator &allocator);
bool DecodeFromString (const dng_string &block1,
dng_memory_allocator &allocator);
dng_memory_block * EncodeAsBinary (dng_memory_allocator &allocator,
uint32 &compressedSize) const;
dng_memory_block * EncodeAsString (dng_memory_allocator &allocator) const;
bool ExtractFromCache (const dng_fingerprint &fingerprint);
bool ReadTableFromXMP (const dng_xmp &xmp,
const char *ns,
const dng_fingerprint &fingerprint);
bool ReadFromXMP (const dng_xmp &xmp,
const char *ns,
const char *path,
dng_big_table_storage &storage);
void WriteToXMP (dng_xmp &xmp,
const char *ns,
const char *path,
dng_big_table_storage &storage) const;
protected:
void RecomputeFingerprint ();
virtual void GetStream (dng_stream &stream) = 0;
virtual void PutStream (dng_stream &stream,
bool forFingerprint) const = 0;
};
/*****************************************************************************/
class dng_big_table_storage
{
public:
dng_big_table_storage ();
virtual ~dng_big_table_storage ();
virtual bool ReadTable (dng_big_table &table,
const dng_fingerprint &fingerprint,
dng_memory_allocator &allocator);
virtual bool WriteTable (const dng_big_table &table,
const dng_fingerprint &fingerprint,
dng_memory_allocator &allocator);
virtual void MissingTable (const dng_fingerprint &fingerprint);
};
/*****************************************************************************/
class dng_look_table : public dng_big_table
{
friend class dng_look_table_cache;
public:
enum
{
// Tables are are allowed to trade off resolution
// between dimensions, but need to keep total
// samples below this limit. This results in
// 216K memory footprint (12 byte per sample)
// which is similar in size to the RGB table
// size limit.
kMaxTotalSamples = 36 * 32 * 16,
// Also each must be within their own limits.
kMaxHueSamples = 360,
kMaxSatSamples = 256,
kMaxValSamples = 256
};
private:
enum
{
kLookTableVersion1 = 1,
kLookTableVersion2 = 2
};
// Table data affecting fingerprint and caching.
struct table_data
{
// 3-D hue/sat table to apply a "look".
dng_hue_sat_map fMap;
// Value (V of HSV) encoding for look table.
uint32 fEncoding;
// Minimum and maximum scale amounts supported by table.
real64 fMinAmount;
real64 fMaxAmount;
// Does this table have only monochrome output (when amount is 1.0)?
bool fMonochrome;
// Constructor to set defaults.
table_data ()
: fMap ()
, fEncoding (encoding_Linear)
, fMinAmount (1.0)
, fMaxAmount (1.0)
, fMonochrome (false)
{
}
// Compute monchrome flag.
void ComputeMonochrome ()
{
fMonochrome = true;
uint32 count = fMap.DeltasCount ();
dng_hue_sat_map::HSBModify * deltas = fMap.GetDeltas ();
for (uint32 index = 0; index < count; index++)
{
if (deltas [index] . fSatScale != 0.0f)
{
fMonochrome = false;
return;
}
}
}
};
table_data fData;
// Amount to apply at runtime (does not affect fingerprint).
real64 fAmount;
public:
dng_look_table ();
dng_look_table (const dng_look_table &table);
dng_look_table & operator= (const dng_look_table &table);
virtual ~dng_look_table ();
bool operator== (const dng_look_table &table) const
{
return Fingerprint () == table.Fingerprint () &&
Amount () == table.Amount () &&
IsMissing () == table.IsMissing ();
}
bool operator!= (const dng_look_table &table) const
{
return !(*this == table);
}
void Set (const dng_hue_sat_map &map,
uint32 encoding);
virtual bool IsValid () const;
void SetInvalid ();
real64 MinAmount () const
{
return fData.fMinAmount;
}
real64 MaxAmount () const
{
return fData.fMaxAmount;
}
void SetAmountRange (real64 minAmount,
real64 maxAmount)
{
fData.fMinAmount = Pin_real64 (0.0,
Round_int32 (minAmount * 100.0) * 0.01,
1.0);
fData.fMaxAmount = Pin_real64 (1.0,
Round_int32 (maxAmount * 100.0) * 0.01,
2.0);
fAmount = Pin_real64 (fData.fMinAmount, fAmount, fData.fMaxAmount);
RecomputeFingerprint ();
}
real64 Amount () const
{
return fAmount;
}
void SetAmount (real64 amount)
{
fAmount = Pin_real64 (fData.fMinAmount,
Round_int32 (amount * 100.0) * 0.01,
fData.fMaxAmount);
// Not part of fingerprint.
}
const dng_hue_sat_map & Map () const
{
return fData.fMap;
}
uint32 Encoding () const
{
return fData.fEncoding;
}
bool Monochrome () const
{
return IsValid () && fAmount == 1.0 && fData.fMonochrome;
}
protected:
virtual void GetStream (dng_stream &stream);
virtual void PutStream (dng_stream &stream,
bool forFingerprint) const;
};
/*****************************************************************************/
class dng_rgb_table : public dng_big_table
{
friend class dng_rgb_table_cache;
public:
enum
{
kMinDivisions1D = 2,
kMaxDivisions1D = 4096,
kMinDivisions3D = 2,
kMaxDivisions3D = 32,
kMaxDivisions3D_InMemory = 128
};
enum primaries_enum
{
primaries_sRGB = 0,
primaries_Adobe,
primaries_ProPhoto,
primaries_P3,
primaries_Rec2020,
primaries_count
};
enum gamma_enum
{
gamma_Linear = 0,
gamma_sRGB,
gamma_1_8,
gamma_2_2,
gamma_Rec2020,
gamma_count
};
enum gamut_enum
{
gamut_clip = 0,
gamut_extend,
gamut_count
};
private:
enum
{
kRGBTableVersion = 1
};
// Table data affecting fingerprint and caching.
struct table_data
{
// Number of dimensions of the table (1 or 3).
uint32 fDimensions;
// Number of samples per side of table.
uint32 fDivisions;
// Sample data. 16-bit unsigned encoding.
// Right zero padded to 64 bits per sample (i.e. RGB0).
dng_ref_counted_block fSamples;
// Color primaries for table.
primaries_enum fPrimaries;
// Gamma encoding for table.
gamma_enum fGamma;
// Gamut processing option for table.
gamut_enum fGamut;
// Minimum and maximum scale amounts supported by table.
real64 fMinAmount;
real64 fMaxAmount;
// Does this table have only monochrome output (when amount is 1.0)?
bool fMonochrome;
// Constructor to set defaults.
table_data ()
: fDimensions (0)
, fDivisions (0)
, fSamples ()
, fPrimaries (primaries_sRGB)
, fGamma (gamma_sRGB)
, fGamut (gamut_clip)
, fMinAmount (0.0)
, fMaxAmount (2.0)
, fMonochrome (false)
{
}
// Compute monchrome flag.
void ComputeMonochrome ()
{
if (fPrimaries != primaries_ProPhoto &&
fGamut != gamut_clip)
{
fMonochrome = false;
return;
}
if (fDimensions != 3)
{
fMonochrome = false;
return;
}
fMonochrome = true;
uint32 count = fDivisions * fDivisions * fDivisions;
const uint16 * sample = fSamples.Buffer_uint16 ();
for (uint32 index = 0; index < count; index++)
{
if (sample [0] != sample [1] ||
sample [0] != sample [2])
{
fMonochrome = false;
return;
}
sample += 4;
}
}
};
table_data fData;
// Amount to apply at runtime (does not affect fingerprint).
real64 fAmount;
public:
dng_rgb_table ();
dng_rgb_table (const dng_rgb_table &table);
dng_rgb_table & operator= (const dng_rgb_table &table);
virtual ~dng_rgb_table ();
bool operator== (const dng_rgb_table &table) const
{
return Fingerprint () == table.Fingerprint () &&
Amount () == table.Amount () &&
IsMissing () == table.IsMissing ();
}
bool operator!= (const dng_rgb_table &table) const
{
return !(*this == table);
}
virtual bool IsValid () const;
void SetInvalid ();
primaries_enum Primaries () const
{
return fData.fPrimaries;
}
void SetPrimaries (primaries_enum primaries)
{
fData.fPrimaries = primaries;
fData.ComputeMonochrome ();
RecomputeFingerprint ();
}
gamma_enum Gamma () const
{
return fData.fGamma;
}
void SetGamma (gamma_enum gamma)
{
fData.fGamma = gamma;
RecomputeFingerprint ();
}
gamut_enum Gamut () const
{
return fData.fGamut;
}
void SetGamut (gamut_enum gamut)
{
fData.fGamut = gamut;
fData.ComputeMonochrome ();
RecomputeFingerprint ();
}
real64 MinAmount () const
{
return fData.fMinAmount;
}
real64 MaxAmount () const
{
return fData.fMaxAmount;
}
void SetAmountRange (real64 minAmount,
real64 maxAmount)
{
fData.fMinAmount = Pin_real64 (0.0,
Round_int32 (minAmount * 100.0) * 0.01,
1.0);
fData.fMaxAmount = Pin_real64 (1.0,
Round_int32 (maxAmount * 100.0) * 0.01,
2.0);
fAmount = Pin_real64 (fData.fMinAmount, fAmount, fData.fMaxAmount);
RecomputeFingerprint ();
}
real64 Amount () const
{
return fAmount;
}
void SetAmount (real64 amount)
{
fAmount = Pin_real64 (fData.fMinAmount,
Round_int32 (amount * 100.0) * 0.01,
fData.fMaxAmount);
// Not part of fingerprint.
}
uint32 Dimensions () const
{
return fData.fDimensions;
}
uint32 Divisions () const
{
return fData.fDivisions;
}
const uint16 * Samples () const
{
return fData.fSamples.Buffer_uint16 ();
}
bool Monochrome () const
{
return IsValid () && fAmount == 1.0 && fData.fMonochrome;
}
void Set (uint32 dimensions,
uint32 divisions,
dng_ref_counted_block samples);
protected:
virtual void GetStream (dng_stream &stream);
virtual void PutStream (dng_stream &stream,
bool forFingerprint) const;
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,66 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_bottlenecks.h"
#include "dng_reference.h"
/*****************************************************************************/
dng_suite gDNGSuite =
{
RefZeroBytes,
RefCopyBytes,
RefSwapBytes16,
RefSwapBytes32,
RefSetArea8,
RefSetArea<Scalar, uint16>,
RefSetArea<Scalar, uint32>,
RefCopyArea8,
RefCopyArea16,
RefCopyArea32,
RefCopyArea8_16,
RefCopyArea8_S16,
RefCopyArea8_32,
RefCopyArea16_S16<Scalar>,
RefCopyArea16_32,
RefCopyArea8_R32,
RefCopyArea16_R32,
RefCopyAreaS16_R32,
RefCopyAreaR32_8,
RefCopyAreaR32_16,
RefCopyAreaR32_S16,
RefRepeatArea8,
RefRepeatArea16,
RefRepeatArea32,
RefShiftRight16,
RefBilinearRow16,
RefBilinearRow32,
RefBaselineABCtoRGB,
RefBaselineABCDtoRGB,
RefBaselineHueSatMap,
RefBaselineRGBtoGray,
RefBaselineRGBtoRGB,
RefBaseline1DTable,
RefBaselineRGBTone,
RefResampleDown16,
RefResampleDown32,
RefResampleAcross16,
RefResampleAcross32,
RefEqualBytes,
RefEqualArea8,
RefEqualArea16,
RefEqualArea32,
RefVignetteMask16,
RefVignette16,
RefVignette32,
RefMapArea16,
RefBaselineMapPoly32
};
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,879 @@
/******************************************************************************/
// Copyright 2006-2019 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.
/******************************************************************************/
/** \file
* Support for DNG camera color profile information.
* Per the \ref spec_dng "DNG 1.1.0 specification", a DNG file can store up to
* two sets of color profile information for a camera in the DNG file from that
* camera. The second set is optional and when there are two sets, they represent
* profiles made under different illumination.
*
* Profiling information is optionally separated into two parts. One part represents
* a profile for a reference camera. (ColorMatrix1 and ColorMatrix2 here.) The
* second is a per-camera calibration that takes into account unit-to-unit variation.
* This is designed to allow replacing the reference color matrix with one of one's
* own construction while maintaining any unit-specific calibration the camera
* manufacturer may have provided.
*
* See Appendix 6 of the \ref spec_dng "DNG 1.1.0 specification" for more information.
*/
#ifndef __dng_camera_profile__
#define __dng_camera_profile__
/******************************************************************************/
#include "dng_auto_ptr.h"
#include "dng_assertions.h"
#include "dng_classes.h"
#include "dng_fingerprint.h"
#include "dng_hue_sat_map.h"
#include "dng_matrix.h"
#include "dng_string.h"
#include "dng_tag_values.h"
#include "dng_tone_curve.h"
/******************************************************************************/
extern const char * kProfileName_Embedded;
extern const char * kAdobeCalibrationSignature;
/******************************************************************************/
/// \brief An ID for a camera profile consisting of a name and optional fingerprint.
class dng_camera_profile_id
{
private:
dng_string fName;
dng_fingerprint fFingerprint;
public:
/// Construct an invalid camera profile ID (empty name and fingerprint).
dng_camera_profile_id ()
: fName ()
, fFingerprint ()
{
}
/// Construct a camera profile ID with the specified name and no fingerprint.
/// \param name The name of the camera profile ID.
dng_camera_profile_id (const char *name)
: fName ()
, fFingerprint ()
{
fName.Set (name);
}
/// Construct a camera profile ID with the specified name and no fingerprint.
/// \param name The name of the camera profile ID.
dng_camera_profile_id (const dng_string &name)
: fName (name)
, fFingerprint ()
{
}
/// Construct a camera profile ID with the specified name and fingerprint.
/// \param name The name of the camera profile ID.
/// \param fingerprint The fingerprint of the camera profile ID.
dng_camera_profile_id (const char *name,
const dng_fingerprint &fingerprint)
: fName ()
, fFingerprint (fingerprint)
{
fName.Set (name);
DNG_ASSERT (!fFingerprint.IsValid () || fName.NotEmpty (),
"Cannot have profile fingerprint without name");
}
/// Construct a camera profile ID with the specified name and fingerprint.
/// \param name The name of the camera profile ID.
/// \param fingerprint The fingerprint of the camera profile ID.
dng_camera_profile_id (const dng_string &name,
const dng_fingerprint &fingerprint)
: fName (name)
, fFingerprint (fingerprint)
{
DNG_ASSERT (!fFingerprint.IsValid () || fName.NotEmpty (),
"Cannot have profile fingerprint without name");
}
/// Getter for the name of the camera profile ID.
/// \retval The name of the camera profile ID.
const dng_string & Name () const
{
return fName;
}
/// Getter for the fingerprint of the camera profile ID.
/// \retval The fingerprint of the camera profile ID.
const dng_fingerprint & Fingerprint () const
{
return fFingerprint;
}
/// Test for equality of two camera profile IDs.
/// \param id The id of the camera profile ID to compare.
bool operator== (const dng_camera_profile_id &id) const
{
return fName == id.fName &&
fFingerprint == id.fFingerprint;
}
/// Test for inequality of two camera profile IDs.
/// \param id The id of the camera profile ID to compare.
bool operator!= (const dng_camera_profile_id &id) const
{
return !(*this == id);
}
/// Returns true iff the camera profile ID is valid.
bool IsValid () const
{
return fName.NotEmpty (); // Fingerprint is optional.
}
/// Resets the name and fingerprint, thereby making this camera profile ID
/// invalid.
void Clear ()
{
*this = dng_camera_profile_id ();
}
};
/******************************************************************************/
/// \brief Container for DNG camera color profile and calibration data.
class dng_camera_profile
{
protected:
// Name of this camera profile.
dng_string fName;
// Light sources for up to two calibrations. These use the EXIF
// encodings for illuminant and are used to distinguish which
// matrix to use.
uint32 fCalibrationIlluminant1;
uint32 fCalibrationIlluminant2;
// Color matrices for up to two calibrations.
// These matrices map XYZ values to non-white balanced camera values.
// Adobe needs to go that direction in order to determine the clipping
// points for highlight recovery logic based on the white point. If
// cameras were all 3-color, the matrix could be stored as a forward matrix,
// but we need the backwards matrix to deal with 4-color cameras.
dng_matrix fColorMatrix1;
dng_matrix fColorMatrix2;
// These matrices map white balanced camera values to XYZ chromatically
// adapted to D50 (the ICC profile PCS white point). If the matrices
// exist, then this implies that white balancing should be done by scaling
// camera values with a diagonal matrix.
dng_matrix fForwardMatrix1;
dng_matrix fForwardMatrix2;
// Dimensionality reduction hints for more than three color cameras.
// This is an optional matrix that maps the camera's color components
// to 3 components. These are only used if the forward matrices don't
// exist, and are used invert the color matrices.
dng_matrix fReductionMatrix1;
dng_matrix fReductionMatrix2;
// MD5 hash for all data bits of the profile.
mutable dng_fingerprint fFingerprint;
// Copyright notice from creator of profile.
dng_string fCopyright;
// Rules for how this profile can be embedded and/or copied.
uint32 fEmbedPolicy;
// 2-D (or 3-D) hue/sat tables to modify colors.
dng_hue_sat_map fHueSatDeltas1;
dng_hue_sat_map fHueSatDeltas2;
// Value (V of HSV) encoding for hue/sat tables.
uint32 fHueSatMapEncoding;
// 3-D hue/sat table to apply a "look".
dng_hue_sat_map fLookTable;
// Value (V of HSV) encoding for look table.
uint32 fLookTableEncoding;
// Baseline exposure offset. When using this profile, this offset value is
// added to the BaselineExposure value for the negative to determine the
// overall baseline exposure to apply.
dng_srational fBaselineExposureOffset;
// Default black rendering.
uint32 fDefaultBlackRender;
// The "as shot" tone curve for this profile. Check IsValid method
// to tell if one exists in profile.
dng_tone_curve fToneCurve;
// If this string matches the fCameraCalibrationSignature of the
// negative, then use the calibration matrix values from the negative.
dng_string fProfileCalibrationSignature;
// If non-empty, only allow use of this profile with camera having
// same unique model name.
dng_string fUniqueCameraModelRestriction;
// Was this profile read from inside a DNG file? (If so, we wnat
// to be sure to include it again when writing out an updated
// DNG file)
bool fWasReadFromDNG;
// Was this profile read from disk (i.e., an external profile)? (If so, we
// may need to refresh when changes are made externally to the profile
// directory.)
bool fWasReadFromDisk;
// Was this profile a built-in "Matrix" profile? (If so, we may need to
// refresh -- i.e., remove it from the list of available profiles -- when
// changes are made externally to the profile directory.)
bool fWasBuiltinMatrix;
// Was this profile stubbed to save memory (and no longer valid
// for building color conversion tables)?
bool fWasStubbed;
public:
dng_camera_profile ();
virtual ~dng_camera_profile ();
// API for profile name:
/// Setter for camera profile name.
/// \param name Name to use for this camera profile.
void SetName (const char *name)
{
fName.Set (name);
ClearFingerprint ();
}
/// Getter for camera profile name.
/// \retval Name of profile.
const dng_string & Name () const
{
return fName;
}
/// Test if this name is embedded.
/// \retval true if the name matches the name of the embedded camera profile.
bool NameIsEmbedded () const
{
return fName.Matches (kProfileName_Embedded, true);
}
// API for calibration illuminants:
/// Setter for first of up to two light sources used for calibration.
/// Uses the EXIF encodings for illuminant and is used to distinguish which
/// matrix to use.
/// Corresponds to the DNG CalibrationIlluminant1 tag.
void SetCalibrationIlluminant1 (uint32 light)
{
fCalibrationIlluminant1 = light;
ClearFingerprint ();
}
/// Setter for second of up to two light sources used for calibration.
/// Uses the EXIF encodings for illuminant and is used to distinguish which
/// matrix to use.
/// Corresponds to the DNG CalibrationIlluminant2 tag.
void SetCalibrationIlluminant2 (uint32 light)
{
fCalibrationIlluminant2 = light;
ClearFingerprint ();
}
/// Getter for first of up to two light sources used for calibration.
/// Uses the EXIF encodings for illuminant and is used to distinguish which
/// matrix to use.
/// Corresponds to the DNG CalibrationIlluminant1 tag.
uint32 CalibrationIlluminant1 () const
{
return fCalibrationIlluminant1;
}
/// Getter for second of up to two light sources used for calibration.
/// Uses the EXIF encodings for illuminant and is used to distinguish which
/// matrix to use.
/// Corresponds to the DNG CalibrationIlluminant2 tag.
uint32 CalibrationIlluminant2 () const
{
return fCalibrationIlluminant2;
}
/// Getter for first of up to two light sources used for calibration, returning
/// result as color temperature.
real64 CalibrationTemperature1 () const
{
return IlluminantToTemperature (CalibrationIlluminant1 ());
}
/// Getter for second of up to two light sources used for calibration, returning
/// result as color temperature.
real64 CalibrationTemperature2 () const
{
return IlluminantToTemperature (CalibrationIlluminant2 ());
}
// API for color matrices:
/// Utility function to normalize the scale of the color matrix.
static void NormalizeColorMatrix (dng_matrix &m);
/// Setter for first of up to two color matrices used for reference camera calibrations.
/// These matrices map XYZ values to camera values. The DNG SDK needs to map colors
/// that direction in order to determine the clipping points for
/// highlight recovery logic based on the white point. If cameras
/// were all three-color, the matrix could be stored as a forward matrix.
/// The inverse matrix is requried to support four-color cameras.
void SetColorMatrix1 (const dng_matrix &m);
/// Setter for second of up to two color matrices used for reference camera calibrations.
/// These matrices map XYZ values to camera values. The DNG SDK needs to map colors
/// that direction in order to determine the clipping points for
/// highlight recovery logic based on the white point. If cameras
/// were all three-color, the matrix could be stored as a forward matrix.
/// The inverse matrix is requried to support four-color cameras.
void SetColorMatrix2 (const dng_matrix &m);
/// Predicate to test if first camera matrix is set
bool HasColorMatrix1 () const;
/// Predicate to test if second camera matrix is set
bool HasColorMatrix2 () const;
/// Getter for first of up to two color matrices used for calibrations.
const dng_matrix & ColorMatrix1 () const
{
return fColorMatrix1;
}
/// Getter for second of up to two color matrices used for calibrations.
const dng_matrix & ColorMatrix2 () const
{
return fColorMatrix2;
}
// API for forward matrices:
/// Utility function to normalize the scale of the forward matrix.
static void NormalizeForwardMatrix (dng_matrix &m);
/// Setter for first of up to two forward matrices used for calibrations.
void SetForwardMatrix1 (const dng_matrix &m);
/// Setter for second of up to two forward matrices used for calibrations.
void SetForwardMatrix2 (const dng_matrix &m);
/// Getter for first of up to two forward matrices used for calibrations.
const dng_matrix & ForwardMatrix1 () const
{
return fForwardMatrix1;
}
/// Getter for second of up to two forward matrices used for calibrations.
const dng_matrix & ForwardMatrix2 () const
{
return fForwardMatrix2;
}
// API for reduction matrices:
/// Setter for first of up to two dimensionality reduction hints for four-color cameras.
/// This is an optional matrix that maps four components to three.
/// See Appendix 6 of the \ref spec_dng "DNG 1.1.0 specification."
void SetReductionMatrix1 (const dng_matrix &m);
/// Setter for second of up to two dimensionality reduction hints for four-color cameras.
/// This is an optional matrix that maps four components to three.
/// See Appendix 6 of the \ref spec_dng "DNG 1.1.0 specification."
void SetReductionMatrix2 (const dng_matrix &m);
/// Getter for first of up to two dimensionality reduction hints for four color cameras.
const dng_matrix & ReductionMatrix1 () const
{
return fReductionMatrix1;
}
/// Getter for second of up to two dimensionality reduction hints for four color cameras.
const dng_matrix & ReductionMatrix2 () const
{
return fReductionMatrix2;
}
/// Getter function from profile fingerprint.
const dng_fingerprint &Fingerprint () const
{
if (!fFingerprint.IsValid ())
CalculateFingerprint ();
return fFingerprint;
}
/// Getter for camera profile unique ID. Use this ID for uniquely
/// identifying profiles (e.g., for syncing purposes).
dng_fingerprint UniqueID () const;
/// Getter for camera profile id.
/// \retval ID of profile.
dng_camera_profile_id ProfileID () const
{
return dng_camera_profile_id (Name (), Fingerprint ());
}
/// Setter for camera profile copyright.
/// \param copyright Copyright string to use for this camera profile.
void SetCopyright (const char *copyright)
{
fCopyright.Set (copyright);
ClearFingerprint ();
}
/// Getter for camera profile copyright.
/// \retval Copyright string for profile.
const dng_string & Copyright () const
{
return fCopyright;
}
// Accessors for embed policy.
/// Setter for camera profile embed policy.
/// \param policy Policy to use for this camera profile.
void SetEmbedPolicy (uint32 policy)
{
fEmbedPolicy = policy;
ClearFingerprint ();
}
/// Getter for camera profile embed policy.
/// \retval Policy for profile.
uint32 EmbedPolicy () const
{
return fEmbedPolicy;
}
/// Returns true iff the profile is legal to embed in a DNG, per the
/// profile's embed policy.
bool IsLegalToEmbed () const
{
return WasReadFromDNG () ||
EmbedPolicy () == pepAllowCopying ||
EmbedPolicy () == pepEmbedIfUsed ||
EmbedPolicy () == pepNoRestrictions;
}
// Accessors for hue sat maps.
/// Returns true iff the profile has a valid HueSatMap color table.
bool HasHueSatDeltas () const
{
return fHueSatDeltas1.IsValid ();
}
/// Getter for first HueSatMap color table (for calibration illuminant 1).
const dng_hue_sat_map & HueSatDeltas1 () const
{
return fHueSatDeltas1;
}
/// Setter for first HueSatMap color table (for calibration illuminant 1).
void SetHueSatDeltas1 (const dng_hue_sat_map &deltas1);
/// Getter for second HueSatMap color table (for calibration illuminant 2).
const dng_hue_sat_map & HueSatDeltas2 () const
{
return fHueSatDeltas2;
}
/// Setter for second HueSatMap color table (for calibration illuminant 2).
void SetHueSatDeltas2 (const dng_hue_sat_map &deltas2);
// Accessors for hue sat map encoding.
/// Returns the hue sat map encoding (see ProfileHueSatMapEncoding tag).
uint32 HueSatMapEncoding () const
{
return fHueSatMapEncoding;
}
/// Sets the hue sat map encoding (see ProfileHueSatMapEncoding tag) to the
/// specified encoding.
void SetHueSatMapEncoding (uint32 encoding)
{
fHueSatMapEncoding = encoding;
ClearFingerprint ();
}
// Accessors for look table.
/// Returns true if the profile has a LookTable.
bool HasLookTable () const
{
return fLookTable.IsValid ();
}
/// Getter for LookTable.
const dng_hue_sat_map & LookTable () const
{
return fLookTable;
}
/// Setter for LookTable.
void SetLookTable (const dng_hue_sat_map &table);
// Accessors for look table encoding.
/// Returns the LookTable encoding (see ProfileLookTableEncoding tag).
uint32 LookTableEncoding () const
{
return fLookTableEncoding;
}
/// Sets the LookTable encoding (see ProfileLookTableEncoding tag) to the
/// specified encoding.
void SetLookTableEncoding (uint32 encoding)
{
fLookTableEncoding = encoding;
ClearFingerprint ();
}
// Accessors for baseline exposure offset.
/// Sets the baseline exposure offset of the profile (see
/// BaselineExposureOffset tag) to the specified value.
void SetBaselineExposureOffset (real64 exposureOffset)
{
fBaselineExposureOffset.Set_real64 (exposureOffset, 100);
ClearFingerprint ();
}
/// Returns the baseline exposure offset of the profile (see
/// BaselineExposureOffset tag).
const dng_srational & BaselineExposureOffset () const
{
return fBaselineExposureOffset;
}
// Accessors for default black render.
/// Sets the default black render of the profile (see DefaultBlackRender tag)
/// to the specified option.
void SetDefaultBlackRender (uint32 defaultBlackRender)
{
fDefaultBlackRender = defaultBlackRender;
ClearFingerprint ();
}
/// Returns the default black render of the profile (see DefaultBlackRender
/// tag).
uint32 DefaultBlackRender () const
{
return fDefaultBlackRender;
}
// Accessors for tone curve.
/// Returns the tone curve of the profile.
const dng_tone_curve & ToneCurve () const
{
return fToneCurve;
}
/// Sets the tone curve of the profile to the specified curve.
void SetToneCurve (const dng_tone_curve &curve)
{
fToneCurve = curve;
ClearFingerprint ();
}
// Accessors for profile calibration signature.
/// Sets the profile calibration signature (see ProfileCalibrationSignature
/// tag) to the specified string.
void SetProfileCalibrationSignature (const char *signature)
{
fProfileCalibrationSignature.Set (signature);
ClearFingerprint ();
}
/// Returns the profile calibration signature (see ProfileCalibrationSignature
/// tag) of the profile.
const dng_string & ProfileCalibrationSignature () const
{
return fProfileCalibrationSignature;
}
/// Setter for camera unique model name to restrict use of this profile.
/// \param camera Camera unique model name designating only camera this
/// profile can be used with. (Empty string for no restriction.)
void SetUniqueCameraModelRestriction (const char *camera)
{
fUniqueCameraModelRestriction.Set (camera);
// Not included in fingerprint, so don't need ClearFingerprint ().
}
/// Getter for camera unique model name to restrict use of this profile.
/// \retval Unique model name of only camera this profile can be used with
/// or empty if no restriction.
const dng_string & UniqueCameraModelRestriction () const
{
return fUniqueCameraModelRestriction;
}
// Accessors for was read from DNG flag.
/// Sets internal flag to indicate this profile was originally read from a
/// DNG file.
void SetWasReadFromDNG (bool state = true)
{
fWasReadFromDNG = state;
}
/// Was this profile read from a DNG?
bool WasReadFromDNG () const
{
return fWasReadFromDNG;
}
// Accessors for was read from disk flag.
/// Sets internal flag to indicate this profile was originally read from
/// disk.
void SetWasReadFromDisk (bool state = true)
{
fWasReadFromDisk = state;
}
/// Was this profile read from disk?
bool WasReadFromDisk () const
{
return fWasReadFromDisk;
}
// Accessors for was built-in matrix flag.
/// Sets internal flag to indicate this profile was originally a built-in
/// matrix profile.
void SetWasBuiltinMatrix (bool state = true)
{
fWasBuiltinMatrix = state;
}
/// Was this profile a built-in matrix profile?
bool WasBuiltinMatrix () const
{
return fWasBuiltinMatrix;
}
/// Determines if this a valid profile for this number of color channels?
/// \retval true if the profile is valid.
bool IsValid (uint32 channels) const;
/// Predicate to check if two camera profiles are colorwise equal, thus ignores
/// the profile name.
/// \param profile Camera profile to compare to.
bool EqualData (const dng_camera_profile &profile) const;
/// Parse profile from dng_camera_profile_info data.
void Parse (dng_stream &stream,
dng_camera_profile_info &profileInfo);
/// Parse from an extended profile stream, which is similar to stand alone
/// TIFF file.
bool ParseExtended (dng_stream &stream);
/// Convert from a three-color to a four-color Bayer profile.
virtual void SetFourColorBayer ();
/// Find the hue/sat table to use for a given white point, if any.
/// The calling routine owns the resulting table.
dng_hue_sat_map * HueSatMapForWhite (const dng_xy_coord &white) const;
/// Stub out the profile (free memory used by large tables).
void Stub ();
/// Was this profile stubbed?
bool WasStubbed () const
{
return fWasStubbed;
}
protected:
static real64 IlluminantToTemperature (uint32 light);
void ClearFingerprint ()
{
fFingerprint.Clear ();
}
void CalculateFingerprint () const;
static bool ValidForwardMatrix (const dng_matrix &m);
static void ReadHueSatMap (dng_stream &stream,
dng_hue_sat_map &hueSatMap,
uint32 hues,
uint32 sats,
uint32 vals,
bool skipSat0);
};
/******************************************************************************/
void SplitCameraProfileName (const dng_string &name,
dng_string &baseName,
int32 &version);
/*****************************************************************************/
void BuildHueSatMapEncodingTable (dng_memory_allocator &allocator,
uint32 encoding,
AutoPtr<dng_1d_table> &encodeTable,
AutoPtr<dng_1d_table> &decodeTable,
bool subSample);
/******************************************************************************/
#endif
/******************************************************************************/

@ -0,0 +1,108 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/*** \file
* Forward class declarations to avoid having to include many .h files in most places.
*/
/*****************************************************************************/
#ifndef __dng_classes__
#define __dng_classes__
/*****************************************************************************/
class dng_1d_function;
class dng_1d_table;
class dng_abort_sniffer;
class dng_area_task;
class dng_area_task_progress;
class dng_base_tile_iterator;
class dng_basic_tag_set;
class dng_big_table;
class dng_camera_profile;
class dng_camera_profile_id;
class dng_camera_profile_info;
class dng_color_space;
class dng_color_spec;
class dng_date_time;
class dng_date_time_info;
class dng_exif;
class dng_fingerprint;
class dng_host;
class dng_hue_sat_map;
class dng_ifd;
class dng_image;
class dng_image_preview;
class dng_image_writer;
class dng_info;
class dng_iptc;
class dng_jpeg_image;
class dng_jpeg_preview;
class dng_linearization_info;
class dng_local_string;
class dng_look_table;
class dng_matrix;
class dng_matrix_3by3;
class dng_matrix_4by3;
class dng_md5_printer;
class dng_memory_allocator;
class dng_memory_block;
class dng_memory_data;
class dng_memory_stream;
class dng_metadata;
class dng_mosaic_info;
class dng_mutex;
class dng_noise_function;
class dng_noise_profile;
class dng_opcode;
class dng_opcode_list;
class dng_orientation;
class dng_negative;
class dng_pixel_buffer;
class dng_point;
class dng_point_real64;
class dng_preview;
class dng_preview_info;
class dng_preview_list;
class dng_raw_preview;
class dng_read_image;
class dng_rect;
class dng_rect_real64;
class dng_ref_counted_block;
class dng_render;
class dng_resample_function;
class dng_resolution;
class dng_rgb_table;
class dng_set_minimum_priority;
class dng_shared;
class dng_spline_solver;
class dng_srational;
class dng_stream;
class dng_string;
class dng_string_list;
class dng_tiff_directory;
class dng_tile_buffer;
class dng_time_zone;
class dng_tone_curve;
class dng_urational;
class dng_vector;
class dng_vector_3;
class dng_xmp;
class dng_xmp_sdk;
class dng_xy_coord;
/*****************************************************************************/
struct dng_xmp_namespace;
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,346 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Standard gamma functions and color spaces used within the DNG SDK.
*/
#ifndef __dng_color_space__
#define __dng_color_space__
/*****************************************************************************/
#include "dng_1d_function.h"
#include "dng_classes.h"
#include "dng_matrix.h"
#include "dng_types.h"
/*****************************************************************************/
/// \brief A dng_1d_function for gamma encoding in sRGB color space
class dng_function_GammaEncode_sRGB: public dng_1d_function
{
public:
virtual real64 Evaluate (real64 x) const;
virtual real64 EvaluateInverse (real64 y) const;
static const dng_1d_function & Get ();
};
/*****************************************************************************/
/// \brief A dng_1d_function for gamma encoding with 1.8 gamma.
class dng_function_GammaEncode_1_8: public dng_1d_function
{
public:
virtual real64 Evaluate (real64 x) const;
virtual real64 EvaluateInverse (real64 y) const;
static const dng_1d_function & Get ();
};
/*****************************************************************************/
/// \brief A dng_1d_function for gamma encoding with 2.2 gamma.
class dng_function_GammaEncode_2_2: public dng_1d_function
{
public:
virtual real64 Evaluate (real64 x) const;
virtual real64 EvaluateInverse (real64 y) const;
static const dng_1d_function & Get ();
};
/*****************************************************************************/
/// \brief An abstract color space
class dng_color_space
{
protected:
dng_matrix fMatrixToPCS;
dng_matrix fMatrixFromPCS;
public:
virtual ~dng_color_space ();
/// Return a matrix which transforms source data in this color space into the
/// Profile Connection Space.
const dng_matrix & MatrixToPCS () const
{
return fMatrixToPCS;
}
/// Return a matrix which transforms Profile Connection Space data into this
/// color space.
const dng_matrix & MatrixFromPCS () const
{
return fMatrixFromPCS;
}
/// Predicate which is true if this color space is monochrome (has only a
/// single column).
bool IsMonochrome () const
{
return fMatrixToPCS.Cols () == 1;
}
/// Getter for the gamma function for this color space.
virtual const dng_1d_function & GammaFunction () const;
/// Returns true if this color space is linear. (I.e. has gamma 1.0.)
bool IsLinear () const
{
return GammaFunction ().IsIdentity ();
}
/// Map an input value through this color space's encoding gamma.
real64 GammaEncode (real64 x) const
{
return GammaFunction ().Evaluate (x);
}
/// Map an input value through this color space's decoding gamma (inverse of
/// the encoding gamma).
real64 GammaDecode (real64 y) const
{
return GammaFunction ().EvaluateInverse (y);
}
/// Getter for ICC profile, if this color space has one.
/// \param size Out parameter which receives size on return.
/// \param data Receives bytes of profile.
/// \retval Returns true if this color space has an ICC profile, false otherwise.
virtual bool ICCProfile (uint32 &size,
const uint8 *&data) const;
protected:
dng_color_space ();
void SetMonochrome ();
void SetMatrixToPCS (const dng_matrix_3by3 &M);
};
/*****************************************************************************/
/// Singleton class for sRGB color space.
class dng_space_sRGB: public dng_color_space
{
protected:
dng_space_sRGB ();
public:
/// Returns dng_function_GammaEncode_sRGB
virtual const dng_1d_function & GammaFunction () const;
/// Returns sRGB IEC61966-2.1 ICC profile
virtual bool ICCProfile (uint32 &size,
const uint8 *&data) const;
/// Static method for getting single global instance of this color space.
static const dng_color_space & Get ();
};
/*****************************************************************************/
/// \brief Singleton class for AdobeRGB color space.
class dng_space_AdobeRGB: public dng_color_space
{
protected:
dng_space_AdobeRGB ();
public:
/// Returns dng_function_GammaEncode_2_2
virtual const dng_1d_function & GammaFunction () const;
/// Returns AdobeRGB (1998) ICC profile
virtual bool ICCProfile (uint32 &size,
const uint8 *&data) const;
/// Static method for getting single global instance of this color space.
static const dng_color_space & Get ();
};
/*****************************************************************************/
/// \brief Singleton class for ColorMatch color space.
class dng_space_ColorMatch: public dng_color_space
{
protected:
dng_space_ColorMatch ();
public:
/// Returns dng_function_GammaEncode_1_8
virtual const dng_1d_function & GammaFunction () const;
/// Returns ColorMatch RGB ICC profile
virtual bool ICCProfile (uint32 &size,
const uint8 *&data) const;
/// Static method for getting single global instance of this color space.
static const dng_color_space & Get ();
};
/*****************************************************************************/
/// \brief Singleton class for ProPhoto RGB color space.
class dng_space_ProPhoto: public dng_color_space
{
protected:
dng_space_ProPhoto ();
public:
/// Returns dng_function_GammaEncode_1_8
virtual const dng_1d_function & GammaFunction () const;
/// Returns ProPhoto RGB ICC profile
virtual bool ICCProfile (uint32 &size,
const uint8 *&data) const;
/// Static method for getting single global instance of this color space.
static const dng_color_space & Get ();
};
/*****************************************************************************/
/// \brief Singleton class for gamma 1.8 grayscale color space.
class dng_space_GrayGamma18: public dng_color_space
{
protected:
dng_space_GrayGamma18 ();
public:
/// Returns dng_function_GammaEncode_1_8
virtual const dng_1d_function & GammaFunction () const;
/// Returns simple grayscale gamma 1.8 ICC profile
virtual bool ICCProfile (uint32 &size,
const uint8 *&data) const;
/// Static method for getting single global instance of this color space.
static const dng_color_space & Get ();
};
/*****************************************************************************/
/// \brief Singleton class for gamma 2.2 grayscale color space.
class dng_space_GrayGamma22: public dng_color_space
{
protected:
dng_space_GrayGamma22 ();
public:
/// Returns dng_function_GammaEncode_2_2
virtual const dng_1d_function & GammaFunction () const;
/// Returns simple grayscale gamma 2.2 ICC profile
virtual bool ICCProfile (uint32 &size,
const uint8 *&data) const;
/// Static method for getting single global instance of this color space.
static const dng_color_space & Get ();
};
/*****************************************************************************/
class dng_space_fakeRGB: public dng_color_space
{
protected:
dng_space_fakeRGB ();
public:
static const dng_color_space & Get ();
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,554 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_color_spec.h"
#include "dng_assertions.h"
#include "dng_camera_profile.h"
#include "dng_exceptions.h"
#include "dng_matrix.h"
#include "dng_negative.h"
#include "dng_temperature.h"
#include "dng_utils.h"
#include "dng_xy_coord.h"
/*****************************************************************************/
dng_matrix_3by3 MapWhiteMatrix (const dng_xy_coord &white1,
const dng_xy_coord &white2)
{
// Use the linearized Bradford adaptation matrix.
dng_matrix_3by3 Mb ( 0.8951, 0.2664, -0.1614,
-0.7502, 1.7135, 0.0367,
0.0389, -0.0685, 1.0296);
dng_vector_3 w1 = Mb * XYtoXYZ (white1);
dng_vector_3 w2 = Mb * XYtoXYZ (white2);
// Negative white coordinates are kind of meaningless.
w1 [0] = Max_real64 (w1 [0], 0.0);
w1 [1] = Max_real64 (w1 [1], 0.0);
w1 [2] = Max_real64 (w1 [2], 0.0);
w2 [0] = Max_real64 (w2 [0], 0.0);
w2 [1] = Max_real64 (w2 [1], 0.0);
w2 [2] = Max_real64 (w2 [2], 0.0);
// Limit scaling to something reasonable.
dng_matrix_3by3 A;
A [0] [0] = Pin_real64 (0.1, w1 [0] > 0.0 ? w2 [0] / w1 [0] : 10.0, 10.0);
A [1] [1] = Pin_real64 (0.1, w1 [1] > 0.0 ? w2 [1] / w1 [1] : 10.0, 10.0);
A [2] [2] = Pin_real64 (0.1, w1 [2] > 0.0 ? w2 [2] / w1 [2] : 10.0, 10.0);
dng_matrix_3by3 B = Invert (Mb) * A * Mb;
return B;
}
/******************************************************************************/
dng_color_spec::dng_color_spec (const dng_negative &negative,
const dng_camera_profile *profile)
: fChannels (negative.ColorChannels ())
, fTemperature1 (0.0)
, fTemperature2 (0.0)
, fColorMatrix1 ()
, fColorMatrix2 ()
, fForwardMatrix1 ()
, fForwardMatrix2 ()
, fReductionMatrix1 ()
, fReductionMatrix2 ()
, fCameraCalibration1 ()
, fCameraCalibration2 ()
, fAnalogBalance ()
, fWhiteXY ()
, fCameraWhite ()
, fCameraToPCS ()
, fPCStoCamera ()
{
if (fChannels > 1)
{
if (!profile || !profile->IsValid (fChannels))
{
ThrowBadFormat ();
}
if (profile->WasStubbed ())
{
ThrowProgramError ("Using stubbed profile");
}
fTemperature1 = profile->CalibrationTemperature1 ();
fTemperature2 = profile->CalibrationTemperature2 ();
fColorMatrix1 = profile->ColorMatrix1 ();
fColorMatrix2 = profile->ColorMatrix2 ();
fForwardMatrix1 = profile->ForwardMatrix1 ();
fForwardMatrix2 = profile->ForwardMatrix2 ();
fReductionMatrix1 = profile->ReductionMatrix1 ();
fReductionMatrix2 = profile->ReductionMatrix2 ();
fCameraCalibration1.SetIdentity (fChannels);
fCameraCalibration2.SetIdentity (fChannels);
if (negative. CameraCalibrationSignature () ==
profile->ProfileCalibrationSignature ())
{
if (negative.CameraCalibration1 ().Rows () == fChannels &&
negative.CameraCalibration1 ().Cols () == fChannels)
{
fCameraCalibration1 = negative.CameraCalibration1 ();
}
if (negative.CameraCalibration2 ().Rows () == fChannels &&
negative.CameraCalibration2 ().Cols () == fChannels)
{
fCameraCalibration2 = negative.CameraCalibration2 ();
}
}
fAnalogBalance = dng_matrix (fChannels, fChannels);
for (uint32 j = 0; j < fChannels; j++)
{
fAnalogBalance [j] [j] = negative.AnalogBalance (j);
}
dng_camera_profile::NormalizeForwardMatrix (fForwardMatrix1);
fColorMatrix1 = fAnalogBalance * fCameraCalibration1 * fColorMatrix1;
if (!profile->HasColorMatrix2 () ||
fTemperature1 <= 0.0 ||
fTemperature2 <= 0.0 ||
fTemperature1 == fTemperature2)
{
fTemperature1 = 5000.0;
fTemperature2 = 5000.0;
fColorMatrix2 = fColorMatrix1;
fForwardMatrix2 = fForwardMatrix1;
fReductionMatrix2 = fReductionMatrix1;
fCameraCalibration2 = fCameraCalibration1;
}
else
{
dng_camera_profile::NormalizeForwardMatrix (fForwardMatrix2);
fColorMatrix2 = fAnalogBalance * fCameraCalibration2 * fColorMatrix2;
// Swap values if temperatures are out of order.
if (fTemperature1 > fTemperature2)
{
real64 temp = fTemperature1;
fTemperature1 = fTemperature2;
fTemperature2 = temp;
dng_matrix T = fColorMatrix1;
fColorMatrix1 = fColorMatrix2;
fColorMatrix2 = T;
T = fForwardMatrix1;
fForwardMatrix1 = fForwardMatrix2;
fForwardMatrix2 = T;
T = fReductionMatrix1;
fReductionMatrix1 = fReductionMatrix2;
fReductionMatrix2 = T;
T = fCameraCalibration1;
fCameraCalibration1 = fCameraCalibration2;
fCameraCalibration2 = T;
}
}
}
}
/*****************************************************************************/
dng_matrix dng_color_spec::FindXYZtoCamera (const dng_xy_coord &white,
dng_matrix *forwardMatrix,
dng_matrix *reductionMatrix,
dng_matrix *cameraCalibration)
{
// Convert to temperature/offset space.
dng_temperature td (white);
// Find fraction to weight the first calibration.
real64 g;
if (td.Temperature () <= fTemperature1)
g = 1.0;
else if (td.Temperature () >= fTemperature2)
g = 0.0;
else
{
real64 invT = 1.0 / td.Temperature ();
g = (invT - (1.0 / fTemperature2)) /
((1.0 / fTemperature1) - (1.0 / fTemperature2));
}
// Interpolate the color matrix.
dng_matrix colorMatrix;
if (g >= 1.0)
colorMatrix = fColorMatrix1;
else if (g <= 0.0)
colorMatrix = fColorMatrix2;
else
colorMatrix = (g ) * fColorMatrix1 +
(1.0 - g) * fColorMatrix2;
// Interpolate forward matrix, if any.
if (forwardMatrix)
{
bool has1 = fForwardMatrix1.NotEmpty ();
bool has2 = fForwardMatrix2.NotEmpty ();
if (has1 && has2)
{
if (g >= 1.0)
*forwardMatrix = fForwardMatrix1;
else if (g <= 0.0)
*forwardMatrix = fForwardMatrix2;
else
*forwardMatrix = (g ) * fForwardMatrix1 +
(1.0 - g) * fForwardMatrix2;
}
else if (has1)
{
*forwardMatrix = fForwardMatrix1;
}
else if (has2)
{
*forwardMatrix = fForwardMatrix2;
}
else
{
forwardMatrix->Clear ();
}
}
// Interpolate reduction matrix, if any.
if (reductionMatrix)
{
bool has1 = fReductionMatrix1.NotEmpty ();
bool has2 = fReductionMatrix2.NotEmpty ();
if (has1 && has2)
{
if (g >= 1.0)
*reductionMatrix = fReductionMatrix1;
else if (g <= 0.0)
*reductionMatrix = fReductionMatrix2;
else
*reductionMatrix = (g ) * fReductionMatrix1 +
(1.0 - g) * fReductionMatrix2;
}
else if (has1)
{
*reductionMatrix = fReductionMatrix1;
}
else if (has2)
{
*reductionMatrix = fReductionMatrix2;
}
else
{
reductionMatrix->Clear ();
}
}
// Interpolate camera calibration matrix.
if (cameraCalibration)
{
if (g >= 1.0)
*cameraCalibration = fCameraCalibration1;
else if (g <= 0.0)
*cameraCalibration = fCameraCalibration2;
else
*cameraCalibration = (g ) * fCameraCalibration1 +
(1.0 - g) * fCameraCalibration2;
}
// Return the interpolated color matrix.
return colorMatrix;
}
/*****************************************************************************/
void dng_color_spec::SetWhiteXY (const dng_xy_coord &white)
{
fWhiteXY = white;
// Deal with monochrome cameras.
if (fChannels == 1)
{
fCameraWhite.SetIdentity (1);
fCameraToPCS = PCStoXYZ ().AsColumn ();
return;
}
// Interpolate an matric values for this white point.
dng_matrix colorMatrix;
dng_matrix forwardMatrix;
dng_matrix reductionMatrix;
dng_matrix cameraCalibration;
colorMatrix = FindXYZtoCamera (fWhiteXY,
&forwardMatrix,
&reductionMatrix,
&cameraCalibration);
// Find the camera white values.
fCameraWhite = colorMatrix * XYtoXYZ (fWhiteXY);
real64 whiteScale = 1.0 / MaxEntry (fCameraWhite);
for (uint32 j = 0; j < fChannels; j++)
{
// We don't support non-positive values for camera neutral values.
fCameraWhite [j] = Pin_real64 (0.001,
whiteScale * fCameraWhite [j],
1.0);
}
// Find PCS to Camera transform. Scale matrix so PCS white can just be
// reached when the first camera channel saturates
fPCStoCamera = colorMatrix * MapWhiteMatrix (PCStoXY (), fWhiteXY);
real64 scale = MaxEntry (fPCStoCamera * PCStoXYZ ());
fPCStoCamera = (1.0 / scale) * fPCStoCamera;
// If we have a forward matrix, then just use that.
if (forwardMatrix.NotEmpty ())
{
dng_matrix individualToReference = Invert (fAnalogBalance * cameraCalibration);
dng_vector refCameraWhite = individualToReference * fCameraWhite;
fCameraToPCS = forwardMatrix *
Invert (refCameraWhite.AsDiagonal ()) *
individualToReference;
}
// Else we need to use the adapt in XYZ method.
else
{
// Invert this PCS to camera matrix. Note that if there are more than three
// camera channels, this inversion is non-unique.
fCameraToPCS = Invert (fPCStoCamera, reductionMatrix);
}
}
/*****************************************************************************/
const dng_xy_coord & dng_color_spec::WhiteXY () const
{
DNG_ASSERT (fWhiteXY.IsValid (), "Using invalid WhiteXY");
return fWhiteXY;
}
/*****************************************************************************/
const dng_vector & dng_color_spec::CameraWhite () const
{
DNG_ASSERT (fCameraWhite.NotEmpty (), "Using invalid CameraWhite");
return fCameraWhite;
}
/*****************************************************************************/
const dng_matrix & dng_color_spec::CameraToPCS () const
{
DNG_ASSERT (fCameraToPCS.NotEmpty (), "Using invalid CameraToPCS");
return fCameraToPCS;
}
/*****************************************************************************/
const dng_matrix & dng_color_spec::PCStoCamera () const
{
DNG_ASSERT (fPCStoCamera.NotEmpty (), "Using invalid PCStoCamera");
return fPCStoCamera;
}
/*****************************************************************************/
dng_xy_coord dng_color_spec::NeutralToXY (const dng_vector &neutral)
{
const uint32 kMaxPasses = 30;
if (fChannels == 1)
{
return PCStoXY ();
}
dng_xy_coord last = D50_xy_coord ();
for (uint32 pass = 0; pass < kMaxPasses; pass++)
{
dng_matrix xyzToCamera = FindXYZtoCamera (last);
dng_xy_coord next = XYZtoXY (Invert (xyzToCamera) * neutral);
if (Abs_real64 (next.x - last.x) +
Abs_real64 (next.y - last.y) < 0.0000001)
{
return next;
}
// If we reach the limit without converging, we are most likely
// in a two value oscillation. So take the average of the last
// two estimates and give up.
if (pass == kMaxPasses - 1)
{
next.x = (last.x + next.x) * 0.5;
next.y = (last.y + next.y) * 0.5;
}
last = next;
}
return last;
}
/*****************************************************************************/

@ -0,0 +1,141 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Class for holding a specific color transform.
*/
#ifndef __dng_color_spec__
#define __dng_color_spec__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_matrix.h"
#include "dng_types.h"
#include "dng_xy_coord.h"
/*****************************************************************************/
/// \brief Compute a 3x3 matrix which maps colors from white point white1 to
/// white point white2
///
/// Uses linearized Bradford adaptation matrix to compute a mapping from
/// colors measured with one white point (white1) to another (white2).
dng_matrix_3by3 MapWhiteMatrix (const dng_xy_coord &white1,
const dng_xy_coord &white2);
/*****************************************************************************/
/// Color transform taking into account white point and camera calibration and
/// individual calibration from DNG negative.
class dng_color_spec
{
private:
uint32 fChannels;
real64 fTemperature1;
real64 fTemperature2;
dng_matrix fColorMatrix1;
dng_matrix fColorMatrix2;
dng_matrix fForwardMatrix1;
dng_matrix fForwardMatrix2;
dng_matrix fReductionMatrix1;
dng_matrix fReductionMatrix2;
dng_matrix fCameraCalibration1;
dng_matrix fCameraCalibration2;
dng_matrix fAnalogBalance;
dng_xy_coord fWhiteXY;
dng_vector fCameraWhite;
dng_matrix fCameraToPCS;
dng_matrix fPCStoCamera;
public:
/// Read calibration info from DNG negative and construct a
/// dng_color_spec.
dng_color_spec (const dng_negative &negative,
const dng_camera_profile *profile);
virtual ~dng_color_spec ()
{
}
/// Number of channels used for this color transform. Three
/// for most cameras.
uint32 Channels () const
{
return fChannels;
}
/// Setter for white point. Value is as XY colorspace coordinate.
/// \param white White point to set as an XY value.
void SetWhiteXY (const dng_xy_coord &white);
/// Getter for white point. Value is as XY colorspace coordinate.
/// \retval XY value of white point.
const dng_xy_coord & WhiteXY () const;
/// Return white point in camera native color coordinates.
/// \retval A dng_vector with components ranging from 0.0 to 1.0
/// that is normalized such that one component is equal to 1.0 .
const dng_vector & CameraWhite () const;
/// Getter for camera to Profile Connection Space color transform.
/// \retval A transform that takes into account all camera calibration
/// transforms and white point.
const dng_matrix & CameraToPCS () const;
/// Getter for Profile Connection Space to camera color transform.
/// \retval A transform that takes into account all camera calibration
/// transforms and white point.
const dng_matrix & PCStoCamera () const;
/// Return the XY value to use for SetWhiteXY for a given camera color
/// space coordinate as the white point.
/// \param neutral A camera color space value to use for white point.
/// Components range from 0.0 to 1.0 and should be normalized such that
/// the largest value is 1.0 .
/// \retval White point in XY space that makes neutral map to this
/// XY value as closely as possible.
dng_xy_coord NeutralToXY (const dng_vector &neutral);
private:
dng_matrix FindXYZtoCamera (const dng_xy_coord &white,
dng_matrix *forwardMatrix = NULL,
dng_matrix *reductionMatrix = NULL,
dng_matrix *cameraCalibration = NULL);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,388 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Functions and classes for working with dates and times in DNG files.
*/
/*****************************************************************************/
#ifndef __dng_date_time__
#define __dng_date_time__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_string.h"
#include "dng_types.h"
/*****************************************************************************/
/// \brief Class for holding a date/time and converting to and from relevant
/// date/time formats
class dng_date_time
{
public:
uint32 fYear;
uint32 fMonth;
uint32 fDay;
uint32 fHour;
uint32 fMinute;
uint32 fSecond;
public:
/// Construct an invalid date/time
dng_date_time ();
/// Construct a date/time with specific values.
/// \param year Year to use as actual integer value, such as 2006.
/// \param month Month to use from 1 - 12, where 1 is January.
/// \param day Day of month to use from 1 -31, where 1 is the first.
/// \param hour Hour of day to use from 0 - 23, where 0 is midnight.
/// \param minute Minute of hour to use from 0 - 59.
/// \param second Second of minute to use from 0 - 59.
dng_date_time (uint32 year,
uint32 month,
uint32 day,
uint32 hour,
uint32 minute,
uint32 second);
/// Predicate to determine if a date is valid.
/// \retval true if all fields are within range.
bool IsValid () const;
/// Predicate to determine if a date is invalid.
/// \retval true if any field is out of range.
bool NotValid () const
{
return !IsValid ();
}
/// Equal operator.
bool operator== (const dng_date_time &dt) const
{
return fYear == dt.fYear &&
fMonth == dt.fMonth &&
fDay == dt.fDay &&
fHour == dt.fHour &&
fMinute == dt.fMinute &&
fSecond == dt.fSecond;
}
// Not-equal operator.
bool operator!= (const dng_date_time &dt) const
{
return !(*this == dt);
}
/// Set date to an invalid value.
void Clear ();
/// Parse an EXIF format date string.
/// \param s Input date string to parse.
/// \retval true if date was parsed successfully and date is valid.
bool Parse (const char *s);
};
/*****************************************************************************/
/// \brief Class for holding a time zone.
class dng_time_zone
{
private:
enum
{
kMaxOffsetHours = 15,
kMinOffsetHours = -kMaxOffsetHours,
kMaxOffsetMinutes = kMaxOffsetHours * 60,
kMinOffsetMinutes = kMinOffsetHours * 60,
kInvalidOffset = kMinOffsetMinutes - 1
};
// Offset from GMT in minutes. Positive numbers are
// ahead of GMT, negative number are behind GMT.
int32 fOffsetMinutes;
public:
dng_time_zone ()
: fOffsetMinutes (kInvalidOffset)
{
}
void Clear ()
{
fOffsetMinutes = kInvalidOffset;
}
void SetOffsetHours (int32 offset)
{
fOffsetMinutes = offset * 60;
}
void SetOffsetMinutes (int32 offset)
{
fOffsetMinutes = offset;
}
void SetOffsetSeconds (int32 offset)
{
fOffsetMinutes = (offset > 0) ? ((offset + 30) / 60)
: ((offset - 30) / 60);
}
bool IsValid () const
{
return fOffsetMinutes >= kMinOffsetMinutes &&
fOffsetMinutes <= kMaxOffsetMinutes;
}
bool NotValid () const
{
return !IsValid ();
}
int32 OffsetMinutes () const
{
return fOffsetMinutes;
}
bool IsExactHourOffset () const
{
return IsValid () && ((fOffsetMinutes % 60) == 0);
}
int32 ExactHourOffset () const
{
return fOffsetMinutes / 60;
}
dng_string Encode_ISO_8601 () const;
};
/*****************************************************************************/
/// \brief Class for holding complete data/time/zone information.
class dng_date_time_info
{
private:
// Is only the date valid and not the time?
bool fDateOnly;
// Date and time.
dng_date_time fDateTime;
// Subseconds string (stored in a separate tag in EXIF).
dng_string fSubseconds;
// Time zone, if known.
dng_time_zone fTimeZone;
public:
dng_date_time_info ();
bool IsValid () const;
bool NotValid () const
{
return !IsValid ();
}
void Clear ()
{
*this = dng_date_time_info ();
}
bool IsDateOnly () const
{
return fDateOnly;
}
const dng_date_time & DateTime () const
{
return fDateTime;
}
void SetDateTime (const dng_date_time &dt)
{
fDateOnly = false;
fDateTime = dt;
}
const dng_string & Subseconds () const
{
return fSubseconds;
}
void SetSubseconds (const dng_string &s)
{
fSubseconds = s;
}
const dng_time_zone & TimeZone () const
{
return fTimeZone;
}
void SetZone (const dng_time_zone &zone)
{
fTimeZone = zone;
}
void ClearZone ()
{
fTimeZone.Clear ();
}
void SetOffsetTime (const dng_string &s);
dng_string OffsetTime () const;
void Decode_ISO_8601 (const char *s);
dng_string Encode_ISO_8601 () const;
void Decode_IPTC_Date (const char *s);
dng_string Encode_IPTC_Date () const;
void Decode_IPTC_Time (const char *s);
dng_string Encode_IPTC_Time () const;
private:
void SetDate (uint32 year,
uint32 month,
uint32 day);
void SetTime (uint32 hour,
uint32 minute,
uint32 second);
};
/*****************************************************************************/
/// Get the current date/time and timezone.
/// \param info Receives current data/time/zone.
void CurrentDateTimeAndZone (dng_date_time_info &info);
/*****************************************************************************/
/// Convert UNIX "seconds since Jan 1, 1970" time to a dng_date_time
void DecodeUnixTime (uint32 unixTime, dng_date_time &dt);
/*****************************************************************************/
/// Return timezone of current location at a given date.
/// \param dt Date at which to compute timezone difference. (For example, used
/// to determine Daylight Savings, etc.)
/// \retval Time zone for date/time dt.
dng_time_zone LocalTimeZone (const dng_date_time &dt);
/*****************************************************************************/
/// Tag to encode date represenation format
enum dng_date_time_format
{
dng_date_time_format_unknown = 0, /// Date format not known
dng_date_time_format_exif = 1, /// EXIF date string
dng_date_time_format_unix_little_endian = 2, /// 32-bit UNIX time as 4-byte little endian
dng_date_time_format_unix_big_endian = 3 /// 32-bit UNIX time as 4-byte big endian
};
/*****************************************************************************/
/// \brief Store file offset from which date was read.
///
/// Used internally by Adobe to update date in original file.
/// \warning Use at your own risk.
class dng_date_time_storage_info
{
private:
uint64 fOffset;
dng_date_time_format fFormat;
public:
/// The default constructor initializes to an invalid state.
dng_date_time_storage_info ();
/// Construct with file offset and date format.
dng_date_time_storage_info (uint64 offset,
dng_date_time_format format);
/// Predicate to determine if an offset is valid.
/// \retval true if offset is valid.
bool IsValid () const;
// The accessors throw if the data is not valid.
/// Getter for offset in file.
/// \exception dng_exception with fErrorCode equal to dng_error_unknown
/// if offset is not valid.
uint64 Offset () const;
/// Get for format date was originally stored in file. Throws a
/// dng_error_unknown exception if offset is invalid.
/// \exception dng_exception with fErrorCode equal to dng_error_unknown
/// if offset is not valid.
dng_date_time_format Format () const;
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,54 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Error code values.
*/
/*****************************************************************************/
#ifndef __dng_errors__
#define __dng_errors__
/*****************************************************************************/
#include "dng_types.h"
/*****************************************************************************/
/// Type for all errors used in DNG SDK. Generally held inside a dng_exception.
typedef int32 dng_error_code;
enum
{
dng_error_none = 0, //!< No error. Success.
dng_error_unknown = 100000, //!< Logic or program error or other unclassifiable error.
dng_error_not_yet_implemented, //!< Functionality requested is not yet implemented.
dng_error_silent, //!< An error which should not be signalled to user.
dng_error_user_canceled, //!< Processing stopped by user (or host application) request
dng_error_host_insufficient, //!< Necessary host functionality is not present.
dng_error_memory, //!< Out of memory.
dng_error_bad_format, //!< File format is not valid.
dng_error_matrix_math, //!< Matrix has wrong shape, is badly conditioned, or similar problem.
dng_error_open_file, //!< Could not open file.
dng_error_read_file, //!< Error reading file.
dng_error_write_file, //!< Error writing file.
dng_error_end_of_file, //!< Unexpected end of file.
dng_error_file_is_damaged, //!< File is damaged in some way.
dng_error_image_too_big_dng, //!< Image is too big to save as DNG.
dng_error_image_too_big_tiff, //!< Image is too big to save as TIFF.
dng_error_unsupported_dng, //!< DNG version is unsupported.
dng_error_overflow //!< Arithmetic overflow.
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,219 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_exceptions.h"
#include "dng_flags.h"
#include "dng_globals.h"
/*****************************************************************************/
#ifndef qDNGReportErrors
// assuming this isn't enable on Win, because it's using printf, but an app can redirect that to console
#define qDNGReportErrors ((qDNGDebug && qMacOS) || qDNGValidate)
#endif
/*****************************************************************************/
void ReportWarning (const char *message,
const char *sub_message)
{
#if qDNGReportErrors
#ifdef cr_logw
cr_logs("report", 2, NULL, 0, cr_logfunc(), "%s %s\n", message, sub_message ? sub_message : "");
#else
if (sub_message)
fprintf (stderr, "*** Warning: %s (%s) ***\n", message, sub_message);
else
fprintf (stderr, "*** Warning: %s ***\n", message);
#endif
#else
(void) message;
(void) sub_message;
#endif
}
/*****************************************************************************/
void ReportError (const char *message,
const char *sub_message)
{
#if qDNGReportErrors
#ifdef cr_loge
cr_logs("report", 3, NULL, 0, cr_logfunc(), "%s %s\n", message, sub_message ? sub_message : "");
#else
if (sub_message)
fprintf (stderr, "*** Error: %s (%s) ***\n", message, sub_message);
else
fprintf (stderr, "*** Error: %s ***\n", message);
#endif
#else
(void) message;
(void) sub_message;
#endif
}
/*****************************************************************************/
void Throw_dng_error (dng_error_code err,
const char *message,
const char *sub_message,
bool silent)
{
#if qDNGReportErrors
{
if (!message)
{
switch (err)
{
case dng_error_none:
case dng_error_silent:
case dng_error_user_canceled:
{
break;
}
case dng_error_not_yet_implemented:
{
message = "Not yet implemented";
break;
}
case dng_error_host_insufficient:
{
message = "Host insufficient";
break;
}
case dng_error_memory:
{
message = "Unable to allocate memory";
break;
}
case dng_error_bad_format:
{
message = "File format is invalid";
break;
}
case dng_error_matrix_math:
{
message = "Matrix math error";
break;
}
case dng_error_open_file:
{
message = "Unable to open file";
break;
}
case dng_error_read_file:
{
message = "File read error";
break;
}
case dng_error_write_file:
{
message = "File write error";
break;
}
case dng_error_end_of_file:
{
message = "Unexpected end-of-file";
break;
}
case dng_error_file_is_damaged:
{
message = "File is damaged";
break;
}
case dng_error_image_too_big_dng:
{
message = "Image is too big to save as DNG";
break;
}
case dng_error_image_too_big_tiff:
{
message = "Image is too big to save as TIFF";
break;
}
case dng_error_unsupported_dng:
{
message = "DNG version is unsupported";
break;
}
case dng_error_overflow:
{
message = "Arithmetic overflow/underflow";
break;
}
default:
{
message = "Unknown error";
break;
}
}
}
if (message && !silent)
{
ReportError (message, sub_message);
}
}
#else
(void) message;
(void) sub_message;
(void) silent;
#endif
throw dng_exception (err);
}
/*****************************************************************************/

@ -0,0 +1,319 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* C++ exception support for DNG SDK.
*/
/*****************************************************************************/
#ifndef __dng_exceptions__
#define __dng_exceptions__
/*****************************************************************************/
#include "dng_errors.h"
#include "dng_flags.h"
/*****************************************************************************/
#ifndef DNG_NO_RETURN
#ifdef __GNUC__
#define DNG_NO_RETURN __attribute__((noreturn))
#else
#define DNG_NO_RETURN
#endif
#endif
/*****************************************************************************/
/// Display a warning message. Note that this may just eat the message.
void ReportWarning (const char *message,
const char *sub_message = NULL);
/*****************************************************************************/
/// Display an error message. Note that this may just eat the message.
void ReportError (const char *message,
const char *sub_message = NULL);
/*****************************************************************************/
/// \brief All exceptions thrown by the DNG SDK use this exception class.
class dng_exception
{
private:
dng_error_code fErrorCode;
public:
/// Construct an exception representing the given error code.
/// \param code Error code this exception is for.
dng_exception (dng_error_code code)
: fErrorCode (code)
{
}
virtual ~dng_exception ()
{
}
/// Getter for error code of this exception
/// \retval The error code of this exception.
dng_error_code ErrorCode () const
{
return fErrorCode;
}
};
/******************************************************************************/
/// \brief Throw an exception based on an arbitrary error code.
void Throw_dng_error (dng_error_code err,
const char * message = NULL,
const char * sub_message = NULL,
bool silent = false) DNG_NO_RETURN;
/******************************************************************************/
/// \brief Convenience function to throw dng_exception with error code if
/// error_code is not dng_error_none .
inline void Fail_dng_error (dng_error_code err)
{
if (err != dng_error_none)
{
Throw_dng_error (err);
}
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_unknown .
inline void ThrowProgramError (const char * sub_message = NULL)
{
Throw_dng_error (dng_error_unknown, NULL, sub_message);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_overflow.
inline void ThrowOverflow (const char * sub_message = NULL)
{
Throw_dng_error (dng_error_overflow, NULL, sub_message);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_not_yet_implemented .
inline void ThrowNotYetImplemented (const char * sub_message = NULL)
{
Throw_dng_error (dng_error_not_yet_implemented, NULL, sub_message);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_silent .
inline void ThrowSilentError ()
{
Throw_dng_error (dng_error_silent);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_user_canceled .
inline void ThrowUserCanceled ()
{
Throw_dng_error (dng_error_user_canceled);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_host_insufficient .
inline void ThrowHostInsufficient (const char * sub_message = NULL,
bool silent = false)
{
Throw_dng_error (dng_error_host_insufficient, NULL, sub_message, silent);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_memory .
inline void ThrowMemoryFull (const char * sub_message = NULL)
{
Throw_dng_error (dng_error_memory, NULL, sub_message);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_bad_format .
inline void ThrowBadFormat (const char * sub_message = NULL)
{
Throw_dng_error (dng_error_bad_format, NULL, sub_message);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_matrix_math .
inline void ThrowMatrixMath (const char * sub_message = NULL)
{
Throw_dng_error (dng_error_matrix_math, NULL, sub_message);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_open_file .
inline void ThrowOpenFile (const char * sub_message = NULL, bool silent = false)
{
Throw_dng_error (dng_error_open_file, NULL, sub_message, silent);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_read_file .
inline void ThrowReadFile (const char *sub_message = NULL)
{
Throw_dng_error (dng_error_read_file, NULL, sub_message);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_write_file .
inline void ThrowWriteFile (const char *sub_message = NULL)
{
Throw_dng_error (dng_error_write_file, NULL, sub_message);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_end_of_file .
inline void ThrowEndOfFile (const char *sub_message = NULL)
{
Throw_dng_error (dng_error_end_of_file, NULL, sub_message);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_file_is_damaged .
inline void ThrowFileIsDamaged ()
{
Throw_dng_error (dng_error_file_is_damaged);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_image_too_big_dng .
inline void ThrowImageTooBigDNG ()
{
Throw_dng_error (dng_error_image_too_big_dng);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_image_too_big_tiff .
inline void ThrowImageTooBigTIFF ()
{
Throw_dng_error (dng_error_image_too_big_tiff);
}
/*****************************************************************************/
/// \brief Convenience function to throw dng_exception with error code
/// dng_error_unsupported_dng .
inline void ThrowUnsupportedDNG ()
{
Throw_dng_error (dng_error_unsupported_dng);
}
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,377 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* EXIF read access support. See the \ref spec_exif "EXIF specification" for full
* description of tags.
*/
/*****************************************************************************/
#ifndef __dng_exif__
#define __dng_exif__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_date_time.h"
#include "dng_fingerprint.h"
#include "dng_types.h"
#include "dng_matrix.h"
#include "dng_rational.h"
#include "dng_string.h"
#include "dng_stream.h"
#include "dng_sdk_limits.h"
/*****************************************************************************/
/// \brief Container class for parsing and holding EXIF tags.
///
/// Public member fields are documented in \ref spec_exif "EXIF specification."
class dng_exif
{
public:
dng_string fImageDescription;
dng_string fMake;
dng_string fModel;
dng_string fSoftware;
dng_string fArtist;
dng_string fCopyright;
dng_string fCopyright2;
dng_string fUserComment;
dng_date_time_info fDateTime;
dng_date_time_storage_info fDateTimeStorageInfo;
dng_date_time_info fDateTimeOriginal;
dng_date_time_storage_info fDateTimeOriginalStorageInfo;
dng_date_time_info fDateTimeDigitized;
dng_date_time_storage_info fDateTimeDigitizedStorageInfo;
uint32 fTIFF_EP_StandardID;
uint32 fExifVersion;
uint32 fFlashPixVersion;
dng_urational fExposureTime;
dng_urational fFNumber;
dng_srational fShutterSpeedValue;
dng_urational fApertureValue;
dng_srational fBrightnessValue;
dng_srational fExposureBiasValue;
dng_urational fMaxApertureValue;
dng_urational fFocalLength;
dng_urational fDigitalZoomRatio;
dng_urational fExposureIndex;
dng_urational fSubjectDistance;
dng_urational fGamma;
dng_urational fBatteryLevelR;
dng_string fBatteryLevelA;
uint32 fExposureProgram;
uint32 fMeteringMode;
uint32 fLightSource;
uint32 fFlash;
uint32 fFlashMask;
uint32 fSensingMethod;
uint32 fColorSpace;
uint32 fFileSource;
uint32 fSceneType;
uint32 fCustomRendered;
uint32 fExposureMode;
uint32 fWhiteBalance;
uint32 fSceneCaptureType;
uint32 fGainControl;
uint32 fContrast;
uint32 fSaturation;
uint32 fSharpness;
uint32 fSubjectDistanceRange;
uint32 fSelfTimerMode;
uint32 fImageNumber;
uint32 fFocalLengthIn35mmFilm;
uint32 fISOSpeedRatings [3]; // EXIF 2.3: PhotographicSensitivity.
// Sensitivity tags added in EXIF 2.3.
uint32 fSensitivityType;
uint32 fStandardOutputSensitivity;
uint32 fRecommendedExposureIndex;
uint32 fISOSpeed;
uint32 fISOSpeedLatitudeyyy;
uint32 fISOSpeedLatitudezzz;
uint32 fSubjectAreaCount;
uint32 fSubjectArea [4];
uint32 fComponentsConfiguration;
dng_urational fCompresssedBitsPerPixel;
uint32 fPixelXDimension;
uint32 fPixelYDimension;
dng_urational fFocalPlaneXResolution;
dng_urational fFocalPlaneYResolution;
uint32 fFocalPlaneResolutionUnit;
uint32 fCFARepeatPatternRows;
uint32 fCFARepeatPatternCols;
uint8 fCFAPattern [kMaxCFAPattern] [kMaxCFAPattern];
dng_fingerprint fImageUniqueID;
uint32 fGPSVersionID;
dng_string fGPSLatitudeRef;
dng_urational fGPSLatitude [3];
dng_string fGPSLongitudeRef;
dng_urational fGPSLongitude [3];
uint32 fGPSAltitudeRef;
dng_urational fGPSAltitude;
dng_urational fGPSTimeStamp [3];
dng_string fGPSSatellites;
dng_string fGPSStatus;
dng_string fGPSMeasureMode;
dng_urational fGPSDOP;
dng_string fGPSSpeedRef;
dng_urational fGPSSpeed;
dng_string fGPSTrackRef;
dng_urational fGPSTrack;
dng_string fGPSImgDirectionRef;
dng_urational fGPSImgDirection;
dng_string fGPSMapDatum;
dng_string fGPSDestLatitudeRef;
dng_urational fGPSDestLatitude [3];
dng_string fGPSDestLongitudeRef;
dng_urational fGPSDestLongitude [3];
dng_string fGPSDestBearingRef;
dng_urational fGPSDestBearing;
dng_string fGPSDestDistanceRef;
dng_urational fGPSDestDistance;
dng_string fGPSProcessingMethod;
dng_string fGPSAreaInformation;
dng_string fGPSDateStamp;
uint32 fGPSDifferential;
dng_urational fGPSHPositioningError;
dng_string fInteroperabilityIndex;
uint32 fInteroperabilityVersion;
dng_string fRelatedImageFileFormat;
uint32 fRelatedImageWidth;
uint32 fRelatedImageLength;
dng_string fCameraSerialNumber; // EXIF 2.3: BodySerialNumber.
dng_urational fLensInfo [4]; // EXIF 2.3: LensSpecification.
dng_string fLensID;
dng_string fLensMake;
dng_string fLensName; // EXIF 2.3: LensModel.
dng_string fLensSerialNumber;
// Was the lens name field read from a LensModel tag?
bool fLensNameWasReadFromExif;
// Private field to hold the approximate focus distance of the lens, in
// meters. This value is often coarsely measured/reported and hence should be
// interpreted only as a rough estimate of the true distance from the plane
// of focus (in object space) to the focal plane. It is still useful for the
// purposes of applying lens corrections.
dng_urational fApproxFocusDistance;
dng_srational fFlashCompensation;
dng_string fOwnerName; // EXIF 2.3: CameraOwnerName.
dng_string fFirmware;
// EXIF 2.3.1:
dng_srational fTemperature;
dng_urational fHumidity;
dng_urational fPressure;
dng_srational fWaterDepth;
dng_urational fAcceleration;
dng_srational fCameraElevationAngle;
// Not really part of EXIF, but some formats may use.
dng_string fTitle;
// Image-specific radial distortion correction metadata that can be
// used later during (UI-driven) lens profile corrections. Same model
// as DNG opcode model.
dng_srational fLensDistortInfo [4];
public:
dng_exif ();
virtual ~dng_exif ();
/// Make clone.
virtual dng_exif * Clone () const;
/// Clear all EXIF fields.
void SetEmpty ();
/// Copy all GPS-related fields.
/// \param exif Source object from which to copy GPS fields.
void CopyGPSFrom (const dng_exif &exif);
/// Utility to fix up common errors and rounding issues with EXIF exposure
/// times.
static real64 SnapExposureTime (real64 et);
/// Set exposure time and shutter speed fields. Optionally fix up common
/// errors and rounding issues with EXIF exposure times.
/// \param et Exposure time in seconds.
/// \param snap Set to true to fix up common errors and rounding issues with
/// EXIF exposure times.
void SetExposureTime (real64 et,
bool snap = true);
/// Set shutter speed value (APEX units) and exposure time.
/// \param ss Shutter speed in APEX units.
void SetShutterSpeedValue (real64 ss);
/// Utility to encode f-number as a rational.
/// \param fs The f-number to encode.
static dng_urational EncodeFNumber (real64 fs);
/// Set the FNumber and ApertureValue fields.
/// \param fs The f-number to set.
void SetFNumber (real64 fs);
/// Set the FNumber and ApertureValue fields.
/// \param av The aperture value (APEX units).
void SetApertureValue (real64 av);
/// Utility to convert aperture value (APEX units) to f-number.
/// \param av The aperture value (APEX units) to convert.
static real64 ApertureValueToFNumber (real64 av);
/// Utility to convert aperture value (APEX units) to f-number.
/// \param av The aperture value (APEX units) to convert.
static real64 ApertureValueToFNumber (const dng_urational &av);
/// Utility to convert f-number to aperture value (APEX units).
/// \param fNumber The f-number to convert.
static real64 FNumberToApertureValue (real64 fNumber);
/// Utility to convert f-number to aperture value (APEX units).
/// \param fNumber The f-number to convert.
static real64 FNumberToApertureValue (const dng_urational &fNumber);
/// Set the DateTime field.
/// \param dt The DateTime value.
void UpdateDateTime (const dng_date_time_info &dt);
/// Returns true iff the EXIF version is at least 2.3.
bool AtLeastVersion0230 () const;
/// Returns true iff the EXIF version is at least 2.3.1.
bool AtLeastVersion0231 () const;
/// Sets the EXIF version to 2.3.1.
void SetVersion0231 ();
bool HasLensDistortInfo () const;
void SetLensDistortInfo (const dng_vector &params);
virtual bool ParseTag (dng_stream &stream,
dng_shared &shared,
uint32 parentCode,
bool isMainIFD,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint64 tagOffset);
virtual void PostParse (dng_host &host,
dng_shared &shared);
protected:
virtual bool Parse_ifd0 (dng_stream &stream,
dng_shared &shared,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint64 tagOffset);
virtual bool Parse_ifd0_main (dng_stream &stream,
dng_shared &shared,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint64 tagOffset);
virtual bool Parse_ifd0_exif (dng_stream &stream,
dng_shared &shared,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint64 tagOffset);
virtual bool Parse_gps (dng_stream &stream,
dng_shared &shared,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint64 tagOffset);
virtual bool Parse_interoperability (dng_stream &stream,
dng_shared &shared,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint64 tagOffset);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,26 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Include file to set optimization to highest level for performance-critical routines.
* Normal files should have otpimization set to normal level to save code size as there is less
* cache pollution this way.
*/
/*****************************************************************************/
// Include this file in modules that contain routines that should be as fast
// as possible, even at the expense of slight code size increases.
/*****************************************************************************/
#ifdef _MSC_VER
#pragma optimize ("t", on)
#endif
/*****************************************************************************/

@ -0,0 +1,182 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_file_stream.h"
#include "dng_exceptions.h"
/*****************************************************************************/
dng_file_stream::dng_file_stream (const char *filename,
bool output,
uint32 bufferSize)
: dng_stream ((dng_abort_sniffer *) NULL,
bufferSize,
0)
, fFile (NULL)
{
fFile = fopen (filename, output ? "wb" : "rb");
if (!fFile)
{
#if qDNGValidate
ReportError ("Unable to open file",
filename);
ThrowSilentError ();
#else
ThrowOpenFile ();
#endif
}
}
/*****************************************************************************/
#if qWinOS
/*****************************************************************************/
dng_file_stream::dng_file_stream (const wchar_t *filename,
bool output,
uint32 bufferSize)
: dng_stream ((dng_abort_sniffer *) NULL,
bufferSize,
0)
, fFile (NULL)
{
fFile = _wfopen (filename, output ? L"wb" : L"rb");
if (!fFile)
{
#if qDNGValidate
char filenameCString[256];
size_t returnCount;
wcstombs_s (&returnCount,
filenameCString,
256,
filename,
_TRUNCATE);
ReportError ("Unable to open file",
filenameCString);
ThrowSilentError ();
#else
ThrowOpenFile ();
#endif // qDNGValidate
}
}
/*****************************************************************************/
#endif // qWinOS
/*****************************************************************************/
dng_file_stream::~dng_file_stream ()
{
if (fFile)
{
fclose (fFile);
fFile = NULL;
}
}
/*****************************************************************************/
uint64 dng_file_stream::DoGetLength ()
{
if (fseek (fFile, 0, SEEK_END) != 0)
{
ThrowReadFile ();
}
return (uint64) ftell (fFile);
}
/*****************************************************************************/
void dng_file_stream::DoRead (void *data,
uint32 count,
uint64 offset)
{
if (fseek (fFile, (long) offset, SEEK_SET) != 0)
{
ThrowReadFile ();
}
uint32 bytesRead = (uint32) fread (data, 1, count, fFile);
if (bytesRead != count)
{
ThrowReadFile ();
}
}
/*****************************************************************************/
void dng_file_stream::DoWrite (const void *data,
uint32 count,
uint64 offset)
{
if (fseek (fFile, (uint32) offset, SEEK_SET) != 0)
{
ThrowWriteFile ();
}
uint32 bytesWritten = (uint32) fwrite (data, 1, count, fFile);
if (bytesWritten != count)
{
ThrowWriteFile ();
}
}
/*****************************************************************************/

@ -0,0 +1,72 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Simple, portable, file read/write support.
*/
/*****************************************************************************/
#ifndef __dng_file_stream__
#define __dng_file_stream__
/*****************************************************************************/
#include "dng_stream.h"
/*****************************************************************************/
/// \brief A stream to/from a disk file. See dng_stream for read/write interface
class dng_file_stream: public dng_stream
{
private:
FILE *fFile;
public:
/// Open a stream on a file.
/// \param filename Pathname in platform synax.
/// \param output Set to true if writing, false otherwise.
/// \param bufferSize size of internal buffer to use. Defaults to 4k.
dng_file_stream (const char *filename,
bool output = false,
uint32 bufferSize = kDefaultBufferSize);
#if qWinOS
dng_file_stream (const wchar_t *filename,
bool output = false,
uint32 bufferSize = kDefaultBufferSize);
#endif // qWinOS
virtual ~dng_file_stream ();
protected:
virtual uint64 DoGetLength ();
virtual void DoRead (void *data,
uint32 count,
uint64 offset);
virtual void DoWrite (const void *data,
uint32 count,
uint64 offset);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,157 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_filter_task.h"
#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#include "dng_image.h"
#include "dng_memory.h"
#include "dng_tag_types.h"
#include "dng_tag_values.h"
#include "dng_utils.h"
/*****************************************************************************/
dng_filter_task::dng_filter_task (const char *name,
const dng_image &srcImage,
dng_image &dstImage)
: dng_area_task (name)
, fSrcImage (srcImage)
, fDstImage (dstImage)
, fSrcPlane (0 )
, fSrcPlanes (srcImage.Planes ())
, fSrcPixelType (srcImage.PixelType ())
, fDstPlane (0 )
, fDstPlanes (dstImage.Planes ())
, fDstPixelType (dstImage.PixelType ())
, fSrcRepeat (1, 1)
, fSrcTileSize (0, 0)
{
}
/*****************************************************************************/
dng_filter_task::~dng_filter_task ()
{
}
/*****************************************************************************/
void dng_filter_task::Start (uint32 threadCount,
const dng_rect & /* dstArea */,
const dng_point &tileSize,
dng_memory_allocator *allocator,
dng_abort_sniffer * /* sniffer */)
{
fSrcTileSize = SrcTileSize (tileSize);
uint32 srcBufferSize = ComputeBufferSize (fSrcPixelType,
fSrcTileSize,
fSrcPlanes,
padSIMDBytes);
uint32 dstBufferSize = ComputeBufferSize (fDstPixelType,
tileSize,
fDstPlanes,
padSIMDBytes);
for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
{
fSrcBuffer [threadIndex] . Reset (allocator->Allocate (srcBufferSize));
fDstBuffer [threadIndex] . Reset (allocator->Allocate (dstBufferSize));
// Zero buffers so any pad bytes have defined values.
DoZeroBytes (fSrcBuffer [threadIndex]->Buffer (),
fSrcBuffer [threadIndex]->LogicalSize ());
DoZeroBytes (fDstBuffer [threadIndex]->Buffer (),
fDstBuffer [threadIndex]->LogicalSize ());
}
}
/*****************************************************************************/
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);
// Safety check.
int32 src_area_w;
int32 src_area_h;
if (!ConvertUint32ToInt32 (srcArea.W (),
&src_area_w) ||
!ConvertUint32ToInt32 (srcArea.H (),
&src_area_h) ||
src_area_w > fSrcTileSize.h ||
src_area_h > fSrcTileSize.v)
{
ThrowMemoryFull ("Area exceeds tile size.");
}
// Setup srcBuffer.
dng_pixel_buffer srcBuffer (srcArea,
fSrcPlane,
fSrcPlanes,
fSrcPixelType,
pcRowInterleavedAlignSIMD,
fSrcBuffer [threadIndex]->Buffer ());
// Setup dstBuffer.
dng_pixel_buffer dstBuffer (area,
fDstPlane,
fDstPlanes,
fDstPixelType,
pcRowInterleavedAlignSIMD,
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);
}
/*****************************************************************************/

@ -0,0 +1,155 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Specialization of dng_area_task for processing an area from one dng_image to an
* area of another.
*/
/*****************************************************************************/
#ifndef __dng_filter_task__
#define __dng_filter_task__
/*****************************************************************************/
#include "dng_area_task.h"
#include "dng_auto_ptr.h"
#include "dng_point.h"
#include "dng_rect.h"
#include "dng_sdk_limits.h"
/*****************************************************************************/
/// \brief Represents a task which filters an area of a source dng_image to an area
/// of a destination dng_image.
class dng_filter_task: public dng_area_task
{
protected:
const dng_image &fSrcImage;
dng_image &fDstImage;
uint32 fSrcPlane;
uint32 fSrcPlanes;
uint32 fSrcPixelType;
uint32 fDstPlane;
uint32 fDstPlanes;
uint32 fDstPixelType;
dng_point fSrcRepeat;
dng_point fSrcTileSize;
AutoPtr<dng_memory_block> fSrcBuffer [kMaxMPThreads];
AutoPtr<dng_memory_block> fDstBuffer [kMaxMPThreads];
public:
/// Construct a filter task given a source and destination images.
/// \param srcImage Image from which source pixels are read.
/// \param dstImage Image to which result pixels are written.
dng_filter_task (const char *name,
const dng_image &srcImage,
dng_image &dstImage);
virtual ~dng_filter_task ();
/// Compute the source area needed for a given destination area. Default
/// implementation assumes destination area is equal to source area for all
/// cases.
///
/// \param dstArea Area to for which pixels will be computed.
///
/// \retval The source area needed as input to calculate the requested
/// destination area.
virtual dng_rect SrcArea (const dng_rect &dstArea)
{
return dstArea;
}
/// Given a destination tile size, calculate input tile size. Simlar to
/// SrcArea, and should seldom be overridden.
///
/// \param dstTileSize The destination tile size that is targeted for output.
///
/// \retval The source tile size needed to compute a tile of the destination
/// size.
virtual dng_point SrcTileSize (const dng_point &dstTileSize)
{
return SrcArea (dng_rect (dstTileSize)).Size ();
}
/// Implements filtering operation from one buffer to another. Source and
/// destination pixels are set up in member fields of this class. Ideally, no
/// allocation should be done in this routine.
///
/// \param threadIndex The thread on which this routine is being called,
/// between 0 and threadCount - 1 for the threadCount passed to Start method.
///
/// \param srcBuffer Input area and source pixels.
///
/// \param dstBuffer Output area and destination pixels.
virtual void ProcessArea (uint32 threadIndex,
dng_pixel_buffer &srcBuffer,
dng_pixel_buffer &dstBuffer) = 0;
/// Called prior to processing on specific threads. Can be used to allocate
/// per-thread memory buffers, etc.
///
/// \param threadCount Total number of threads that will be used for
/// processing. Less than or equal to MaxThreads of dng_area_task.
///
/// \param tileSize Size of source tiles which will be processed. (Not all
/// tiles will be this size due to edge conditions.)
///
/// \param allocator dng_memory_allocator to use for allocating temporary
/// buffers, etc.
///
/// \param sniffer Sniffer to test for user cancellation and to set up
/// progress.
virtual void Start (uint32 threadCount,
const dng_rect &dstArea,
const dng_point &tileSize,
dng_memory_allocator *allocator,
dng_abort_sniffer *sniffer);
/// Process one tile or partitioned area. Should not be overridden. Instead,
/// override ProcessArea, which is where to implement filter processing for a
/// specific type of dng_filter_task. There is no allocator parameter as all
/// allocation should be done in Start.
///
/// \param threadIndex 0 to threadCount - 1 index indicating which thread
/// this is. (Can be used to get a thread-specific buffer allocated in the
/// Start method.)
///
/// \param area Size of tiles to be used for sizing buffers, etc. (Edges of
/// processing can be smaller.)
///
/// \param sniffer dng_abort_sniffer to use to check for user cancellation
/// and progress updates.
virtual void Process (uint32 threadIndex,
const dng_rect &area,
dng_abort_sniffer *sniffer);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,618 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_fingerprint.h"
#include "dng_assertions.h"
#include "dng_flags.h"
/*****************************************************************************/
dng_fingerprint::dng_fingerprint ()
{
for (uint32 j = 0; j < kDNGFingerprintSize; j++)
{
data [j] = 0;
}
}
/*****************************************************************************/
dng_fingerprint::dng_fingerprint (const char *hex)
{
if (!hex || strlen (hex) != kDNGFingerprintSize * 2 || !FromUtf8HexString (hex))
{
Clear ();
}
}
/*****************************************************************************/
bool dng_fingerprint::IsNull () const
{
for (uint32 j = 0; j < kDNGFingerprintSize; j++)
{
if (data [j] != 0)
{
return false;
}
}
return true;
}
/*****************************************************************************/
bool dng_fingerprint::operator== (const dng_fingerprint &print) const
{
for (uint32 j = 0; j < kDNGFingerprintSize; j++)
{
if (data [j] != print.data [j])
{
return false;
}
}
return true;
}
/******************************************************************************/
bool dng_fingerprint::operator< (const dng_fingerprint &print) const
{
for (uint32 j = 0; j < kDNGFingerprintSize; j++)
{
if (data [j] != print.data [j])
{
return data [j] < print.data [j];
}
}
return false;
}
/******************************************************************************/
uint32 dng_fingerprint::Collapse32 () const
{
uint32 x = 0;
for (uint32 j = 0; j < 4; j++)
{
uint32 y = 0;
for (uint32 k = 0; k < 4; k++)
{
y = (y << 8) + (uint32) data [j * 4 + k];
}
x = x ^ y;
}
return x;
}
/******************************************************************************/
static char NumToHexChar (unsigned int c)
{
if (c < 10)
{
return (char) ('0' + c);
}
else
{
return (char) ('A' + c - 10);
}
}
/*****************************************************************************/
void dng_fingerprint::ToUtf8HexString (char resultStr [2 * kDNGFingerprintSize + 1]) const
{
for (size_t i = 0; i < kDNGFingerprintSize; i++)
{
unsigned char c = data [i];
resultStr [i * 2 ] = NumToHexChar (c >> 4);
resultStr [i * 2 + 1] = NumToHexChar (c & 15);
}
resultStr [kDNGFingerprintSize * 2] = '\0';
}
/******************************************************************************/
static int HexCharToNum (char hexChar)
{
if (hexChar >= '0' && hexChar <= '9')
{
return hexChar - '0';
}
else if (hexChar >= 'A' && hexChar <= 'F')
{
return hexChar - 'A' + 10;
}
else if (hexChar >= 'a' && hexChar <= 'f')
{
return hexChar - 'a' + 10;
}
return -1;
}
/*****************************************************************************/
bool dng_fingerprint::FromUtf8HexString (const char inputStr [2 * kDNGFingerprintSize + 1])
{
for (size_t i = 0; i < kDNGFingerprintSize; i++)
{
int highNibble = HexCharToNum (inputStr [i * 2]);
if (highNibble < 0)
{
return false;
}
int lowNibble = HexCharToNum (inputStr [i * 2 + 1]);
if (lowNibble < 0)
{
return false;
}
data [i] = (uint8) ((highNibble << 4) + lowNibble);
}
return true;
}
/******************************************************************************/
// Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
// rights reserved.
//
// License to copy and use this software is granted provided that it
// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
// Algorithm" in all material mentioning or referencing this software
// or this function.
//
// License is also granted to make and use derivative works provided
// that such works are identified as "derived from the RSA Data
// Security, Inc. MD5 Message-Digest Algorithm" in all material
// mentioning or referencing the derived work.
//
// RSA Data Security, Inc. makes no representations concerning either
// the merchantability of this software or the suitability of this
// software for any particular purpose. It is provided "as is"
// without express or implied warranty of any kind.
//
// These notices must be retained in any copies of any part of this
// documentation and/or software.
/******************************************************************************/
dng_md5_printer::dng_md5_printer ()
: final (false)
, result ()
{
Reset ();
}
/******************************************************************************/
void dng_md5_printer::Reset ()
{
// No bits processed yet.
count [0] = 0;
count [1] = 0;
// Load magic initialization constants.
state [0] = 0x67452301;
state [1] = 0xefcdab89;
state [2] = 0x98badcfe;
state [3] = 0x10325476;
// Not finalized yet.
final = false;
}
/******************************************************************************/
void dng_md5_printer::Process (const void *data,
uint32 inputLen)
{
DNG_ASSERT (!final, "Fingerprint already finalized!");
const uint8 *input = (const uint8 *) data;
// Compute number of bytes mod 64
uint32 index = (count [0] >> 3) & 0x3F;
// Update number of bits
if ((count [0] += inputLen << 3) < (inputLen << 3))
{
count [1]++;
}
count [1] += inputLen >> 29;
// Transform as many times as possible.
uint32 i = 0;
uint32 partLen = 64 - index;
if (inputLen >= partLen)
{
memcpy (&buffer [index],
input,
partLen);
MD5Transform (state, buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
{
MD5Transform (state, &input [i]);
}
index = 0;
}
// Buffer remaining input
memcpy (&buffer [index],
&input [i],
inputLen - i);
}
/******************************************************************************/
const dng_fingerprint & dng_md5_printer::Result ()
{
if (!final)
{
static uint8 PADDING [64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
// Save number of bits
uint8 bits [8];
Encode (bits, count, 8);
// Pad out to 56 mod 64.
uint32 index = (count [0] >> 3) & 0x3f;
uint32 padLen = (index < 56) ? (56 - index) : (120 - index);
Process (PADDING, padLen);
// Append length (before padding)
Process (bits, 8);
// Store state in digest
Encode (result.data, state, 16);
// We are now finalized.
final = true;
}
return result;
}
/******************************************************************************/
// Encodes input (uint32) into output (uint8). Assumes len is
// a multiple of 4.
void dng_md5_printer::Encode (uint8 *output,
const uint32 *input,
uint32 len)
{
uint32 i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
{
output [j ] = (uint8) ((input [i] ) & 0xff);
output [j+1] = (uint8) ((input [i] >> 8) & 0xff);
output [j+2] = (uint8) ((input [i] >> 16) & 0xff);
output [j+3] = (uint8) ((input [i] >> 24) & 0xff);
}
}
/******************************************************************************/
// Decodes input (uint8) into output (uint32). Assumes len is
// a multiple of 4.
void dng_md5_printer::Decode (uint32 *output,
const uint8 *input,
uint32 len)
{
// Check for non-aligned case.
if (((uintptr) input) & 3)
{
uint32 i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
{
output [i] = (((uint32) input [j ]) ) |
(((uint32) input [j+1]) << 8) |
(((uint32) input [j+2]) << 16) |
(((uint32) input [j+3]) << 24);
}
}
// Else use optimized code for aligned case.
else
{
len = len >> 2;
const uint32 *sPtr = (const uint32 *) input;
uint32 *dPtr = output;
while (len--)
{
#if qDNGBigEndian
uint32 data = *(sPtr++);
data = (data >> 24) |
((data >> 8) & 0x0000FF00) |
((data << 8) & 0x00FF0000) |
(data << 24);
*(dPtr++) = data;
#else
*(dPtr++) = *(sPtr++);
#endif
}
}
}
/******************************************************************************/
// MD5 basic transformation. Transforms state based on block.
DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
void dng_md5_printer::MD5Transform (uint32 state [4],
const uint8 block [64])
{
enum
{
S11 = 7,
S12 = 12,
S13 = 17,
S14 = 22,
S21 = 5,
S22 = 9,
S23 = 14,
S24 = 20,
S31 = 4,
S32 = 11,
S33 = 16,
S34 = 23,
S41 = 6,
S42 = 10,
S43 = 15,
S44 = 21
};
#if qDNGBigEndian
uint32 x [16];
Decode (x, block, 64);
#else
uint32 temp [16];
const uint32 *x;
if (((uintptr) block) & 3)
{
Decode (temp, block, 64);
x = temp;
}
else
x = (const uint32 *) block;
#endif
uint32 a = state [0];
uint32 b = state [1];
uint32 c = state [2];
uint32 d = state [3];
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state [0] += a;
state [1] += b;
state [2] += c;
state [3] += d;
}
/*****************************************************************************/
// End of RSA Data Security, Inc. derived code.
/*****************************************************************************/

@ -0,0 +1,400 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Fingerprint (cryptographic hashing) support for generating strong hashes of image
* data.
*/
/*****************************************************************************/
#ifndef __dng_fingerprint__
#define __dng_fingerprint__
/*****************************************************************************/
#include "dng_exceptions.h"
#include "dng_types.h"
#include "dng_stream.h"
#include <cstring>
/*****************************************************************************/
/// \brief Container fingerprint (MD5 only at present).
class dng_fingerprint
{
public:
static const size_t kDNGFingerprintSize = 16;
uint8 data [kDNGFingerprintSize];
public:
dng_fingerprint ();
dng_fingerprint (const char *hex);
/// Check if fingerprint is all zeros.
bool IsNull () const;
/// Same as IsNull but expresses intention of testing validity.
bool IsValid () const
{
return !IsNull ();
}
/// Set to all zeros, a value used to indicate an invalid fingerprint.
void Clear ()
{
*this = dng_fingerprint ();
}
/// Test if two fingerprints are equal.
bool operator== (const dng_fingerprint &print) const;
/// Test if two fingerprints are not equal.
bool operator!= (const dng_fingerprint &print) const
{
return !(*this == print);
}
/// Comparision test for fingerprints.
bool operator< (const dng_fingerprint &print) const;
/// Produce a 32-bit hash value from fingerprint used for faster hashing of
/// fingerprints.
uint32 Collapse32 () const;
/// Convert fingerprint to UTF-8 string.
///
/// \param resultStr The output array to which the UTF-8 encoding of the
/// fingerprint will be written.
void ToUtf8HexString (char resultStr [2 * kDNGFingerprintSize + 1]) const;
/// Convert UTF-8 string to fingerprint. Returns true on success, false on
/// failure.
///
/// \param inputStr The input array from which the UTF-8 encoding of the
/// fingerprint will be read.
///
/// \retval True indicates success.
bool FromUtf8HexString (const char inputStr [2 * kDNGFingerprintSize + 1]);
};
/*****************************************************************************/
/// \brief Utility to compare fingerprints (e.g., for sorting).
struct dng_fingerprint_less_than
{
/// Less-than comparison.
bool operator() (const dng_fingerprint &a,
const dng_fingerprint &b) const
{
return memcmp (a.data,
b.data,
sizeof (a.data)) < 0;
}
};
/******************************************************************************/
/// \brief Utility to hash fingerprints (e.g., for hashtables).
struct dng_fingerprint_hash
{
/// Hash function.
size_t operator () (const dng_fingerprint &digest) const
{
return (size_t) digest.Collapse32 ();
}
};
/******************************************************************************/
// Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
// rights reserved.
//
// License to copy and use this software is granted provided that it
// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
// Algorithm" in all material mentioning or referencing this software
// or this function.
//
// License is also granted to make and use derivative works provided
// that such works are identified as "derived from the RSA Data
// Security, Inc. MD5 Message-Digest Algorithm" in all material
// mentioning or referencing the derived work.
//
// RSA Data Security, Inc. makes no representations concerning either
// the merchantability of this software or the suitability of this
// software for any particular purpose. It is provided "as is"
// without express or implied warranty of any kind.
//
// These notices must be retained in any copies of any part of this
// documentation and/or software.
/// \brief Class to hash binary data to a fingerprint using the MD5 Message-Digest
/// Algorithm.
class dng_md5_printer
{
public:
dng_md5_printer ();
virtual ~dng_md5_printer ()
{
}
/// Reset the fingerprint.
void Reset ();
/// Append the data to the stream to be hashed.
/// \param data The data to be hashed.
/// \param inputLen The length of data, in bytes.
void Process (const void *data,
uint32 inputLen);
/// Append the string to the stream to be hashed.
/// \param text The string to be hashed.
void Process (const char *text)
{
Process (text, (uint32) strlen (text));
}
/// Get the fingerprint (i.e., result of the hash).
const dng_fingerprint & Result ();
private:
static void Encode (uint8 *output,
const uint32 *input,
uint32 len);
static void Decode (uint32 *output,
const uint8 *input,
uint32 len);
// F, G, H and I are basic MD5 functions.
static inline uint32 F (uint32 x,
uint32 y,
uint32 z)
{
return (x & y) | (~x & z);
}
static inline uint32 G (uint32 x,
uint32 y,
uint32 z)
{
return (x & z) | (y & ~z);
}
static inline uint32 H (uint32 x,
uint32 y,
uint32 z)
{
return x ^ y ^ z;
}
static inline uint32 I (uint32 x,
uint32 y,
uint32 z)
{
return y ^ (x | ~z);
}
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
static inline void FF (uint32 &a,
uint32 b,
uint32 c,
uint32 d,
uint32 x,
uint32 s,
uint32 ac)
{
a += F (b, c, d) + x + ac;
a = (a << s) | (a >> (32 - s));
a += b;
}
DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
static inline void GG (uint32 &a,
uint32 b,
uint32 c,
uint32 d,
uint32 x,
uint32 s,
uint32 ac)
{
a += G (b, c, d) + x + ac;
a = (a << s) | (a >> (32 - s));
a += b;
}
DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
static inline void HH (uint32 &a,
uint32 b,
uint32 c,
uint32 d,
uint32 x,
uint32 s,
uint32 ac)
{
a += H (b, c, d) + x + ac;
a = (a << s) | (a >> (32 - s));
a += b;
}
DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
static inline void II (uint32 &a,
uint32 b,
uint32 c,
uint32 d,
uint32 x,
uint32 s,
uint32 ac)
{
a += I (b, c, d) + x + ac;
a = (a << s) | (a >> (32 - s));
a += b;
}
static void MD5Transform (uint32 state [4],
const uint8 block [64]);
private:
uint32 state [4];
uint32 count [2];
uint8 buffer [64];
bool final;
dng_fingerprint result;
};
/*****************************************************************************/
/// \brief A dng_stream based interface to the MD5 printing logic.
class dng_md5_printer_stream : public dng_stream, dng_md5_printer
{
private:
uint64 fNextOffset;
public:
/// Create an empty MD5 printer stream.
dng_md5_printer_stream ()
: fNextOffset (0)
{
}
virtual uint64 DoGetLength ()
{
return fNextOffset;
}
virtual void DoRead (void * /* data */,
uint32 /* count */,
uint64 /* offset */)
{
ThrowProgramError ();
}
virtual void DoSetLength (uint64 length)
{
if (length != fNextOffset)
{
ThrowProgramError ();
}
}
virtual void DoWrite (const void *data,
uint32 count2,
uint64 offset)
{
if (offset != fNextOffset)
{
ThrowProgramError ();
}
Process (data, count2);
fNextOffset += count2;
}
const dng_fingerprint & Result ()
{
Flush ();
return dng_md5_printer::Result ();
}
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,402 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Conditional compilation flags for DNG SDK.
*
* All conditional compilation macros for the DNG SDK begin with a lowercase 'q'.
*/
/*****************************************************************************/
#ifndef __dng_flags__
#define __dng_flags__
/*****************************************************************************/
/// \def qMacOS
/// 1 if compiling for Mac OS X.
/// \def qWinOS
/// 1 if compiling for Windows.
// Make sure a platform is defined
#if !(defined(qMacOS) || defined(qWinOS) || defined(qAndroid) || defined(qiPhone) || defined(qLinux))
#include "RawEnvironment.h"
#endif
// This requires a force include or compiler define. These are the unique platforms.
#if !(defined(qMacOS) || defined(qWinOS) || defined(qAndroid) || defined(qiPhone) || defined(qLinux))
#error Unable to figure out platform
#endif
/*****************************************************************************/
// Platforms.
// Zeros out any undefined platforms, so that #if can be used in place of #ifdef.
#ifndef qMacOS
#define qMacOS 0
#endif
#ifndef qiPhone
#define qiPhone 0
#endif
#ifndef qiPhoneSimulator
#define qiPhoneSimulator 0
#endif
#ifndef qAndroid
#define qAndroid 0
#endif
#ifndef qWinOS
#define qWinOS 0
#endif
#ifndef qWinRT
#define qWinRT 0
#endif
#ifndef qLinux
#define qLinux 0
#endif
#ifndef qWeb
#define qWeb 0
#endif
/*****************************************************************************/
#if qiPhoneSimulator
#if !qiPhone
#error "qiPhoneSimulator set and not qiPhone"
#endif
#endif
#if qWinRT
#if !qWinOS
#error "qWinRT set but not qWinOS"
#endif
#endif
/*****************************************************************************/
// arm and neon support
// arm detect (apple vs. win)
#if defined(__arm__) || defined(__arm64__) || defined(_M_ARM)
#define qARM 1
#endif
// arm_neon detect
#if defined(__ARM_NEON__) || defined(_M_ARM)
#define qARMNeon 1
#endif
#ifndef qARM
#define qARM 0
#endif
#ifndef qARMNeon
#define qARMNeon 0
#endif
/*****************************************************************************/
// Establish WIN32 and WIN64 definitions.
#if defined(_WIN32) && !defined(WIN32)
#define WIN32 1
#endif
#if defined(_WIN64) && !defined(WIN64)
#define WIN64 1
#endif
/*****************************************************************************/
/// \def qDNGDebug
/// 1 if debug code is compiled in, 0 otherwise. Enables assertions and other debug
/// checks in exchange for slower processing.
// Figure out if debug build or not.
#ifndef qDNGDebug
#if defined(Debug)
#define qDNGDebug Debug
#elif defined(_DEBUG)
#define qDNGDebug _DEBUG
#else
#define qDNGDebug 0
#endif
#endif
/*****************************************************************************/
// Support Intel Thread Building Blocks (TBB)?
//
// This flag needs to be configured via the project, because there are sources
// outside the cr_sdk (such as the CTJPEG and ACE libs) that need to use the
// same flag to determine whether to use TBB or not.
//
// By default, configure to 0 (disabled).
#ifndef qCRSupportTBB
#define qCRSupportTBB 0
#endif
#if qCRSupportTBB
#ifndef TBB_DEPRECATED
#define TBB_DEPRECATED 0
#endif
#endif
// This is not really a switch, but rather a shorthand for determining whether
// or not we're building a particular translation unit (source file) using the
// Intel Compiler.
#ifndef qDNGIntelCompiler
#if defined(__INTEL_COMPILER)
#define qDNGIntelCompiler (__INTEL_COMPILER >= 1700)
#else
#define qDNGIntelCompiler 0
#endif
#endif
/*****************************************************************************/
// Figure out byte order.
/// \def qDNGBigEndian
/// 1 if this target platform is big endian (e.g. PowerPC Macintosh), else 0.
///
/// \def qDNGLittleEndian
/// 1 if this target platform is little endian (e.g. x86 processors), else 0.
#ifndef qDNGBigEndian
#if defined(qDNGLittleEndian)
#define qDNGBigEndian !qDNGLittleEndian
#elif defined(__POWERPC__)
#define qDNGBigEndian 1
#elif defined(__INTEL__)
#define qDNGBigEndian 0
#elif defined(_M_IX86)
#define qDNGBigEndian 0
#elif defined(_M_X64) || defined(__amd64__)
#define qDNGBigEndian 0
#elif defined(__LITTLE_ENDIAN__)
#define qDNGBigEndian 0
#elif defined(__BIG_ENDIAN__)
#define qDNGBigEndian 1
#elif defined(_ARM_)
#define qDNGBigEndian 0
#else
#ifndef qXCodeRez
#error Unable to figure out byte order.
#endif
#endif
#endif
#ifndef qXCodeRez
#ifndef qDNGLittleEndian
#define qDNGLittleEndian !qDNGBigEndian
#endif
#endif
/*****************************************************************************/
/// \def qDNG64Bit
/// 1 if this target platform uses 64-bit addresses, 0 otherwise.
#ifndef qDNG64Bit
#if qMacOS
#ifdef __LP64__
#if __LP64__
#define qDNG64Bit 1
#endif
#endif
#elif qWinOS
#ifdef WIN64
#if WIN64
#define qDNG64Bit 1
#endif
#endif
#elif qLinux
#ifdef __LP64__
#if __LP64__
#define qDNG64Bit 1
#endif
#endif
#endif
#ifndef qDNG64Bit
#define qDNG64Bit 0
#endif
#endif
/*****************************************************************************/
/// \def qDNGThreadSafe
/// 1 if target platform has thread support and threadsafe libraries, 0 otherwise.
#ifndef qDNGThreadSafe
#define qDNGThreadSafe (qMacOS || qWinOS)
#endif
/*****************************************************************************/
/// \def qDNGValidateTarget
/// 1 if dng_validate command line tool is being built, 0 otherwise.
#ifndef qDNGValidateTarget
#define qDNGValidateTarget 0
#endif
/*****************************************************************************/
/// \def qDNGValidate
/// 1 if DNG validation code is enabled, 0 otherwise.
#ifndef qDNGValidate
#define qDNGValidate qDNGValidateTarget
#endif
/*****************************************************************************/
/// \def qDNGPrintMessages
/// 1 if dng_show_message should use fprintf to stderr. 0 if it should use a platform
/// specific interrupt mechanism.
#ifndef qDNGPrintMessages
#define qDNGPrintMessages qDNGValidate
#endif
/*****************************************************************************/
// Experimental features -- work in progress for Lightroom and Camera Raw
// major releases. Turn this off for Lightroom & Camera Raw dot releases.
#ifndef qDNGExperimental
#define qDNGExperimental 1
#endif
/*****************************************************************************/
/// \def qDNGXMPFiles
/// 1 to use XMPFiles.
#ifndef qDNGXMPFiles
#define qDNGXMPFiles 1
#endif
/*****************************************************************************/
/// \def qDNGXMPDocOps
/// 1 to use XMPDocOps.
#ifndef qDNGXMPDocOps
#define qDNGXMPDocOps (!qDNGValidateTarget)
#endif
/*****************************************************************************/
/// \def qDNGUseLibJPEG
/// 1 to use open-source libjpeg for lossy jpeg processing.
#ifndef qDNGUseLibJPEG
#define qDNGUseLibJPEG qDNGValidateTarget
#endif
/*****************************************************************************/
#ifndef qDNGAVXSupport
#define qDNGAVXSupport ((qMacOS || qWinOS) && qDNG64Bit && !qARM && 1)
#endif
#if qDNGAVXSupport && !(qDNG64Bit && !qARM)
#error AVX support is enabled when 64-bit support is not or ARM is
#endif
/*****************************************************************************/
#ifndef qDNGSupportVC5
#define qDNGSupportVC5 (1)
#endif
/*****************************************************************************/
/// \def qDNGUsingSanitizer
/// Set to 1 when using a Sanitizer tool.
#ifndef qDNGUsingSanitizer
#define qDNGUsingSanitizer (0)
#endif
/*****************************************************************************/
#ifndef DNG_ATTRIB_NO_SANITIZE
#if qDNGUsingSanitizer && defined(__clang__)
#define DNG_ATTRIB_NO_SANITIZE(type) __attribute__((no_sanitize(type)))
#else
#define DNG_ATTRIB_NO_SANITIZE(type)
#endif
#endif
/*****************************************************************************/
/// \def qDNGDepthSupport
/// 1 to add support for depth maps in DNG format.
/// Deprecated 2018-09-19.
#ifdef __cplusplus
#define qDNGDepthSupport #error
#endif
/*****************************************************************************/
/// \def qDNGPreserveBlackPoint
/// 1 to add support for non-zero black point in early raw pipeline.
/// Deprecated 2018-09-19.
#ifdef __cplusplus
#define qDNGPreserveBlackPoint #error
#endif
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,644 @@
/*****************************************************************************/
// Copyright 2008-2019 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.
/*****************************************************************************/
#include "dng_gain_map.h"
#include "dng_exceptions.h"
#include "dng_globals.h"
#include "dng_host.h"
#include "dng_negative.h"
#include "dng_pixel_buffer.h"
#include "dng_stream.h"
#include "dng_tag_values.h"
/*****************************************************************************/
class dng_gain_map_interpolator
{
private:
const dng_gain_map &fMap;
dng_point_real64 fScale;
dng_point_real64 fOffset;
int32 fColumn;
int32 fPlane;
uint32 fRowIndex1;
uint32 fRowIndex2;
real32 fRowFract;
int32 fResetColumn;
real32 fValueBase;
real32 fValueStep;
real32 fValueIndex;
public:
dng_gain_map_interpolator (const dng_gain_map &map,
const dng_rect &mapBounds,
int32 row,
int32 column,
uint32 plane);
real32 Interpolate () const
{
return fValueBase + fValueStep * fValueIndex;
}
void Increment ()
{
if (++fColumn >= fResetColumn)
{
ResetColumn ();
}
else
{
fValueIndex += 1.0f;
}
}
private:
real32 InterpolateEntry (uint32 colIndex);
void ResetColumn ();
};
/*****************************************************************************/
dng_gain_map_interpolator::dng_gain_map_interpolator (const dng_gain_map &map,
const dng_rect &mapBounds,
int32 row,
int32 column,
uint32 plane)
: fMap (map)
, fScale (1.0 / mapBounds.H (),
1.0 / mapBounds.W ())
, fOffset (0.5 - mapBounds.t,
0.5 - mapBounds.l)
, fColumn (column)
, fPlane (plane)
, fRowIndex1 (0)
, fRowIndex2 (0)
, fRowFract (0.0f)
, fResetColumn (0)
, fValueBase (0.0f)
, fValueStep (0.0f)
, fValueIndex (0.0f)
{
real64 rowIndexF = (fScale.v * (row + fOffset.v) -
fMap.Origin ().v) / fMap.Spacing ().v;
if (rowIndexF <= 0.0)
{
fRowIndex1 = 0;
fRowIndex2 = 0;
fRowFract = 0.0f;
}
else
{
if (fMap.Points ().v < 1)
{
ThrowProgramError ("Empty gain map");
}
uint32 lastRow = static_cast<uint32> (fMap.Points ().v - 1);
if (rowIndexF >= static_cast<real64> (lastRow))
{
fRowIndex1 = lastRow;
fRowIndex2 = fRowIndex1;
fRowFract = 0.0f;
}
else
{
// If we got here, we know that rowIndexF can safely be converted to
// a uint32 and that static_cast<uint32> (rowIndexF) < lastRow. This
// implies fRowIndex2 <= lastRow below.
fRowIndex1 = static_cast<uint32> (rowIndexF);
fRowIndex2 = fRowIndex1 + 1;
fRowFract = (real32) (rowIndexF - (real64) fRowIndex1);
}
}
ResetColumn ();
}
/*****************************************************************************/
real32 dng_gain_map_interpolator::InterpolateEntry (uint32 colIndex)
{
return fMap.Entry (fRowIndex1, colIndex, fPlane) * (1.0f - fRowFract) +
fMap.Entry (fRowIndex2, colIndex, fPlane) * ( fRowFract);
}
/*****************************************************************************/
void dng_gain_map_interpolator::ResetColumn ()
{
real64 colIndexF = ((fScale.h * (fColumn + fOffset.h)) -
fMap.Origin ().h) / fMap.Spacing ().h;
if (colIndexF <= 0.0)
{
fValueBase = InterpolateEntry (0);
fValueStep = 0.0f;
fResetColumn = (int32) ceil (fMap.Origin ().h / fScale.h - fOffset.h);
}
else
{
if (fMap.Points ().h < 1)
{
ThrowProgramError ("Empty gain map");
}
uint32 lastCol = static_cast<uint32> (fMap.Points ().h - 1);
if (colIndexF >= static_cast<real64> (lastCol))
{
fValueBase = InterpolateEntry (lastCol);
fValueStep = 0.0f;
fResetColumn = 0x7FFFFFFF;
}
else
{
// If we got here, we know that colIndexF can safely be converted
// to a uint32 and that static_cast<uint32> (colIndexF) < lastCol.
// This implies colIndex + 1 <= lastCol, i.e. the argument to
// InterpolateEntry() below is valid.
uint32 colIndex = static_cast<uint32> (colIndexF);
real64 base = InterpolateEntry (colIndex);
real64 delta = InterpolateEntry (colIndex + 1) - base;
fValueBase = (real32) (base + delta * (colIndexF - (real64) colIndex));
fValueStep = (real32) ((delta * fScale.h) / fMap.Spacing ().h);
fResetColumn = (int32) ceil (((colIndex + 1) * fMap.Spacing ().h +
fMap.Origin ().h) / fScale.h - fOffset.h);
}
}
fValueIndex = 0.0f;
}
/*****************************************************************************/
DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
dng_gain_map::dng_gain_map (dng_memory_allocator &allocator,
const dng_point &points,
const dng_point_real64 &spacing,
const dng_point_real64 &origin,
uint32 planes)
: fPoints (points)
, fSpacing (spacing)
, fOrigin (origin)
, fPlanes (planes)
, fRowStep (planes * points.h)
, fBuffer ()
{
fBuffer.Reset (allocator.Allocate (ComputeBufferSize (ttFloat,
fPoints,
fPlanes,
padSIMDBytes)));
}
/*****************************************************************************/
real32 dng_gain_map::Interpolate (int32 row,
int32 col,
uint32 plane,
const dng_rect &bounds) const
{
dng_gain_map_interpolator interp (*this,
bounds,
row,
col,
plane);
return interp.Interpolate ();
}
/*****************************************************************************/
uint32 dng_gain_map::PutStreamSize () const
{
return 44 + fPoints.v * fPoints.h * fPlanes * 4;
}
/*****************************************************************************/
void dng_gain_map::PutStream (dng_stream &stream) const
{
stream.Put_uint32 (fPoints.v);
stream.Put_uint32 (fPoints.h);
stream.Put_real64 (fSpacing.v);
stream.Put_real64 (fSpacing.h);
stream.Put_real64 (fOrigin.v);
stream.Put_real64 (fOrigin.h);
stream.Put_uint32 (fPlanes);
for (int32 rowIndex = 0; rowIndex < fPoints.v; rowIndex++)
{
for (int32 colIndex = 0; colIndex < fPoints.h; colIndex++)
{
for (uint32 plane = 0; plane < fPlanes; plane++)
{
stream.Put_real32 (Entry (rowIndex,
colIndex,
plane));
}
}
}
}
/*****************************************************************************/
dng_gain_map * dng_gain_map::GetStream (dng_host &host,
dng_stream &stream)
{
dng_point mapPoints;
mapPoints.v = stream.Get_uint32 ();
mapPoints.h = stream.Get_uint32 ();
dng_point_real64 mapSpacing;
mapSpacing.v = stream.Get_real64 ();
mapSpacing.h = stream.Get_real64 ();
dng_point_real64 mapOrigin;
mapOrigin.v = stream.Get_real64 ();
mapOrigin.h = stream.Get_real64 ();
uint32 mapPlanes = stream.Get_uint32 ();
#if qDNGValidate
if (gVerbose)
{
printf ("Points: v=%d, h=%d\n",
(int) mapPoints.v,
(int) mapPoints.h);
printf ("Spacing: v=%.6f, h=%.6f\n",
mapSpacing.v,
mapSpacing.h);
printf ("Origin: v=%.6f, h=%.6f\n",
mapOrigin.v,
mapOrigin.h);
printf ("Planes: %u\n",
(unsigned) mapPlanes);
}
#endif
if (mapPoints.v == 1)
{
mapSpacing.v = 1.0;
mapOrigin.v = 0.0;
}
if (mapPoints.h == 1)
{
mapSpacing.h = 1.0;
mapOrigin.h = 0.0;
}
if (mapPoints.v < 1 ||
mapPoints.h < 1 ||
mapSpacing.v <= 0.0 ||
mapSpacing.h <= 0.0 ||
mapPlanes < 1)
{
ThrowBadFormat ();
}
AutoPtr<dng_gain_map> map (new dng_gain_map (host.Allocator (),
mapPoints,
mapSpacing,
mapOrigin,
mapPlanes));
#if qDNGValidate
uint32 linesPrinted = 0;
uint32 linesSkipped = 0;
#endif
for (int32 rowIndex = 0; rowIndex < mapPoints.v; rowIndex++)
{
for (int32 colIndex = 0; colIndex < mapPoints.h; colIndex++)
{
for (uint32 plane = 0; plane < mapPlanes; plane++)
{
real32 x = stream.Get_real32 ();
map->Entry (rowIndex, colIndex, plane) = x;
#if qDNGValidate
if (gVerbose)
{
if (linesPrinted < gDumpLineLimit)
{
printf (" Map [%3u] [%3u] [%u] = %.4f\n",
(unsigned) rowIndex,
(unsigned) colIndex,
(unsigned) plane,
x);
linesPrinted++;
}
else
linesSkipped++;
}
#endif
}
}
}
#if qDNGValidate
if (linesSkipped)
{
printf (" ... %u map entries skipped\n", (unsigned) linesSkipped);
}
#endif
return map.Release ();
}
/*****************************************************************************/
dng_opcode_GainMap::dng_opcode_GainMap (const dng_area_spec &areaSpec,
AutoPtr<dng_gain_map> &gainMap)
: dng_inplace_opcode (dngOpcode_GainMap,
dngVersion_1_3_0_0,
kFlag_None)
, fAreaSpec (areaSpec)
, fGainMap ()
{
fGainMap.Reset (gainMap.Release ());
}
/*****************************************************************************/
dng_opcode_GainMap::dng_opcode_GainMap (dng_host &host,
dng_stream &stream)
: dng_inplace_opcode (dngOpcode_GainMap,
stream,
"GainMap")
, fAreaSpec ()
, fGainMap ()
{
uint32 byteCount = stream.Get_uint32 ();
uint64 startPosition = stream.Position ();
fAreaSpec.GetData (stream);
fGainMap.Reset (dng_gain_map::GetStream (host, stream));
if (stream.Position () != startPosition + byteCount)
{
ThrowBadFormat ();
}
}
/*****************************************************************************/
void dng_opcode_GainMap::PutData (dng_stream &stream) const
{
stream.Put_uint32 (dng_area_spec::kDataSize +
fGainMap->PutStreamSize ());
fAreaSpec.PutData (stream);
fGainMap->PutStream (stream);
}
/*****************************************************************************/
void dng_opcode_GainMap::ProcessArea (dng_negative &negative,
uint32 /* threadIndex */,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds)
{
dng_rect overlap = fAreaSpec.Overlap (dstArea);
if (overlap.NotEmpty ())
{
uint16 blackLevel = (Stage () >= 2) ? negative.Stage3BlackLevel () : 0;
real32 blackScale1 = 1.0f;
real32 blackScale2 = 1.0f;
real32 blackOffset1 = 0.0f;
real32 blackOffset2 = 0.0f;
if (blackLevel != 0)
{
blackOffset2 = ((real32) blackLevel) / 65535.0f;
blackScale2 = 1.0f - blackOffset2;
blackScale1 = 1.0f / blackScale2;
blackOffset1 = 1.0f - blackScale1;
}
uint32 cols = overlap.W ();
uint32 colPitch = fAreaSpec.ColPitch ();
colPitch = Min_uint32 (colPitch, cols);
for (uint32 plane = fAreaSpec.Plane ();
plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
plane < buffer.Planes ();
plane++)
{
uint32 mapPlane = Min_uint32 (plane, fGainMap->Planes () - 1);
for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
{
real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
dng_gain_map_interpolator interp (*fGainMap,
imageBounds,
row,
overlap.l,
mapPlane);
if (blackLevel != 0)
{
for (uint32 col = 0; col < cols; col += colPitch)
{
dPtr [col] = dPtr [col] * blackScale1 + blackOffset1;
}
}
for (uint32 col = 0; col < cols; col += colPitch)
{
real32 gain = interp.Interpolate ();
dPtr [col] = Min_real32 (dPtr [col] * gain, 1.0f);
for (uint32 j = 0; j < colPitch; j++)
{
interp.Increment ();
}
}
if (blackLevel != 0)
{
for (uint32 col = 0; col < cols; col += colPitch)
{
dPtr [col] = dPtr [col] * blackScale2 + blackOffset2;
}
}
}
}
}
}
/*****************************************************************************/

@ -0,0 +1,200 @@
/*****************************************************************************/
// Copyright 2008-2019 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.
/*****************************************************************************/
/** \file
* Opcode to fix 2D uniformity defects, such as shading.
*/
/*****************************************************************************/
#ifndef __dng_gain_map__
#define __dng_gain_map__
/*****************************************************************************/
#include "dng_memory.h"
#include "dng_misc_opcodes.h"
#include "dng_tag_types.h"
#include "dng_uncopyable.h"
/*****************************************************************************/
/// \brief Holds a discrete (i.e., sampled) 2D representation of a gain map. This is
/// effectively an image containing scale factors.
class dng_gain_map: private dng_uncopyable
{
private:
dng_point fPoints;
dng_point_real64 fSpacing;
dng_point_real64 fOrigin;
uint32 fPlanes;
uint32 fRowStep;
AutoPtr<dng_memory_block> fBuffer;
public:
/// Construct a gain map with the specified memory allocator, number of
/// samples (points), sample spacing, origin, and number of color planes.
dng_gain_map (dng_memory_allocator &allocator,
const dng_point &points,
const dng_point_real64 &spacing,
const dng_point_real64 &origin,
uint32 planes);
/// The number of samples in the horizontal and vertical directions.
const dng_point & Points () const
{
return fPoints;
}
/// The space between adjacent samples in the horizontal and vertical
/// directions.
const dng_point_real64 & Spacing () const
{
return fSpacing;
}
/// The 2D coordinate for the first (i.e., top-left-most) sample.
const dng_point_real64 & Origin () const
{
return fOrigin;
}
/// The number of color planes.
uint32 Planes () const
{
return fPlanes;
}
/// Getter for a gain map sample (specified by row, column, and plane).
real32 & Entry (uint32 rowIndex,
uint32 colIndex,
uint32 plane)
{
return *(fBuffer->Buffer_real32 () +
rowIndex * fRowStep +
colIndex * fPlanes +
plane);
}
/// Getter for a gain map sample (specified by row index, column index, and
/// plane index).
const real32 & Entry (uint32 rowIndex,
uint32 colIndex,
uint32 plane) const
{
return *(fBuffer->Buffer_real32 () +
rowIndex * fRowStep +
colIndex * fPlanes +
plane);
}
/// Compute the interpolated gain (i.e., scale factor) at the specified pixel
/// position and color plane, within the specified image bounds (in pixels).
real32 Interpolate (int32 row,
int32 col,
uint32 plane,
const dng_rect &bounds) const;
/// The number of bytes needed to hold the gain map data.
uint32 PutStreamSize () const;
/// Write the gain map to the specified stream.
void PutStream (dng_stream &stream) const;
/// Read a gain map from the specified stream.
static dng_gain_map * GetStream (dng_host &host,
dng_stream &stream);
};
/*****************************************************************************/
/// \brief An opcode to fix 2D spatially-varying light falloff or color casts (i.e.,
/// uniformity issues). This is commonly due to shading.
class dng_opcode_GainMap: public dng_inplace_opcode,
private dng_uncopyable
{
private:
dng_area_spec fAreaSpec;
AutoPtr<dng_gain_map> fGainMap;
public:
/// Construct a GainMap opcode for the specified image area and the specified
/// gain map.
dng_opcode_GainMap (const dng_area_spec &areaSpec,
AutoPtr<dng_gain_map> &gainMap);
/// Construct a GainMap opcode from the specified stream.
dng_opcode_GainMap (dng_host &host,
dng_stream &stream);
/// Write the opcode to the specified stream.
virtual void PutData (dng_stream &stream) const;
/// The pixel data type of this opcode.
virtual uint32 BufferPixelType (uint32 /* imagePixelType */)
{
return ttFloat;
}
/// The adjusted bounds (processing area) of this opcode. It is limited to
/// the intersection of the specified image area and the GainMap area.
virtual dng_rect ModifiedBounds (const dng_rect &imageBounds)
{
return fAreaSpec.Overlap (imageBounds);
}
/// Apply the gain map.
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,52 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_globals.h"
#include "dng_simd_type.h"
/*****************************************************************************/
#if qDNGValidate
bool gVerbose = false;
uint32 gDumpLineLimit = 100;
#endif
/******************************************************************************/
bool gDNGUseFakeTimeZonesInXMP = false;
/*****************************************************************************/
bool gDNGShowTimers = true;
/*****************************************************************************/
uint32 gDNGStreamBlockSize = 4096;
uint32 gDNGMaxStreamBufferSize = 1024 * 1024;
/*****************************************************************************/
bool gImagecore = false;
bool gPrintTimings = false;
bool gPrintAsserts = true;
bool gBreakOnAsserts = true;
/*****************************************************************************/
// This is declared in dng_simd_type.h
SIMDType gDNGMaxSIMD = Scalar;
/*****************************************************************************/

@ -0,0 +1,85 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Definitions of global variables controling DNG SDK behavior.
*/
/*****************************************************************************/
#ifndef __dng_globals__
#define __dng_globals__
/*****************************************************************************/
#include "dng_flags.h"
#include "dng_types.h"
/*****************************************************************************/
#if qDNGValidate
/// When validation (qValidate) is turned on, this global enables verbose
/// output about DNG tags and other properties.
extern bool gVerbose;
/// When validation (qValidate) is turned on, and verbose mode (gVerbose) is
/// enabled, limits the number of lines of text that are dumped for each tag.
extern uint32 gDumpLineLimit;
#endif
/*****************************************************************************/
// Print out results from dng_timers?
extern bool gDNGShowTimers;
/******************************************************************************/
// MWG says don't use fake time zones in XMP, but there is some
// old software that requires them to work correctly.
extern bool gDNGUseFakeTimeZonesInXMP;
/*****************************************************************************/
// Stream block size. Choose a size that the OS likes for file system
// efficent read/write alignment.
extern uint32 gDNGStreamBlockSize;
// Maximum stream buffer size to use on large reads and writes.
extern uint32 gDNGMaxStreamBufferSize;
/*****************************************************************************/
// Are we running as part of the imagecore library?
extern bool gImagecore;
// Print out timing info for area tasks?
extern bool gPrintTimings;
// Print assert messages?
extern bool gPrintAsserts;
// Break into debugger on asserts?
extern bool gBreakOnAsserts;
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,587 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_host.h"
#include "dng_abort_sniffer.h"
#include "dng_area_task.h"
#include "dng_bad_pixels.h"
#include "dng_exceptions.h"
#include "dng_exif.h"
#include "dng_gain_map.h"
#include "dng_ifd.h"
#include "dng_lens_correction.h"
#include "dng_memory.h"
#include "dng_misc_opcodes.h"
#include "dng_negative.h"
#include "dng_resample.h"
#include "dng_shared.h"
#include "dng_simple_image.h"
#include "dng_xmp.h"
/*****************************************************************************/
dng_host::dng_host (dng_memory_allocator *allocator,
dng_abort_sniffer *sniffer)
: fAllocator (allocator)
, fSniffer (sniffer)
, fNeedsMeta (true)
, fNeedsImage (true)
, fForPreview (false)
, fMinimumSize (0)
, fPreferredSize (0)
, fMaximumSize (0)
, fCropFactor (1.0)
, fSaveDNGVersion (dngVersion_None)
, fSaveLinearDNG (false)
, fKeepOriginalFile (false)
, fForFastSaveToDNG (false)
, fFastSaveToDNGSize (0)
, fPreserveStage2 (false)
{
}
/*****************************************************************************/
dng_host::~dng_host ()
{
}
/*****************************************************************************/
dng_memory_allocator & dng_host::Allocator ()
{
if (fAllocator)
{
return *fAllocator;
}
else
{
return gDefaultDNGMemoryAllocator;
}
}
/*****************************************************************************/
dng_memory_block * dng_host::Allocate (uint32 logicalSize)
{
return Allocator ().Allocate (logicalSize);
}
/*****************************************************************************/
void dng_host::SniffForAbort ()
{
dng_abort_sniffer::SniffForAbort (Sniffer ());
}
/*****************************************************************************/
void dng_host::ValidateSizes ()
{
// The maximum size limits the other two sizes.
if (MaximumSize ())
{
SetMinimumSize (Min_uint32 (MinimumSize (), MaximumSize ()));
SetPreferredSize (Min_uint32 (PreferredSize (), MaximumSize ()));
}
// If we have a preferred size, it limits the minimum size.
if (PreferredSize ())
{
SetMinimumSize (Min_uint32 (MinimumSize (), PreferredSize ()));
}
// Else find default value for preferred size.
else
{
// If preferred size is zero, then we want the maximim
// size image.
if (MaximumSize ())
{
SetPreferredSize (MaximumSize ());
}
}
// If we don't have a minimum size, find default.
if (!MinimumSize ())
{
// A common size for embedded thumbnails is 120 by 160 pixels,
// So allow 120 by 160 pixels to be used for thumbnails when the
// preferred size is 256 pixel.
if (PreferredSize () >= 160 && PreferredSize () <= 256)
{
SetMinimumSize (160);
}
// Many sensors are near a multiple of 1024 pixels in size, but after
// the default crop, they are a just under. We can get an extra factor
// of size reduction if we allow a slight undershoot in the final size
// when computing large previews.
else if (PreferredSize () >= 490 && PreferredSize () <= 512)
{
SetMinimumSize (490);
}
else if (PreferredSize () >= 980 && PreferredSize () <= 1024)
{
SetMinimumSize (980);
}
else if (PreferredSize () >= 1470 && PreferredSize () <= 1536)
{
SetMinimumSize (1470);
}
else if (PreferredSize () >= 1960 && PreferredSize () <= 2048)
{
SetMinimumSize (1960);
}
else if (PreferredSize () >= 2400 && PreferredSize () <= 2560)
{
SetMinimumSize (2400);
}
// The following resolutions are typically on HiDPI displays where a
// greater degree of upsampling remains visually ok for previews. The
// following ratios are all based on 20% upsampling in a linear
// dimension.
else if (PreferredSize () >= 2448 && PreferredSize () <= 2880)
{
SetMinimumSize (2448);
}
// 1st-generation Surface Book.
else if (PreferredSize () >= 2560 && PreferredSize () <= 3000)
{
SetMinimumSize (2560);
}
// 4K (actually 3840).
else if (PreferredSize () >= 3480 && PreferredSize () <= 4096)
{
SetMinimumSize (3480);
}
// Surface Studio.
else if (PreferredSize () >= 3824 && PreferredSize () <= 4500)
{
SetMinimumSize (3824);
}
// 5K.
else if (PreferredSize () >= 4352 && PreferredSize () <= 5120)
{
SetMinimumSize (4352);
}
// 8K.
else if (PreferredSize () >= 6528 && PreferredSize () <= 7680)
{
SetMinimumSize (6528);
}
// Else minimum size is same as preferred size.
else
{
SetMinimumSize (PreferredSize ());
}
}
}
/*****************************************************************************/
uint32 dng_host::SaveDNGVersion () const
{
return fSaveDNGVersion;
}
/*****************************************************************************/
bool dng_host::SaveLinearDNG (const dng_negative & /* negative */) const
{
return fSaveLinearDNG;
}
/*****************************************************************************/
bool dng_host::IsTransientError (dng_error_code code)
{
switch (code)
{
case dng_error_memory:
case dng_error_user_canceled:
{
return true;
}
default:
break;
}
return false;
}
/*****************************************************************************/
void dng_host::PerformAreaTask (dng_area_task &task,
const dng_rect &area,
dng_area_task_progress *progress)
{
dng_area_task::Perform (task,
area,
&Allocator (),
Sniffer (),
progress);
}
/*****************************************************************************/
uint32 dng_host::PerformAreaTaskThreads ()
{
return 1;
}
/*****************************************************************************/
dng_exif * dng_host::Make_dng_exif ()
{
dng_exif *result = new dng_exif ();
if (!result)
{
ThrowMemoryFull ();
}
return result;
}
/*****************************************************************************/
dng_xmp * dng_host::Make_dng_xmp ()
{
dng_xmp *result = new dng_xmp (Allocator ());
if (!result)
{
ThrowMemoryFull ();
}
return result;
}
/*****************************************************************************/
dng_shared * dng_host::Make_dng_shared ()
{
dng_shared *result = new dng_shared ();
if (!result)
{
ThrowMemoryFull ();
}
return result;
}
/*****************************************************************************/
dng_ifd * dng_host::Make_dng_ifd ()
{
dng_ifd *result = new dng_ifd ();
if (!result)
{
ThrowMemoryFull ();
}
return result;
}
/*****************************************************************************/
dng_negative * dng_host::Make_dng_negative ()
{
return dng_negative::Make (*this);
}
/*****************************************************************************/
dng_image * dng_host::Make_dng_image (const dng_rect &bounds,
uint32 planes,
uint32 pixelType)
{
dng_image *result = new dng_simple_image (bounds,
planes,
pixelType,
Allocator ());
if (!result)
{
ThrowMemoryFull ();
}
return result;
}
/*****************************************************************************/
dng_opcode * dng_host::Make_dng_opcode (uint32 opcodeID,
dng_stream &stream)
{
dng_opcode *result = NULL;
switch (opcodeID)
{
case dngOpcode_WarpRectilinear:
{
result = new dng_opcode_WarpRectilinear (stream);
break;
}
case dngOpcode_WarpFisheye:
{
result = new dng_opcode_WarpFisheye (stream);
break;
}
case dngOpcode_FixVignetteRadial:
{
result = new dng_opcode_FixVignetteRadial (stream);
break;
}
case dngOpcode_FixBadPixelsConstant:
{
result = new dng_opcode_FixBadPixelsConstant (stream);
break;
}
case dngOpcode_FixBadPixelsList:
{
result = new dng_opcode_FixBadPixelsList (stream);
break;
}
case dngOpcode_TrimBounds:
{
result = new dng_opcode_TrimBounds (stream);
break;
}
case dngOpcode_MapTable:
{
result = new dng_opcode_MapTable (*this,
stream);
break;
}
case dngOpcode_MapPolynomial:
{
result = new dng_opcode_MapPolynomial (stream);
break;
}
case dngOpcode_GainMap:
{
result = new dng_opcode_GainMap (*this,
stream);
break;
}
case dngOpcode_DeltaPerRow:
{
result = new dng_opcode_DeltaPerRow (*this,
stream);
break;
}
case dngOpcode_DeltaPerColumn:
{
result = new dng_opcode_DeltaPerColumn (*this,
stream);
break;
}
case dngOpcode_ScalePerRow:
{
result = new dng_opcode_ScalePerRow (*this,
stream);
break;
}
case dngOpcode_ScalePerColumn:
{
result = new dng_opcode_ScalePerColumn (*this,
stream);
break;
}
default:
{
result = new dng_opcode_Unknown (*this,
opcodeID,
stream);
}
}
if (!result)
{
ThrowMemoryFull ();
}
return result;
}
/*****************************************************************************/
void dng_host::ApplyOpcodeList (dng_opcode_list &list,
dng_negative &negative,
AutoPtr<dng_image> &image)
{
list.Apply (*this,
negative,
image);
}
/*****************************************************************************/
void dng_host::ResampleImage (const dng_image &srcImage,
dng_image &dstImage)
{
::ResampleImage (*this,
srcImage,
dstImage,
srcImage.Bounds (),
dstImage.Bounds (),
dng_resample_bicubic::Get ());
}
/*****************************************************************************/

@ -0,0 +1,444 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Class definition for dng_host, initial point of contact and control between
* host application and DNG SDK.
*/
/*****************************************************************************/
#ifndef __dng_host__
#define __dng_host__
/*****************************************************************************/
#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_errors.h"
#include "dng_types.h"
#include "dng_uncopyable.h"
/*****************************************************************************/
/// \brief The main class for communication between the application and the
/// DNG SDK. Used to customize memory allocation and other behaviors.
///
/// dng_host allows setting parameters for the DNG conversion, mediates callback
/// style interactions between the host application and the DNG SDK, and allows
/// controlling certain internal behavior of the SDK such as memory allocation.
/// Many applications will be able to use the default implementation of dng_host
/// by just setting the dng_memory_allocator and dng_abort_sniffer in the
/// constructor. More complex interactions will require deriving a class from
/// dng_host.
///
/// Multiple dng_host objects can be allocated in a single process. This may
/// be useful for DNG processing on separate threads. (Distinct dng_host objects
/// are completely threadsafe for read/write. The application is responsible for
/// establishing mutual exclusion for read/write access to a single dng_host
/// object if it is used in multiple threads.)
class dng_host: private dng_uncopyable
{
private:
dng_memory_allocator *fAllocator;
dng_abort_sniffer *fSniffer;
// Does the host require all the image metadata (vs. just checking
// to see if the file is readable)?
bool fNeedsMeta;
// Does the host require actual image data (vs. just getting metadata
// or just checking to see if the file is readable)?
bool fNeedsImage;
// If we need the image data, can it be read at preview quality?
bool fForPreview;
// If non-zero, the minimum size (longer of the two pixel dimensions)
// image to read. If zero, or if the full size image is smaller than
// this, read the full size image.
uint32 fMinimumSize;
// What is the preferred size for a preview image? This can
// be slightly larger than the minimum size. Zero if we want
// the full resolution image.
uint32 fPreferredSize;
// What is the maximum size for a preview image? Zero if there
// is no maximum size limit.
uint32 fMaximumSize;
// The fraction of the image kept after a crop. This is used to
// adjust the sizes to take into account the cropping that
// will be peformed.
real64 fCropFactor;
// What DNG version should we keep enough data to save?
uint32 fSaveDNGVersion;
// Do we want to force saving to a linear DNG?
bool fSaveLinearDNG;
// Keep the original raw file data block?
bool fKeepOriginalFile;
// Is this host being used to perform a negative read for fast
// conversion to DNG?
bool fForFastSaveToDNG;
uint32 fFastSaveToDNGSize;
bool fPreserveStage2;
public:
/// Allocate a dng_host object, possiblly with custom allocator and sniffer.
/// \param allocator Allows controlling all memory allocation done via this
/// dng_host. Defaults to singleton global dng_memory_allocator, which calls
/// new/delete dng_malloc_block for appropriate size.
/// \param sniffer Used to periodically check if pending DNG conversions
/// should be aborted and to communicate progress updates. Defaults to singleton
/// global dng_abort_sniffer, which never aborts and ignores progress updated.
dng_host (dng_memory_allocator *allocator = NULL,
dng_abort_sniffer *sniffer = NULL);
/// Clean up direct memory for dng_host. Memory allocator and abort sniffer
/// are not deleted. Objects such as dng_image and others returned from
/// host can still be used after host is deleted.
virtual ~dng_host ();
/// Getter for host's memory allocator.
dng_memory_allocator & Allocator ();
/// Alocate a new dng_memory_block using the host's memory allocator.
/// Uses the Allocator() property of host to allocate a new block of memory.
/// Will call ThrowMemoryFull if block cannot be allocated.
/// \param logicalSize Number of usable bytes returned dng_memory_block
/// must contain.
virtual dng_memory_block * Allocate (uint32 logicalSize);
/// Setter for host's abort sniffer.
void SetSniffer (dng_abort_sniffer *sniffer)
{
fSniffer = sniffer;
}
/// Getter for host's abort sniffer.
dng_abort_sniffer * Sniffer ()
{
return fSniffer;
}
/// Check for pending abort. Should call ThrowUserCanceled if an abort
/// is pending.
virtual void SniffForAbort ();
/// Setter for flag determining whether all XMP metadata should be parsed.
/// Defaults to true. One might not want metadata when doing a quick check
/// to see if a file is readable.
/// \param needs If true, metadata is needed.
void SetNeedsMeta (bool needs)
{
fNeedsMeta = needs;
}
/// Getter for flag determining whether all XMP metadata should be parsed.
bool NeedsMeta () const
{
return fNeedsMeta;
}
/// Setter for flag determining whether DNG image data is needed. Defaults
/// to true. Image data might not be needed for applications which only
/// manipulate metadata.
/// \param needs If true, image data is needed.
void SetNeedsImage (bool needs)
{
fNeedsImage = needs;
}
/// Setter for flag determining whether DNG image data is needed.
bool NeedsImage () const
{
return fNeedsImage;
}
/// Setter for flag determining whether image should be preview quality,
/// or full quality.
/// \param preview If true, rendered images are for preview.
void SetForPreview (bool preview)
{
fForPreview = preview;
}
/// Getter for flag determining whether image should be preview quality.
/// Preview quality images may be rendered more quickly. Current DNG SDK
/// does not change rendering behavior based on this flag, but derived
/// versions may use this getter to choose between a slower more accurate path
/// and a faster "good enough for preview" one. Data produce with ForPreview set
/// to true should not be written back to a DNG file, except as a preview image.
bool ForPreview () const
{
return fForPreview;
}
/// Setter for the minimum preview size.
/// \param size Minimum pixel size (long side of image).
void SetMinimumSize (uint32 size)
{
fMinimumSize = size;
}
/// Getter for the minimum preview size.
uint32 MinimumSize () const
{
return fMinimumSize;
}
/// Setter for the preferred preview size.
/// \param size Preferred pixel size (long side of image).
void SetPreferredSize (uint32 size)
{
fPreferredSize = size;
}
/// Getter for the preferred preview size.
uint32 PreferredSize () const
{
return fPreferredSize;
}
/// Setter for the maximum preview size.
/// \param size Maximum pixel size (long side of image).
void SetMaximumSize (uint32 size)
{
fMaximumSize = size;
}
/// Getter for the maximum preview size.
uint32 MaximumSize () const
{
return fMaximumSize;
}
/// Setter for the perform fast save to DNG.
/// \param flag True if the host is being used to perform a negative
/// read for fast conversion to DNG, false otherwise.
void SetForFastSaveToDNG (bool flag,
uint32 size)
{
fForFastSaveToDNG = flag;
fFastSaveToDNGSize = size;
}
/// Getter for the Boolean value that indicates whether this host is
/// being used to perform a negative read for fast conversion to DNG.
bool ForFastSaveToDNG () const
{
return fForFastSaveToDNG;
}
uint32 FastSaveToDNGSize () const
{
return fFastSaveToDNGSize;
}
/// Setter for the cropping factor.
/// \param cropFactor Fraction of image to be used after crop.
void SetCropFactor (real64 cropFactor)
{
fCropFactor = cropFactor;
}
/// Getter for the cropping factor.
real64 CropFactor () const
{
return fCropFactor;
}
/// Makes sures minimum, preferred, and maximum sizes are reasonable.
void ValidateSizes ();
/// Setter for what version to save DNG file compatible with.
/// \param version What version to save DNG file compatible with.
void SetSaveDNGVersion (uint32 version)
{
fSaveDNGVersion = version;
}
/// Getter for what version to save DNG file compatible with.
virtual uint32 SaveDNGVersion () const;
/// Setter for flag determining whether to force saving a linear DNG file.
/// \param linear If true, we should force saving a linear DNG file.
void SetSaveLinearDNG (bool linear)
{
fSaveLinearDNG = linear;
}
/// Getter for flag determining whether to save a linear DNG file.
virtual bool SaveLinearDNG (const dng_negative &negative) const;
/// Setter for flag determining whether to keep original RAW file data.
/// \param keep If true, origianl RAW data will be kept.
void SetKeepOriginalFile (bool keep)
{
fKeepOriginalFile = keep;
}
/// Getter for flag determining whether to keep original RAW file data.
bool KeepOriginalFile ()
{
return fKeepOriginalFile;
}
/// Determine if an error is the result of a temporary, but planned-for
/// occurence such as user cancellation or memory exhaustion. This method is
/// sometimes used to determine whether to try and continue processing a DNG
/// file despite errors in the file format, etc. In such cases, processing will
/// be continued if IsTransientError returns false. This is so that user cancellation
/// and memory exhaustion always terminate processing.
/// \param code Error to test for transience.
virtual bool IsTransientError (dng_error_code code);
/// General top-level botttleneck for image processing tasks.
/// Default implementation calls dng_area_task::PerformAreaTask method on
/// task. Can be overridden in derived classes to support multiprocessing,
/// for example.
/// \param task Image processing task to perform on area.
/// \param area Rectangle over which to perform image processing task.
virtual void PerformAreaTask (dng_area_task &task,
const dng_rect &area,
dng_area_task_progress *progress = NULL);
/// How many multiprocessing threads does PerformAreaTask use?
/// Default implementation always returns 1 since it is single threaded.
virtual uint32 PerformAreaTaskThreads ();
/// Factory method for dng_exif class. Can be used to customize allocation or
/// to ensure a derived class is used instead of dng_exif.
virtual dng_exif * Make_dng_exif ();
/// Factory method for dng_xmp class. Can be used to customize allocation or
/// to ensure a derived class is used instead of dng_xmp.
virtual dng_xmp * Make_dng_xmp ();
/// Factory method for dng_shared class. Can be used to customize allocation
/// or to ensure a derived class is used instead of dng_shared.
virtual dng_shared * Make_dng_shared ();
/// Factory method for dng_ifd class. Can be used to customize allocation or
/// to ensure a derived class is used instead of dng_ifd.
virtual dng_ifd * Make_dng_ifd ();
/// Factory method for dng_negative class. Can be used to customize allocation
/// or to ensure a derived class is used instead of dng_negative.
virtual dng_negative * Make_dng_negative ();
/// Factory method for dng_image class. Can be used to customize allocation
/// or to ensure a derived class is used instead of dng_simple_image.
virtual dng_image * Make_dng_image (const dng_rect &bounds,
uint32 planes,
uint32 pixelType);
/// Factory method for parsing dng_opcode based classs. Can be used to
/// override opcode implementations.
virtual dng_opcode * Make_dng_opcode (uint32 opcodeID,
dng_stream &stream);
/// Factory method to apply a dng_opcode_list. Can be used to override
/// opcode list applications.
virtual void ApplyOpcodeList (dng_opcode_list &list,
dng_negative &negative,
AutoPtr<dng_image> &image);
/// Factory method to resample an image. Can be used to override
/// image method used to resample images.
virtual void ResampleImage (const dng_image &srcImage,
dng_image &dstImage);
/// Getter for flag determining whether we should preserve the stage 2
/// image after building the stage 3 image.
bool WantsPreserveStage2 () const
{
return fPreserveStage2;
}
/// Setter for flag determining whether we should preserve the stage 2
/// image after building the stage 3 image.
void SetWantsPreserveStage2 (bool flag)
{
fPreserveStage2 = flag;
}
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,405 @@
/*****************************************************************************/
// Copyright 2007-2019 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.
/*****************************************************************************/
#include "dng_hue_sat_map.h"
#include "dng_assertions.h"
#include "dng_auto_ptr.h"
#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#include "dng_host.h"
/*****************************************************************************/
std::atomic<uint64> dng_hue_sat_map::sRuntimeFingerprintCounter (0);
/*****************************************************************************/
dng_hue_sat_map::dng_hue_sat_map ()
: fHueDivisions (0)
, fSatDivisions (0)
, fValDivisions (0)
, fHueStep (0)
, fValStep (0)
, fRuntimeFingerprint ()
, fDeltas ()
{
}
/*****************************************************************************/
dng_hue_sat_map::dng_hue_sat_map (const dng_hue_sat_map &src)
: fHueDivisions (0)
, fSatDivisions (0)
, fValDivisions (0)
, fHueStep (0)
, fValStep (0)
, fRuntimeFingerprint ()
, fDeltas ()
{
*this = src;
}
/*****************************************************************************/
dng_hue_sat_map &dng_hue_sat_map::operator= (const dng_hue_sat_map &rhs)
{
if (this != &rhs)
{
if (!rhs.IsValid ())
{
SetInvalid ();
}
else
{
fHueDivisions = rhs.fHueDivisions;
fSatDivisions = rhs.fSatDivisions;
fValDivisions = rhs.fValDivisions;
fHueStep = rhs.fHueStep;
fValStep = rhs.fValStep;
fRuntimeFingerprint = rhs.fRuntimeFingerprint;
fDeltas = rhs.fDeltas;
}
}
return *this;
}
/*****************************************************************************/
dng_hue_sat_map::~dng_hue_sat_map ()
{
}
/*****************************************************************************/
void dng_hue_sat_map::SetDivisions (uint32 hueDivisions,
uint32 satDivisions,
uint32 valDivisions)
{
DNG_ASSERT (hueDivisions >= 1, "Must have at least 1 hue division.");
DNG_ASSERT (satDivisions >= 2, "Must have at least 2 sat divisions.");
if (valDivisions == 0)
valDivisions = 1;
if (hueDivisions == fHueDivisions &&
satDivisions == fSatDivisions &&
valDivisions == fValDivisions)
{
return;
}
fHueDivisions = hueDivisions;
fSatDivisions = satDivisions;
fValDivisions = valDivisions;
fHueStep = satDivisions;
fValStep = hueDivisions * fHueStep;
dng_safe_uint32 size (DeltasCount ());
size *= (uint32) sizeof (HSBModify);
fDeltas.Allocate (size.Get ());
DoZeroBytes (fDeltas.Buffer (), size.Get ());
fRuntimeFingerprint.Clear ();
}
/*****************************************************************************/
void dng_hue_sat_map::GetDelta (uint32 hueDiv,
uint32 satDiv,
uint32 valDiv,
HSBModify &modify) const
{
if (hueDiv >= fHueDivisions ||
satDiv >= fSatDivisions ||
valDiv >= fValDivisions ||
fDeltas.Buffer () == NULL)
{
DNG_REPORT ("Bad parameters to dng_hue_sat_map::GetDelta");
ThrowProgramError ();
}
int32 offset = valDiv * fValStep +
hueDiv * fHueStep +
satDiv;
const HSBModify *deltas = GetConstDeltas ();
modify.fHueShift = deltas [offset].fHueShift;
modify.fSatScale = deltas [offset].fSatScale;
modify.fValScale = deltas [offset].fValScale;
}
/*****************************************************************************/
void dng_hue_sat_map::SetDeltaKnownWriteable (uint32 hueDiv,
uint32 satDiv,
uint32 valDiv,
const HSBModify &modify)
{
if (hueDiv >= fHueDivisions ||
satDiv >= fSatDivisions ||
valDiv >= fValDivisions ||
fDeltas.Buffer () == NULL)
{
DNG_REPORT ("Bad parameters to dng_hue_sat_map::SetDelta");
ThrowProgramError ();
}
// Set this entry.
int32 offset = valDiv * fValStep +
hueDiv * fHueStep +
satDiv;
SafeGetDeltas () [offset] = modify;
// The zero saturation entry is required to have a value scale
// of 1.0f.
if (satDiv == 0)
{
if (modify.fValScale != 1.0f)
{
#if qDNGValidate
ReportWarning ("Value scale for zero saturation entries must be 1.0");
#endif
SafeGetDeltas () [offset] . fValScale = 1.0f;
}
}
// If we are settings the first saturation entry and we have not
// set the zero saturation entry yet, fill in the zero saturation entry
// by extrapolating first saturation entry.
if (satDiv == 1)
{
HSBModify zeroSatModify;
GetDelta (hueDiv, 0, valDiv, zeroSatModify);
if (zeroSatModify.fValScale != 1.0f)
{
zeroSatModify.fHueShift = modify.fHueShift;
zeroSatModify.fSatScale = modify.fSatScale;
zeroSatModify.fValScale = 1.0f;
SetDelta (hueDiv, 0, valDiv, zeroSatModify);
}
}
}
/*****************************************************************************/
void dng_hue_sat_map::AssignNewUniqueRuntimeFingerprint ()
{
const uint64 uid = ++sRuntimeFingerprintCounter;
dng_md5_printer printer;
printer.Process (&uid, sizeof (uid));
fRuntimeFingerprint = printer.Result ();
}
/*****************************************************************************/
bool dng_hue_sat_map::operator== (const dng_hue_sat_map &rhs) const
{
if (fHueDivisions != rhs.fHueDivisions ||
fSatDivisions != rhs.fSatDivisions ||
fValDivisions != rhs.fValDivisions)
return false;
if (!IsValid ())
return true;
return memcmp (GetConstDeltas (),
rhs.GetConstDeltas (),
DeltasCount () * sizeof (HSBModify)) == 0;
}
/*****************************************************************************/
dng_hue_sat_map * dng_hue_sat_map::Interpolate (const dng_hue_sat_map &map1,
const dng_hue_sat_map &map2,
real64 weight1)
{
if (weight1 >= 1.0)
{
if (!map1.IsValid ())
{
DNG_REPORT ("map1 is not valid");
ThrowProgramError ();
}
return new dng_hue_sat_map (map1);
}
if (weight1 <= 0.0)
{
if (!map2.IsValid ())
{
DNG_REPORT ("map2 is not valid");
ThrowProgramError ();
}
return new dng_hue_sat_map (map2);
}
// Both maps must be valid if we are using both.
if (!map1.IsValid () || !map2.IsValid ())
{
DNG_REPORT ("map1 or map2 is not valid");
ThrowProgramError ();
}
// Must have the same dimensions.
if (map1.fHueDivisions != map2.fHueDivisions ||
map1.fSatDivisions != map2.fSatDivisions ||
map1.fValDivisions != map2.fValDivisions)
{
DNG_REPORT ("map1 and map2 have different sizes");
ThrowProgramError ();
}
// Make table to hold interpolated results.
AutoPtr<dng_hue_sat_map> result (new dng_hue_sat_map);
result->SetDivisions (map1.fHueDivisions,
map1.fSatDivisions,
map1.fValDivisions);
// Interpolate between the tables.
real32 w1 = (real32) weight1;
real32 w2 = 1.0f - w1;
const HSBModify *data1 = map1.GetConstDeltas ();
const HSBModify *data2 = map2.GetConstDeltas ();
HSBModify *data3 = result->SafeGetDeltas ();
uint32 count = map1.DeltasCount ();
for (uint32 index = 0; index < count; index++)
{
data3->fHueShift = w1 * data1->fHueShift +
w2 * data2->fHueShift;
data3->fSatScale = w1 * data1->fSatScale +
w2 * data2->fSatScale;
data3->fValScale = w1 * data1->fValScale +
w2 * data2->fValScale;
data1++;
data2++;
data3++;
}
// Compute a fingerprint based on the inputs for the new dng_hue_sat_map
// so that repeated interpolations of the same objects with the same
// parameters produce the same fingerprint each time.
{
dng_md5_printer printer;
printer.Process ("Interpolate", 11);
printer.Process (&weight1, sizeof(weight1));
printer.Process (map1.RuntimeFingerprint ().data,
dng_fingerprint::kDNGFingerprintSize);
printer.Process (map2.RuntimeFingerprint ().data,
dng_fingerprint::kDNGFingerprintSize);
result->SetRuntimeFingerprint (printer.Result ());
}
// Return interpolated tables.
return result.Release ();
}
/*****************************************************************************/

@ -0,0 +1,258 @@
/*****************************************************************************/
// Copyright 2007-2019 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.
/*****************************************************************************/
/** \file
* Table-based color correction data structure.
*/
/*****************************************************************************/
#ifndef __dng_hue_sat_map__
#define __dng_hue_sat_map__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_fingerprint.h"
#include "dng_ref_counted_block.h"
#include "dng_safe_arithmetic.h"
#include "dng_types.h"
#include <atomic>
/*****************************************************************************/
/// \brief A 3D table that maps HSV (hue, saturation, and value) floating-point
/// input coordinates in the range [0,1] to delta signals. The table must have at
/// least 1 sample in the hue dimension, at least 2 samples in the saturation
/// dimension, and at least 1 sample in the value dimension. Tables are stored in
/// value-hue-saturation order.
class dng_hue_sat_map
{
public:
/// HSV delta signal. fHueShift is a delta value specified in degrees.
/// This parameter, added to the original hue, determines the output hue. A
/// value of 0 means no change. fSatScale and fValScale are
/// scale factors that are applied to saturation and value components,
/// respectively. These scale factors, multiplied by the original saturation
/// and value, determine the output saturation and value. A scale factor of
/// 1.0 means no change.
struct HSBModify
{
real32 fHueShift;
real32 fSatScale;
real32 fValScale;
};
private:
uint32 fHueDivisions;
uint32 fSatDivisions;
uint32 fValDivisions;
uint32 fHueStep;
uint32 fValStep;
// This fingerprint is intended to be used for certain rendering
// optimizations. Also, it can vary from session to session.
// In general, dng_hue_sat_map objects loaded from raw data
// will be given unique values for the session while dng_hue_sat_map
// objects derived from other dng_hue_sat_map objects will be
// given fingerprint values based on their inputs so that if they
// are recomputed, they get the same value (again, in that sesssion).
dng_fingerprint fRuntimeFingerprint;
static std::atomic<uint64> sRuntimeFingerprintCounter;
dng_ref_counted_block fDeltas;
HSBModify *SafeGetDeltas ()
{
return (HSBModify *) fDeltas.Buffer_real32 ();
}
public:
/// Construct an empty (and invalid) hue sat map.
dng_hue_sat_map ();
/// Copy an existing hue sat map.
dng_hue_sat_map (const dng_hue_sat_map &src);
/// Copy an existing hue sat map.
dng_hue_sat_map & operator= (const dng_hue_sat_map &rhs);
/// Destructor.
virtual ~dng_hue_sat_map ();
/// Is this hue sat map invalid?
bool IsNull () const
{
return !IsValid ();
}
/// Is this hue sat map valid?
bool IsValid () const
{
return fHueDivisions > 0 &&
fSatDivisions > 1 &&
fValDivisions > 0 &&
fDeltas.Buffer ();
}
/// Clear the hue sat map, making it invalid.
void SetInvalid ()
{
fHueDivisions = 0;
fSatDivisions = 0;
fValDivisions = 0;
fHueStep = 0;
fValStep = 0;
fRuntimeFingerprint.Clear ();
fDeltas.Clear ();
}
/// Get the table dimensions (number of samples in each dimension).
void GetDivisions (uint32 &hueDivisions,
uint32 &satDivisions,
uint32 &valDivisions) const
{
hueDivisions = fHueDivisions;
satDivisions = fSatDivisions;
valDivisions = fValDivisions;
}
/// Set the table dimensions (number of samples in each dimension). This
/// erases any existing table data.
void SetDivisions (uint32 hueDivisions,
uint32 satDivisions,
uint32 valDivisions = 1);
/// Get a specific table entry, specified by table indices.
void GetDelta (uint32 hueDiv,
uint32 satDiv,
uint32 valDiv,
HSBModify &modify) const;
/// Make sure the table is writeable.
void EnsureWriteable ()
{
fDeltas.EnsureWriteable ();
}
/// Set a specific table entry, specified by table indices.
void SetDelta (uint32 hueDiv,
uint32 satDiv,
uint32 valDiv,
const HSBModify &modify)
{
EnsureWriteable ();
SetDeltaKnownWriteable (hueDiv,
satDiv,
valDiv,
modify);
}
/// Same as SetDelta, without checking that the table is writeable.
void SetDeltaKnownWriteable (uint32 hueDiv,
uint32 satDiv,
uint32 valDiv,
const HSBModify &modify);
/// Get the total number of samples (across all dimensions).
uint32 DeltasCount () const
{
return (dng_safe_uint32 (fValDivisions) *
dng_safe_uint32 (fHueDivisions) *
dng_safe_uint32 (fSatDivisions)).Get ();
}
/// Direct read/write access to table entries. The entries are stored in
/// value-hue-saturation order (outer to inner).
HSBModify *GetDeltas ()
{
EnsureWriteable ();
return (HSBModify *) fDeltas.Buffer_real32 ();
}
/// Direct read-only access to table entries. The entries are stored in
/// value-hue-saturation order (outer to inner).
const HSBModify *GetConstDeltas () const
{
return (const HSBModify *) fDeltas.Buffer_real32 ();
}
void AssignNewUniqueRuntimeFingerprint ();
/// Set Fingerprint. Rare use cases want to set the fingerprint.
void SetRuntimeFingerprint (const dng_fingerprint fingerprint)
{
fRuntimeFingerprint = fingerprint;
}
/// Get the runtime fingerprint of this hue sat map.
const dng_fingerprint & RuntimeFingerprint () const
{
return fRuntimeFingerprint;
}
/// Equality test.
bool operator== (const dng_hue_sat_map &rhs) const;
/// Compute a linearly-interpolated hue sat map (i.e., delta and scale factors)
/// from the specified tables, with the specified weight. map1 and map2 must
/// have the same dimensions.
static dng_hue_sat_map * Interpolate (const dng_hue_sat_map &map1,
const dng_hue_sat_map &map2,
real64 weight1);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,311 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* DNG image file directory support.
*/
/*****************************************************************************/
#ifndef __dng_ifd__
#define __dng_ifd__
/*****************************************************************************/
#include "dng_fingerprint.h"
#include "dng_negative.h"
#include "dng_rect.h"
#include "dng_shared.h"
#include "dng_stream.h"
#include "dng_string.h"
#include "dng_sdk_limits.h"
#include "dng_tag_values.h"
/*****************************************************************************/
class dng_preview_info
{
public:
bool fIsPrimary;
dng_string fApplicationName;
dng_string fApplicationVersion;
dng_string fSettingsName;
dng_fingerprint fSettingsDigest;
PreviewColorSpaceEnum fColorSpace;
dng_string fDateTime;
real64 fRawToPreviewGain;
uint32 fCacheVersion;
public:
dng_preview_info ();
~dng_preview_info ();
};
/*****************************************************************************/
/// \brief Container for a single image file directory of a digital negative.
///
/// See \ref spec_dng "DNG 1.1.0 specification" for documentation of specific tags.
class dng_ifd
{
public:
bool fUsesNewSubFileType;
uint32 fNewSubFileType;
uint32 fImageWidth;
uint32 fImageLength;
uint32 fBitsPerSample [kMaxSamplesPerPixel];
uint32 fCompression;
uint32 fPredictor;
uint32 fPhotometricInterpretation;
uint32 fFillOrder;
uint32 fOrientation;
uint32 fOrientationType;
uint64 fOrientationOffset;
bool fOrientationBigEndian;
uint32 fSamplesPerPixel;
uint32 fPlanarConfiguration;
real64 fXResolution;
real64 fYResolution;
uint32 fResolutionUnit;
bool fUsesStrips;
bool fUsesTiles;
uint32 fTileWidth;
uint32 fTileLength;
enum
{
kMaxTileInfo = 32
};
uint32 fTileOffsetsType;
uint32 fTileOffsetsCount;
uint64 fTileOffsetsOffset;
uint64 fTileOffset [kMaxTileInfo];
uint32 fTileByteCountsType;
uint32 fTileByteCountsCount;
uint64 fTileByteCountsOffset;
uint32 fTileByteCount [kMaxTileInfo];
uint32 fSubIFDsCount;
uint64 fSubIFDsOffset;
uint32 fExtraSamplesCount;
uint32 fExtraSamples [kMaxSamplesPerPixel];
uint32 fSampleFormat [kMaxSamplesPerPixel];
uint32 fJPEGTablesCount;
uint64 fJPEGTablesOffset;
uint64 fJPEGInterchangeFormat;
uint32 fJPEGInterchangeFormatLength;
real64 fYCbCrCoefficientR;
real64 fYCbCrCoefficientG;
real64 fYCbCrCoefficientB;
uint32 fYCbCrSubSampleH;
uint32 fYCbCrSubSampleV;
uint32 fYCbCrPositioning;
real64 fReferenceBlackWhite [6];
uint32 fCFARepeatPatternRows;
uint32 fCFARepeatPatternCols;
uint8 fCFAPattern [kMaxCFAPattern] [kMaxCFAPattern];
uint8 fCFAPlaneColor [kMaxColorPlanes];
uint32 fCFALayout;
uint32 fLinearizationTableType;
uint32 fLinearizationTableCount;
uint64 fLinearizationTableOffset;
uint32 fBlackLevelRepeatRows;
uint32 fBlackLevelRepeatCols;
real64 fBlackLevel [kMaxBlackPattern] [kMaxBlackPattern] [kMaxSamplesPerPixel];
uint32 fBlackLevelDeltaHType;
uint32 fBlackLevelDeltaHCount;
uint64 fBlackLevelDeltaHOffset;
uint32 fBlackLevelDeltaVType;
uint32 fBlackLevelDeltaVCount;
uint64 fBlackLevelDeltaVOffset;
real64 fWhiteLevel [kMaxSamplesPerPixel];
dng_urational fDefaultScaleH;
dng_urational fDefaultScaleV;
dng_urational fBestQualityScale;
dng_urational fDefaultCropOriginH;
dng_urational fDefaultCropOriginV;
dng_urational fDefaultCropSizeH;
dng_urational fDefaultCropSizeV;
dng_urational fDefaultUserCropT;
dng_urational fDefaultUserCropL;
dng_urational fDefaultUserCropB;
dng_urational fDefaultUserCropR;
uint32 fBayerGreenSplit;
dng_urational fChromaBlurRadius;
dng_urational fAntiAliasStrength;
dng_rect fActiveArea;
uint32 fMaskedAreaCount;
dng_rect fMaskedArea [kMaxMaskedAreas];
uint32 fRowInterleaveFactor;
uint32 fSubTileBlockRows;
uint32 fSubTileBlockCols;
dng_preview_info fPreviewInfo;
uint32 fOpcodeList1Count;
uint64 fOpcodeList1Offset;
uint32 fOpcodeList2Count;
uint64 fOpcodeList2Offset;
uint32 fOpcodeList3Count;
uint64 fOpcodeList3Offset;
dng_noise_profile fNoiseProfile;
dng_string fEnhanceParams;
dng_urational fBaselineSharpness;
dng_urational fNoiseReductionApplied;
bool fLosslessJPEGBug16;
uint32 fSampleBitShift;
uint64 fThisIFD;
uint64 fNextIFD;
int32 fCompressionQuality;
bool fPatchFirstJPEGByte;
public:
dng_ifd ();
virtual ~dng_ifd ();
virtual dng_ifd * Clone () const;
virtual bool ParseTag (dng_stream &stream,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint64 tagOffset);
virtual void PostParse ();
virtual bool IsValidDNG (dng_shared &shared,
uint32 parentCode);
dng_rect Bounds () const
{
return dng_rect (0,
0,
fImageLength,
fImageWidth);
}
uint32 TilesAcross () const;
uint32 TilesDown () const;
uint32 TilesPerImage () const;
dng_rect TileArea (uint32 rowIndex,
uint32 colIndex) const;
virtual uint32 TileByteCount (const dng_rect &tile) const;
void SetSingleStrip ();
void FindTileSize (uint32 bytesPerTile = 128 * 1024,
uint32 cellH = 16,
uint32 cellV = 16);
void FindStripSize (uint32 bytesPerStrip = 128 * 1024,
uint32 cellV = 16);
virtual uint32 PixelType () const;
virtual bool IsBaselineJPEG () const;
virtual bool CanRead () const;
virtual void ReadImage (dng_host &host,
dng_stream &stream,
dng_image &image,
dng_jpeg_image *jpegImage = NULL,
dng_fingerprint *jpegDigest = NULL) const;
protected:
virtual bool IsValidCFA (dng_shared &shared,
uint32 parentCode);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,854 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_image.h"
#include "dng_assertions.h"
#include "dng_exceptions.h"
#include "dng_orientation.h"
#include "dng_pixel_buffer.h"
#include "dng_tag_types.h"
#include "dng_tile_iterator.h"
#include "dng_utils.h"
/*****************************************************************************/
dng_tile_buffer::dng_tile_buffer (const dng_image &image,
const dng_rect &tile,
bool dirty)
: fImage (image)
, fRefData (NULL)
{
fImage.AcquireTileBuffer (*this,
tile,
dirty);
}
/*****************************************************************************/
dng_tile_buffer::~dng_tile_buffer ()
{
fImage.ReleaseTileBuffer (*this);
}
/*****************************************************************************/
dng_const_tile_buffer::dng_const_tile_buffer (const dng_image &image,
const dng_rect &tile)
: dng_tile_buffer (image, tile, false)
{
}
/*****************************************************************************/
dng_const_tile_buffer::~dng_const_tile_buffer ()
{
}
/*****************************************************************************/
dng_dirty_tile_buffer::dng_dirty_tile_buffer (dng_image &image,
const dng_rect &tile)
: dng_tile_buffer (image, tile, true)
{
}
/*****************************************************************************/
dng_dirty_tile_buffer::~dng_dirty_tile_buffer ()
{
}
/*****************************************************************************/
dng_image::dng_image (const dng_rect &bounds,
uint32 planes,
uint32 pixelType)
: fBounds (bounds)
, fPlanes (planes)
, fPixelType (pixelType)
{
if (bounds.IsEmpty () || planes == 0 || PixelSize () == 0)
{
#if qDNGValidate
ReportError ("Fuzz: Attempt to create zero size image");
#endif
ThrowBadFormat ();
}
// Allow up to 2 * kMaxImageSide to deal with intermediate image objects
// (e.g., rotated and padded).
static const uint32 kLimit = 2 * kMaxImageSide;
if (bounds.W () > kLimit ||
bounds.H () > kLimit)
{
ThrowBadFormat ("dng_image bounds too large");
}
}
/*****************************************************************************/
dng_image::~dng_image ()
{
}
/*****************************************************************************/
dng_image * dng_image::Clone () const
{
ThrowProgramError ("Clone is not supported by this dng_image subclass");
return NULL;
}
/*****************************************************************************/
void dng_image::SetPixelType (uint32 pixelType)
{
if (TagTypeSize (pixelType) != PixelSize ())
{
ThrowProgramError ("Cannot change pixel size for existing image");
}
fPixelType = pixelType;
}
/*****************************************************************************/
uint32 dng_image::PixelSize () const
{
return TagTypeSize (PixelType ());
}
/*****************************************************************************/
uint32 dng_image::PixelRange () const
{
switch (fPixelType)
{
case ttByte:
case ttSByte:
{
return 0x0FF;
}
case ttShort:
case ttSShort:
{
return 0x0FFFF;
}
case ttLong:
case ttSLong:
{
return 0xFFFFFFFF;
}
default:
break;
}
return 0;
}
/*****************************************************************************/
dng_rect dng_image::RepeatingTile () const
{
return fBounds;
}
/*****************************************************************************/
void dng_image::AcquireTileBuffer (dng_tile_buffer & /* buffer */,
const dng_rect & /* area */,
bool /* dirty */) const
{
ThrowProgramError ();
}
/*****************************************************************************/
void dng_image::ReleaseTileBuffer (dng_tile_buffer & /* buffer */) const
{
}
/*****************************************************************************/
void dng_image::DoGet (dng_pixel_buffer &buffer) const
{
dng_rect tile;
dng_tile_iterator iter (*this, buffer.fArea);
while (iter.GetOneTile (tile))
{
dng_const_tile_buffer tileBuffer (*this, tile);
buffer.CopyArea (tileBuffer,
tile,
buffer.fPlane,
buffer.fPlanes);
}
}
/*****************************************************************************/
void dng_image::DoPut (const dng_pixel_buffer &buffer)
{
dng_rect tile;
dng_tile_iterator iter (*this, buffer.fArea);
while (iter.GetOneTile (tile))
{
dng_dirty_tile_buffer tileBuffer (*this, tile);
tileBuffer.CopyArea (buffer,
tile,
buffer.fPlane,
buffer.fPlanes);
}
}
/*****************************************************************************/
void dng_image::GetRepeat (dng_pixel_buffer &buffer,
const dng_rect &srcArea,
const dng_rect &dstArea) const
{
// If we already have the entire srcArea in the
// buffer, we can just repeat that.
if ((srcArea & buffer.fArea) == srcArea)
{
buffer.RepeatArea (srcArea,
dstArea);
}
// Else we first need to get the srcArea into the buffer area.
else
{
// Find repeating pattern size.
dng_point repeat = srcArea.Size ();
// Find pattern phase at top-left corner of destination area.
dng_point phase = dng_pixel_buffer::RepeatPhase (srcArea,
dstArea);
// Find new source area at top-left of dstArea.
dng_rect newArea = srcArea + (dstArea.TL () -
srcArea.TL ());
// Find quadrant split coordinates.
int32 splitV = newArea.t + repeat.v - phase.v;
int32 splitH = newArea.l + repeat.h - phase.h;
// Top-left quadrant.
dng_rect dst1 (dng_rect (newArea.t,
newArea.l,
splitV,
splitH) & dstArea);
if (dst1.NotEmpty ())
{
dng_pixel_buffer temp (buffer);
temp.fArea = dst1 + (srcArea.TL () -
dstArea.TL () +
dng_point (phase.v, phase.h));
temp.fData = buffer.DirtyPixel (dst1.t,
dst1.l,
buffer.fPlane);
DoGet (temp);
}
// Top-right quadrant.
dng_rect dst2 (dng_rect (newArea.t,
splitH,
splitV,
newArea.r) & dstArea);
if (dst2.NotEmpty ())
{
dng_pixel_buffer temp (buffer);
temp.fArea = dst2 + (srcArea.TL () -
dstArea.TL () +
dng_point (phase.v, -phase.h));
temp.fData = buffer.DirtyPixel (dst2.t,
dst2.l,
buffer.fPlane);
DoGet (temp);
}
// Bottom-left quadrant.
dng_rect dst3 (dng_rect (splitV,
newArea.l,
newArea.b,
splitH) & dstArea);
if (dst3.NotEmpty ())
{
dng_pixel_buffer temp (buffer);
temp.fArea = dst3 + (srcArea.TL () -
dstArea.TL () +
dng_point (-phase.v, phase.h));
temp.fData = buffer.DirtyPixel (dst3.t,
dst3.l,
buffer.fPlane);
DoGet (temp);
}
// Bottom-right quadrant.
dng_rect dst4 (dng_rect (splitV,
splitH,
newArea.b,
newArea.r) & dstArea);
if (dst4.NotEmpty ())
{
dng_pixel_buffer temp (buffer);
temp.fArea = dst4 + (srcArea.TL () -
dstArea.TL () +
dng_point (-phase.v, -phase.h));
temp.fData = buffer.DirtyPixel (dst4.t,
dst4.l,
buffer.fPlane);
DoGet (temp);
}
// Replicate this new source area.
buffer.RepeatArea (newArea,
dstArea);
}
}
/*****************************************************************************/
void dng_image::GetEdge (dng_pixel_buffer &buffer,
edge_option edgeOption,
const dng_rect &srcArea,
const dng_rect &dstArea) const
{
switch (edgeOption)
{
case edge_zero:
{
buffer.SetZero (dstArea,
buffer.fPlane,
buffer.fPlanes);
break;
}
case edge_repeat:
{
GetRepeat (buffer,
srcArea,
dstArea);
break;
}
case edge_repeat_zero_last:
{
if (buffer.fPlanes > 1)
{
dng_pixel_buffer buffer1 (buffer);
buffer1.fPlanes--;
GetEdge (buffer1,
edge_repeat,
srcArea,
dstArea);
}
dng_pixel_buffer buffer2 (buffer);
buffer2.fPlane = buffer.fPlanes - 1;
buffer2.fPlanes = 1;
buffer2.fData = buffer.DirtyPixel (buffer2.fArea.t,
buffer2.fArea.l,
buffer2.fPlane);
GetEdge (buffer2,
edge_zero,
srcArea,
dstArea);
break;
}
default:
{
ThrowProgramError ();
}
}
}
/*****************************************************************************/
void dng_image::Get (dng_pixel_buffer &buffer,
edge_option edgeOption,
uint32 repeatV,
uint32 repeatH) const
{
// Find the overlap with the image bounds.
dng_rect overlap = buffer.fArea & fBounds;
// Move the overlapping pixels.
if (overlap.NotEmpty ())
{
dng_pixel_buffer temp (buffer);
temp.fArea = overlap;
temp.fData = buffer.DirtyPixel (overlap.t,
overlap.l,
buffer.fPlane);
DoGet (temp);
}
// See if we need to pad the edge values.
if ((edgeOption != edge_none) && (overlap != buffer.fArea))
{
dng_rect areaT (buffer.fArea);
dng_rect areaL (buffer.fArea);
dng_rect areaB (buffer.fArea);
dng_rect areaR (buffer.fArea);
areaT.b = Min_int32 (areaT.b, fBounds.t);
areaL.r = Min_int32 (areaL.r, fBounds.l);
areaB.t = Max_int32 (areaB.t, fBounds.b);
areaR.l = Max_int32 (areaR.l, fBounds.r);
dng_rect areaH (buffer.fArea);
dng_rect areaV (buffer.fArea);
areaH.l = Max_int32 (areaH.l, fBounds.l);
areaH.r = Min_int32 (areaH.r, fBounds.r);
areaV.t = Max_int32 (areaV.t, fBounds.t);
areaV.b = Min_int32 (areaV.b, fBounds.b);
// Top left.
dng_rect areaTL = areaT & areaL;
if (areaTL.NotEmpty ())
{
GetEdge (buffer,
edgeOption,
dng_rect (fBounds.t,
fBounds.l,
fBounds.t + repeatV,
fBounds.l + repeatH),
areaTL);
}
// Top middle.
dng_rect areaTM = areaT & areaH;
if (areaTM.NotEmpty ())
{
GetEdge (buffer,
edgeOption,
dng_rect (fBounds.t,
areaTM.l,
fBounds.t + repeatV,
areaTM.r),
areaTM);
}
// Top right.
dng_rect areaTR = areaT & areaR;
if (areaTR.NotEmpty ())
{
GetEdge (buffer,
edgeOption,
dng_rect (fBounds.t,
fBounds.r - repeatH,
fBounds.t + repeatV,
fBounds.r),
areaTR);
}
// Left middle.
dng_rect areaLM = areaL & areaV;
if (areaLM.NotEmpty ())
{
GetEdge (buffer,
edgeOption,
dng_rect (areaLM.t,
fBounds.l,
areaLM.b,
fBounds.l + repeatH),
areaLM);
}
// Right middle.
dng_rect areaRM = areaR & areaV;
if (areaRM.NotEmpty ())
{
GetEdge (buffer,
edgeOption,
dng_rect (areaRM.t,
fBounds.r - repeatH,
areaRM.b,
fBounds.r),
areaRM);
}
// Bottom left.
dng_rect areaBL = areaB & areaL;
if (areaBL.NotEmpty ())
{
GetEdge (buffer,
edgeOption,
dng_rect (fBounds.b - repeatV,
fBounds.l,
fBounds.b,
fBounds.l + repeatH),
areaBL);
}
// Bottom middle.
dng_rect areaBM = areaB & areaH;
if (areaBM.NotEmpty ())
{
GetEdge (buffer,
edgeOption,
dng_rect (fBounds.b - repeatV,
areaBM.l,
fBounds.b,
areaBM.r),
areaBM);
}
// Bottom right.
dng_rect areaBR = areaB & areaR;
if (areaBR.NotEmpty ())
{
GetEdge (buffer,
edgeOption,
dng_rect (fBounds.b - repeatV,
fBounds.r - repeatH,
fBounds.b,
fBounds.r),
areaBR);
}
}
}
/*****************************************************************************/
void dng_image::Put (const dng_pixel_buffer &buffer)
{
// Move the overlapping pixels.
dng_rect overlap = buffer.fArea & fBounds;
if (overlap.NotEmpty ())
{
dng_pixel_buffer temp (buffer);
temp.fArea = overlap;
temp.fData = (void *) buffer.ConstPixel (overlap.t,
overlap.l,
buffer.fPlane);
// Move the overlapping planes.
if (temp.fPlane < Planes ())
{
temp.fPlanes = Min_uint32 (temp.fPlanes,
Planes () - temp.fPlane);
DoPut (temp);
}
}
}
/*****************************************************************************/
void dng_image::Trim (const dng_rect &r)
{
if (r != Bounds ())
{
ThrowProgramError ("Trim is not support by this dng_image subclass");
}
}
/*****************************************************************************/
void dng_image::Rotate (const dng_orientation &orientation)
{
if (orientation != dng_orientation::Normal ())
{
ThrowProgramError ("Rotate is not support by this dng_image subclass");
}
}
/*****************************************************************************/
void dng_image::DoCopyArea (const dng_image &src,
const dng_rect &area,
uint32 srcPlane,
uint32 dstPlane,
uint32 planes)
{
if (&src == this)
return;
dng_tile_iterator destIter(*this, area);
dng_rect destTileArea;
while (destIter.GetOneTile(destTileArea))
{
dng_tile_iterator srcIter(src, destTileArea);
dng_rect srcTileArea;
while (srcIter.GetOneTile(srcTileArea))
{
dng_dirty_tile_buffer destTile(*this, srcTileArea);
dng_const_tile_buffer srcTile(src, srcTileArea);
destTile.CopyArea (srcTile, srcTileArea, srcPlane, dstPlane, planes);
}
}
}
/*****************************************************************************/
bool dng_image::EqualArea (const dng_image &src,
const dng_rect &area,
uint32 plane,
uint32 planes) const
{
if (&src == this)
return true;
dng_tile_iterator destIter (*this, area);
dng_rect destTileArea;
while (destIter.GetOneTile (destTileArea))
{
dng_tile_iterator srcIter (src, destTileArea);
dng_rect srcTileArea;
while (srcIter.GetOneTile (srcTileArea))
{
dng_const_tile_buffer destTile (*this, srcTileArea);
dng_const_tile_buffer srcTile (src , srcTileArea);
if (!destTile.EqualArea (srcTile, srcTileArea, plane, planes))
{
return false;
}
}
}
return true;
}
/*****************************************************************************/
void dng_image::SetConstant (uint32 value,
const dng_rect &area)
{
dng_tile_iterator iter (*this, area);
dng_rect tileArea;
while (iter.GetOneTile (tileArea))
{
dng_dirty_tile_buffer buffer (*this, tileArea);
buffer.SetConstant (tileArea,
0,
fPlanes,
value);
}
}
/*****************************************************************************/

@ -0,0 +1,433 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Support for working with image data in DNG SDK.
*/
/*****************************************************************************/
#ifndef __dng_image__
#define __dng_image__
/*****************************************************************************/
#include "dng_assertions.h"
#include "dng_classes.h"
#include "dng_pixel_buffer.h"
#include "dng_point.h"
#include "dng_rect.h"
#include "dng_tag_types.h"
#include "dng_types.h"
#include "dng_uncopyable.h"
/*****************************************************************************/
/// \brief Class to get resource acquisition is instantiation behavior for tile
/// buffers. Can be dirty or constant tile access.
class dng_tile_buffer: public dng_pixel_buffer,
private dng_uncopyable
{
protected:
const dng_image &fImage;
void *fRefData;
protected:
/// Obtain a tile from an image.
/// \param image Image tile will come from.
/// \param tile Rectangle denoting extent of tile.
/// \param dirty Flag indicating whether this is read-only or read-write acesss.
dng_tile_buffer (const dng_image &image,
const dng_rect &tile,
bool dirty);
virtual ~dng_tile_buffer ();
public:
void SetRefData (void *refData)
{
fRefData = refData;
}
void * GetRefData () const
{
return fRefData;
}
};
/*****************************************************************************/
/// \brief Class to get resource acquisition is instantiation behavior for
/// constant (read-only) tile buffers.
class dng_const_tile_buffer: public dng_tile_buffer
{
public:
/// Obtain a read-only tile from an image.
/// \param image Image tile will come from.
/// \param tile Rectangle denoting extent of tile.
dng_const_tile_buffer (const dng_image &image,
const dng_rect &tile);
virtual ~dng_const_tile_buffer ();
};
/*****************************************************************************/
/// \brief Class to get resource acquisition is instantiation behavior for
/// dirty (writable) tile buffers.
class dng_dirty_tile_buffer: public dng_tile_buffer
{
public:
/// Obtain a writable tile from an image.
/// \param image Image tile will come from.
/// \param tile Rectangle denoting extent of tile.
dng_dirty_tile_buffer (dng_image &image,
const dng_rect &tile);
virtual ~dng_dirty_tile_buffer ();
};
/*****************************************************************************/
/// \brief Base class for holding image data in DNG SDK. See dng_simple_image
/// for derived class most often used in DNG SDK.
class dng_image
{
friend class dng_tile_buffer;
protected:
// Bounds for this image.
dng_rect fBounds;
// Number of image planes.
uint32 fPlanes;
// Basic pixel type (TIFF tag type code).
uint32 fPixelType;
public:
/// How to handle requests to get image areas outside the image bounds.
enum edge_option
{
/// Leave edge pixels unchanged.
edge_none,
/// Pad with zeros.
edge_zero,
/// Repeat edge pixels.
edge_repeat,
/// Repeat edge pixels, except for last plane which is zero padded.
edge_repeat_zero_last
};
protected:
dng_image (const dng_rect &bounds,
uint32 planes,
uint32 pixelType);
public:
virtual ~dng_image ();
virtual dng_image * Clone () const;
/// Getter method for bounds of an image.
const dng_rect & Bounds () const
{
return fBounds;
}
/// Getter method for size of an image.
dng_point Size () const
{
return Bounds ().Size ();
}
/// Getter method for width of an image.
uint32 Width () const
{
return Bounds ().W ();
}
/// Getter method for height of an image.
uint32 Height () const
{
return Bounds ().H ();
}
/// Getter method for number of planes in an image.
uint32 Planes () const
{
return fPlanes;
}
/// Getter for pixel type.
/// \retval See dng_tagtypes.h . Valid values are ttByte, ttShort, ttSShort,
/// ttLong, ttFloat .
uint32 PixelType () const
{
return fPixelType;
}
/// Setter for pixel type.
/// \param pixelType The new pixel type .
virtual void SetPixelType (uint32 pixelType);
/// Getter for pixel size.
/// \retval Size, in bytes, of pixel type for this image .
uint32 PixelSize () const;
/// Getter for pixel range.
/// For unsigned types, range is 0 to return value.
/// For signed types, range is return value - 0x8000U.
/// For ttFloat type, pixel range is 0.0 to 1.0 and this routine returns 1.
uint32 PixelRange () const;
/// Getter for best "tile stride" for accessing image.
virtual dng_rect RepeatingTile () const;
/// Get a pixel buffer of data on image with proper edge padding.
/// \param buffer Receives resulting pixel buffer.
/// \param edgeOption edge_option describing how to pad edges.
/// \param repeatV Amount of repeated padding needed in vertical for
/// edge_repeat and edge_repeat_zero_last edgeOption cases.
/// \param repeatH Amount of repeated padding needed in horizontal for
/// edge_repeat and edge_repeat_zero_last edgeOption cases.
void Get (dng_pixel_buffer &buffer,
edge_option edgeOption = edge_none,
uint32 repeatV = 1,
uint32 repeatH = 1) const;
/// Put a pixel buffer into image.
/// \param buffer Pixel buffer to copy from.
void Put (const dng_pixel_buffer &buffer);
/// Shrink bounds of image to given rectangle.
/// \param r Rectangle to crop to.
virtual void Trim (const dng_rect &r);
/// Rotate image to reflect given orientation change.
/// \param orientation Directive to rotate image in a certain way.
virtual void Rotate (const dng_orientation &orientation);
/// Copy image data from an area of one image to same area of another.
/// \param src Image to copy from.
/// \param area Rectangle of images to copy.
/// \param srcPlane Plane to start copying in src.
/// \param dstPlane Plane to start copying in this.
/// \param planes Number of planes to copy.
void CopyArea (const dng_image &src,
const dng_rect &area,
uint32 srcPlane,
uint32 dstPlane,
uint32 planes)
{
DoCopyArea (src, area, srcPlane, dstPlane, planes);
}
/// Copy image data from an area of one image to same area of another.
/// \param src Image to copy from.
/// \param area Rectangle of images to copy.
/// \param plane Plane to start copying in src and this.
/// \param planes Number of planes to copy.
void CopyArea (const dng_image &src,
const dng_rect &area,
uint32 plane,
uint32 planes)
{
DoCopyArea (src, area, plane, plane, planes);
}
/// Return true if the contents of an area of the image are the same as those of another.
/// \param rhs Image to compare against.
/// \param area Rectangle of image to test.
/// \param plane Plane to start comparing.
/// \param planes Number of planes to compare.
virtual bool EqualArea (const dng_image &rhs,
const dng_rect &area,
uint32 plane,
uint32 planes) const;
// Routines to set the entire image to a constant value.
void SetConstant_uint8 (uint8 value,
const dng_rect &area)
{
DNG_ASSERT (fPixelType == ttByte, "Mismatched pixel type");
SetConstant ((uint32) value, area);
}
void SetConstant_uint8 (uint8 value)
{
SetConstant (value, Bounds ());
}
void SetConstant_uint16 (uint16 value,
const dng_rect &area)
{
DNG_ASSERT (fPixelType == ttShort, "Mismatched pixel type");
SetConstant ((uint32) value, area);
}
void SetConstant_uint16 (uint16 value)
{
SetConstant_uint16 (value, Bounds ());
}
void SetConstant_int16 (int16 value,
const dng_rect &area)
{
DNG_ASSERT (fPixelType == ttSShort, "Mismatched pixel type");
SetConstant ((uint32) (uint16) value, area);
}
void SetConstant_int16 (int16 value)
{
SetConstant_int16 (value, Bounds ());
}
void SetConstant_uint32 (uint32 value,
const dng_rect &area)
{
DNG_ASSERT (fPixelType == ttLong, "Mismatched pixel type");
SetConstant (value, area);
}
void SetConstant_uint32 (uint32 value)
{
SetConstant_uint32 (value, Bounds ());
}
void SetConstant_real32 (real32 value,
const dng_rect &area)
{
DNG_ASSERT (fPixelType == ttFloat, "Mismatched pixel type");
union
{
uint32 i;
real32 f;
} x;
x.f = value;
SetConstant (x.i, area);
}
void SetConstant_real32 (real32 value)
{
SetConstant_real32 (value, Bounds ());
}
virtual void GetRepeat (dng_pixel_buffer &buffer,
const dng_rect &srcArea,
const dng_rect &dstArea) const;
protected:
virtual void AcquireTileBuffer (dng_tile_buffer &buffer,
const dng_rect &area,
bool dirty) const;
virtual void ReleaseTileBuffer (dng_tile_buffer &buffer) const;
virtual void DoGet (dng_pixel_buffer &buffer) const;
virtual void DoPut (const dng_pixel_buffer &buffer);
virtual void DoCopyArea (const dng_image &src,
const dng_rect &area,
uint32 srcPlane,
uint32 dstPlane,
uint32 planes);
void GetEdge (dng_pixel_buffer &buffer,
edge_option edgeOption,
const dng_rect &srcArea,
const dng_rect &dstArea) const;
virtual void SetConstant (uint32 value,
const dng_rect &area);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,179 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Class for holding top-level information about a DNG image.
*/
/*****************************************************************************/
#ifndef __dng_info__
#define __dng_info__
/*****************************************************************************/
#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_errors.h"
#include "dng_exif.h"
#include "dng_ifd.h"
#include "dng_sdk_limits.h"
#include "dng_shared.h"
#include "dng_uncopyable.h"
#include <vector>
/*****************************************************************************/
/// \brief Top-level structure of DNG file with access to metadata.
///
/// See \ref spec_dng "DNG 1.1.0 specification" for information on member fields of this class.
class dng_info: private dng_uncopyable
{
public:
uint64 fTIFFBlockOffset;
uint64 fTIFFBlockOriginalOffset;
bool fBigEndian;
uint32 fMagic;
AutoPtr<dng_exif> fExif;
AutoPtr<dng_shared> fShared;
int32 fMainIndex;
int32 fMaskIndex;
int32 fDepthIndex;
int32 fEnhancedIndex;
std::vector <dng_ifd *> fIFD;
std::vector <dng_ifd *> fChainedIFD;
std::vector <std::vector <dng_ifd *> > fChainedSubIFD;
protected:
uint32 fMakerNoteNextIFD;
public:
dng_info ();
virtual ~dng_info ();
/// Returns the number of parsed SubIFDs (including the main IFD).
uint32 IFDCount () const
{
return (uint32) fIFD.size ();
}
/// Returns the number of chained IFDs.
uint32 ChainedIFDCount () const
{
return (uint32) fChainedIFD.size ();
}
/// Returns number SubIFDs for a chained IFD.
uint32 ChainedSubIFDCount (uint32 chainIndex) const
{
if (chainIndex >= fChainedSubIFD.size ())
return 0;
else
return (uint32) fChainedSubIFD [chainIndex].size ();
}
/// Read dng_info from a dng_stream
/// \param host DNG host used for progress updating, abort testing, buffer allocation, etc.
/// \param stream Stream to read DNG data from.
virtual void Parse (dng_host &host,
dng_stream &stream);
/// Must be called immediately after a successful Parse operation.
virtual void PostParse (dng_host &host);
/// Test validity of DNG data.
/// \retval true if stream provided a valid DNG.
virtual bool IsValidDNG ();
protected:
virtual void ValidateMagic ();
virtual void ParseTag (dng_host &host,
dng_stream &stream,
dng_exif *exif,
dng_shared *shared,
dng_ifd *ifd,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint64 tagOffset,
int64 offsetDelta);
virtual bool ValidateIFD (dng_stream &stream,
uint64 ifdOffset,
int64 offsetDelta);
virtual void ParseIFD (dng_host &host,
dng_stream &stream,
dng_exif *exif,
dng_shared *shared,
dng_ifd *ifd,
uint64 ifdOffset,
int64 offsetDelta,
uint32 parentCode);
virtual bool ParseMakerNoteIFD (dng_host &host,
dng_stream &stream,
uint64 ifdSize,
uint64 ifdOffset,
int64 offsetDelta,
uint64 minOffset,
uint64 maxOffset,
uint32 parentCode);
virtual void ParseMakerNote (dng_host &host,
dng_stream &stream,
uint32 makerNoteCount,
uint64 makerNoteOffset,
int64 offsetDelta,
uint64 minOffset,
uint64 maxOffset);
virtual void ParseSonyPrivateData (dng_host &host,
dng_stream &stream,
uint64 count,
uint64 oldOffset,
uint64 newOffset);
virtual void ParseDNGPrivateData (dng_host &host,
dng_stream &stream);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,978 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_iptc.h"
#include "dng_assertions.h"
#include "dng_auto_ptr.h"
#include "dng_memory_stream.h"
#include "dng_stream.h"
#include "dng_utils.h"
/*****************************************************************************/
dng_iptc::dng_iptc ()
: fTitle ()
, fUrgency (-1)
, fCategory ()
, fSupplementalCategories ()
, fKeywords ()
, fInstructions ()
, fDateTimeCreated ()
, fDigitalCreationDateTime ()
, fAuthors ()
, fAuthorsPosition ()
, fCity ()
, fState ()
, fCountry ()
, fCountryCode ()
, fLocation ()
, fTransmissionReference ()
, fHeadline ()
, fCredit ()
, fSource ()
, fCopyrightNotice ()
, fDescription ()
, fDescriptionWriter ()
{
}
/*****************************************************************************/
dng_iptc::~dng_iptc ()
{
}
/*****************************************************************************/
bool dng_iptc::IsEmpty () const
{
if (fTitle.NotEmpty ())
{
return false;
}
if (fUrgency >= 0)
{
return false;
}
if (fCategory.NotEmpty ())
{
return false;
}
if (fSupplementalCategories.Count () > 0)
{
return false;
}
if (fKeywords.Count () > 0)
{
return false;
}
if (fInstructions.NotEmpty ())
{
return false;
}
if (fDateTimeCreated.IsValid ())
{
return false;
}
if (fDigitalCreationDateTime.IsValid ())
{
return false;
}
if (fAuthors.Count () != 0 ||
fAuthorsPosition.NotEmpty ())
{
return false;
}
if (fCity .NotEmpty () ||
fState .NotEmpty () ||
fCountry.NotEmpty ())
{
return false;
}
if (fCountryCode.NotEmpty ())
{
return false;
}
if (fLocation.NotEmpty ())
{
return false;
}
if (fTransmissionReference.NotEmpty ())
{
return false;
}
if (fHeadline.NotEmpty ())
{
return false;
}
if (fCredit.NotEmpty ())
{
return false;
}
if (fSource.NotEmpty ())
{
return false;
}
if (fCopyrightNotice.NotEmpty ())
{
return false;
}
if (fDescription .NotEmpty () ||
fDescriptionWriter.NotEmpty ())
{
return false;
}
return true;
}
/*****************************************************************************/
void dng_iptc::ParseString (dng_stream &stream,
dng_string &s,
CharSet charSet)
{
uint32 length = stream.Get_uint16 ();
dng_memory_data buffer (length + 1);
char *c = buffer.Buffer_char ();
stream.Get (c, length);
c [length] = 0;
switch (charSet)
{
case kCharSetUTF8:
{
s.Set_UTF8 (c);
break;
}
default:
{
s.Set_SystemEncoding (c);
}
}
s.SetLineEndingsToNewLines ();
s.StripLowASCII ();
s.TrimTrailingBlanks ();
}
/*****************************************************************************/
void dng_iptc::Parse (const void *blockData,
uint32 blockSize,
uint64 offsetInOriginalFile)
{
dng_stream stream (blockData,
blockSize,
offsetInOriginalFile);
stream.SetBigEndian ();
// Make a first pass though the data, trying to figure out the
// character set.
CharSet charSet = kCharSetUnknown;
bool isValidUTF8 = true;
bool hasEncodingMarker = false;
uint64 firstOffset = stream.Position ();
uint64 nextOffset = firstOffset;
while (nextOffset + 5 < stream.Length ())
{
stream.SetReadPosition (nextOffset);
uint8 firstByte = stream.Get_uint8 ();
if (firstByte != 0x1C) break;
uint8 record = stream.Get_uint8 ();
uint8 dataSet = stream.Get_uint8 ();
uint32 dataSize = stream.Get_uint16 ();
nextOffset = stream.Position () + dataSize;
if (record == 1)
{
switch (dataSet)
{
case 90:
{
hasEncodingMarker = true;
if (dataSize == 3)
{
uint32 byte1 = stream.Get_uint8 ();
uint32 byte2 = stream.Get_uint8 ();
uint32 byte3 = stream.Get_uint8 ();
if (byte1 == 27 /* Escape */ &&
byte2 == 0x25 &&
byte3 == 0x47)
{
charSet = kCharSetUTF8;
}
}
break;
}
default:
break;
}
}
else if (record == 2)
{
dng_memory_data buffer (dataSize + 1);
char *s = buffer.Buffer_char ();
stream.Get (s, dataSize);
s [dataSize] = 0;
isValidUTF8 = isValidUTF8 && dng_string::IsUTF8 (s);
}
}
// If we don't have an encoding marker, and the data is valid
// UTF-8, then assume that it is UTF-8 (rather than system encoding).
if (!hasEncodingMarker && isValidUTF8)
{
charSet = kCharSetUTF8;
}
// Make a second pass though the data, actually reading the data.
nextOffset = firstOffset;
while (nextOffset + 5 < stream.Length ())
{
stream.SetReadPosition (nextOffset);
uint8 firstByte = stream.Get_uint8 ();
if (firstByte != 0x1C) break;
uint8 record = stream.Get_uint8 ();
uint8 dataSet = stream.Get_uint8 ();
uint32 dataSize = stream.Get_uint16 ();
nextOffset = stream.Position () + dataSize;
if (record == 2)
{
stream.SetReadPosition (stream.Position () - 2);
switch ((DataSet) dataSet)
{
case kObjectNameSet:
{
ParseString (stream, fTitle, charSet);
break;
}
case kUrgencySet:
{
int32 size = stream.Get_uint16 ();
if (size == 1)
{
char c = stream.Get_int8 ();
if (c >= '0' && c <= '9')
{
fUrgency = c - '0';
}
}
break;
}
case kCategorySet:
{
ParseString (stream, fCategory, charSet);
break;
}
case kSupplementalCategoriesSet:
{
dng_string category;
ParseString (stream, category, charSet);
if (category.NotEmpty ())
{
fSupplementalCategories.Append (category);
}
break;
}
case kKeywordsSet:
{
dng_string keyword;
ParseString (stream, keyword, charSet);
if (keyword.NotEmpty ())
{
fKeywords.Append (keyword);
}
break;
}
case kSpecialInstructionsSet:
{
ParseString (stream, fInstructions, charSet);
break;
}
case kDateCreatedSet:
{
uint32 length = stream.Get_uint16 ();
if (length == 8)
{
char date [9];
stream.Get (date, 8);
date [8] = 0;
fDateTimeCreated.Decode_IPTC_Date (date);
}
break;
}
case kTimeCreatedSet:
{
uint32 length = stream.Get_uint16 ();
if (length >= 4 && length <= 11)
{
char time [12];
stream.Get (time, length);
time [length] = 0;
fDateTimeCreated.Decode_IPTC_Time (time);
}
break;
}
case kDigitalCreationDateSet:
{
uint32 length = stream.Get_uint16 ();
if (length == 8)
{
char date [9];
stream.Get (date, 8);
date [8] = 0;
fDigitalCreationDateTime.Decode_IPTC_Date (date);
}
break;
}
case kDigitalCreationTimeSet:
{
uint32 length = stream.Get_uint16 ();
if (length >= 4 && length <= 11)
{
char time [12];
stream.Get (time, length);
time [length] = 0;
fDigitalCreationDateTime.Decode_IPTC_Time (time);
}
break;
}
case kBylineSet:
{
dng_string author;
ParseString (stream, author, charSet);
if (author.NotEmpty ())
{
fAuthors.Append (author);
}
break;
}
case kBylineTitleSet:
{
ParseString (stream, fAuthorsPosition, charSet);
break;
}
case kCitySet:
{
ParseString (stream, fCity, charSet);
break;
}
case kProvinceStateSet:
{
ParseString (stream, fState, charSet);
break;
}
case kCountryNameSet:
{
ParseString (stream, fCountry, charSet);
break;
}
case kCountryCodeSet:
{
ParseString (stream, fCountryCode, charSet);
break;
}
case kSublocationSet:
{
ParseString (stream, fLocation, charSet);
break;
}
case kOriginalTransmissionReferenceSet:
{
ParseString (stream, fTransmissionReference, charSet);
break;
}
case kHeadlineSet:
{
ParseString (stream, fHeadline, charSet);
break;
}
case kCreditSet:
{
ParseString (stream, fCredit, charSet);
break;
}
case kSourceSet:
{
ParseString (stream, fSource, charSet);
break;
}
case kCopyrightNoticeSet:
{
ParseString (stream, fCopyrightNotice, charSet);
break;
}
case kCaptionSet:
{
ParseString (stream, fDescription, charSet);
break;
}
case kCaptionWriterSet:
{
ParseString (stream, fDescriptionWriter, charSet);
break;
}
// All other IPTC records are not part of the IPTC core
// and/or are not kept in sync with XMP tags, so we ignore
// them.
default:
break;
}
}
}
}
/*****************************************************************************/
void dng_iptc::SpoolString (dng_stream &stream,
const dng_string &s,
uint8 dataSet,
uint32 maxChars,
CharSet charSet)
{
if (s.IsEmpty ())
{
return;
}
stream.Put_uint16 (0x1C02);
stream.Put_uint8 (dataSet);
dng_string ss (s);
ss.SetLineEndingsToReturns ();
if (charSet == kCharSetUTF8)
{
// UTF-8 encoding.
if (ss.Length () > maxChars)
{
ss.Truncate (maxChars);
}
uint32 len = ss.Length ();
stream.Put_uint16 ((uint16) len);
stream.Put (ss.Get (), len);
}
else
{
// System character set encoding.
dng_memory_data buffer;
uint32 len = ss.Get_SystemEncoding (buffer);
if (len > maxChars)
{
uint32 lower = 0;
uint32 upper = ss.Length () - 1;
while (upper > lower)
{
uint32 middle = (upper + lower + 1) >> 1;
dng_string sss (ss);
sss.Truncate (middle);
len = sss.Get_SystemEncoding (buffer);
if (len <= maxChars)
{
lower = middle;
}
else
{
upper = middle - 1;
}
}
ss.Truncate (lower);
len = ss.Get_SystemEncoding (buffer);
}
stream.Put_uint16 ((uint16) len);
stream.Put (buffer.Buffer_char (), len);
}
}
/*****************************************************************************/
dng_memory_block * dng_iptc::Spool (dng_memory_allocator &allocator,
bool padForTIFF)
{
uint32 j;
char s [64];
dng_memory_stream stream (allocator, NULL, 2048);
stream.SetBigEndian ();
// Medata working group - now we just always write UTF-8.
CharSet charSet = kCharSetUTF8;
// UTF-8 encoding marker.
if (charSet == kCharSetUTF8)
{
stream.Put_uint16 (0x1C01);
stream.Put_uint8 (90);
stream.Put_uint16 (3);
stream.Put_uint8 (27);
stream.Put_uint8 (0x25);
stream.Put_uint8 (0x47);
}
stream.Put_uint16 (0x1C02);
stream.Put_uint8 (kRecordVersionSet);
stream.Put_uint16 (2);
stream.Put_uint16 (4);
SpoolString (stream,
fTitle,
kObjectNameSet,
64,
charSet);
if (fUrgency >= 0)
{
sprintf (s, "%1u", (unsigned) fUrgency);
stream.Put_uint16 (0x1C02);
stream.Put_uint8 (kUrgencySet);
stream.Put_uint16 (1);
stream.Put (s, 1);
}
SpoolString (stream,
fCategory,
kCategorySet,
3,
charSet);
for (j = 0; j < fSupplementalCategories.Count (); j++)
{
SpoolString (stream,
fSupplementalCategories [j],
kSupplementalCategoriesSet,
32,
charSet);
}
for (j = 0; j < fKeywords.Count (); j++)
{
SpoolString (stream,
fKeywords [j],
kKeywordsSet,
64,
charSet);
}
SpoolString (stream,
fInstructions,
kSpecialInstructionsSet,
255,
charSet);
if (fDateTimeCreated.IsValid ())
{
dng_string dateString = fDateTimeCreated.Encode_IPTC_Date ();
if (dateString.NotEmpty ())
{
DNG_ASSERT (dateString.Length () == 8, "Wrong length IPTC date");
stream.Put_uint16 (0x1C02);
stream.Put_uint8 (kDateCreatedSet);
stream.Put_uint16 (8);
stream.Put (dateString.Get (), 8);
}
dng_string timeString = fDateTimeCreated.Encode_IPTC_Time ();
if (timeString.NotEmpty ())
{
stream.Put_uint16 (0x1C02);
stream.Put_uint8 (kTimeCreatedSet);
stream.Put_uint16 ((uint16)timeString.Length ());
stream.Put (timeString.Get (), timeString.Length ());
}
}
if (fDigitalCreationDateTime.IsValid ())
{
dng_string dateString = fDigitalCreationDateTime.Encode_IPTC_Date ();
if (dateString.NotEmpty ())
{
DNG_ASSERT (dateString.Length () == 8, "Wrong length IPTC date");
stream.Put_uint16 (0x1C02);
stream.Put_uint8 (kDigitalCreationDateSet);
stream.Put_uint16 (8);
stream.Put (dateString.Get (), 8);
}
dng_string timeString = fDigitalCreationDateTime.Encode_IPTC_Time ();
if (timeString.NotEmpty ())
{
stream.Put_uint16 (0x1C02);
stream.Put_uint8 (kDigitalCreationTimeSet);
stream.Put_uint16 ((uint16)timeString.Length ());
stream.Put (timeString.Get (), timeString.Length ());
}
}
for (j = 0; j < fAuthors.Count (); j++)
{
SpoolString (stream,
fAuthors [j],
kBylineSet,
32,
charSet);
}
SpoolString (stream,
fAuthorsPosition,
kBylineTitleSet,
32,
charSet);
SpoolString (stream,
fCity,
kCitySet,
32,
charSet);
SpoolString (stream,
fLocation,
kSublocationSet,
32,
charSet);
SpoolString (stream,
fState,
kProvinceStateSet,
32,
charSet);
SpoolString (stream,
fCountryCode,
kCountryCodeSet,
3,
charSet);
SpoolString (stream,
fCountry,
kCountryNameSet,
64,
charSet);
SpoolString (stream,
fTransmissionReference,
kOriginalTransmissionReferenceSet,
32,
charSet);
SpoolString (stream,
fHeadline,
kHeadlineSet,
255,
charSet);
SpoolString (stream,
fCredit,
kCreditSet,
32,
charSet);
SpoolString (stream,
fSource,
kSourceSet,
32,
charSet);
SpoolString (stream,
fCopyrightNotice,
kCopyrightNoticeSet,
128,
charSet);
SpoolString (stream,
fDescription,
kCaptionSet,
2000,
charSet);
SpoolString (stream,
fDescriptionWriter,
kCaptionWriterSet,
32,
charSet);
if (padForTIFF)
{
while (stream.Length () & 3)
{
stream.Put_uint8 (0);
}
}
stream.Flush ();
return stream.AsMemoryBlock (allocator);
}
/*****************************************************************************/

@ -0,0 +1,167 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Support for IPTC metadata within DNG files.
*/
/*****************************************************************************/
#ifndef __dng_iptc__
#define __dng_iptc__
/*****************************************************************************/
#include "dng_date_time.h"
#include "dng_string.h"
#include "dng_string_list.h"
/*****************************************************************************/
/// \brief Class for reading and holding IPTC metadata associated with a DNG file.
///
/// See the \ref spec_iptc "IPTC specification"
/// for information on member fields of this class.
class dng_iptc
{
public:
dng_string fTitle;
int32 fUrgency;
dng_string fCategory;
dng_string_list fSupplementalCategories;
dng_string_list fKeywords;
dng_string fInstructions;
dng_date_time_info fDateTimeCreated;
dng_date_time_info fDigitalCreationDateTime;
dng_string_list fAuthors;
dng_string fAuthorsPosition;
dng_string fCity;
dng_string fState;
dng_string fCountry;
dng_string fCountryCode;
dng_string fLocation;
dng_string fTransmissionReference;
dng_string fHeadline;
dng_string fCredit;
dng_string fSource;
dng_string fCopyrightNotice;
dng_string fDescription;
dng_string fDescriptionWriter;
protected:
enum DataSet
{
kRecordVersionSet = 0,
kObjectNameSet = 5,
kUrgencySet = 10,
kCategorySet = 15,
kSupplementalCategoriesSet = 20,
kKeywordsSet = 25,
kSpecialInstructionsSet = 40,
kDateCreatedSet = 55,
kTimeCreatedSet = 60,
kDigitalCreationDateSet = 62,
kDigitalCreationTimeSet = 63,
kBylineSet = 80,
kBylineTitleSet = 85,
kCitySet = 90,
kSublocationSet = 92,
kProvinceStateSet = 95,
kCountryCodeSet = 100,
kCountryNameSet = 101,
kOriginalTransmissionReferenceSet = 103,
kHeadlineSet = 105,
kCreditSet = 110,
kSourceSet = 115,
kCopyrightNoticeSet = 116,
kCaptionSet = 120,
kCaptionWriterSet = 122
};
enum CharSet
{
kCharSetUnknown = 0,
kCharSetUTF8 = 1
};
public:
dng_iptc ();
virtual ~dng_iptc ();
/// Test if IPTC metadata exists.
/// \retval true if no IPTC metadata exists for this DNG.
bool IsEmpty () const;
/// Test if IPTC metadata exists.
/// \retval true if IPTC metadata exists for this DNG.
bool NotEmpty () const
{
return !IsEmpty ();
}
/// Parse a complete block of IPTC data.
/// \param blockData The block of IPTC data.
/// \param blockSize Size in bytes of data block.
/// \param offsetInOriginalFile Used to enable certain file patching operations such as updating date/time in place.
void Parse (const void *blockData,
uint32 blockSize,
uint64 offsetInOriginalFile);
/// Serialize IPTC data to a memory block.
/// \param allocator Memory allocator used to acquire memory block.
/// \param padForTIFF Forces length of block to be a multiple of four bytes in accordance with TIFF standard.
/// \retval Memory block
dng_memory_block * Spool (dng_memory_allocator &allocator,
bool padForTIFF);
protected:
void ParseString (dng_stream &stream,
dng_string &s,
CharSet charSet);
void SpoolString (dng_stream &stream,
const dng_string &s,
uint8 dataSet,
uint32 maxChars,
CharSet charSet);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,354 @@
/*****************************************************************************/
// Copyright 2011-2019 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.
/*****************************************************************************/
#include "dng_jpeg_image.h"
#include "dng_abort_sniffer.h"
#include "dng_area_task.h"
#include "dng_assertions.h"
#include "dng_host.h"
#include "dng_ifd.h"
#include "dng_image.h"
#include "dng_image_writer.h"
#include "dng_memory_stream.h"
#include "dng_safe_arithmetic.h"
#include "dng_uncopyable.h"
#include <atomic>
/*****************************************************************************/
dng_jpeg_image::dng_jpeg_image ()
: fImageSize ()
, fTileSize ()
, fUsesStrips (false)
, fJPEGTables ()
, fJPEGData ()
{
}
/*****************************************************************************/
class dng_jpeg_image_encode_task : public dng_area_task,
private dng_uncopyable
{
private:
dng_host &fHost;
dng_image_writer &fWriter;
const dng_image &fImage;
dng_jpeg_image &fJPEGImage;
uint32 fTileCount;
const dng_ifd &fIFD;
std::atomic_uint fNextTileIndex;
public:
dng_jpeg_image_encode_task (dng_host &host,
dng_image_writer &writer,
const dng_image &image,
dng_jpeg_image &jpegImage,
uint32 tileCount,
const dng_ifd &ifd)
: dng_area_task ("dng_jpeg_image_encode_task")
, fHost (host)
, fWriter (writer)
, fImage (image)
, fJPEGImage (jpegImage)
, fTileCount (tileCount)
, fIFD (ifd)
, fNextTileIndex (0)
{
fMinTaskArea = 16 * 16;
fUnitCell = dng_point (16, 16);
fMaxTileSize = dng_point (16, 16);
}
void Process (uint32 /* threadIndex */,
const dng_rect & /* tile */,
dng_abort_sniffer *sniffer)
{
AutoPtr<dng_memory_block> compressedBuffer;
AutoPtr<dng_memory_block> uncompressedBuffer;
AutoPtr<dng_memory_block> subTileBlockBuffer;
AutoPtr<dng_memory_block> tempBuffer;
uint32 uncompressedSize = SafeUint32Mult (fIFD.fTileLength,
fIFD.fTileWidth,
fIFD.fSamplesPerPixel);
uncompressedBuffer.Reset (fHost.Allocate (uncompressedSize));
uint32 tilesAcross = fIFD.TilesAcross ();
while (true)
{
// Note: fNextTileIndex is atomic
uint32 tileIndex = fNextTileIndex++;
if (tileIndex >= fTileCount)
{
return;
}
dng_abort_sniffer::SniffForAbort (sniffer);
uint32 rowIndex = tileIndex / tilesAcross;
uint32 colIndex = tileIndex % tilesAcross;
dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex);
dng_memory_stream stream (fHost.Allocator ());
fWriter.WriteTile (fHost,
fIFD,
stream,
fImage,
tileArea,
1,
compressedBuffer,
uncompressedBuffer,
subTileBlockBuffer,
tempBuffer,
true);
fJPEGImage.fJPEGData [tileIndex].Reset (stream.AsMemoryBlock (fHost.Allocator ()));
}
}
};
/*****************************************************************************/
void dng_jpeg_image::Encode (dng_host &host,
const dng_negative &negative,
dng_image_writer &writer,
const dng_image &image)
{
#if qDNGValidate
dng_timer timer ("Encode JPEG Proxy time");
#endif
DNG_ASSERT (image.PixelType () == ttByte, "Cannot JPEG encode non-byte image");
fImageSize = image.Bounds ().Size ();
dng_ifd ifd;
ifd.fImageWidth = fImageSize.h;
ifd.fImageLength = fImageSize.v;
ifd.fSamplesPerPixel = image.Planes ();
ifd.fBitsPerSample [0] = 8;
ifd.fBitsPerSample [1] = 8;
ifd.fBitsPerSample [2] = 8;
ifd.fBitsPerSample [3] = 8;
ifd.fPhotometricInterpretation = piLinearRaw;
ifd.fCompression = ccLossyJPEG;
ifd.FindTileSize (512 * 512 * ifd.fSamplesPerPixel);
fTileSize.h = ifd.fTileWidth;
fTileSize.v = ifd.fTileLength;
// Need a higher quality for raw proxies than non-raw proxies, since users
// often perform much greater color changes. Also, if we are targeting a
// "large" size proxy (larger than 5 MP), or this is a full size proxy,
// then use a higher quality.
bool useHigherQuality = (uint64) ifd.fImageWidth *
(uint64) ifd.fImageLength > 5000000 ||
image.Bounds ().Size () == negative.OriginalDefaultFinalSize ();
if (negative.ColorimetricReference () == crSceneReferred)
{
ifd.fCompressionQuality = useHigherQuality ? 11 : 10;
}
else
{
ifd.fCompressionQuality = useHigherQuality ? 10 : 8;
}
uint32 tilesAcross = ifd.TilesAcross ();
uint32 tilesDown = ifd.TilesDown ();
uint32 tileCount = tilesAcross * tilesDown;
fJPEGData.Reset (new dng_jpeg_image_tile_ptr [tileCount]);
uint32 threadCount = Min_uint32 (tileCount,
host.PerformAreaTaskThreads ());
dng_jpeg_image_encode_task task (host,
writer,
image,
*this,
tileCount,
ifd);
host.PerformAreaTask (task,
dng_rect (0, 0, 16, 16 * threadCount));
}
/*****************************************************************************/
class dng_jpeg_image_find_digest_task : public dng_area_task,
private dng_uncopyable
{
private:
const dng_jpeg_image &fJPEGImage;
uint32 fTileCount;
dng_fingerprint *fDigests;
std::atomic_uint fNextTileIndex;
public:
dng_jpeg_image_find_digest_task (const dng_jpeg_image &jpegImage,
uint32 tileCount,
dng_fingerprint *digests)
: dng_area_task ("dng_jpeg_image_find_digest_task")
, fJPEGImage (jpegImage)
, fTileCount (tileCount)
, fDigests (digests)
, fNextTileIndex (0)
{
fMinTaskArea = 16 * 16;
fUnitCell = dng_point (16, 16);
fMaxTileSize = dng_point (16, 16);
}
void Process (uint32 /* threadIndex */,
const dng_rect & /* tile */,
dng_abort_sniffer *sniffer)
{
while (true)
{
// Note: fNextTileIndex is atomic
uint32 tileIndex = fNextTileIndex++;
if (tileIndex >= fTileCount)
{
return;
}
dng_abort_sniffer::SniffForAbort (sniffer);
dng_md5_printer printer;
printer.Process (fJPEGImage.fJPEGData [tileIndex]->Buffer (),
fJPEGImage.fJPEGData [tileIndex]->LogicalSize ());
fDigests [tileIndex] = printer.Result ();
}
}
};
/*****************************************************************************/
dng_fingerprint dng_jpeg_image::FindDigest (dng_host &host) const
{
uint32 tileCount = TileCount ();
uint32 arrayCount = tileCount + (fJPEGTables.Get () ? 1 : 0);
AutoArray<dng_fingerprint> digests (new dng_fingerprint [arrayCount]);
// Compute digest of each compressed tile.
{
uint32 threadCount = Min_uint32 (tileCount,
host.PerformAreaTaskThreads ());
dng_jpeg_image_find_digest_task task (*this,
tileCount,
digests.Get ());
host.PerformAreaTask (task,
dng_rect (0, 0, 16, 16 * threadCount));
}
// Compute digest of JPEG tables, if any.
if (fJPEGTables.Get ())
{
dng_md5_printer printer;
printer.Process (fJPEGTables->Buffer (),
fJPEGTables->LogicalSize ());
digests [tileCount] = printer.Result ();
}
// Combine digests into a single digest.
{
dng_md5_printer printer;
for (uint32 k = 0; k < arrayCount; k++)
{
printer.Process (digests [k].data,
dng_fingerprint::kDNGFingerprintSize);
}
return printer.Result ();
}
}
/*****************************************************************************/

@ -0,0 +1,85 @@
/*****************************************************************************/
// Copyright 2011-2019 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.
/*****************************************************************************/
#ifndef __dng_jpeg_image__
#define __dng_jpeg_image__
/*****************************************************************************/
#include "dng_auto_ptr.h"
#include "dng_memory.h"
#include "dng_point.h"
/*****************************************************************************/
typedef AutoPtr<dng_memory_block> dng_jpeg_image_tile_ptr;
/*****************************************************************************/
class dng_jpeg_image
{
public:
dng_point fImageSize;
dng_point fTileSize;
bool fUsesStrips;
AutoPtr<dng_memory_block> fJPEGTables;
AutoArray<dng_jpeg_image_tile_ptr> fJPEGData;
public:
dng_jpeg_image ();
uint32 TilesAcross () const
{
if (fTileSize.h)
{
return (fImageSize.h + fTileSize.h - 1) / fTileSize.h;
}
else
{
return 0;
}
}
uint32 TilesDown () const
{
if (fTileSize.v)
{
return (fImageSize.v + fTileSize.v - 1) / fTileSize.v;
}
else
{
return 0;
}
}
uint32 TileCount () const
{
return TilesAcross () * TilesDown ();
}
void Encode (dng_host &host,
const dng_negative &negative,
dng_image_writer &writer,
const dng_image &image);
dng_fingerprint FindDigest (dng_host &host) const;
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,670 @@
/*****************************************************************************/
// Copyright 2008-2019 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.
/*****************************************************************************/
/** \file
* Opcodes to fix lens aberrations such as geometric distortion, lateral chromatic
* aberration, and vignetting (peripheral illumination falloff).
*/
/*****************************************************************************/
#ifndef __dng_lens_correction__
#define __dng_lens_correction__
/*****************************************************************************/
#include "dng_1d_function.h"
#include "dng_matrix.h"
#include "dng_memory.h"
#include "dng_opcodes.h"
#include "dng_pixel_buffer.h"
#include "dng_point.h"
#include "dng_resample.h"
#include "dng_sdk_limits.h"
/*****************************************************************************/
/// \brief Abstract base class holding common warp opcode parameters (e.g.,
/// number of planes, optical center) and common warp routines.
class dng_warp_params
{
public:
// Number of planes to be warped. Must be either 1 or equal to the
// number of planes of the image to be processed. If set to 1, then a
// single set of warp parameters applies to all planes of the image.
// fPlanes must be at least 1 and no greater than kMaxColorPlanes (see
// dng_sdk_limits.h).
uint32 fPlanes;
// The optical center of the lens in normalized [0,1] coordinates with
// respect to the image's active area. For example, a value of (0.5,
// 0.5) indicates that the optical center of the lens is at the center
// of the image's active area. A normalized radius of 1.0 corresponds to
// the distance from fCenter to the farthest corner of the image's
// active area. Each component of fCenter must lie in the range [0,1].
dng_point_real64 fCenter;
public:
/// Create empty (invalid) warp parameters.
dng_warp_params ();
/// Create warp parameters with specified number of planes and image
/// center.
///
/// \param planes The number of planes of parameters specified: It must
/// be either 1 or equal to the number of planes of the image to be
/// processed.
///
/// \param fCenter The image center in relative coordinates.
dng_warp_params (uint32 planes,
const dng_point_real64 &fCenter);
virtual ~dng_warp_params ();
/// Is the entire correction a NOP for all planes?
virtual bool IsNOPAll () const;
/// Is the entire correction a NOP for the specified plane?
virtual bool IsNOP (uint32 plane) const;
/// Is the radial correction a NOP for all planes?
virtual bool IsRadNOPAll () const;
/// Is the radial correction a NOP for the specified plane?
virtual bool IsRadNOP (uint32 plane) const;
/// Is the tangential correction a NOP for all planes?
virtual bool IsTanNOPAll () const;
/// Is the tangential correction a NOP for the specified plane?
virtual bool IsTanNOP (uint32 plane) const;
/// Do these warp params appear valid?
virtual bool IsValid () const;
/// Are these warp params valid for the specified negative?
virtual bool IsValidForNegative (const dng_negative &negative) const;
/// Propagate warp parameters from first plane to all other planes.
virtual void PropagateToAllPlanes (uint32 totalPlanes) = 0;
/// Evaluate the 1D radial warp function for the specified plane.
/// Parameter r is the destination (i.e., corrected) normalized radius,
/// i.e., the normalized Euclidean distance between a corrected pixel
/// position and the optical center in the image. r lies in the range
/// [0,1]. The returned result is non-negative.
virtual real64 Evaluate (uint32 plane,
real64 r) const = 0;
/// Compute and return the inverse of Evaluate () above. The base
/// implementation uses Newton's method to perform the inversion.
/// Parameter r is the source (i.e., uncorrected) normalized radius,
/// i.e., normalized Euclidean distance between a corrected pixel
/// position and the optical center in the image. Both r and the
/// computed result are non-negative.
virtual real64 EvaluateInverse (uint32 plane,
real64 r) const;
/// Evaluate the 1D radial warp ratio function for the specified plane.
/// Parameter r2 is the square of the destination (i.e., corrected)
/// normalized radius, i.e., the square of the normalized Euclidean
/// distance between a corrected pixel position and the optical center
/// in the image. r2 must lie in the range [0,1]. Note that this is
/// different than the Evaluate () function, above, in that the argument
/// to EvaluateRatio () is the square of the radius, not the radius
/// itself. The returned result is non-negative. Mathematically,
/// EvaluateRatio (r * r) is the same as Evaluate (r) / r.
virtual real64 EvaluateRatio (uint32 plane,
real64 r2) const = 0;
/// Evaluate the 2D tangential warp for the specified plane. Parameter
/// r2 is the square of the destination (i.e., corrected) normalized
/// radius, i.e., the square of the normalized Euclidean distance
/// between a corrected pixel position P and the optical center in the
/// image. r2 must lie in the range [0,1]. diff contains the vertical
/// and horizontal Euclidean distances (in pixels) between P and the
/// optical center. diff2 contains the squares of the vertical and
/// horizontal Euclidean distances (in pixels) between P and the optical
/// center. The returned result is the tangential warp offset, measured
/// in pixels.
virtual dng_point_real64 EvaluateTangential (uint32 plane,
real64 r2,
const dng_point_real64 &diff,
const dng_point_real64 &diff2) const = 0;
/// Evaluate the 2D tangential warp for the specified plane. diff
/// contains the vertical and horizontal Euclidean distances (in pixels)
/// between the destination (i.e., corrected) pixel position and the
/// optical center in the image. The returned result is the tangential
/// warp offset, measured in pixels.
dng_point_real64 EvaluateTangential2 (uint32 plane,
const dng_point_real64 &diff) const;
/// Evaluate the 2D tangential warp for the specified plane. Parameter
/// r2 is the square of the destination (i.e., corrected) normalized
/// radius, i.e., the square of the normalized Euclidean distance
/// between a corrected pixel position P and the optical center in the
/// image. r2 must lie in the range [0,1]. diff contains the vertical
/// and horizontal Euclidean distances (in pixels) between P and the
/// optical center. The returned result is the tangential warp offset,
/// measured in pixels.
dng_point_real64 EvaluateTangential3 (uint32 plane,
real64 r2,
const dng_point_real64 &diff) const;
/// Compute and return the maximum warped radius gap. Let D be a
/// rectangle in a destination (corrected) image. Let rDstFar and
/// rDstNear be the farthest and nearest points to the image center,
/// respectively. Then the specified parameter maxDstGap is the
/// Euclidean distance between rDstFar and rDstNear. Warp D through this
/// warp function to a closed and bounded (generally not rectangular)
/// region S. Let rSrcfar and rSrcNear be the farthest and nearest
/// points to the image center, respectively. This routine returns a
/// value that is at least (rSrcFar - rSrcNear).
virtual real64 MaxSrcRadiusGap (real64 maxDstGap) const = 0;
/// Compute and return the maximum warped tangential gap. minDst is the
/// top-left pixel of the image in normalized pixel coordinates. maxDst
/// is the bottom-right pixel of the image in normalized pixel
/// coordinates. MaxSrcTanGap () computes the maximum absolute shift in
/// normalized pixels in the horizontal and vertical directions that can
/// occur as a result of the tangential warp.
virtual dng_point_real64 MaxSrcTanGap (dng_point_real64 minDst,
dng_point_real64 maxDst) const = 0;
/// Compute and return the minimum src/dst ratio that should be used
/// for this warp.
virtual real64 SafeMinRatio () const = 0;
/// Compute and return the maximum src/dst ratio that should be used
/// for this warp.
virtual real64 SafeMaxRatio () const = 0;
/// Debug parameters.
virtual void Dump () const;
};
/*****************************************************************************/
/// \brief Warp parameters for pinhole perspective rectilinear (not fisheye)
/// camera model. Supports radial and tangential (decentering) distortion
/// correction parameters.
///
/// Note the restrictions described below.
class dng_warp_params_rectilinear: public dng_warp_params
{
public:
// Radial and tangential polynomial coefficients. These define a warp
// from corrected pixel coordinates (xDst, yDst) to uncorrected pixel
// coordinates (xSrc, ySrc) for each plane P as follows:
//
// Let kr0 = fRadParams [P][0]
// kr1 = fRadParams [P][1]
// kr2 = fRadParams [P][2]
// kr3 = fRadParams [P][3]
//
// kt0 = fTanParams [P][0]
// kt1 = fTanParams [P][1]
//
// Let (xCenter, yCenter) be the optical image center (see fCenter,
// below) expressed in pixel coordinates. Let maxDist be the Euclidean
// distance (in pixels) from (xCenter, yCenter) to the farthest image
// corner.
//
// First, compute the normalized distance of the corrected pixel
// position (xDst, yDst) from the image center:
//
// dx = (xDst - xCenter) / maxDist
// dy = (yDst - yCenter) / maxDist
//
// r^2 = dx^2 + dy^2
//
// Compute the radial correction term:
//
// ratio = kr0 + (kr1 * r^2) + (kr2 * r^4) + (kr3 * r^6)
//
// dxRad = dx * ratio
// dyRad = dy * ratio
//
// Compute the tangential correction term:
//
// dxTan = (2 * kt0 * dx * dy) + kt1 * (r^2 + 2 * dx^2)
// dyTan = (2 * kt1 * dx * dy) + kt0 * (r^2 + 2 * dy^2)
//
// Compute the uncorrected pixel position (xSrc, ySrc):
//
// xSrc = xCenter + (dxRad + dxTan) * maxDist
// ySrc = yCenter + (dyRad + dyTan) * maxDist
//
// Mathematical definitions and restrictions:
//
// Let { xSrc, ySrc } = f (xDst, yDst) be the warp function defined
// above.
//
// Let xSrc = fx (xDst, yDst) be the x-component of the warp function.
// Let ySrc = fy (xDst, yDst) be the y-component of the warp function.
//
// f (x, y) must be an invertible function.
//
// fx (x, y) must be an increasing function of x.
// fy (x, y) must be an increasing function of x.
//
// The parameters kr0, kr1, kr2, and kr3 must define an increasing
// radial warp function. Specifically, let w (r) be the radial warp
// function:
//
// w (r) = (kr0 * r) + (kr1 * r^3) + (kr2 * r^5) + (kr3 * r^7).
//
// w (r) must be an increasing function.
dng_vector fRadParams [kMaxColorPlanes];
dng_vector fTanParams [kMaxColorPlanes];
public:
/// Create empty (invalid) rectilinear warp parameters.
dng_warp_params_rectilinear ();
/// Create rectilinear warp parameters with the specified number of
/// planes, radial component terms, tangential component terms, and
/// image center in relative coordinates.
dng_warp_params_rectilinear (uint32 planes,
const dng_vector radParams [],
const dng_vector tanParams [],
const dng_point_real64 &fCenter);
virtual ~dng_warp_params_rectilinear ();
// Overridden methods.
virtual bool IsRadNOP (uint32 plane) const;
virtual bool IsTanNOP (uint32 plane) const;
virtual bool IsValid () const;
virtual void PropagateToAllPlanes (uint32 totalPlanes);
virtual real64 Evaluate (uint32 plane,
real64 r) const;
virtual real64 EvaluateRatio (uint32 plane,
real64 r2) const;
virtual dng_point_real64 EvaluateTangential (uint32 plane,
real64 r2,
const dng_point_real64 &diff,
const dng_point_real64 &diff2) const;
virtual real64 MaxSrcRadiusGap (real64 maxDstGap) const;
virtual dng_point_real64 MaxSrcTanGap (dng_point_real64 minDst,
dng_point_real64 maxDst) const;
virtual real64 SafeMinRatio () const;
virtual real64 SafeMaxRatio () const;
virtual void Dump () const;
};
/*****************************************************************************/
/// \brief Warp parameters for fisheye camera model (radial component only).
/// Note the restrictions described below.
class dng_warp_params_fisheye: public dng_warp_params
{
public:
// Radial warp coefficients. These define a warp from corrected pixel
// coordinates (xDst, yDst) to uncorrected pixel coordinates (xSrc,
// ySrc) for each plane P as follows:
//
// Let kr0 = fRadParams [P][0]
// kr1 = fRadParams [P][1]
// kr2 = fRadParams [P][2]
// kr3 = fRadParams [P][3]
//
// Let (xCenter, yCenter) be the optical image center (see fCenter,
// below) expressed in pixel coordinates. Let maxDist be the Euclidean
// distance (in pixels) from (xCenter, yCenter) to the farthest image
// corner.
//
// First, compute the normalized distance of the corrected pixel
// position (xDst, yDst) from the image center:
//
// dx = (xDst - xCenter) / maxDist
// dy = (yDst - yCenter) / maxDist
//
// r = sqrt (dx^2 + dy^2)
//
// Compute the radial correction term:
//
// t = atan (r)
//
// rWarp = (kr0 * t) + (kr1 * t^3) + (kr2 * t^5) + (kr3 * t^7)
//
// ratio = rWarp / r
//
// dxRad = dx * ratio
// dyRad = dy * ratio
//
// Compute the uncorrected pixel position (xSrc, ySrc):
//
// xSrc = xCenter + (dxRad * maxDist)
// ySrc = yCenter + (dyRad * maxDist)
//
// The parameters kr0, kr1, kr2, and kr3 must define an increasing
// radial warp function. Specifically, let w (r) be the radial warp
// function:
//
// t = atan (r)
//
// w (r) = (kr0 * t) + (kr1 * t^3) + (kr2 * t^5) + (kr3 * t^7).
//
// w (r) must be an increasing function.
dng_vector fRadParams [kMaxColorPlanes];
public:
/// Create empty (invalid) fisheye warp parameters.
dng_warp_params_fisheye ();
/// Create rectilinear warp parameters with the specified number of
/// planes, radial component terms, and image center in relative
/// coordinates.
dng_warp_params_fisheye (uint32 planes,
const dng_vector radParams [],
const dng_point_real64 &fCenter);
virtual ~dng_warp_params_fisheye ();
// Overridden methods.
virtual bool IsRadNOP (uint32 plane) const;
virtual bool IsTanNOP (uint32 plane) const;
virtual bool IsValid () const;
virtual void PropagateToAllPlanes (uint32 totalPlanes);
virtual real64 Evaluate (uint32 plane,
real64 r) const;
virtual real64 EvaluateRatio (uint32 plane,
real64 r2) const;
virtual dng_point_real64 EvaluateTangential (uint32 plane,
real64 r2,
const dng_point_real64 &diff,
const dng_point_real64 &diff2) const;
virtual real64 MaxSrcRadiusGap (real64 maxDstGap) const;
virtual dng_point_real64 MaxSrcTanGap (dng_point_real64 minDst,
dng_point_real64 maxDst) const;
virtual real64 SafeMinRatio () const;
virtual real64 SafeMaxRatio () const;
virtual void Dump () const;
};
/*****************************************************************************/
/// \brief Warp opcode for pinhole perspective (rectilinear) camera model.
class dng_opcode_WarpRectilinear: public dng_opcode
{
protected:
dng_warp_params_rectilinear fWarpParams;
public:
dng_opcode_WarpRectilinear (const dng_warp_params_rectilinear &params,
uint32 flags);
explicit dng_opcode_WarpRectilinear (dng_stream &stream);
// Overridden methods.
virtual bool IsNOP () const;
virtual bool IsValidForNegative (const dng_negative &negative) const;
virtual void PutData (dng_stream &stream) const;
virtual void Apply (dng_host &host,
dng_negative &negative,
AutoPtr<dng_image> &image);
// Other methods.
bool HasDistort () const;
bool HasLateralCA () const;
const dng_warp_params_rectilinear & Params () const
{
return fWarpParams;
}
protected:
static uint32 ParamBytes (uint32 planes);
};
/*****************************************************************************/
/// \brief Warp opcode for fisheye camera model.
class dng_opcode_WarpFisheye: public dng_opcode
{
protected:
dng_warp_params_fisheye fWarpParams;
public:
dng_opcode_WarpFisheye (const dng_warp_params_fisheye &params,
uint32 flags);
explicit dng_opcode_WarpFisheye (dng_stream &stream);
// Overridden methods.
virtual bool IsNOP () const;
virtual bool IsValidForNegative (const dng_negative &negative) const;
virtual void PutData (dng_stream &stream) const;
virtual void Apply (dng_host &host,
dng_negative &negative,
AutoPtr<dng_image> &image);
protected:
static uint32 ParamBytes (uint32 planes);
};
/*****************************************************************************/
/// \brief Radially-symmetric vignette (peripheral illuminational falloff)
/// correction parameters.
class dng_vignette_radial_params
{
public:
static const uint32 kNumTerms = 5;
public:
// Let v be an uncorrected pixel value of a pixel p in linear space.
//
// Let r be the Euclidean distance between p and the optical center.
//
// Compute corrected pixel value v' = v * g, where g is the gain.
//
// Let k0 = fParams [0]
// Let k1 = fParams [1]
// Let k2 = fParams [2]
// Let k3 = fParams [3]
// Let k4 = fParams [4]
//
// Gain g = 1 + (k0 * r^2) + (k1 * r^4) + (k2 * r^6) + (k3 * r^8) + (k4 * r^10)
dng_std_vector<real64> fParams;
dng_point_real64 fCenter;
public:
dng_vignette_radial_params ();
dng_vignette_radial_params (const dng_std_vector<real64> &params,
const dng_point_real64 &center);
dng_vignette_radial_params (const dng_vignette_radial_params &params);
bool IsNOP () const;
bool IsValid () const;
// For debugging.
void Dump () const;
};
/*****************************************************************************/
/// \brief Radially-symmetric lens vignette correction opcode.
class dng_opcode_FixVignetteRadial: public dng_inplace_opcode
{
protected:
dng_vignette_radial_params fParams;
uint32 fImagePlanes;
int64 fSrcOriginH;
int64 fSrcOriginV;
int64 fSrcStepH;
int64 fSrcStepV;
uint32 fTableInputBits;
uint32 fTableOutputBits;
AutoPtr<dng_memory_block> fGainTable;
AutoPtr<dng_memory_block> fMaskBuffers [kMaxMPThreads];
public:
dng_opcode_FixVignetteRadial (const dng_vignette_radial_params &params,
uint32 flags);
explicit dng_opcode_FixVignetteRadial (dng_stream &stream);
const dng_vignette_radial_params & Params () const
{
return fParams;
}
virtual bool IsNOP () const;
virtual bool IsValidForNegative (const dng_negative &) const;
virtual void PutData (dng_stream &stream) const;
virtual uint32 BufferPixelType (uint32 /* imagePixelType */)
{
return ttFloat;
}
virtual void Prepare (dng_negative &negative,
uint32 threadCount,
const dng_point &tileSize,
const dng_rect &imageBounds,
uint32 imagePlanes,
uint32 bufferPixelType,
dng_memory_allocator &allocator);
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
protected:
static uint32 ParamBytes ();
virtual dng_vignette_radial_params MakeParamsForRender (const dng_negative &negative);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,161 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Support for linearization table and black level tags.
*/
/*****************************************************************************/
#ifndef __dng_linearization_info__
#define __dng_linearization_info__
/*****************************************************************************/
#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_memory.h"
#include "dng_rational.h"
#include "dng_rect.h"
#include "dng_sdk_limits.h"
/*****************************************************************************/
/// \brief Class for managing data values related to DNG linearization.
///
/// See LinearizationTable, BlackLevel, BlackLevelRepeatDim, BlackLevelDeltaH,
/// BlackLevelDeltaV and WhiteLevel tags in the \ref spec_dng "DNG 1.1.0 specification".
class dng_linearization_info
{
public:
/// This rectangle defines the active (non-masked) pixels of the sensor.
/// The order of the rectangle coordinates is: top, left, bottom, right.
dng_rect fActiveArea;
/// Number of rectangles in fMaskedArea
uint32 fMaskedAreaCount;
/// List of non-overlapping rectangle coordinates of fully masked pixels.
/// Can be optionally used by DNG readers to measure the black encoding level.
/// The order of each rectangle's coordinates is: top, left, bottom, right.
/// If the raw image data has already had its black encoding level subtracted, then this tag should
/// not be used, since the masked pixels are no longer useful.
/// Note that DNG writers are still required to include an estimate and store the black encoding level
/// using the black level DNG tags. Support for the MaskedAreas tag is not required of DNG
/// readers.
dng_rect fMaskedArea [kMaxMaskedAreas];
/// A lookup table that maps stored values into linear values.
/// This tag is typically used to increase compression ratios by storing the raw data in a non-linear, more
/// visually uniform space with fewer total encoding levels.
/// If SamplesPerPixel is not equal to one, e.g. Fuji S3 type sensor, this single table applies to all the samples for each
/// pixel.
AutoPtr<dng_memory_block> fLinearizationTable;
/// Actual number of rows in fBlackLevel pattern
uint32 fBlackLevelRepeatRows;
/// Actual number of columns in fBlackLevel pattern
uint32 fBlackLevelRepeatCols;
/// Repeating pattern of black level deltas fBlackLevelRepeatRows by fBlackLevelRepeatCols in size.
real64 fBlackLevel [kMaxBlackPattern] [kMaxBlackPattern] [kMaxSamplesPerPixel];
/// Memory block of double-precision floating point deltas between baseline black level and a given column's black level
AutoPtr<dng_memory_block> fBlackDeltaH;
/// Memory block of double-precision floating point deltas between baseline black level and a given row's black level
AutoPtr<dng_memory_block> fBlackDeltaV;
/// Single white level (maximum sensor value) for each sample plane.
real64 fWhiteLevel [kMaxSamplesPerPixel];
protected:
int32 fBlackDenom;
public:
dng_linearization_info ();
virtual ~dng_linearization_info ();
void RoundBlacks ();
virtual void Parse (dng_host &host,
dng_stream &stream,
dng_info &info);
virtual void PostParse (dng_host &host,
dng_negative &negative);
/// Compute the maximum black level for a given sample plane taking into account base
/// black level, repeated black level patter, and row/column delta maps.
real64 MaxBlackLevel (uint32 plane) const;
/// Convert raw data from in-file format to a true linear image using linearization data from DNG.
/// \param host Used to allocate buffers, check for aborts, and post progress updates.
/// \param negative Used to remember preserved black point.
/// \param srcImage Input pre-linearization RAW samples.
/// \param dstImage Output linearized image.
virtual void Linearize (dng_host &host,
dng_negative &negative,
const dng_image &srcImage,
dng_image &dstImage);
/// Compute black level for one coordinate and sample plane in the image.
/// \param row Row to compute black level for.
/// \param col Column to compute black level for.
/// \param plane Sample plane to compute black level for.
dng_urational BlackLevel (uint32 row,
uint32 col,
uint32 plane) const;
/// Number of per-row black level deltas in fBlackDeltaV.
uint32 RowBlackCount () const;
/// Lookup black level delta for a given row.
/// \param row Row to get black level for.
/// \retval black level for indicated row.
dng_srational RowBlack (uint32 row) const;
/// Number of per-column black level deltas in fBlackDeltaV.
uint32 ColumnBlackCount () const;
/// Lookup black level delta for a given column.
/// \param col Column to get black level for.
/// \retval black level for indicated column.
dng_srational ColumnBlack (uint32 col) const;
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,191 @@
/*****************************************************************************/
// Copyright 2015-2019 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.
/*****************************************************************************/
#include "dng_local_string.h"
/*****************************************************************************/
dng_local_string::dng_local_string ()
: fDefaultText ()
, fDictionary ()
{
}
/*****************************************************************************/
dng_local_string::dng_local_string (const dng_string &s)
: fDefaultText (s)
, fDictionary ()
{
}
/*****************************************************************************/
dng_local_string::~dng_local_string ()
{
}
/*****************************************************************************/
void dng_local_string::Clear ()
{
fDefaultText.Clear ();
fDictionary.clear ();
}
/*****************************************************************************/
void dng_local_string::SetDefaultText (const dng_string &s)
{
fDefaultText = s;
}
/*****************************************************************************/
void dng_local_string::AddTranslation (const dng_string &language,
const dng_string &translation)
{
dng_string safeLanguage (language);
safeLanguage.Truncate (255);
fDictionary.push_back (dictionary_entry (safeLanguage,
translation));
}
/*****************************************************************************/
void dng_local_string::Set (const char *s)
{
dng_string defaultText;
defaultText.Set (s);
*this = dng_local_string (defaultText);
}
/*****************************************************************************/
const dng_string & dng_local_string::LocalText (const dng_string &locale) const
{
// Pass 1 - try for a match starting with the entire locale string.
if (locale.Length () >= 5)
{
for (uint32 index = 0; index < TranslationCount (); index++)
{
if (Language (index).StartsWith (locale.Get (), false))
{
return Translation (index);
}
}
}
// Pass 2 - try for a language only match.
if (locale.Length () >= 2)
{
dng_string languageOnly (locale);
languageOnly.Truncate (2);
for (uint32 index = 0; index < TranslationCount (); index++)
{
if (Language (index).StartsWith (languageOnly.Get (), false))
{
return Translation (index);
}
}
}
// Otherwise use default text.
return DefaultText ();
}
/*****************************************************************************/
bool dng_local_string::operator== (const dng_local_string &s) const
{
if (DefaultText () != s.DefaultText ())
{
return false;
}
if (TranslationCount () != s.TranslationCount ())
{
return false;
}
for (uint32 index = 0; index < TranslationCount (); index++)
{
if (Language (index) != s.Language (index))
{
return false;
}
if (Translation (index) != s.Translation (index))
{
return false;
}
}
return true;
}
/*****************************************************************************/
void dng_local_string::Truncate (uint32 maxBytes)
{
fDefaultText.Truncate (maxBytes);
for (uint32 index = 0; index < TranslationCount (); index++)
{
fDictionary [index] . fTranslation . Truncate (maxBytes);
}
}
/*****************************************************************************/

@ -0,0 +1,119 @@
/*****************************************************************************/
// Copyright 2015-2019 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.
/*****************************************************************************/
#ifndef __dng_local_string__
#define __dng_local_string__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_string.h"
#include "dng_types.h"
#include <vector>
/*****************************************************************************/
class dng_local_string
{
private:
dng_string fDefaultText;
struct dictionary_entry
{
dng_string fLanguage;
dng_string fTranslation;
dictionary_entry (const dng_string &language,
const dng_string &translation)
: fLanguage (language)
, fTranslation (translation)
{
}
};
std::vector<dictionary_entry> fDictionary;
public:
dng_local_string ();
dng_local_string (const dng_string &s);
~dng_local_string ();
void Clear ();
void SetDefaultText (const dng_string &s);
void AddTranslation (const dng_string &language,
const dng_string &translation);
void Set (const char *s);
const dng_string & DefaultText () const
{
return fDefaultText;
}
dng_string & DefaultText ()
{
return fDefaultText;
}
uint32 TranslationCount () const
{
return (uint32) fDictionary.size ();
}
const dng_string & Language (uint32 index) const
{
return fDictionary [index] . fLanguage;
}
const dng_string & Translation (uint32 index) const
{
return fDictionary [index] . fTranslation;
}
const dng_string & LocalText (const dng_string &locale) const;
bool IsEmpty () const
{
return DefaultText ().IsEmpty ();
}
bool NotEmpty () const
{
return !IsEmpty ();
}
bool operator== (const dng_local_string &s) const;
bool operator!= (const dng_local_string &s) const
{
return !(*this == s);
}
void Truncate (uint32 maxBytes);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,65 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Functions for encoding and decoding lossless JPEG format.
*/
/*****************************************************************************/
#ifndef __dng_lossless_jpeg__
#define __dng_lossless_jpeg__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_types.h"
/*****************************************************************************/
class dng_spooler
{
protected:
virtual ~dng_spooler ()
{
}
public:
virtual void Spool (const void *data,
uint32 count) = 0;
};
/*****************************************************************************/
void DecodeLosslessJPEG (dng_stream &stream,
dng_spooler &spooler,
uint32 minDecodedSize,
uint32 maxDecodedSize,
bool bug16,
uint64 endOfData);
/*****************************************************************************/
void EncodeLosslessJPEG (const uint16 *srcData,
uint32 srcRows,
uint32 srcCols,
uint32 srcChannels,
uint32 srcBitDepth,
int32 srcRowStep,
int32 srcColStep,
dng_stream &stream);
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,365 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Matrix and vector classes, including specialized 3x3 and 4x3 versions as
* well as length 3 vectors.
*/
/*****************************************************************************/
#ifndef __dng_matrix__
#define __dng_matrix__
/*****************************************************************************/
#include "dng_sdk_limits.h"
#include "dng_types.h"
/*****************************************************************************/
/// \brief Class to represent 2D matrix up to kMaxColorPlanes x kMaxColorPlanes
/// in size.
class dng_matrix
{
protected:
uint32 fRows;
uint32 fCols;
real64 fData [kMaxColorPlanes] [kMaxColorPlanes];
public:
dng_matrix ();
dng_matrix (uint32 rows,
uint32 cols);
dng_matrix (const dng_matrix &m);
virtual ~dng_matrix ()
{
}
void Clear ();
void SetIdentity (uint32 count);
uint32 Rows () const
{
return fRows;
}
uint32 Cols () const
{
return fCols;
}
real64 * operator [] (uint32 row)
{
return fData [row];
}
const real64 * operator [] (uint32 row) const
{
return fData [row];
}
bool operator== (const dng_matrix &m) const;
bool operator!= (const dng_matrix &m) const
{
return !(*this == m);
}
bool IsEmpty () const
{
return fRows == 0 || fCols == 0;
}
bool NotEmpty () const
{
return !IsEmpty ();
}
bool IsDiagonal () const;
bool IsIdentity () const;
real64 MaxEntry () const;
real64 MinEntry () const;
void Scale (real64 factor);
void Round (real64 factor);
void SafeRound (real64 factor);
bool AlmostEqual (const dng_matrix &m,
real64 slop = 1.0e-8) const;
bool AlmostIdentity (real64 slop = 1.0e-8) const;
};
/*****************************************************************************/
/// \brief A 3x3 matrix.
class dng_matrix_3by3: public dng_matrix
{
public:
dng_matrix_3by3 ();
dng_matrix_3by3 (const dng_matrix &m);
dng_matrix_3by3 (real64 a00, real64 a01, real64 a02,
real64 a10, real64 a11, real64 a12,
real64 a20, real64 a21, real64 a22);
dng_matrix_3by3 (real64 a00, real64 a11, real64 a22);
};
/*****************************************************************************/
/// \brief A 4x3 matrix. Handy for working with 4-color cameras.
class dng_matrix_4by3: public dng_matrix
{
public:
dng_matrix_4by3 ();
dng_matrix_4by3 (const dng_matrix &m);
dng_matrix_4by3 (real64 a00, real64 a01, real64 a02,
real64 a10, real64 a11, real64 a12,
real64 a20, real64 a21, real64 a22,
real64 a30, real64 a31, real64 a32);
};
/*****************************************************************************/
/// \brief A 4x4 matrix. Handy for GPU APIs.
class dng_matrix_4by4: public dng_matrix
{
public:
dng_matrix_4by4 ();
dng_matrix_4by4 (const dng_matrix &m);
dng_matrix_4by4 (real64 a00, real64 a01, real64 a02, real64 a03,
real64 a10, real64 a11, real64 a12, real64 a13,
real64 a20, real64 a21, real64 a22, real64 a23,
real64 a30, real64 a31, real64 a32, real64 a33);
dng_matrix_4by4 (real64 a00, real64 a11, real64 a22, real64 a33);
};
/*****************************************************************************/
/// \brief Class to represent 1-dimensional vector with up to kMaxColorPlanes
/// components.
class dng_vector
{
protected:
uint32 fCount;
real64 fData [kMaxColorPlanes];
public:
dng_vector ();
dng_vector (uint32 count);
dng_vector (const dng_vector &v);
virtual ~dng_vector ()
{
}
void Clear ();
void SetIdentity (uint32 count);
uint32 Count () const
{
return fCount;
}
real64 & operator [] (uint32 index)
{
return fData [index];
}
const real64 & operator [] (uint32 index) const
{
return fData [index];
}
bool operator== (const dng_vector &v) const;
bool operator!= (const dng_vector &v) const
{
return !(*this == v);
}
bool IsEmpty () const
{
return fCount == 0;
}
bool NotEmpty () const
{
return !IsEmpty ();
}
real64 MaxEntry () const;
real64 MinEntry () const;
void Scale (real64 factor);
void Round (real64 factor);
dng_matrix AsDiagonal () const;
dng_matrix AsColumn () const;
};
/*****************************************************************************/
/// \brief A 3-element vector.
class dng_vector_3: public dng_vector
{
public:
dng_vector_3 ();
dng_vector_3 (const dng_vector &v);
dng_vector_3 (real64 a0,
real64 a1,
real64 a2);
};
/*****************************************************************************/
/// \brief A 4-element vector.
class dng_vector_4: public dng_vector
{
public:
dng_vector_4 ();
dng_vector_4 (const dng_vector &v);
dng_vector_4 (real64 a0,
real64 a1,
real64 a2,
real64 a3);
};
/*****************************************************************************/
dng_matrix operator* (const dng_matrix &A,
const dng_matrix &B);
dng_vector operator* (const dng_matrix &A,
const dng_vector &B);
dng_matrix operator* (real64 scale,
const dng_matrix &A);
dng_vector operator* (real64 scale,
const dng_vector &A);
/*****************************************************************************/
dng_matrix operator+ (const dng_matrix &A,
const dng_matrix &B);
/*****************************************************************************/
dng_vector operator- (const dng_vector &a,
const dng_vector &b);
/*****************************************************************************/
dng_matrix Transpose (const dng_matrix &A);
/*****************************************************************************/
dng_matrix Invert (const dng_matrix &A);
dng_matrix Invert (const dng_matrix &A,
const dng_matrix &hint);
/*****************************************************************************/
inline real64 MaxEntry (const dng_matrix &A)
{
return A.MaxEntry ();
}
inline real64 MaxEntry (const dng_vector &A)
{
return A.MaxEntry ();
}
/*****************************************************************************/
inline real64 MinEntry (const dng_matrix &A)
{
return A.MinEntry ();
}
inline real64 MinEntry (const dng_vector &A)
{
return A.MinEntry ();
}
/*****************************************************************************/
real64 Dot (const dng_vector &a,
const dng_vector &b);
/*****************************************************************************/
real64 Distance (const dng_vector &a,
const dng_vector &b);
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,284 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_memory.h"
#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#ifdef _MSC_VER
#include <Windows.h>
#endif
/*****************************************************************************/
dng_memory_data::dng_memory_data ()
: fBuffer (NULL)
{
}
/*****************************************************************************/
dng_memory_data::dng_memory_data (uint32 size)
: fBuffer (NULL)
{
Allocate (size);
}
/*****************************************************************************/
dng_memory_data::dng_memory_data (const dng_safe_uint32 &size)
: fBuffer (NULL)
{
Allocate (size.Get ());
}
/*****************************************************************************/
dng_memory_data::dng_memory_data (uint32 count,
std::size_t elementSize)
: fBuffer (NULL)
{
Allocate (count, elementSize);
}
/*****************************************************************************/
dng_memory_data::~dng_memory_data ()
{
Clear ();
}
/*****************************************************************************/
void dng_memory_data::Allocate (uint32 size)
{
Clear ();
if (size)
{
//printf("Calling malloc from %s\n", __FUNCTION__);
fBuffer = (char *) malloc (size);
if (!fBuffer)
{
ThrowMemoryFull ();
}
}
}
/*****************************************************************************/
void dng_memory_data::Allocate (const dng_safe_uint32 &size)
{
Allocate (size.Get ());
}
/*****************************************************************************/
void dng_memory_data::Allocate (uint32 count,
std::size_t elementSize)
{
// Convert elementSize to a uint32.
const uint32 elementSizeAsUint32 = static_cast<uint32> (elementSize);
if (static_cast<std::size_t> (elementSizeAsUint32) != elementSize)
{
ThrowOverflow ("elementSize overflow");
}
// Compute required number of bytes and allocate memory.
dng_safe_uint32 numBytes = dng_safe_uint32 (count) * elementSizeAsUint32;
Allocate (numBytes.Get ());
}
/*****************************************************************************/
void dng_memory_data::Allocate (const dng_safe_uint32 &count,
std::size_t elementSize)
{
Allocate (count.Get (), elementSize);
}
/*****************************************************************************/
void dng_memory_data::Clear ()
{
if (fBuffer)
{
free (fBuffer);
fBuffer = NULL;
}
}
/*****************************************************************************/
dng_memory_block * dng_memory_block::Clone (dng_memory_allocator &allocator) const
{
uint32 size = LogicalSize ();
dng_memory_block * result = allocator.Allocate (size);
DoCopyBytes (Buffer (), result->Buffer (), size);
return result;
}
/*****************************************************************************/
dng_malloc_block::dng_malloc_block (uint32 logicalSize)
: dng_memory_block (logicalSize)
, fMalloc (NULL)
{
#if qLinux
// TO DO: Need to change this alignment for AVX support?
int err = ::posix_memalign ((void **) &fMalloc,
16,
(size_t) PhysicalSize ());
if (err)
{
ThrowMemoryFull ();
}
#elif qAndroid
fMalloc = memalign (16, (size_t) PhysicalSize ());
if (!fMalloc)
{
ThrowMemoryFull ();
}
#else
//fMalloc = (char *) VirtualAlloc (NULL, PhysicalSize (), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
//printf("Calling malloc from %s\n", __FUNCTION__);
fMalloc = (char *)malloc(PhysicalSize());
if (!fMalloc)
{
ThrowMemoryFull ();
}
//*(size_t*)(fMalloc) = size_t(PhysicalSize() + 16);
//fMalloc = (char*)fMalloc+16;
#endif
SetBuffer (fMalloc);
}
/*****************************************************************************/
dng_malloc_block::~dng_malloc_block ()
{
if (fMalloc)
{
//size_t size = *(size_t*)((char*)fMalloc - 16);
//VirtualFree(fMalloc, 0, MEM_RELEASE);
free (fMalloc);
}
}
/*****************************************************************************/
dng_memory_block * dng_memory_allocator::Allocate (uint32 size)
{
dng_memory_block *result = new dng_malloc_block (size);
if (!result)
{
ThrowMemoryFull ();
}
return result;
}
/*****************************************************************************/
void * dng_memory_allocator::Malloc (size_t size)
{
return malloc (size);
}
/*****************************************************************************/
void dng_memory_allocator::Free (void *ptr)
{
free (ptr);
}
/*****************************************************************************/
dng_memory_allocator gDefaultDNGMemoryAllocator;
/*****************************************************************************/

@ -0,0 +1,652 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** Support for memory allocation.
*/
/*****************************************************************************/
#ifndef __dng_memory__
#define __dng_memory__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_exceptions.h"
#include "dng_flags.h"
#include "dng_safe_arithmetic.h"
#include "dng_types.h"
#include "dng_uncopyable.h"
#include <cstdlib>
#include <vector>
/*****************************************************************************/
#if qDNGAVXSupport
#define DNG_ALIGN_SIMD(x) ((((uintptr) (x)) + 31) & ~((uintptr) 31))
#else
#define DNG_ALIGN_SIMD(x) ((((uintptr) (x)) + 15) & ~((uintptr) 15))
#endif
/*****************************************************************************/
/// \brief Class to provide resource acquisition is instantiation discipline
/// for small memory allocations.
///
/// This class does not use dng_memory_allocator for memory allocation.
class dng_memory_data: private dng_uncopyable
{
private:
char *fBuffer;
public:
/// Construct an empty memory buffer using malloc.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
dng_memory_data ();
/// Construct memory buffer of size bytes using malloc.
/// \param size Number of bytes of memory needed.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
dng_memory_data (uint32 size);
dng_memory_data (const dng_safe_uint32 &size);
/// Note: This constructor is for internal use only and should not be
/// considered part of the DNG SDK API.
///
/// Construct memory buffer of count elements of elementSize bytes each.
/// \param count Number of elements.
/// \param elementSize Size of each element.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
dng_memory_data (uint32 count,
std::size_t elementSize);
/// Release memory buffer using free.
~dng_memory_data ();
/// Clear existing memory buffer and allocate new memory of size bytes.
/// \param size Number of bytes of memory needed.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
void Allocate (uint32 size);
void Allocate (const dng_safe_uint32 &size);
/// Note: This method is for internal use only and should not be
/// considered part of the DNG SDK API.
///
/// Clear existing memory buffer and allocate new memory of count
/// elements of elementSize bytes each.
/// \param count Number of elements.
/// \param elementSize Size of each element.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
void Allocate (uint32 count,
std::size_t elementSize);
void Allocate (const dng_safe_uint32 &count,
std::size_t elementSize);
/// Release any allocated memory using free. Object is still valid and
/// Allocate can be called again.
void Clear ();
/// Return pointer to allocated memory as a void *..
/// \retval void * valid for as many bytes as were allocated.
void * Buffer ()
{
return fBuffer;
}
/// Return pointer to allocated memory as a const void *.
/// \retval const void * valid for as many bytes as were allocated.
const void * Buffer () const
{
return fBuffer;
}
/// Return pointer to allocated memory as a char *.
/// \retval char * valid for as many bytes as were allocated.
char * Buffer_char ()
{
return (char *) Buffer ();
}
/// Return pointer to allocated memory as a const char *.
/// \retval const char * valid for as many bytes as were allocated.
const char * Buffer_char () const
{
return (const char *) Buffer ();
}
/// Return pointer to allocated memory as a uint8 *.
/// \retval uint8 * valid for as many bytes as were allocated.
uint8 * Buffer_uint8 ()
{
return (uint8 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint8 *.
/// \retval const uint8 * valid for as many bytes as were allocated.
const uint8 * Buffer_uint8 () const
{
return (const uint8 *) Buffer ();
}
/// Return pointer to allocated memory as a uint16 *.
/// \retval uint16 * valid for as many bytes as were allocated.
uint16 * Buffer_uint16 ()
{
return (uint16 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint16 *.
/// \retval const uint16 * valid for as many bytes as were allocated.
const uint16 * Buffer_uint16 () const
{
return (const uint16 *) Buffer ();
}
/// Return pointer to allocated memory as a int16 *.
/// \retval int16 * valid for as many bytes as were allocated.
int16 * Buffer_int16 ()
{
return (int16 *) Buffer ();
}
/// Return pointer to allocated memory as a const int16 *.
/// \retval const int16 * valid for as many bytes as were allocated.
const int16 * Buffer_int16 () const
{
return (const int16 *) Buffer ();
}
/// Return pointer to allocated memory as a uint32 *.
/// \retval uint32 * valid for as many bytes as were allocated.
uint32 * Buffer_uint32 ()
{
return (uint32 *) Buffer ();
}
/// Return pointer to allocated memory as a uint32 *.
/// \retval uint32 * valid for as many bytes as were allocated.
const uint32 * Buffer_uint32 () const
{
return (const uint32 *) Buffer ();
}
/// Return pointer to allocated memory as a const int32 *.
/// \retval const int32 * valid for as many bytes as were allocated.
int32 * Buffer_int32 ()
{
return (int32 *) Buffer ();
}
/// Return pointer to allocated memory as a const int32 *.
/// \retval const int32 * valid for as many bytes as were allocated.
const int32 * Buffer_int32 () const
{
return (const int32 *) Buffer ();
}
/// Return pointer to allocated memory as a uint64 *.
/// \retval uint64 * valid for as many bytes as were allocated.
uint64 * Buffer_uint64 ()
{
return (uint64 *) Buffer ();
}
/// Return pointer to allocated memory as a uint64 *.
/// \retval uint64 * valid for as many bytes as were allocated.
const uint64 * Buffer_uint64 () const
{
return (const uint64 *) Buffer ();
}
/// Return pointer to allocated memory as a const int64 *.
/// \retval const int64 * valid for as many bytes as were allocated.
int64 * Buffer_int64 ()
{
return (int64 *) Buffer ();
}
/// Return pointer to allocated memory as a const int64 *.
/// \retval const int64 * valid for as many bytes as were allocated.
const int64 * Buffer_int64 () const
{
return (const int64 *) Buffer ();
}
/// Return pointer to allocated memory as a real32 *.
/// \retval real32 * valid for as many bytes as were allocated.
real32 * Buffer_real32 ()
{
return (real32 *) Buffer ();
}
/// Return pointer to allocated memory as a const real32 *.
/// \retval const real32 * valid for as many bytes as were allocated.
const real32 * Buffer_real32 () const
{
return (const real32 *) Buffer ();
}
/// Return pointer to allocated memory as a real64 *.
/// \retval real64 * valid for as many bytes as were allocated.
real64 * Buffer_real64 ()
{
return (real64 *) Buffer ();
}
/// Return pointer to allocated memory as a const real64 *.
/// \retval const real64 * valid for as many bytes as were allocated.
const real64 * Buffer_real64 () const
{
return (const real64 *) Buffer ();
}
};
/*****************************************************************************/
/// \brief Class to provide resource acquisition is instantiation discipline for
/// image buffers and other larger memory allocations.
///
/// This class requires a dng_memory_allocator for allocation.
class dng_memory_block: private dng_uncopyable
{
private:
uint32 fLogicalSize;
char *fBuffer;
protected:
dng_memory_block (uint32 logicalSize)
: fLogicalSize (logicalSize)
, fBuffer (NULL)
{
}
uint32 PhysicalSize ()
{
// This size is padded for TWO reasons! The first is allow
// alignment to 16-byte boundaries if the allocator does not do
// that already. The second, which is very important, so to
// provide safe overread areas for SSE2-type bottlenecks, which
// can often be written faster by allowing them to reading
// slightly block. Someone on the image core them did not
// understand this and removed this padding. I'm undoing this
// removal and restoring this padding, since removing it might
// lead to memory access crashes in some cases.
//
// Please do NOT change the following padding unless you are very
// sure what you are doing.
dng_safe_uint32 safeLogicalSize (fLogicalSize);
#if qDNGAVXSupport
// Allow 32-byte alignment + 64-byte overread in both directions:
// 32 + 64 + 64 = 160.
return (safeLogicalSize + 160u).Get ();
#else
// Allow 16-byte alignment + overread.
return (safeLogicalSize + 64u).Get ();
#endif // qDNGAVXSupport
}
void SetBuffer (void *p)
{
fBuffer = (char *) DNG_ALIGN_SIMD (p);
}
public:
virtual ~dng_memory_block ()
{
}
dng_memory_block * Clone (dng_memory_allocator &allocator) const;
/// Getter for available size, in bytes, of memory block.
/// \retval size in bytes of available memory in memory block.
uint32 LogicalSize () const
{
return fLogicalSize;
}
/// Return pointer to allocated memory as a void *..
/// \retval void * valid for as many bytes as were allocated.
void * Buffer ()
{
return fBuffer;
}
/// Return pointer to allocated memory as a const void *.
/// \retval const void * valid for as many bytes as were allocated.
const void * Buffer () const
{
return fBuffer;
}
/// Return pointer to allocated memory as a char *.
/// \retval char * valid for as many bytes as were allocated.
char * Buffer_char ()
{
return (char *) Buffer ();
}
/// Return pointer to allocated memory as a const char *.
/// \retval const char * valid for as many bytes as were allocated.
const char * Buffer_char () const
{
return (const char *) Buffer ();
}
/// Return pointer to allocated memory as a uint8 *.
/// \retval uint8 * valid for as many bytes as were allocated.
uint8 * Buffer_uint8 ()
{
return (uint8 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint8 *.
/// \retval const uint8 * valid for as many bytes as were allocated.
const uint8 * Buffer_uint8 () const
{
return (const uint8 *) Buffer ();
}
/// Return pointer to allocated memory as a uint16 *.
/// \retval uint16 * valid for as many bytes as were allocated.
uint16 * Buffer_uint16 ()
{
return (uint16 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint16 *.
/// \retval const uint16 * valid for as many bytes as were allocated.
const uint16 * Buffer_uint16 () const
{
return (const uint16 *) Buffer ();
}
/// Return pointer to allocated memory as a int16 *.
/// \retval int16 * valid for as many bytes as were allocated.
int16 * Buffer_int16 ()
{
return (int16 *) Buffer ();
}
/// Return pointer to allocated memory as a const int16 *.
/// \retval const int16 * valid for as many bytes as were allocated.
const int16 * Buffer_int16 () const
{
return (const int16 *) Buffer ();
}
/// Return pointer to allocated memory as a uint32 *.
/// \retval uint32 * valid for as many bytes as were allocated.
uint32 * Buffer_uint32 ()
{
return (uint32 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint32 *.
/// \retval const uint32 * valid for as many bytes as were allocated.
const uint32 * Buffer_uint32 () const
{
return (const uint32 *) Buffer ();
}
/// Return pointer to allocated memory as a int32 *.
/// \retval int32 * valid for as many bytes as were allocated.
int32 * Buffer_int32 ()
{
return (int32 *) Buffer ();
}
/// Return pointer to allocated memory as a const int32 *.
/// \retval const int32 * valid for as many bytes as were allocated.
const int32 * Buffer_int32 () const
{
return (const int32 *) Buffer ();
}
/// Return pointer to allocated memory as a real32 *.
/// \retval real32 * valid for as many bytes as were allocated.
real32 * Buffer_real32 ()
{
return (real32 *) Buffer ();
}
/// Return pointer to allocated memory as a const real32 *.
/// \retval const real32 * valid for as many bytes as were allocated.
const real32 * Buffer_real32 () const
{
return (const real32 *) Buffer ();
}
/// Return pointer to allocated memory as a real64 *.
/// \retval real64 * valid for as many bytes as were allocated.
real64 * Buffer_real64 ()
{
return (real64 *) Buffer ();
}
/// Return pointer to allocated memory as a const real64 *.
/// \retval const real64 * valid for as many bytes as were allocated.
const real64 * Buffer_real64 () const
{
return (const real64 *) Buffer ();
}
};
/*****************************************************************************/
/// \brief Interface for dng_memory_block allocator.
class dng_memory_allocator
{
public:
virtual ~dng_memory_allocator ()
{
}
/// Allocate a dng_memory block.
/// \param size Number of bytes in memory block.
/// \retval A dng_memory_block with at least size bytes of valid storage.
/// \exception dng_exception with fErrorCode equal to dng_error_memory.
virtual dng_memory_block * Allocate (uint32 size);
/// Directly allocate a block of at least 'size' bytes.
/// \param size Number of bytes in memory block.
/// \retval A pointer to a contiguous block of memory with at least
/// size bytes of valid storage.
/// Caller is responsible for freeing the memory with Free.
/// Default implementation uses standard library 'malloc' routine.
virtual void * Malloc (size_t size);
/// Free the specified block of memory previously allocated with Malloc.
/// Default implementation uses standard library 'free' routine.
virtual void Free (void *ptr);
};
/*****************************************************************************/
class dng_malloc_block : public dng_memory_block
{
private:
void *fMalloc;
public:
dng_malloc_block (uint32 logicalSize);
virtual ~dng_malloc_block ();
};
/*****************************************************************************/
/// \brief Default memory allocator used if NULL is passed in for allocator
/// when constructing a dng_host.
///
/// Uses new and delete for memory block object and malloc/free for underlying
/// buffer.
extern dng_memory_allocator gDefaultDNGMemoryAllocator;
/*****************************************************************************/
/// \brief C++ allocator (i.e. an implementation of the Allocator concept)
/// that throws a dng_exception with error code dng_error_memory if it cannot
/// allocate memory.
template <typename T>
class dng_std_allocator
{
public:
typedef T value_type;
#if defined(_MSC_VER) && _MSC_VER >= 1900
// Default implementations of default constructor and copy
// constructor.
dng_std_allocator () = default;
// dng_std_allocator (const dng_std_allocator &) = default;
template<class U> dng_std_allocator (const dng_std_allocator<U> &) {}
#endif
T * allocate (size_t n)
{
const size_t size = SafeSizetMult (n, sizeof (T));
T *retval = static_cast<T *> (malloc (size));
if (!retval)
{
ThrowMemoryFull ();
}
return retval;
}
void deallocate (T *ptr,
size_t /* n */)
{
free (ptr);
}
};
template <class T>
bool operator== (const dng_std_allocator<T> & /* a1 */,
const dng_std_allocator<T> & /* a2 */)
{
return true;
}
template <class T>
bool operator!= (const dng_std_allocator<T> & /* a1 */,
const dng_std_allocator<T> & /* a2 */)
{
return false;
}
/*****************************************************************************/
// std::vector specialized to use dng_std_allocator for allocation.
#if 0
// original implementation without using custom allocator
#define dng_std_vector std::vector
#else
// preferred implementation using custom allocator, requires C++11
template <class T> using dng_std_vector = std::vector<T, dng_std_allocator<T> >;
#endif
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,282 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_memory_stream.h"
#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#include "dng_safe_arithmetic.h"
#include "dng_utils.h"
/*****************************************************************************/
dng_memory_stream::dng_memory_stream (dng_memory_allocator &allocator,
dng_abort_sniffer *sniffer,
uint32 pageSize)
: dng_stream (sniffer,
kDefaultBufferSize,
kDNGStreamInvalidOffset)
, fAllocator (allocator)
, fPageSize (pageSize )
, fPageCount (0)
, fPagesAllocated (0)
, fPageList (NULL)
, fMemoryStreamLength (0)
, fLengthLimit (0)
{
}
/*****************************************************************************/
dng_memory_stream::~dng_memory_stream ()
{
if (fPageList)
{
for (uint32 index = 0; index < fPageCount; index++)
{
delete fPageList [index];
}
free (fPageList);
}
}
/*****************************************************************************/
uint64 dng_memory_stream::DoGetLength ()
{
return fMemoryStreamLength;
}
/*****************************************************************************/
void dng_memory_stream::DoRead (void *data,
uint32 count,
uint64 offset)
{
if (offset + count > fMemoryStreamLength)
{
ThrowEndOfFile ();
}
uint64 baseOffset = offset;
while (count)
{
uint32 pageIndex = (uint32) (offset / fPageSize);
uint32 pageOffset = (uint32) (offset % fPageSize);
uint32 blockCount = Min_uint32 (fPageSize - pageOffset, count);
const uint8 *sPtr = fPageList [pageIndex]->Buffer_uint8 () +
pageOffset;
uint8 *dPtr = ((uint8 *) data) + (uint32) (offset - baseOffset);
DoCopyBytes (sPtr, dPtr, blockCount);
offset += blockCount;
count -= blockCount;
}
}
/*****************************************************************************/
void dng_memory_stream::DoSetLength (uint64 length)
{
if (fLengthLimit && length > fLengthLimit)
{
Throw_dng_error (dng_error_end_of_file,
"dng_memory_stream::fLengthLimit",
NULL,
true);
}
while (length > fPageCount * (uint64) fPageSize)
{
if (fPageCount == fPagesAllocated)
{
uint32 newSizeTemp1 = 0;
uint32 newSizeTemp2 = 0;
if (!SafeUint32Add (fPagesAllocated, 32u, &newSizeTemp1) ||
!SafeUint32Mult (fPagesAllocated, 2u, &newSizeTemp2))
{
ThrowOverflow ("Arithmetic overflow in DoSetLength");
}
uint32 newSize = Max_uint32 (newSizeTemp1,
newSizeTemp2);
uint32 numBytes;
if (!SafeUint32Mult (newSize,
sizeof (dng_memory_block *),
&numBytes))
{
ThrowOverflow ("Arithmetic overflow in DoSetLength");
}
dng_memory_block **list = (dng_memory_block **) malloc (numBytes);
if (!list)
{
ThrowMemoryFull ();
}
if (fPageCount)
{
// The multiplication here is safe against overflow.
// fPageCount can never reach a value that is large enough to
// cause overflow because the computation of numBytes above
// would fail before a list of that size could be allocated.
DoCopyBytes (fPageList,
list,
fPageCount * (uint32) sizeof (dng_memory_block *));
}
if (fPageList)
{
free (fPageList);
}
fPageList = list;
fPagesAllocated = newSize;
}
fPageList [fPageCount] = fAllocator.Allocate (fPageSize);
fPageCount++;
}
fMemoryStreamLength = length;
}
/*****************************************************************************/
void dng_memory_stream::DoWrite (const void *data,
uint32 count,
uint64 offset)
{
DoSetLength (Max_uint64 (fMemoryStreamLength,
offset + count));
uint64 baseOffset = offset;
while (count)
{
uint32 pageIndex = (uint32) (offset / fPageSize);
uint32 pageOffset = (uint32) (offset % fPageSize);
uint32 blockCount = Min_uint32 (fPageSize - pageOffset, count);
const uint8 *sPtr = ((const uint8 *) data) + (uint32) (offset - baseOffset);
uint8 *dPtr = fPageList [pageIndex]->Buffer_uint8 () +
pageOffset;
DoCopyBytes (sPtr, dPtr, blockCount);
offset += blockCount;
count -= blockCount;
}
}
/*****************************************************************************/
void dng_memory_stream::CopyToStream (dng_stream &dstStream,
uint64 count)
{
if (count < kBigBufferSize)
{
dng_stream::CopyToStream (dstStream, count);
}
else
{
Flush ();
uint64 offset = Position ();
if (offset + count > Length ())
{
ThrowEndOfFile ();
}
while (count)
{
uint32 pageIndex = (uint32) (offset / fPageSize);
uint32 pageOffset = (uint32) (offset % fPageSize);
uint32 blockCount = (uint32) Min_uint64 (fPageSize - pageOffset, count);
const uint8 *sPtr = fPageList [pageIndex]->Buffer_uint8 () +
pageOffset;
dstStream.Put (sPtr, blockCount);
offset += blockCount;
count -= blockCount;
}
SetReadPosition (offset);
}
}
/*****************************************************************************/

@ -0,0 +1,93 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Stream abstraction to/from in-memory data.
*/
/*****************************************************************************/
#ifndef __dng_memory_stream__
#define __dng_memory_stream__
/*****************************************************************************/
#include "dng_stream.h"
/*****************************************************************************/
/// \brief A dng_stream which can be read from or written to memory.
///
/// Stream is populated via writing and either read or accessed by asking for contents as a pointer.
class dng_memory_stream: public dng_stream
{
protected:
dng_memory_allocator &fAllocator;
uint32 fPageSize;
uint32 fPageCount;
uint32 fPagesAllocated;
dng_memory_block **fPageList;
uint64 fMemoryStreamLength;
uint64 fLengthLimit;
public:
/// Construct a new memory-based stream.
/// \param allocator Allocator to use to allocate memory in stream as needed.
/// \param sniffer If non-NULL used to check for user cancellation.
/// \param pageSize Unit of allocation for data stored in stream.
dng_memory_stream (dng_memory_allocator &allocator,
dng_abort_sniffer *sniffer = NULL,
uint32 pageSize = 64 * 1024);
virtual ~dng_memory_stream ();
/// Sets a maximum length limit.
void SetLengthLimit (uint64 limit)
{
fLengthLimit = limit;
}
/// Copy a specified number of bytes to a target stream.
/// \param dstStream The target stream.
/// \param count The number of bytes to copy.
virtual void CopyToStream (dng_stream &dstStream,
uint64 count);
protected:
virtual uint64 DoGetLength ();
virtual void DoRead (void *data,
uint32 count,
uint64 offset);
virtual void DoSetLength (uint64 length);
virtual void DoWrite (const void *data,
uint32 count,
uint64 offset);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,445 @@
/*****************************************************************************/
// Copyright 2008-2019 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.
/*****************************************************************************/
/** \file
* Miscellaneous DNG opcodes.
*/
/*****************************************************************************/
#ifndef __dng_misc_opcodes__
#define __dng_misc_opcodes__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_opcodes.h"
/*****************************************************************************/
/// \brief Opcode to trim image to a specified rectangle.
class dng_opcode_TrimBounds: public dng_opcode
{
private:
dng_rect fBounds;
public:
/// Create opcode to trim image to the specified bounds.
dng_opcode_TrimBounds (const dng_rect &bounds);
dng_opcode_TrimBounds (dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual void Apply (dng_host &host,
dng_negative &negative,
AutoPtr<dng_image> &image);
};
/*****************************************************************************/
/// \brief A class to describe an area of an image, including a pixel subrectangle,
/// plane range, and row/column pitch (e.g., for mosaic images). Useful for
/// specifying opcodes that only apply to specific color planes or pixel types (e.g.,
/// only one of the two green Bayer pixels).
class dng_area_spec
{
public:
enum
{
kDataSize = 32
};
private:
dng_rect fArea;
uint32 fPlane;
uint32 fPlanes;
uint32 fRowPitch;
uint32 fColPitch;
public:
/// Create an empty area.
dng_area_spec (const dng_rect &area = dng_rect (),
uint32 plane = 0,
uint32 planes = 1,
uint32 rowPitch = 1,
uint32 colPitch = 1)
: fArea (area)
, fPlane (plane)
, fPlanes (planes)
, fRowPitch (rowPitch)
, fColPitch (colPitch)
{
}
/// The pixel area.
const dng_rect & Area () const
{
return fArea;
}
/// The first plane.
uint32 Plane () const
{
return fPlane;
}
/// The total number of planes.
uint32 Planes () const
{
return fPlanes;
}
/// The row pitch (i.e., stride). A pitch of 1 means all rows.
uint32 RowPitch () const
{
return fRowPitch;
}
/// The column pitch (i.e., stride). A pitch of 1 means all columns.
uint32 ColPitch () const
{
return fColPitch;
}
/// Read area data from the specified stream.
void GetData (dng_stream &stream);
/// Write area data to the specified stream.
void PutData (dng_stream &stream) const;
/// Compute and return pixel area overlap (i.e., intersection) between this
/// area and the specified tile.
dng_rect Overlap (const dng_rect &tile) const;
};
/*****************************************************************************/
/// \brief An opcode to apply a 1D function (represented as a 16-bit table) to an
/// image area.
class dng_opcode_MapTable: public dng_inplace_opcode
{
private:
dng_area_spec fAreaSpec;
AutoPtr<dng_memory_block> fTable;
uint32 fCount;
AutoPtr<dng_memory_block> fBlackAdjustedTable;
public:
/// Create a MapTable opcode with the specified area, table, and number of
/// table entries.
dng_opcode_MapTable (dng_host &host,
const dng_area_spec &areaSpec,
const uint16 *table,
uint32 count = 0x10000);
dng_opcode_MapTable (dng_host &host,
dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual uint32 BufferPixelType (uint32 imagePixelType);
virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
virtual void Prepare (dng_negative &negative,
uint32 threadCount,
const dng_point &tileSize,
const dng_rect &imageBounds,
uint32 imagePlanes,
uint32 bufferPixelType,
dng_memory_allocator &allocator);
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
private:
void ReplicateLastEntry ();
};
/*****************************************************************************/
/// \brief An opcode to apply a 1D function (represented as a polynomial) to an
/// image area.
class dng_opcode_MapPolynomial: public dng_inplace_opcode
{
public:
enum
{
kMaxDegree = 8
};
protected:
dng_area_spec fAreaSpec;
uint32 fDegree;
real64 fCoefficient [kMaxDegree + 1];
real32 fCoefficient32 [kMaxDegree + 1];
public:
/// Create a MapPolynomial opcode with the specified area, polynomial
/// degree, and polynomial coefficients. The function that will be
/// applied to each pixel x is:
///
/// f (x) = coefficient [0] + ((x * coefficient [1]) +
/// (x^2 * coefficient [2]) +
/// (x^3 * coefficient [3]) +
/// (x^4 * coefficient [4]) ...
dng_opcode_MapPolynomial (const dng_area_spec &areaSpec,
uint32 degree,
const real64 *coefficient);
dng_opcode_MapPolynomial (dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual uint32 BufferPixelType (uint32 imagePixelType);
virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
uint32 Degree () const
{
return fDegree;
}
const real64 * Coefficients () const
{
return fCoefficient;
}
protected:
virtual void DoProcess (dng_pixel_buffer &buffer,
const dng_rect &area,
const uint32 plane,
const uint32 rowPitch,
const uint32 colPitch,
const real32 *coefficients,
const uint32 degree,
uint16 blackLevel) const;
};
/*****************************************************************************/
/// \brief An opcode to apply a delta (i.e., offset) that varies per row. Within
/// a row, the same delta value is applied to all specified pixels.
class dng_opcode_DeltaPerRow: public dng_inplace_opcode
{
private:
dng_area_spec fAreaSpec;
AutoPtr<dng_memory_block> fTable;
real32 fScale;
public:
/// Create a DeltaPerRow opcode with the specified area and row deltas
/// (specified as a table of 32-bit floats).
dng_opcode_DeltaPerRow (const dng_area_spec &areaSpec,
AutoPtr<dng_memory_block> &table);
dng_opcode_DeltaPerRow (dng_host &host,
dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual uint32 BufferPixelType (uint32 imagePixelType);
virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
};
/*****************************************************************************/
/// \brief An opcode to apply a delta (i.e., offset) that varies per column.
/// Within a column, the same delta value is applied to all specified pixels.
class dng_opcode_DeltaPerColumn: public dng_inplace_opcode
{
private:
dng_area_spec fAreaSpec;
AutoPtr<dng_memory_block> fTable;
real32 fScale;
public:
/// Create a DeltaPerColumn opcode with the specified area and column
/// deltas (specified as a table of 32-bit floats).
dng_opcode_DeltaPerColumn (const dng_area_spec &areaSpec,
AutoPtr<dng_memory_block> &table);
dng_opcode_DeltaPerColumn (dng_host &host,
dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual uint32 BufferPixelType (uint32 imagePixelType);
virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
};
/*****************************************************************************/
/// \brief An opcode to apply a scale factor that varies per row. Within a row,
/// the same scale factor is applied to all specified pixels.
class dng_opcode_ScalePerRow: public dng_inplace_opcode
{
private:
dng_area_spec fAreaSpec;
AutoPtr<dng_memory_block> fTable;
public:
/// Create a ScalePerRow opcode with the specified area and row scale
/// factors (specified as a table of 32-bit floats).
dng_opcode_ScalePerRow (const dng_area_spec &areaSpec,
AutoPtr<dng_memory_block> &table);
dng_opcode_ScalePerRow (dng_host &host,
dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual uint32 BufferPixelType (uint32 imagePixelType);
virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
};
/*****************************************************************************/
/// \brief An opcode to apply a scale factor that varies per column. Within a
/// column, the same scale factor is applied to all specified pixels.
class dng_opcode_ScalePerColumn: public dng_inplace_opcode
{
private:
dng_area_spec fAreaSpec;
AutoPtr<dng_memory_block> fTable;
public:
/// Create a ScalePerColumn opcode with the specified area and column
/// scale factors (specified as a table of 32-bit floats).
dng_opcode_ScalePerColumn (const dng_area_spec &areaSpec,
AutoPtr<dng_memory_block> &table);
dng_opcode_ScalePerColumn (dng_host &host,
dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual uint32 BufferPixelType (uint32 imagePixelType);
virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,198 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Support for descriptive information about color filter array patterns.
*/
/*****************************************************************************/
#ifndef __dng_mosaic_info__
#define __dng_mosaic_info__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_rect.h"
#include "dng_sdk_limits.h"
#include "dng_types.h"
/*****************************************************************************/
/// \brief Support for describing color filter array patterns and manipulating mosaic sample data.
///
/// See CFAPattern tag in \ref spec_tiff_ep "TIFF/EP specification" and CFAPlaneColor, CFALayout, and BayerGreenSplit
/// tags in the \ref spec_dng "DNG 1.1.0 specification".
class dng_mosaic_info
{
public:
/// Size of fCFAPattern.
dng_point fCFAPatternSize;
/// CFA pattern from CFAPattern tag in the \ref spec_tiff_ep "TIFF/EP specification."
uint8 fCFAPattern [kMaxCFAPattern] [kMaxCFAPattern];
/// Number of color planes in DNG input.
uint32 fColorPlanes;
uint8 fCFAPlaneColor [kMaxColorPlanes];
/// Value of CFALayout tag in the \ref spec_dng "DNG 1.3 specification."
/// CFALayout describes the spatial layout of the CFA. The currently defined values are:
/// - 1 = Rectangular (or square) layout.
/// - 2 = Staggered layout A: even columns are offset down by 1/2 row.
/// - 3 = Staggered layout B: even columns are offset up by 1/2 row.
/// - 4 = Staggered layout C: even rows are offset right by 1/2 column.
/// - 5 = Staggered layout D: even rows are offset left by 1/2 column.
/// - 6 = Staggered layout E: even rows are offset up by 1/2 row, even columns are offset left by 1/2 column.
/// - 7 = Staggered layout F: even rows are offset up by 1/2 row, even columns are offset right by 1/2 column.
/// - 8 = Staggered layout G: even rows are offset down by 1/2 row, even columns are offset left by 1/2 column.
/// - 9 = Staggered layout H: even rows are offset down by 1/2 row, even columns are offset right by 1/2 column.
uint32 fCFALayout;
/// Value of BayerGreeSplit tag in DNG file.
/// BayerGreenSplit only applies to CFA images using a Bayer pattern filter array. This tag
/// specifies, in arbitrary units, how closely the values of the green pixels in the blue/green rows
/// track the values of the green pixels in the red/green rows.
///
/// A value of zero means the two kinds of green pixels track closely, while a non-zero value
/// means they sometimes diverge. The useful range for this tag is from 0 (no divergence) to about
/// 5000 (large divergence).
uint32 fBayerGreenSplit;
protected:
dng_point fSrcSize;
dng_point fCroppedSize;
real64 fAspectRatio;
public:
dng_mosaic_info ();
virtual ~dng_mosaic_info ();
virtual void Parse (dng_host &host,
dng_stream &stream,
dng_info &info);
virtual void PostParse (dng_host &host,
dng_negative &negative);
/// Returns whether the RAW data in this DNG file from a color filter array (mosaiced) source.
/// \retval true if this DNG file is from a color filter array (mosiaced) source.
bool IsColorFilterArray () const
{
return fCFAPatternSize != dng_point (0, 0);
}
/// Enable generating four-plane output from three-plane Bayer input.
/// Extra plane is a second version of the green channel. First green is produced
/// using green mosaic samples from one set of rows/columns (even/odd) and the second
/// green channel is produced using the other set of rows/columns. One can compare the
/// two versions to judge whether BayerGreenSplit needs to be set for a given input source.
virtual bool SetFourColorBayer ();
/// Returns scaling factor relative to input size needed to capture output data.
/// Staggered (or rotated) sensing arrays are produced to a larger output than the number of input samples.
/// This method indicates how much larger.
/// \retval a point with integer scaling factors for the horizotal and vertical dimensions.
virtual dng_point FullScale () const;
/// Returns integer factors by which mosaic data must be downsampled to produce an image which is as close
/// to prefSize as possible in longer dimension, but no smaller than minSize.
/// \param minSize Number of pixels as minium for longer dimension of downsampled image.
/// \param prefSize Number of pixels as target for longer dimension of downsampled image.
/// \param cropFactor Faction of the image to be used after cropping.
/// \retval Point containing integer factors by which image must be downsampled.
virtual dng_point DownScale (uint32 minSize,
uint32 prefSize,
real64 cropFactor) const;
/// Return size of demosaiced image for passed in downscaling factor.
/// \param downScale Integer downsampling factor obtained from DownScale method.
/// \retval Size of resulting demosaiced image.
virtual dng_point DstSize (const dng_point &downScale) const;
/// Demosaic interpolation of a single plane for non-downsampled case.
/// \param host dng_host to use for buffer allocation requests, user cancellation testing, and progress updates.
/// \param negative DNG negative of mosaiced data.
/// \param srcImage Source image for mosaiced data.
/// \param dstImage Destination image for resulting interpolated data.
/// \param srcPlane Which plane to interpolate.
virtual void InterpolateGeneric (dng_host &host,
dng_negative &negative,
const dng_image &srcImage,
dng_image &dstImage,
uint32 srcPlane = 0) const;
/// Demosaic interpolation of a single plane for downsampled case.
/// \param host dng_host to use for buffer allocation requests, user cancellation testing, and progress updates.
/// \param negative DNG negative of mosaiced data.
/// \param srcImage Source image for mosaiced data.
/// \param dstImage Destination image for resulting interpolated data.
/// \param downScale Amount (in horizontal and vertical) by which to subsample image.
/// \param srcPlane Which plane to interpolate.
virtual void InterpolateFast (dng_host &host,
dng_negative &negative,
const dng_image &srcImage,
dng_image &dstImage,
const dng_point &downScale,
uint32 srcPlane = 0) const;
/// Demosaic interpolation of a single plane. Chooses between generic and fast interpolators based on parameters.
/// \param host dng_host to use for buffer allocation requests, user cancellation testing, and progress updates.
/// \param negative DNG negative of mosaiced data.
/// \param srcImage Source image for mosaiced data.
/// \param dstImage Destination image for resulting interpolated data.
/// \param downScale Amount (in horizontal and vertical) by which to subsample image.
/// \param srcPlane Which plane to interpolate.
virtual void Interpolate (dng_host &host,
dng_negative &negative,
const dng_image &srcImage,
dng_image &dstImage,
const dng_point &downScale,
uint32 srcPlane = 0,
dng_matrix *scaleTransforms = NULL) const;
virtual bool SupportsPreservedBlackLevels () const;
protected:
virtual bool IsSafeDownScale (const dng_point &downScale) const;
uint32 SizeForDownScale (const dng_point &downScale) const;
virtual bool ValidSizeDownScale (const dng_point &downScale,
uint32 minSize) const;
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,516 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_abort_sniffer.h"
#include "dng_mutex.h"
#include "dng_assertions.h"
#include "dng_exceptions.h"
#include <stdlib.h>
/*****************************************************************************/
// do mutex lock level tracking, asserts stripped in non-debug so don't track there
#ifndef qDNGThreadTestMutexLevels
#define qDNGThreadTestMutexLevels (qDNGThreadSafe && qDNGDebug)
#endif
#if qDNGThreadTestMutexLevels
namespace
{
class InnermostMutexHolder
{
private:
pthread_key_t fInnermostMutexKey;
public:
InnermostMutexHolder ()
: fInnermostMutexKey ()
{
int result = pthread_key_create (&fInnermostMutexKey, NULL);
DNG_ASSERT (result == 0, "pthread_key_create failed.");
if (result != 0)
ThrowProgramError ();
}
~InnermostMutexHolder ()
{
pthread_key_delete (fInnermostMutexKey);
}
void SetInnermostMutex (dng_mutex *mutex)
{
int result;
result = pthread_setspecific (fInnermostMutexKey, (void *)mutex);
DNG_ASSERT (result == 0, "pthread_setspecific failed.");
(void) result;
#if 0 // Hard failure here was causing crash on quit.
if (result != 0)
ThrowProgramError ();
#endif
}
dng_mutex *GetInnermostMutex ()
{
void *result = pthread_getspecific (fInnermostMutexKey);
return reinterpret_cast<dng_mutex *> (result);
}
};
InnermostMutexHolder gInnermostMutexHolder;
}
#endif
/*****************************************************************************/
dng_mutex::dng_mutex (const char *mutexName, uint32 mutexLevel)
#if qDNGThreadSafe
: fPthreadMutex ()
, fMutexLevel (mutexLevel)
, fRecursiveLockCount (0)
, fPrevHeldMutex (NULL)
, fMutexName (mutexName)
#endif
{
#if qDNGThreadSafe
#if qWinOS
// Win is already a recursive mutex by default
if (pthread_mutex_init (&fPthreadMutex, NULL) != 0)
{
ThrowMemoryFull ();
}
#else
// make recursive mutex, can lock within itself
pthread_mutexattr_t mta;
pthread_mutexattr_init(&mta);
pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
if (pthread_mutex_init (&fPthreadMutex, &mta) != 0)
{
ThrowMemoryFull ();
}
#endif
#endif
}
/*****************************************************************************/
dng_mutex::~dng_mutex ()
{
#if qDNGThreadSafe
pthread_mutex_destroy (&fPthreadMutex);
#endif
}
/*****************************************************************************/
void dng_mutex::Lock ()
{
#if qDNGThreadSafe
#if qDNGThreadTestMutexLevels
dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex ();
if (innermostMutex != NULL)
{
if (innermostMutex == this)
{
int result = pthread_mutex_lock (&fPthreadMutex);
if (result != 0)
{
DNG_ASSERT (result == 0, "pthread_mutex_lock failed.");
ThrowProgramError ();
}
fRecursiveLockCount++;
return;
}
bool lockOrderPreserved = fMutexLevel > innermostMutex->fMutexLevel;
// to allow cloning of class internals both with a dng_mutex and get closer to the C++ mutex,
// test for MutexLevelIgnore and don't generate level violations
if (!lockOrderPreserved)
{
if ((fMutexLevel == kDNGMutexLevelIgnore) || (innermostMutex->fMutexLevel == kDNGMutexLevelIgnore))
lockOrderPreserved = true;
}
if (!lockOrderPreserved)
{
char msg[1024];
sprintf(msg,
"Lock order violation: This mutex: %s v Innermost mutex: %s",
this->MutexName (),
innermostMutex->MutexName ());
DNG_REPORT(msg); // asserts inside of mutex lock, any locks within that must be lower
}
}
int result = pthread_mutex_lock (&fPthreadMutex);
if (result != 0)
{
DNG_ASSERT (result == 0, "pthread_mutex_lock failed.");
ThrowProgramError ();
}
fPrevHeldMutex = innermostMutex;
gInnermostMutexHolder.SetInnermostMutex (this);
#else
// Register the fact that we're trying to lock this mutex.
int result = pthread_mutex_lock (&fPthreadMutex);
if (result != 0)
{
DNG_REPORT ("pthread_mutex_lock failed");
ThrowProgramError ();
}
// Register the fact that we've now successfully acquired the mutex.
#endif
#endif
}
/*****************************************************************************/
void dng_mutex::Unlock ()
{
#if qDNGThreadSafe
#if qDNGThreadTestMutexLevels
DNG_ASSERT (gInnermostMutexHolder.GetInnermostMutex () == this, "Mutexes unlocked out of order!!!");
if (fRecursiveLockCount > 0)
{
fRecursiveLockCount--;
pthread_mutex_unlock (&fPthreadMutex);
return;
}
gInnermostMutexHolder.SetInnermostMutex (fPrevHeldMutex);
fPrevHeldMutex = NULL;
#endif
pthread_mutex_unlock (&fPthreadMutex);
#endif
}
/*****************************************************************************/
const char *dng_mutex::MutexName () const
{
#if qDNGThreadSafe
if (fMutexName)
return fMutexName;
#endif
return "< unknown >";
}
/*****************************************************************************/
dng_lock_mutex::dng_lock_mutex (dng_mutex *mutex)
: fMutex (mutex)
{
if (fMutex)
fMutex->Lock ();
}
/*****************************************************************************/
dng_lock_mutex::dng_lock_mutex (dng_mutex &mutex)
: fMutex (&mutex)
{
if (fMutex)
fMutex->Lock ();
}
/*****************************************************************************/
dng_lock_mutex::~dng_lock_mutex ()
{
if (fMutex)
fMutex->Unlock ();
}
/*****************************************************************************/
dng_unlock_mutex::dng_unlock_mutex (dng_mutex *mutex)
: fMutex (mutex)
{
if (fMutex)
fMutex->Unlock ();
}
/*****************************************************************************/
dng_unlock_mutex::dng_unlock_mutex (dng_mutex &mutex)
: fMutex (&mutex)
{
if (fMutex)
fMutex->Unlock ();
}
/*****************************************************************************/
dng_unlock_mutex::~dng_unlock_mutex ()
{
if (fMutex)
fMutex->Lock ();
}
/*****************************************************************************/
dng_condition::dng_condition ()
#if qDNGThreadSafe
: fPthreadCondition ()
#endif
{
#if qDNGThreadSafe
int result;
result = pthread_cond_init (&fPthreadCondition, NULL);
DNG_ASSERT (result == 0, "pthread_cond_init failed.");
if (result != 0)
{
ThrowProgramError ();
}
#endif
}
/*****************************************************************************/
dng_condition::~dng_condition ()
{
#if qDNGThreadSafe
pthread_cond_destroy (&fPthreadCondition);
#endif
}
/*****************************************************************************/
bool dng_condition::Wait (dng_mutex &mutex, double timeoutSecs)
{
#if qDNGThreadSafe
bool timedOut = false;
#if qDNGThreadTestMutexLevels
dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex ();
DNG_ASSERT (innermostMutex == &mutex, "Attempt to wait on non-innermost mutex.");
(void) innermostMutex;
innermostMutex = mutex.fPrevHeldMutex;
gInnermostMutexHolder.SetInnermostMutex (innermostMutex);
mutex.fPrevHeldMutex = NULL;
#endif
if (timeoutSecs < 0)
{
pthread_cond_wait (&fPthreadCondition, &mutex.fPthreadMutex);
}
else
{
struct timespec now;
dng_pthread_now (&now);
timeoutSecs += now.tv_sec;
timeoutSecs += now.tv_nsec / 1000000000.0;
now.tv_sec = (long) timeoutSecs;
now.tv_nsec = (long) ((timeoutSecs - now.tv_sec) * 1000000000);
#if defined(_MSC_VER) && _MSC_VER >= 1900
struct dng_timespec tempNow;
tempNow.tv_sec = (long) now.tv_sec;
tempNow.tv_nsec = now.tv_nsec;
timedOut = (pthread_cond_timedwait (&fPthreadCondition, &mutex.fPthreadMutex, &tempNow) == ETIMEDOUT);
#else
timedOut = (pthread_cond_timedwait (&fPthreadCondition, &mutex.fPthreadMutex, &now) == ETIMEDOUT);
#endif
}
#if qDNGThreadTestMutexLevels
mutex.fPrevHeldMutex = innermostMutex;
gInnermostMutexHolder.SetInnermostMutex (&mutex);
#endif
return !timedOut;
#else
return true;
#endif
}
/*****************************************************************************/
void dng_condition::Signal ()
{
#if qDNGThreadSafe
int result;
result = pthread_cond_signal (&fPthreadCondition);
DNG_ASSERT (result == 0, "pthread_cond_signal failed.");
if (result != 0)
ThrowProgramError ();
#endif
}
/*****************************************************************************/
void dng_condition::Broadcast ()
{
#if qDNGThreadSafe
int result;
result = pthread_cond_broadcast (&fPthreadCondition);
DNG_ASSERT (result == 0, "pthread_cond_broadcast failed.");
if (result != 0)
ThrowProgramError ();
#endif
}
/*****************************************************************************/

@ -0,0 +1,145 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#ifndef DNG_MUTEX
#define DNG_MUTEX
/******************************************************************************/
#include "dng_flags.h"
#include "dng_types.h"
#include "dng_uncopyable.h"
#if qDNGThreadSafe
#include "dng_pthread.h"
#endif
#include <mutex>
typedef std::mutex dng_std_mutex;
typedef std::lock_guard<std::mutex> dng_lock_std_mutex;
typedef std::unique_lock<std::mutex> dng_unique_lock;
// We should try to phase out use of dng_mutex over time.
//
// Note that dng_mutex differs from dng_std_mutex (std::mutex) in that
// dng_mutex supports recursive locking (hierarchical mutex).
/******************************************************************************/
class dng_mutex: private dng_uncopyable
{
public:
enum
{
kDNGMutexLevelLeaf = 0x70000000u,
kDNGMutexLevelIgnore = 0x7FFFFFFFu
};
dng_mutex (const char *mutexName,
uint32 mutexLevel = kDNGMutexLevelLeaf);
virtual ~dng_mutex ();
void Lock ();
void Unlock ();
const char *MutexName () const;
protected:
#if qDNGThreadSafe
pthread_mutex_t fPthreadMutex;
const uint32 fMutexLevel;
uint32 fRecursiveLockCount;
dng_mutex *fPrevHeldMutex;
const char * const fMutexName;
friend class dng_condition;
#endif
};
/*****************************************************************************/
class dng_lock_mutex: private dng_uncopyable
{
private:
dng_mutex *fMutex;
public:
dng_lock_mutex (dng_mutex *mutex);
dng_lock_mutex (dng_mutex &mutex);
~dng_lock_mutex ();
};
/*****************************************************************************/
class dng_unlock_mutex: private dng_uncopyable
{
private:
dng_mutex *fMutex;
public:
dng_unlock_mutex (dng_mutex *mutex);
dng_unlock_mutex (dng_mutex &mutex);
~dng_unlock_mutex ();
};
/*****************************************************************************/
class dng_condition: private dng_uncopyable
{
public:
dng_condition ();
~dng_condition ();
bool Wait (dng_mutex &mutex, double timeoutSecs = -1.0);
void Signal ();
void Broadcast ();
protected:
#if qDNGThreadSafe
pthread_cond_t fPthreadCondition;
#endif // qDNGThreadSafe
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,272 @@
/*****************************************************************************/
// Copyright 2008-2019 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.
/*****************************************************************************/
#include "dng_opcode_list.h"
#include "dng_globals.h"
#include "dng_host.h"
#include "dng_memory_stream.h"
#include "dng_negative.h"
#include "dng_tag_values.h"
#include "dng_utils.h"
#include <algorithm>
/*****************************************************************************/
dng_opcode_list::dng_opcode_list (uint32 stage)
: fList ()
, fAlwaysApply (false)
, fStage (stage)
{
}
/******************************************************************************/
dng_opcode_list::~dng_opcode_list ()
{
Clear ();
}
/******************************************************************************/
void dng_opcode_list::Clear ()
{
for (size_t index = 0; index < fList.size (); index++)
{
if (fList [index])
{
delete fList [index];
fList [index] = NULL;
}
}
fList.clear ();
fAlwaysApply = false;
}
/******************************************************************************/
void dng_opcode_list::Swap (dng_opcode_list &otherList)
{
fList.swap (otherList.fList);
std::swap (fAlwaysApply, otherList.fAlwaysApply);
std::swap (fStage, otherList.fStage);
}
/******************************************************************************/
uint32 dng_opcode_list::MinVersion (bool includeOptional) const
{
uint32 result = dngVersion_None;
for (size_t index = 0; index < fList.size (); index++)
{
if (includeOptional || !fList [index]->Optional ())
{
result = Max_uint32 (result, fList [index]->MinVersion ());
}
}
return result;
}
/*****************************************************************************/
void dng_opcode_list::Apply (dng_host &host,
dng_negative &negative,
AutoPtr<dng_image> &image)
{
DNG_REQUIRE (image.Get (), "Bad image in dng_opcode_list::Apply");
for (uint32 index = 0; index < Count (); index++)
{
dng_opcode &opcode (Entry (index));
if (opcode.AboutToApply (host,
negative,
image->Bounds (),
image->Planes ()))
{
opcode.Apply (host,
negative,
image);
}
}
}
/*****************************************************************************/
void dng_opcode_list::Append (AutoPtr<dng_opcode> &opcode)
{
if (opcode->OpcodeID () == dngOpcode_Private)
{
SetAlwaysApply ();
}
opcode->SetStage (fStage);
fList.push_back (NULL);
fList [fList.size () - 1] = opcode.Release ();
}
/*****************************************************************************/
dng_memory_block * dng_opcode_list::Spool (dng_host &host) const
{
if (IsEmpty ())
{
return NULL;
}
if (AlwaysApply ())
{
ThrowProgramError ();
}
dng_memory_stream stream (host.Allocator ());
stream.SetBigEndian ();
stream.Put_uint32 ((uint32) fList.size ());
for (size_t index = 0; index < fList.size (); index++)
{
stream.Put_uint32 (fList [index]->OpcodeID ());
stream.Put_uint32 (fList [index]->MinVersion ());
stream.Put_uint32 (fList [index]->Flags ());
fList [index]->PutData (stream);
}
return stream.AsMemoryBlock (host.Allocator ());
}
/*****************************************************************************/
void dng_opcode_list::FingerprintToStream (dng_stream &stream) const
{
if (IsEmpty ())
{
return;
}
stream.Put_uint32 ((uint32) fList.size ());
for (size_t index = 0; index < fList.size (); index++)
{
stream.Put_uint32 (fList [index]->OpcodeID ());
stream.Put_uint32 (fList [index]->MinVersion ());
stream.Put_uint32 (fList [index]->Flags ());
if (fList [index]->OpcodeID () != dngOpcode_Private)
{
fList [index]->PutData (stream);
}
}
}
/*****************************************************************************/
void dng_opcode_list::Parse (dng_host &host,
dng_stream &stream,
uint32 byteCount,
uint64 streamOffset)
{
Clear ();
TempBigEndian tempBigEndian (stream);
stream.SetReadPosition (streamOffset);
uint32 count = stream.Get_uint32 ();
#if qDNGValidate
if (gVerbose)
{
if (count == 1)
{
printf ("1 opcode\n");
}
else
{
printf ("%u opcodes\n", (unsigned) count);
}
}
#endif
for (uint32 index = 0; index < count; index++)
{
uint32 opcodeID = stream.Get_uint32 ();
AutoPtr<dng_opcode> opcode (host.Make_dng_opcode (opcodeID,
stream));
Append (opcode);
}
if (stream.Position () != streamOffset + byteCount)
{
ThrowBadFormat ("Error parsing opcode list");
}
}
/*****************************************************************************/

@ -0,0 +1,153 @@
/*****************************************************************************/
// Copyright 2008-2019 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.
/*****************************************************************************/
/** \file
* List of opcodes.
*/
/*****************************************************************************/
#ifndef __dng_opcode_list__
#define __dng_opcode_list__
/*****************************************************************************/
#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_opcodes.h"
#include "dng_uncopyable.h"
#include <vector>
/*****************************************************************************/
/// A list of opcodes.
class dng_opcode_list: private dng_uncopyable
{
private:
dng_std_vector<dng_opcode *> fList;
bool fAlwaysApply;
uint32 fStage;
public:
/// Create an empty opcode list for the specific image stage (1, 2, or 3).
dng_opcode_list (uint32 stage);
~dng_opcode_list ();
/// Is the opcode list empty?
bool IsEmpty () const
{
return fList.size () == 0;
}
/// Does the list contain at least 1 opcode?
bool NotEmpty () const
{
return !IsEmpty ();
}
/// Should the opcode list always be applied to the image?
bool AlwaysApply () const
{
return fAlwaysApply && NotEmpty ();
}
/// Set internal flag to indicate this opcode list should always be
/// applied.
void SetAlwaysApply ()
{
fAlwaysApply = true;
}
/// The number of opcodes in this list.
uint32 Count () const
{
return (uint32) fList.size ();
}
/// Retrieve read/write opcode by index (must be in the range 0 to Count
/// () - 1).
dng_opcode & Entry (uint32 index)
{
return *fList [index];
}
/// Retrieve read-only opcode by index (must be in the range 0 to Count
/// () - 1).
const dng_opcode & Entry (uint32 index) const
{
return *fList [index];
}
/// Remove all opcodes from the list.
void Clear ();
/// Swap two opcode lists.
void Swap (dng_opcode_list &otherList);
/// Return minimum DNG version required to support all opcodes in this
/// list. If includeOptional is set to true, then this calculation will
/// include optional opcodes.
uint32 MinVersion (bool includeOptional) const;
/// Apply this opcode list to the specified image with corresponding
/// negative.
void Apply (dng_host &host,
dng_negative &negative,
AutoPtr<dng_image> &image);
/// Append the specified opcode to this list.
void Append (AutoPtr<dng_opcode> &opcode);
/// Serialize this opcode list to a block of memory. The caller is
/// responsible for deleting this block.
dng_memory_block * Spool (dng_host &host) const;
/// Write a fingerprint of this opcode list to the specified stream.
void FingerprintToStream (dng_stream &stream) const;
/// Read an opcode list from the specified stream, starting at the
/// specified offset (streamOffset, in bytes). byteCount is provided for
/// error checking purposes. A bad format exception
/// will be thrown if the length of the opcode stream does not exactly
/// match byteCount.
void Parse (dng_host &host,
dng_stream &stream,
uint32 byteCount,
uint64 streamOffset);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,563 @@
/*****************************************************************************/
// Copyright 2008-2019 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.
/*****************************************************************************/
#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,
const dng_rect &imageBounds,
uint32 imagePlanes)
{
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 ())
{
DoAboutToApply (host,
negative,
imageBounds,
imagePlanes);
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 ("dng_filter_opcode_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_rect &dstArea,
const dng_point &tileSize,
dng_memory_allocator *allocator,
dng_abort_sniffer *sniffer)
{
dng_filter_task::Start (threadCount,
dstArea,
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 ("dng_inplace_opcode_task")
, fOpcode (opcode)
, fNegative (negative)
, fImage (image)
, fPixelType (opcode.BufferPixelType (image.PixelType ()))
{
}
virtual void Start (uint32 threadCount,
const dng_rect & /* dstArea */,
const dng_point &tileSize,
dng_memory_allocator *allocator,
dng_abort_sniffer * /* sniffer */)
{
uint32 bufferSize = ComputeBufferSize (fPixelType,
tileSize,
fImage.Planes (),
padSIMDBytes);
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,
pcRowInterleavedAlignSIMD,
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);
}
}
/*****************************************************************************/

@ -0,0 +1,523 @@
/*****************************************************************************/
// Copyright 2008-2019 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.
/*****************************************************************************/
/** \file
* Base class and common data structures for opcodes (introduced in DNG 1.3).
*/
/*****************************************************************************/
#ifndef __dng_opcodes__
#define __dng_opcodes__
/*****************************************************************************/
#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_rect.h"
#include "dng_types.h"
/*****************************************************************************/
/// \brief List of supported opcodes (by ID).
enum dng_opcode_id
{
// Internal use only opcode. Never written to DNGs.
dngOpcode_Private = 0,
// Warp image to correct distortion and lateral chromatic aberration for
// rectilinear lenses.
dngOpcode_WarpRectilinear = 1,
// Warp image to correction distortion for fisheye lenses (i.e., map the
// fisheye projection to a perspective projection).
dngOpcode_WarpFisheye = 2,
// Radial vignette correction.
dngOpcode_FixVignetteRadial = 3,
// Patch bad Bayer pixels which are marked with a special value in the image.
dngOpcode_FixBadPixelsConstant = 4,
// Patch bad Bayer pixels/rectangles at a list of specified coordinates.
dngOpcode_FixBadPixelsList = 5,
// Trim image to specified bounds.
dngOpcode_TrimBounds = 6,
// Map an area through a 16-bit LUT.
dngOpcode_MapTable = 7,
// Map an area using a polynomial function.
dngOpcode_MapPolynomial = 8,
// Apply a gain map to an area.
dngOpcode_GainMap = 9,
// Apply a per-row delta to an area.
dngOpcode_DeltaPerRow = 10,
// Apply a per-column delta to an area.
dngOpcode_DeltaPerColumn = 11,
// Apply a per-row scale to an area.
dngOpcode_ScalePerRow = 12,
// Apply a per-column scale to an area.
dngOpcode_ScalePerColumn = 13
};
/*****************************************************************************/
/// \brief Virtual base class for opcode.
class dng_opcode
{
public:
/// Opcode flags.
enum
{
kFlag_None = 0, //!< No flag.
kFlag_Optional = 1, //!< This opcode is optional.
kFlag_SkipIfPreview = 2 //!< May skip opcode for preview images.
};
private:
uint32 fOpcodeID;
uint32 fMinVersion;
uint32 fFlags;
bool fWasReadFromStream;
uint32 fStage;
protected:
dng_opcode (uint32 opcodeID,
uint32 minVersion,
uint32 flags);
dng_opcode (uint32 opcodeID,
dng_stream &stream,
const char *name);
// This helper routine will be called by AboutToApply if AboutToApply
// passes its internal checking and plans to return true. This is an
// opportunity for subclasses to perform some internal preparation
// based on the negative, image bounds, and number of image planes.
virtual void DoAboutToApply (dng_host & /* host */,
dng_negative & /* negative */,
const dng_rect & /* imageBounds */,
uint32 /* imagePlanes */)
{
}
public:
virtual ~dng_opcode ();
/// The ID of this opcode.
uint32 OpcodeID () const
{
return fOpcodeID;
}
/// The first DNG version that supports this opcode.
uint32 MinVersion () const
{
return fMinVersion;
}
/// The flags for this opcode.
uint32 Flags () const
{
return fFlags;
}
/// Is this opcode optional?
bool Optional () const
{
return (Flags () & kFlag_Optional) != 0;
}
/// Should the opcode be skipped when rendering preview images?
bool SkipIfPreview () const
{
return (Flags () & kFlag_SkipIfPreview) != 0;
}
/// Was this opcode read from a data stream?
bool WasReadFromStream () const
{
return fWasReadFromStream;
}
/// Which image processing stage (1, 2, 3) is associated with this
/// opcode?
uint32 Stage () const
{
return fStage;
}
/// Set the image processing stage (1, 2, 3) for this opcode. Stage 1 is
/// the original image data, including masked areas. Stage 2 is
/// linearized image data and trimmed to the active area. Stage 3 is
/// demosaiced and trimmed to the active area.
void SetStage (uint32 stage)
{
fStage = stage;
}
/// Is the opcode a NOP (i.e., does nothing)? An opcode could be a NOP
/// for some specific parameters.
virtual bool IsNOP () const
{
return false;
}
/// Is this opcode valid for the specified negative?
virtual bool IsValidForNegative (const dng_negative & /* negative */) const
{
return true;
}
/// Write opcode to a stream.
/// \param stream The stream to which to write the opcode data.
virtual void PutData (dng_stream &stream) const;
/// Perform error checking prior to applying this opcode to the
/// specified negative. Returns true if this opcode should be applied to
/// the negative, false otherwise.
bool AboutToApply (dng_host &host,
dng_negative &negative,
const dng_rect &imageBounds,
uint32 imagePlanes);
/// Apply this opcode to the specified image with associated negative.
virtual void Apply (dng_host &host,
dng_negative &negative,
AutoPtr<dng_image> &image) = 0;
};
/*****************************************************************************/
/// \brief Class to represent unknown opcodes (e.g, opcodes defined in future
/// DNG versions).
class dng_opcode_Unknown: public dng_opcode
{
private:
AutoPtr<dng_memory_block> fData;
public:
dng_opcode_Unknown (dng_host &host,
uint32 opcodeID,
dng_stream &stream);
virtual void PutData (dng_stream &stream) const;
virtual void Apply (dng_host &host,
dng_negative &negative,
AutoPtr<dng_image> &image);
};
/*****************************************************************************/
/// \brief Class to represent a filter opcode, such as a convolution.
class dng_filter_opcode: public dng_opcode
{
protected:
dng_filter_opcode (uint32 opcodeID,
uint32 minVersion,
uint32 flags);
dng_filter_opcode (uint32 opcodeID,
dng_stream &stream,
const char *name);
public:
/// The pixel data type of this opcode.
virtual uint32 BufferPixelType (uint32 imagePixelType)
{
return imagePixelType;
}
/// The adjusted bounds (processing area) of this opcode. It is limited to
/// the intersection of the specified image area and the GainMap area.
virtual dng_rect ModifiedBounds (const dng_rect &imageBounds)
{
return imageBounds;
}
/// Returns the width and height (in pixels) of the repeating mosaic pattern.
virtual dng_point SrcRepeat ()
{
return dng_point (1, 1);
}
/// Returns the source pixel area needed to process a destination pixel area
/// that lies within the specified bounds.
/// \param dstArea The destination pixel area to be computed.
/// \param imageBounds The overall image area (dstArea will lie within these
/// bounds).
/// \retval The source pixel area needed to process the specified dstArea.
virtual dng_rect SrcArea (const dng_rect &dstArea,
const dng_rect &imageBounds)
{
(void) imageBounds;
return dstArea;
}
/// Given a destination tile size, calculate input tile size. Simlar to
/// SrcArea, and should seldom be overridden.
///
/// \param dstTileSize The destination tile size that is targeted for output.
///
/// \param imageBounds The image bounds (the destination tile will
/// always lie within these bounds).
///
/// \retval The source tile size needed to compute a tile of the destination
/// size.
virtual dng_point SrcTileSize (const dng_point &dstTileSize,
const dng_rect &imageBounds)
{
return SrcArea (dng_rect (dstTileSize),
imageBounds).Size ();
}
/// Startup method called before any processing is performed on pixel areas.
/// It can be used to allocate (per-thread) memory and setup tasks.
///
/// \param negative The negative object to be processed.
///
/// \param threadCount Total number of threads that will be used for
/// processing. Less than or equal to MaxThreads.
///
/// \param tileSize Size of source tiles which will be processed. (Not all
/// tiles will be this size due to edge conditions.)
///
/// \param imageBounds Total size of image to be processed.
///
/// \param imagePlanes Number of planes in the image. Less than or equal to
/// kMaxColorPlanes.
///
/// \param bufferPixelType Pixel type of image buffer (see dng_tag_types.h).
///
/// \param allocator dng_memory_allocator to use for allocating temporary
/// buffers, etc.
virtual void Prepare (dng_negative &negative,
uint32 threadCount,
const dng_point &tileSize,
const dng_rect &imageBounds,
uint32 imagePlanes,
uint32 bufferPixelType,
dng_memory_allocator &allocator)
{
(void) negative;
(void) threadCount;
(void) tileSize;
(void) imageBounds;
(void) imagePlanes;
(void) bufferPixelType;
(void) allocator;
}
/// Implements filtering operation from one buffer to another. Source
/// and destination pixels are set up in member fields of this class.
/// Ideally, no allocation should be done in this routine.
///
/// \param negative The negative associated with the pixels to be
/// processed.
///
/// \param threadIndex The thread on which this routine is being called,
/// between 0 and threadCount - 1 for the threadCount passed to Prepare
/// method.
///
/// \param srcBuffer Input area and source pixels.
///
/// \param dstBuffer Destination pixels.
///
/// \param dstArea Destination pixel processing area.
///
/// \param imageBounds Total image area to be processed; dstArea will
/// always lie within these bounds.
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &srcBuffer,
dng_pixel_buffer &dstBuffer,
const dng_rect &dstArea,
const dng_rect &imageBounds) = 0;
virtual void Apply (dng_host &host,
dng_negative &negative,
AutoPtr<dng_image> &image);
};
/*****************************************************************************/
/// \brief Class to represent an in-place (i.e., pointwise, per-pixel) opcode,
/// such as a global tone curve.
class dng_inplace_opcode: public dng_opcode
{
protected:
dng_inplace_opcode (uint32 opcodeID,
uint32 minVersion,
uint32 flags);
dng_inplace_opcode (uint32 opcodeID,
dng_stream &stream,
const char *name);
public:
/// The pixel data type of this opcode.
virtual uint32 BufferPixelType (uint32 imagePixelType)
{
return imagePixelType;
}
/// The adjusted bounds (processing area) of this opcode. It is limited to
/// the intersection of the specified image area and the GainMap area.
virtual dng_rect ModifiedBounds (const dng_rect &imageBounds)
{
return imageBounds;
}
/// Startup method called before any processing is performed on pixel areas.
/// It can be used to allocate (per-thread) memory and setup tasks.
///
/// \param negative The negative object to be processed.
///
/// \param threadCount Total number of threads that will be used for
/// processing. Less than or equal to MaxThreads.
///
/// \param tileSize Size of source tiles which will be processed. (Not all
/// tiles will be this size due to edge conditions.)
///
/// \param imageBounds Total size of image to be processed.
///
/// \param imagePlanes Number of planes in the image. Less than or equal to
/// kMaxColorPlanes.
///
/// \param bufferPixelType Pixel type of image buffer (see dng_tag_types.h).
///
/// \param allocator dng_memory_allocator to use for allocating temporary
/// buffers, etc.
virtual void Prepare (dng_negative &negative,
uint32 threadCount,
const dng_point &tileSize,
const dng_rect &imageBounds,
uint32 imagePlanes,
uint32 bufferPixelType,
dng_memory_allocator &allocator)
{
(void) negative;
(void) threadCount;
(void) tileSize;
(void) imageBounds;
(void) imagePlanes;
(void) bufferPixelType;
(void) allocator;
}
/// Implements image processing operation in a single buffer. The source
/// pixels are provided as input to the buffer, and this routine
/// calculates and writes the destination pixels to the same buffer.
/// Ideally, no allocation should be done in this routine.
///
/// \param negative The negative associated with the pixels to be
/// processed.
///
/// \param threadIndex The thread on which this routine is being called,
/// between 0 and threadCount - 1 for the threadCount passed to Prepare
/// method.
///
/// \param buffer Source and Destination pixels.
///
/// \param dstArea Destination pixel processing area.
///
/// \param imageBounds Total image area to be processed; dstArea will
/// always lie within these bounds.
virtual void ProcessArea (dng_negative &negative,
uint32 threadIndex,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect &imageBounds) = 0;
virtual void Apply (dng_host &host,
dng_negative &negative,
AutoPtr<dng_image> &image);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,391 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_orientation.h"
/*****************************************************************************/
void dng_orientation::SetTIFF (uint32 tiff)
{
switch (tiff)
{
case 1:
{
fAdobeOrientation = kNormal;
break;
}
case 2:
{
fAdobeOrientation = kMirror;
break;
}
case 3:
{
fAdobeOrientation = kRotate180;
break;
}
case 4:
{
fAdobeOrientation = kMirror180;
break;
}
case 5:
{
fAdobeOrientation = kMirror90CCW;
break;
}
case 6:
{
fAdobeOrientation = kRotate90CW;
break;
}
case 7:
{
fAdobeOrientation = kMirror90CW;
break;
}
case 8:
{
fAdobeOrientation = kRotate90CCW;
break;
}
case 9:
{
fAdobeOrientation = kUnknown;
break;
}
default:
{
fAdobeOrientation = kNormal;
}
}
}
/*****************************************************************************/
uint32 dng_orientation::GetTIFF () const
{
switch (fAdobeOrientation)
{
case kNormal:
{
return 1;
}
case kMirror:
{
return 2;
}
case kRotate180:
{
return 3;
}
case kMirror180:
{
return 4;
}
case kMirror90CCW:
{
return 5;
}
case kRotate90CW:
{
return 6;
}
case kMirror90CW:
{
return 7;
}
case kRotate90CCW:
{
return 8;
}
case kUnknown:
{
return 9;
}
default:
break;
}
return 1;
}
/*****************************************************************************/
bool dng_orientation::FlipD () const
{
return (fAdobeOrientation & 1) != 0;
}
/*****************************************************************************/
bool dng_orientation::FlipH () const
{
if (fAdobeOrientation & 4)
return (fAdobeOrientation & 2) == 0;
else
return (fAdobeOrientation & 2) != 0;
}
/*****************************************************************************/
bool dng_orientation::FlipV () const
{
if (fAdobeOrientation & 4)
return FlipD () == FlipH ();
else
return FlipD () != FlipH ();
}
/*****************************************************************************/
dng_orientation dng_orientation::operator- () const
{
uint32 x = GetAdobe ();
if ((x & 5) == 5)
{
x ^= 2;
}
dng_orientation result;
result.SetAdobe (((4 - x) & 3) | (x & 4));
return result;
}
/*****************************************************************************/
dng_orientation dng_orientation::operator+ (const dng_orientation &b) const
{
uint32 x = GetAdobe ();
uint32 y = b.GetAdobe ();
if (y & 4)
{
if (x & 1)
x ^= 6;
else
x ^= 4;
}
dng_orientation result;
result.SetAdobe (((x + y) & 3) | (x & 4));
return result;
}
/*****************************************************************************/
bool dng_orientation::CalcForwardMatrix3by3 (dng_matrix &orientationMatrix,
const bool horizontalFirstRow) const
{
bool hasOrient = false;
orientationMatrix.SetIdentity (3);
if (FlipH ())
{
hasOrient = true;
if (horizontalFirstRow)
{
orientationMatrix = dng_matrix_3by3 (-1.0, 0.0, 1.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0) *
orientationMatrix;
}
else
{
orientationMatrix = dng_matrix_3by3 (1.0, 0.0, 0.0,
0.0, -1.0, 1.0,
0.0, 0.0, 1.0) *
orientationMatrix;
}
}
if (FlipV ())
{
hasOrient = true;
if (horizontalFirstRow)
{
orientationMatrix = dng_matrix_3by3 (1.0, 0.0, 0.0,
0.0, -1.0, 1.0,
0.0, 0.0, 1.0) *
orientationMatrix;
}
else
{
orientationMatrix = dng_matrix_3by3 (-1.0, 0.0, 1.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0) *
orientationMatrix;
}
}
if (FlipD ())
{
hasOrient = true;
orientationMatrix = dng_matrix_3by3 (0.0, 1.0, 0.0,
1.0, 0.0, 0.0,
0.0, 0.0, 1.0) *
orientationMatrix;
}
return hasOrient;
}
/*****************************************************************************/
bool dng_orientation::CalcForwardMatrix4by4 (dng_matrix &orientationMatrix,
const bool horizontalFirstRow) const
{
bool hasOrient = false;
orientationMatrix.SetIdentity (4);
if (FlipH ())
{
hasOrient = true;
if (horizontalFirstRow)
{
orientationMatrix = dng_matrix_4by4 (-1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
}
else
{
orientationMatrix = dng_matrix_4by4 (1.0, 0.0, 0.0, 0.0,
0.0, -1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
}
}
if (FlipV ())
{
hasOrient = true;
if (horizontalFirstRow)
{
orientationMatrix = dng_matrix_4by4 (1.0, 0.0, 0.0, 0.0,
0.0, -1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0) *
orientationMatrix;
}
else
{
orientationMatrix = dng_matrix_4by4 (-1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0) *
orientationMatrix;
}
}
if (FlipD ())
{
hasOrient = true;
orientationMatrix = dng_matrix_4by4 (0.0, 1.0, 0.0, 0.0,
1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0) *
orientationMatrix;
}
return hasOrient;
}
/*****************************************************************************/

@ -0,0 +1,197 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#ifndef __dng_orientation__
#define __dng_orientation__
/******************************************************************************/
#include "dng_matrix.h"
#include "dng_types.h"
/******************************************************************************/
class dng_orientation
{
private:
// We internally use an orientation encoding ("Adobe") that is
// different than the TIFF orientation encoding ("TIFF").
uint32 fAdobeOrientation;
public:
enum
{
kNormal = 0,
kRotate90CW = 1,
kRotate180 = 2,
kRotate90CCW = 3,
kMirror = 4,
kMirror90CW = 5,
kMirror180 = 6,
kMirror90CCW = 7,
kUnknown = 8
};
dng_orientation ()
: fAdobeOrientation (kNormal)
{
}
void SetAdobe (uint32 adobe)
{
fAdobeOrientation = adobe;
}
uint32 GetAdobe () const
{
return fAdobeOrientation;
}
void SetTIFF (uint32 tiff);
uint32 GetTIFF () const;
static dng_orientation AdobeToDNG (uint32 adobe)
{
dng_orientation result;
result.SetAdobe (adobe);
return result;
}
static dng_orientation TIFFtoDNG (uint32 tiff)
{
dng_orientation result;
result.SetTIFF (tiff);
return result;
}
static dng_orientation Normal ()
{
return AdobeToDNG (kNormal);
}
static dng_orientation Rotate90CW ()
{
return AdobeToDNG (kRotate90CW);
}
static dng_orientation Rotate180 ()
{
return AdobeToDNG (kRotate180);
}
static dng_orientation Rotate90CCW ()
{
return AdobeToDNG (kRotate90CCW);
}
static dng_orientation Mirror ()
{
return AdobeToDNG (kMirror);
}
static dng_orientation Mirror90CW ()
{
return AdobeToDNG (kMirror90CW);
}
static dng_orientation Mirror180 ()
{
return AdobeToDNG (kMirror180);
}
static dng_orientation Mirror90CCW ()
{
return AdobeToDNG (kMirror90CCW);
}
static dng_orientation Unknown ()
{
return AdobeToDNG (kUnknown);
}
bool IsValid () const
{
return fAdobeOrientation < kUnknown;
}
bool NotValid () const
{
return !IsValid ();
}
bool FlipD () const;
bool FlipH () const;
bool FlipV () const;
bool operator== (const dng_orientation &b) const
{
return fAdobeOrientation == b.fAdobeOrientation;
}
bool operator!= (const dng_orientation &b) const
{
return !(*this == b);
}
dng_orientation operator- () const;
dng_orientation operator+ (const dng_orientation &b) const;
dng_orientation operator- (const dng_orientation &b) const
{
return (*this) + (-b);
}
void operator+= (const dng_orientation &b)
{
*this = *this + b;
}
void operator-= (const dng_orientation &b)
{
*this = *this - b;
}
// If horizontalFirstRow is true, then the x (horizontal h) component
// of the transform will be in the first row of the resulting matrix,
// and the y (vertical v) component will be in the second row.
//
// If horizontalFirstRow is false, then the y (vertical v) component
// of the transform will be in the first row of the resulting matrix,
// and the x (horizontal h) component will be in the second row.
bool CalcForwardMatrix3by3 (dng_matrix &matrix,
bool horizontalFirstRow) const;
bool CalcForwardMatrix4by4 (dng_matrix &matrix,
bool horizontalFirstRow) const;
};
/******************************************************************************/
#endif
/******************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,231 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#ifndef __dng_parse_utils__
#define __dng_parse_utils__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_flags.h"
#include "dng_types.h"
#include "dng_stream.h"
#include "dng_string.h"
#include "dng_matrix.h"
/*****************************************************************************/
#if qDNGValidate
/*****************************************************************************/
const char * LookupParentCode (uint32 parentCode);
/*****************************************************************************/
const char * LookupTagCode (uint32 parentCode,
uint32 tagCode);
/*****************************************************************************/
const char * LookupTagType (uint32 tagType);
/*****************************************************************************/
const char * LookupNewSubFileType (uint32 key);
const char * LookupCompression (uint32 key);
const char * LookupPredictor (uint32 key);
const char * LookupSampleFormat (uint32 key);
const char * LookupPhotometricInterpretation (uint32 key);
const char * LookupOrientation (uint32 key);
const char * LookupResolutionUnit (uint32 key);
const char * LookupCFAColor (uint32 key);
const char * LookupSensingMethod (uint32 key);
const char * LookupExposureProgram (uint32 key);
const char * LookupMeteringMode (uint32 key);
const char * LookupLightSource (uint32 key);
const char * LookupColorSpace (uint32 key);
const char * LookupFileSource (uint32 key);
const char * LookupSceneType (uint32 key);
const char * LookupCustomRendered (uint32 key);
const char * LookupExposureMode (uint32 key);
const char * LookupWhiteBalance (uint32 key);
const char * LookupSceneCaptureType (uint32 key);
const char * LookupGainControl (uint32 key);
const char * LookupContrast (uint32 key);
const char * LookupSaturation (uint32 key);
const char * LookupSharpness (uint32 key);
const char * LookupSubjectDistanceRange (uint32 key);
const char * LookupComponent (uint32 key);
const char * LookupCFALayout (uint32 key);
const char * LookupMakerNoteSafety (uint32 key);
const char * LookupColorimetricReference (uint32 key);
const char * LookupPreviewColorSpace (uint32 key);
const char * LookupJPEGMarker (uint32 key);
const char * LookupSensitivityType (uint32 key);
const char * LookupDepthFormat (uint32 key);
const char * LookupDepthUnits (uint32 key);
const char * LookupDepthMeasureType (uint32 key);
/*****************************************************************************/
void DumpHexAscii (dng_stream &stream,
uint32 count);
void DumpHexAscii (const uint8 *buf,
uint32 count);
void DumpXMP (dng_stream &stream,
uint32 count);
void DumpString (const dng_string &s);
void DumpTagValues (dng_stream &stream,
const char *entry_name,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
const char *tag_name = NULL);
void DumpMatrix (const dng_matrix &m);
void DumpVector (const dng_vector &v);
void DumpDateTime (const dng_date_time &dt);
void DumpExposureTime (real64 x);
void DumpFingerprint (const dng_fingerprint &p);
void DumpHueSatMap (dng_stream &stream,
uint32 hues,
uint32 sats,
uint32 vals,
bool skipSat0);
/*****************************************************************************/
#endif
/*****************************************************************************/
bool CheckTagType (uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint16 validType0,
uint16 validType1 = 0,
uint16 validType2 = 0,
uint16 validType3 = 0);
bool CheckTagCount (uint32 parentCode,
uint32 tagCode,
uint32 tagCount,
uint32 minCount,
uint32 maxCount = 0);
bool CheckColorImage (uint32 parentCode,
uint32 tagCode,
uint32 colorPlanes);
bool CheckMainIFD (uint32 parentCode,
uint32 tagCode,
uint32 newSubFileType);
bool CheckRawIFD (uint32 parentCode,
uint32 tagCode,
uint32 photometricInterpretation);
bool CheckCFA (uint32 parentCode,
uint32 tagCode,
uint32 photometricInterpretation);
/*****************************************************************************/
void ParseStringTag (dng_stream &stream,
uint32 parentCode,
uint32 tagCode,
uint32 tagCount,
dng_string &s,
bool trimBlanks = true);
void ParseDualStringTag (dng_stream &stream,
uint32 parentCode,
uint32 tagCode,
uint32 tagCount,
dng_string &s1,
dng_string &s2);
void ParseEncodedStringTag (dng_stream &stream,
uint32 parentCode,
uint32 tagCode,
uint32 tagCount,
dng_string &s);
bool ParseMatrixTag (dng_stream &stream,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint32 rows,
uint32 cols,
dng_matrix &m);
bool ParseVectorTag (dng_stream &stream,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
uint32 count,
dng_vector &v);
bool ParseDateTimeTag (dng_stream &stream,
uint32 parentCode,
uint32 tagCode,
uint32 tagType,
uint32 tagCount,
dng_date_time &dt);
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,764 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
/** \file
* Support for holding buffers of sample data.
*/
/*****************************************************************************/
#ifndef __dng_pixel_buffer__
#define __dng_pixel_buffer__
/*****************************************************************************/
#include "dng_assertions.h"
#include "dng_rect.h"
#include "dng_safe_arithmetic.h"
#include "dng_tag_types.h"
/*****************************************************************************/
/// Compute best set of step values for a given source and destination area and stride.
void OptimizeOrder (const void *&sPtr,
void *&dPtr,
uint32 sPixelSize,
uint32 dPixelSize,
uint32 &count0,
uint32 &count1,
uint32 &count2,
int32 &sStep0,
int32 &sStep1,
int32 &sStep2,
int32 &dStep0,
int32 &dStep1,
int32 &dStep2);
void OptimizeOrder (const void *&sPtr,
uint32 sPixelSize,
uint32 &count0,
uint32 &count1,
uint32 &count2,
int32 &sStep0,
int32 &sStep1,
int32 &sStep2);
void OptimizeOrder (void *&dPtr,
uint32 dPixelSize,
uint32 &count0,
uint32 &count1,
uint32 &count2,
int32 &dStep0,
int32 &dStep1,
int32 &dStep2);
/*****************************************************************************/
#define qDebugPixelType 0
#if qDebugPixelType
#define ASSERT_PIXEL_TYPE(typeVal) CheckPixelType (typeVal)
#else
#define ASSERT_PIXEL_TYPE(typeVal) DNG_ASSERT (fPixelType == typeVal, "Pixel type access mismatch")
#endif
/*****************************************************************************/
/// \brief Holds a buffer of pixel data with "pixel geometry" metadata.
///
/// The pixel geometry describes the layout in terms of how many planes, rows and columns
/// plus the steps (in bytes) between each column, row and plane.
class dng_pixel_buffer
{
public:
// Area this buffer holds.
dng_rect fArea;
// Range of planes this buffer holds.
uint32 fPlane;
uint32 fPlanes;
// Steps between pixels.
int32 fRowStep;
int32 fColStep;
int32 fPlaneStep;
// Basic pixel type (TIFF tag type code).
uint32 fPixelType;
// Size of pixel type in bytes.
uint32 fPixelSize;
// Pointer to buffer's data.
void *fData;
// Do we have write-access to this data?
bool fDirty;
private:
void * InternalPixel (int32 row,
int32 col,
uint32 plane = 0) const
{
// TO DO: review this. do we set up buffers sometimes with "col" parameter
// equal to 0, which would then cause this exception to throw?!
#if 0
// Ensure pixel to be accessed lies inside valid area.
if (row < fArea.t || row >= fArea.b ||
col < fArea.l || col >= fArea.r ||
plane < fPlane || (plane - fPlane) >= fPlanes)
{
ThrowProgramError ("Out-of-range pixel access");
}
// Compute offset of pixel.
const int64 rowOffset = SafeInt64Mult(fRowStep,
static_cast<int64> (row) - static_cast<int64> (fArea.t));
const int64 colOffset = SafeInt64Mult(fColStep,
static_cast<int64> (col) - static_cast<int64> (fArea.l));
const int64 planeOffset = SafeInt64Mult(fPlaneStep,
static_cast<int64> (plane - fPlane));
const int64 offset = SafeInt64Mult(static_cast<int64>(fPixelSize),
SafeInt64Add(SafeInt64Add(rowOffset, colOffset), planeOffset));
// Add offset to buffer base address.
return static_cast<void *> (static_cast<uint8 *> (fData) + offset);
#else
#if qDNG64Bit
return (void *)
(((uint8 *) fData) + (int64) fPixelSize *
(fRowStep * (int64) (row - fArea.t) +
fColStep * (int64) (col - fArea.l) +
fPlaneStep * (int64) (plane - fPlane )));
#else
return (void *)
(((uint8 *) fData) + (int32) fPixelSize *
(fRowStep * (int32) (row - fArea.t) +
fColStep * (int32) (col - fArea.l) +
fPlaneStep * (int32) (plane - fPlane )));
#endif
#endif
}
#if qDebugPixelType
void CheckPixelType (uint32 pixelType) const;
#endif
public:
dng_pixel_buffer ();
/// Note: This constructor is for internal use only and should not be
/// considered part of the DNG SDK API.
///
/// Initialize the pixel buffer according to the given parameters (see
/// below). May throw an error if arithmetic overflow occurs when
/// computing the row, column or plane step, or if an invalid value
/// was passed for planarConfiguration.
///
/// \param area Area covered by the pixel buffer
/// \param plane Index of the first plane
/// \param planes Number of planes
/// \param pixelType Pixel data type (one of the values defined in
/// dng_tag_types.h)
/// \param planarConfiguration Layout of the pixel planes in memory: One
/// of pcInterleaved, pcPlanar, or pcRowInterleaved (defined in
/// dng_tag_values.h)
/// \param data Pointer to the pixel data
dng_pixel_buffer (const dng_rect &area,
uint32 plane,
uint32 planes,
uint32 pixelType,
uint32 planarConfiguration,
void *data);
dng_pixel_buffer (const dng_pixel_buffer &buffer);
dng_pixel_buffer & operator= (const dng_pixel_buffer &buffer);
virtual ~dng_pixel_buffer ();
/// Get the range of pixel values.
/// \retval Range of value a pixel can take. (Meaning [0, max] for unsigned case. Signed case is biased so [-32768, max - 32768].)
uint32 PixelRange () const;
/// Get extent of pixels in buffer
/// \retval Rectangle giving valid extent of buffer.
const dng_rect & Area () const
{
return fArea;
}
/// Number of planes of image data.
/// \retval Number of planes held in buffer.
uint32 Planes () const
{
return fPlanes;
}
/// Step, in pixels not bytes, between rows of data in buffer.
/// \retval row step in pixels. May be negative.
int32 RowStep () const
{
return fRowStep;
}
/// Step, in pixels not bytes, between planes of data in buffer.
/// \retval plane step in pixels. May be negative.
int32 PlaneStep () const
{
return fPlaneStep;
}
/// Get read-only untyped (void *) pointer to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as void *.
const void * ConstPixel (int32 row,
int32 col,
uint32 plane = 0) const
{
return InternalPixel (row, col, plane);
}
/// Get a writable untyped (void *) pointer to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as void *.
void * DirtyPixel (int32 row,
int32 col,
uint32 plane = 0)
{
DNG_ASSERT (fDirty, "Dirty access to const pixel buffer");
return InternalPixel (row, col, plane);
}
/// Get read-only uint8 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as uint8 *.
const uint8 * ConstPixel_uint8 (int32 row,
int32 col,
uint32 plane = 0) const
{
ASSERT_PIXEL_TYPE (ttByte);
return (const uint8 *) ConstPixel (row, col, plane);
}
const uint8 * ConstPixel_uint8_overrideType (int32 row,
int32 col,
uint32 plane = 0) const
{
// No type check
return (const uint8 *) ConstPixel (row, col, plane);
}
/// Get a writable uint8 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as uint8 *.
uint8 * DirtyPixel_uint8 (int32 row,
int32 col,
uint32 plane = 0)
{
ASSERT_PIXEL_TYPE (ttByte);
return (uint8 *) DirtyPixel (row, col, plane);
}
uint8 * DirtyPixel_uint8_overrideType (int32 row,
int32 col,
uint32 plane = 0)
{
// No type check
return (uint8 *) DirtyPixel (row, col, plane);
}
/// Get read-only int8 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as int8 *.
const int8 * ConstPixel_int8 (int32 row,
int32 col,
uint32 plane = 0) const
{
ASSERT_PIXEL_TYPE (ttSByte);
return (const int8 *) ConstPixel (row, col, plane);
}
/// Get a writable int8 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as int8 *.
int8 * DirtyPixel_int8 (int32 row,
int32 col,
uint32 plane = 0)
{
ASSERT_PIXEL_TYPE (ttSByte);
return (int8 *) DirtyPixel (row, col, plane);
}
/// Get read-only uint16 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as uint16 *.
const uint16 * ConstPixel_uint16 (int32 row,
int32 col,
uint32 plane = 0) const
{
ASSERT_PIXEL_TYPE (ttShort);
return (const uint16 *) ConstPixel (row, col, plane);
}
/// Get a writable uint16 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as uint16 *.
uint16 * DirtyPixel_uint16 (int32 row,
int32 col,
uint32 plane = 0)
{
ASSERT_PIXEL_TYPE (ttShort);
return (uint16 *) DirtyPixel (row, col, plane);
}
/// Get read-only int16 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as int16 *.
const int16 * ConstPixel_int16 (int32 row,
int32 col,
uint32 plane = 0) const
{
ASSERT_PIXEL_TYPE (ttSShort);
return (const int16 *) ConstPixel (row, col, plane);
}
/// Get a writable int16 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as int16 *.
int16 * DirtyPixel_int16 (int32 row,
int32 col,
uint32 plane = 0)
{
ASSERT_PIXEL_TYPE (ttSShort);
return (int16 *) DirtyPixel (row, col, plane);
}
/// Get read-only uint32 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as uint32 *.
const uint32 * ConstPixel_uint32 (int32 row,
int32 col,
uint32 plane = 0) const
{
ASSERT_PIXEL_TYPE (ttLong);
return (const uint32 *) ConstPixel (row, col, plane);
}
/// Get a writable uint32 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as uint32 *.
uint32 * DirtyPixel_uint32 (int32 row,
int32 col,
uint32 plane = 0)
{
ASSERT_PIXEL_TYPE (ttLong);
return (uint32 *) DirtyPixel (row, col, plane);
}
/// Get read-only int32 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as int32 *.
const int32 * ConstPixel_int32 (int32 row,
int32 col,
uint32 plane = 0) const
{
ASSERT_PIXEL_TYPE (ttSLong);
return (const int32 *) ConstPixel (row, col, plane);
}
/// Get a writable int32 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as int32 *.
int32 * DirtyPixel_int32 (int32 row,
int32 col,
uint32 plane = 0)
{
ASSERT_PIXEL_TYPE (ttSLong);
return (int32 *) DirtyPixel (row, col, plane);
}
/// Get read-only real32 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as real32 *.
const real32 * ConstPixel_real32 (int32 row,
int32 col,
uint32 plane = 0) const
{
ASSERT_PIXEL_TYPE (ttFloat);
return (const real32 *) ConstPixel (row, col, plane);
}
/// Get a writable real32 * to pixel data starting at a specific pixel in the buffer.
/// \param row Start row for buffer pointer.
/// \param col Start column for buffer pointer.
/// \param plane Start plane for buffer pointer.
/// \retval Pointer to pixel data as real32 *.
real32 * DirtyPixel_real32 (int32 row,
int32 col,
uint32 plane = 0)
{
ASSERT_PIXEL_TYPE (ttFloat);
return (real32 *) DirtyPixel (row, col, plane);
}
/// Initialize a rectangular area of pixel buffer to a constant.
/// \param area Rectangle of pixel buffer to set.
/// \param plane Plane to start filling on.
/// \param planes Number of planes to fill.
/// \param value Constant value to set pixels to.
void SetConstant (const dng_rect &area,
uint32 plane,
uint32 planes,
uint32 value);
/// Initialize a rectangular area of pixel buffer to a constant unsigned 8-bit value.
/// \param area Rectangle of pixel buffer to set.
/// \param plane Plane to start filling on.
/// \param planes Number of planes to fill.
/// \param value Constant uint8 value to set pixels to.
void SetConstant_uint8 (const dng_rect &area,
uint32 plane,
uint32 planes,
uint8 value)
{
DNG_ASSERT (fPixelType == ttByte, "Mismatched pixel type");
SetConstant (area, plane, planes, (uint32) value);
}
/// Initialize a rectangular area of pixel buffer to a constant unsigned 16-bit value.
/// \param area Rectangle of pixel buffer to set.
/// \param plane Plane to start filling on.
/// \param planes Number of planes to fill.
/// \param value Constant uint16 value to set pixels to.
void SetConstant_uint16 (const dng_rect &area,
uint32 plane,
uint32 planes,
uint16 value)
{
DNG_ASSERT (fPixelType == ttShort, "Mismatched pixel type");
SetConstant (area, plane, planes, (uint32) value);
}
/// Initialize a rectangular area of pixel buffer to a constant signed 16-bit value.
/// \param area Rectangle of pixel buffer to set.
/// \param plane Plane to start filling on.
/// \param planes Number of planes to fill.
/// \param value Constant int16 value to set pixels to.
void SetConstant_int16 (const dng_rect &area,
uint32 plane,
uint32 planes,
int16 value)
{
DNG_ASSERT (fPixelType == ttSShort, "Mismatched pixel type");
SetConstant (area, plane, planes, (uint32) (uint16) value);
}
/// Initialize a rectangular area of pixel buffer to a constant unsigned 32-bit value.
/// \param area Rectangle of pixel buffer to set.
/// \param plane Plane to start filling on.
/// \param planes Number of planes to fill.
/// \param value Constant uint32 value to set pixels to.
void SetConstant_uint32 (const dng_rect &area,
uint32 plane,
uint32 planes,
uint32 value)
{
DNG_ASSERT (fPixelType == ttLong, "Mismatched pixel type");
SetConstant (area, plane, planes, value);
}
/// Initialize a rectangular area of pixel buffer to a constant real 32-bit value.
/// \param area Rectangle of pixel buffer to set.
/// \param plane Plane to start filling on.
/// \param planes Number of planes to fill.
/// \param value Constant real32 value to set pixels to.
void SetConstant_real32 (const dng_rect &area,
uint32 plane,
uint32 planes,
real32 value)
{
DNG_ASSERT (fPixelType == ttFloat, "Mismatched pixel type");
union
{
uint32 i;
real32 f;
} x;
x.f = value;
SetConstant (area, plane, planes, x.i);
}
/// Initialize a rectangular area of pixel buffer to zeros.
/// \param area Rectangle of pixel buffer to zero.
/// \param plane Plane to start filling on.
/// \param planes Number of planes to fill.
void SetZero (const dng_rect &area,
uint32 plane,
uint32 planes);
/// Copy image data from an area of one pixel buffer to same area of another.
/// \param src Buffer to copy from.
/// \param area Rectangle of pixel buffer to copy.
/// \param srcPlane Plane to start copy in src.
/// \param dstPlane Plane to start copy in dst.
/// \param planes Number of planes to copy.
void CopyArea (const dng_pixel_buffer &src,
const dng_rect &area,
uint32 srcPlane,
uint32 dstPlane,
uint32 planes);
/// Copy image data from an area of one pixel buffer to same area of another.
/// \param src Buffer to copy from.
/// \param area Rectangle of pixel buffer to copy.
/// \param plane Plane to start copy in src and this.
/// \param planes Number of planes to copy.
void CopyArea (const dng_pixel_buffer &src,
const dng_rect &area,
uint32 plane,
uint32 planes)
{
CopyArea (src, area, plane, plane, planes);
}
/// Calculate the offset phase of destination rectangle relative to source rectangle.
/// Phase is based on a 0,0 origin and the notion of repeating srcArea across dstArea.
/// It is the number of pixels into srcArea to start repeating from when tiling dstArea.
/// \retval dng_point containing horizontal and vertical phase.
static dng_point RepeatPhase (const dng_rect &srcArea,
const dng_rect &dstArea);
/// Repeat the image data in srcArea across dstArea.
/// (Generally used for padding operations.)
/// \param srcArea Area to repeat from.
/// \param dstArea Area to fill with data from srcArea.
void RepeatArea (const dng_rect &srcArea,
const dng_rect &dstArea);
/// Replicates a sub-area of a buffer to fill the entire buffer.
void RepeatSubArea (const dng_rect subArea,
uint32 repeatV = 1,
uint32 repeatH = 1);
/// Apply a right shift (C++ oerpator >>) to all pixel values. Only implemented for 16-bit (signed or unsigned) pixel buffers.
/// \param shift Number of bits by which to right shift each pixel value.
void ShiftRight (uint32 shift);
/// Change metadata so pixels are iterated in opposite horizontal order.
/// This operation does not require movement of actual pixel data.
void FlipH ();
/// Change metadata so pixels are iterated in opposite vertical order.
/// This operation does not require movement of actual pixel data.
void FlipV ();
/// Change metadata so pixels are iterated in opposite plane order.
/// This operation does not require movement of actual pixel data.
void FlipZ (); // Flip planes
/// Return true if the contents of an area of the pixel buffer area are the same as those of another.
/// \param rhs Buffer to compare against.
/// \param area Rectangle of pixel buffer to test.
/// \param plane Plane to start comparing.
/// \param planes Number of planes to compare.
/// \retval bool true if areas are equal, false otherwise.
bool EqualArea (const dng_pixel_buffer &rhs,
const dng_rect &area,
uint32 plane,
uint32 planes) const;
/// Return the absolute value of the maximum difference between two pixel buffers. Used for comparison testing with tolerance
/// \param rhs Buffer to compare against.
/// \param area Rectangle of pixel buffer to test.
/// \param plane Plane to start comparing.
/// \param planes Number of planes to compare.
/// \retval larges absolute value difference between the corresponding pixels each buffer across area.
real64 MaximumDifference (const dng_pixel_buffer &rhs,
const dng_rect &area,
uint32 plane,
uint32 planes) const;
};
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,15 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#include "dng_point.h"
/*****************************************************************************/
// Currently all inlined.
/*****************************************************************************/

@ -0,0 +1,313 @@
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#ifndef __dng_point__
#define __dng_point__
/*****************************************************************************/
#include <cmath>
#include "dng_types.h"
#include "dng_utils.h"
/*****************************************************************************/
class dng_point
{
public:
int32 v;
int32 h;
public:
dng_point ()
: v (0)
, h (0)
{
}
dng_point (int32 vv, int32 hh)
: v (vv)
, h (hh)
{
}
bool operator== (const dng_point &pt) const
{
return (v == pt.v) &&
(h == pt.h);
}
bool operator!= (const dng_point &pt) const
{
return !(*this == pt);
}
real64 Length () const
{
return hypot ((real64) v, (real64) h);
}
};
/*****************************************************************************/
class dng_point_real64
{
public:
real64 v;
real64 h;
public:
dng_point_real64 ()
: v (0.0)
, h (0.0)
{
}
dng_point_real64 (real64 vv, real64 hh)
: v (vv)
, h (hh)
{
}
dng_point_real64 (const dng_point &pt)
: v ((real64) pt.v)
, h ((real64) pt.h)
{
}
bool operator== (const dng_point_real64 &pt) const
{
return (v == pt.v) &&
(h == pt.h);
}
bool operator!= (const dng_point_real64 &pt) const
{
return !(*this == pt);
}
dng_point Round () const
{
return dng_point (Round_int32 (v),
Round_int32 (h));
}
real64 Length () const
{
return hypot (v, h);
}
void Scale (real64 scale)
{
v *= scale;
h *= scale;
}
void Normalize ()
{
Scale (1.0 / Length ());
}
};
/*****************************************************************************/
inline dng_point operator+ (const dng_point &a,
const dng_point &b)
{
return dng_point (a.v + b.v,
a.h + b.h);
}
/*****************************************************************************/
inline dng_point_real64 operator+ (const dng_point_real64 &a,
const dng_point_real64 &b)
{
return dng_point_real64 (a.v + b.v,
a.h + b.h);
}
/*****************************************************************************/
inline dng_point operator- (const dng_point &a,
const dng_point &b)
{
return dng_point (a.v - b.v,
a.h - b.h);
}
/*****************************************************************************/
inline dng_point_real64 operator- (const dng_point_real64 &a,
const dng_point_real64 &b)
{
return dng_point_real64 (a.v - b.v,
a.h - b.h);
}
/*****************************************************************************/
inline real64 Distance (const dng_point_real64 &a,
const dng_point_real64 &b)
{
return (a - b).Length ();
}
/*****************************************************************************/
inline real64 DistanceSquared (const dng_point_real64 &a,
const dng_point_real64 &b)
{
dng_point_real64 diff = a - b;
return (diff.v * diff.v) + (diff.h * diff.h);
}
/*****************************************************************************/
// Finds distance squared from point p to line segment from v to w.
inline real64 DistanceSquared (const dng_point_real64 &p,
const dng_point_real64 &v,
const dng_point_real64 &w)
{
real64 len2 = DistanceSquared (v, w);
if (len2 == 0.0)
return DistanceSquared (p, v);
real64 t = ((p.h - v.h) * (w.h - v.h) +
(p.v - v.v) * (w.v - v.v)) / len2;
if (t <= 0.0)
return DistanceSquared (p, v);
if (t >= 1.0)
return DistanceSquared (p, w);
dng_point_real64 z;
z.h = v.h + t * (w.h - v.h);
z.v = v.v + t * (w.v - v.v);
return DistanceSquared (p, z);
}
/*****************************************************************************/
inline dng_point Transpose (const dng_point &a)
{
return dng_point (a.h, a.v);
}
/*****************************************************************************/
inline dng_point_real64 Transpose (const dng_point_real64 &a)
{
return dng_point_real64 (a.h, a.v);
}
/*****************************************************************************/
inline dng_point_real64 Lerp (const dng_point_real64 &a,
const dng_point_real64 &b,
const real64 t)
{
return dng_point_real64 (Lerp_real64 (a.v, b.v, t),
Lerp_real64 (a.h, b.h, t));
}
/*****************************************************************************/
inline real64 Dot (const dng_point_real64 &a,
const dng_point_real64 &b)
{
return (a.h * b.h) + (a.v * b.v);
}
/*****************************************************************************/
inline dng_point_real64 operator* (const real64 scale,
const dng_point_real64 &pt)
{
dng_point_real64 result = pt;
result.h *= scale;
result.v *= scale;
return result;
}
/*****************************************************************************/
inline dng_point MakePerpendicular (const dng_point &pt)
{
return dng_point (-pt.h, pt.v);
}
/*****************************************************************************/
inline dng_point_real64 MakePerpendicular (const dng_point_real64 &pt)
{
return dng_point_real64 (-pt.h, pt.v);
}
/*****************************************************************************/
#endif
/*****************************************************************************/

@ -0,0 +1,802 @@
/*****************************************************************************/
// Copyright 2007-2019 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.
/*****************************************************************************/
#include "dng_preview.h"
#include "dng_assertions.h"
#include "dng_image.h"
#include "dng_image_writer.h"
#include "dng_memory.h"
#include "dng_stream.h"
#include "dng_tag_codes.h"
#include "dng_tag_values.h"
/*****************************************************************************/
class dng_preview_tag_set: public dng_basic_tag_set
{
private:
tag_string fApplicationNameTag;
tag_string fApplicationVersionTag;
tag_string fSettingsNameTag;
dng_fingerprint fSettingsDigest;
tag_uint8_ptr fSettingsDigestTag;
tag_uint32 fColorSpaceTag;
tag_string fDateTimeTag;
tag_real64 fRawToPreviewGainTag;
tag_uint32 fCacheVersionTag;
public:
dng_preview_tag_set (dng_tiff_directory &directory,
const dng_preview &preview,
const dng_ifd &ifd);
virtual ~dng_preview_tag_set ();
};
/*****************************************************************************/
dng_preview_tag_set::dng_preview_tag_set (dng_tiff_directory &directory,
const dng_preview &preview,
const dng_ifd &ifd)
: dng_basic_tag_set (directory, ifd)
, fApplicationNameTag (tcPreviewApplicationName,
preview.fInfo.fApplicationName,
false)
, fApplicationVersionTag (tcPreviewApplicationVersion,
preview.fInfo.fApplicationVersion,
false)
, fSettingsNameTag (tcPreviewSettingsName,
preview.fInfo.fSettingsName,
false)
, fSettingsDigest (preview.fInfo.fSettingsDigest)
, fSettingsDigestTag (tcPreviewSettingsDigest,
fSettingsDigest.data,
16)
, fColorSpaceTag (tcPreviewColorSpace,
preview.fInfo.fColorSpace)
, fDateTimeTag (tcPreviewDateTime,
preview.fInfo.fDateTime,
true)
, fRawToPreviewGainTag (tcRawToPreviewGain,
preview.fInfo.fRawToPreviewGain)
, fCacheVersionTag (tcCacheVersion,
preview.fInfo.fCacheVersion)
{
if (preview.fInfo.fApplicationName.NotEmpty ())
{
directory.Add (&fApplicationNameTag);
}
if (preview.fInfo.fApplicationVersion.NotEmpty ())
{
directory.Add (&fApplicationVersionTag);
}
if (preview.fInfo.fSettingsName.NotEmpty ())
{
directory.Add (&fSettingsNameTag);
}
if (preview.fInfo.fSettingsDigest.IsValid ())
{
directory.Add (&fSettingsDigestTag);
}
if (preview.fInfo.fColorSpace != previewColorSpace_MaxEnum)
{
directory.Add (&fColorSpaceTag);
}
if (preview.fInfo.fDateTime.NotEmpty ())
{
directory.Add (&fDateTimeTag);
}
if (preview.fInfo.fRawToPreviewGain != 1.0)
{
directory.Add (&fRawToPreviewGainTag);
}
if (preview.fInfo.fCacheVersion != 0)
{
directory.Add (&fCacheVersionTag);
}
}
/*****************************************************************************/
dng_preview_tag_set::~dng_preview_tag_set ()
{
}
/*****************************************************************************/
dng_preview::dng_preview ()
: fInfo ()
{
}
/*****************************************************************************/
dng_preview::~dng_preview ()
{
}
/*****************************************************************************/
dng_image_preview::dng_image_preview ()
: fImage ()
, fIFD ()
{
}
/*****************************************************************************/
dng_image_preview::~dng_image_preview ()
{
}
/*****************************************************************************/
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_image_preview::WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const
{
writer.WriteImage (host,
fIFD,
basic,
stream,
*fImage.Get ());
}
/*****************************************************************************/
class dng_jpeg_preview_tag_set: public dng_preview_tag_set
{
private:
dng_urational fCoefficientsData [3];
tag_urational_ptr fCoefficientsTag;
uint16 fSubSamplingData [2];
tag_uint16_ptr fSubSamplingTag;
tag_uint16 fPositioningTag;
dng_urational fReferenceData [6];
tag_urational_ptr fReferenceTag;
public:
dng_jpeg_preview_tag_set (dng_tiff_directory &directory,
const dng_jpeg_preview &preview,
const dng_ifd &ifd);
virtual ~dng_jpeg_preview_tag_set ();
};
/******************************************************************************/
dng_jpeg_preview_tag_set::dng_jpeg_preview_tag_set (dng_tiff_directory &directory,
const dng_jpeg_preview &preview,
const dng_ifd &ifd)
: dng_preview_tag_set (directory, preview, ifd)
, fCoefficientsTag (tcYCbCrCoefficients, fCoefficientsData, 3)
, fSubSamplingTag (tcYCbCrSubSampling, fSubSamplingData, 2)
, fPositioningTag (tcYCbCrPositioning, preview.fYCbCrPositioning)
, fReferenceTag (tcReferenceBlackWhite, fReferenceData, 6)
{
if (preview.fPhotometricInterpretation == piYCbCr)
{
fCoefficientsData [0] = dng_urational (299, 1000);
fCoefficientsData [1] = dng_urational (587, 1000);
fCoefficientsData [2] = dng_urational (114, 1000);
directory.Add (&fCoefficientsTag);
fSubSamplingData [0] = (uint16) preview.fYCbCrSubSampling.h;
fSubSamplingData [1] = (uint16) preview.fYCbCrSubSampling.v;
directory.Add (&fSubSamplingTag);
directory.Add (&fPositioningTag);
fReferenceData [0] = dng_urational ( 0, 1);
fReferenceData [1] = dng_urational (255, 1);
fReferenceData [2] = dng_urational (128, 1);
fReferenceData [3] = dng_urational (255, 1);
fReferenceData [4] = dng_urational (128, 1);
fReferenceData [5] = dng_urational (255, 1);
directory.Add (&fReferenceTag);
}
}
/*****************************************************************************/
dng_jpeg_preview_tag_set::~dng_jpeg_preview_tag_set ()
{
}
/*****************************************************************************/
dng_jpeg_preview::dng_jpeg_preview ()
: fPreviewSize ()
, fPhotometricInterpretation (piYCbCr)
, fYCbCrSubSampling (1, 1)
, fYCbCrPositioning (2)
, fCompressedData ()
{
}
/*****************************************************************************/
dng_jpeg_preview::~dng_jpeg_preview ()
{
}
/*****************************************************************************/
dng_basic_tag_set * dng_jpeg_preview::AddTagSet (dng_tiff_directory &directory) const
{
dng_ifd ifd;
ifd.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage
: sfAltPreviewImage;
ifd.fImageWidth = fPreviewSize.h;
ifd.fImageLength = fPreviewSize.v;
ifd.fPhotometricInterpretation = fPhotometricInterpretation;
ifd.fBitsPerSample [0] = 8;
ifd.fBitsPerSample [1] = 8;
ifd.fBitsPerSample [2] = 8;
ifd.fSamplesPerPixel = (fPhotometricInterpretation == piBlackIsZero ? 1 : 3);
ifd.fCompression = ccJPEG;
ifd.fPredictor = cpNullPredictor;
ifd.SetSingleStrip ();
return new dng_jpeg_preview_tag_set (directory, *this, ifd);
}
/*****************************************************************************/
void dng_jpeg_preview::WriteData (dng_host & /* host */,
dng_image_writer & /* writer */,
dng_basic_tag_set &basic,
dng_stream &stream) const
{
basic.SetTileOffset (0, (uint32) stream.Position ());
basic.SetTileByteCount (0, fCompressedData->LogicalSize ());
stream.Put (fCompressedData->Buffer (),
fCompressedData->LogicalSize ());
if (fCompressedData->LogicalSize () & 1)
{
stream.Put_uint8 (0);
}
}
/*****************************************************************************/
void dng_jpeg_preview::SpoolAdobeThumbnail (dng_stream &stream) const
{
DNG_ASSERT (fCompressedData.Get (),
"SpoolAdobeThumbnail: no data");
DNG_ASSERT (fPhotometricInterpretation == piYCbCr,
"SpoolAdobeThumbnail: Non-YCbCr");
uint32 compressedSize = fCompressedData->LogicalSize ();
stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
stream.Put_uint16 (1036);
stream.Put_uint16 (0);
stream.Put_uint32 (compressedSize + 28);
uint32 widthBytes = (fPreviewSize.h * 24 + 31) / 32 * 4;
stream.Put_uint32 (1);
stream.Put_uint32 (fPreviewSize.h);
stream.Put_uint32 (fPreviewSize.v);
stream.Put_uint32 (widthBytes);
stream.Put_uint32 (widthBytes * fPreviewSize.v);
stream.Put_uint32 (compressedSize);
stream.Put_uint16 (24);
stream.Put_uint16 (1);
stream.Put (fCompressedData->Buffer (),
compressedSize);
if (compressedSize & 1)
{
stream.Put_uint8 (0);
}
}
/*****************************************************************************/
class dng_raw_preview_tag_set: public dng_preview_tag_set
{
private:
tag_data_ptr fOpcodeList2Tag;
tag_uint32_ptr fWhiteLevelTag;
uint32 fWhiteLevelData [kMaxColorPlanes];
tag_urational_ptr fBlackLevelTag;
dng_urational fBlackLevelData [kMaxColorPlanes];
public:
dng_raw_preview_tag_set (dng_tiff_directory &directory,
const dng_raw_preview &preview,
const dng_ifd &ifd);
virtual ~dng_raw_preview_tag_set ();
};
/*****************************************************************************/
dng_raw_preview_tag_set::dng_raw_preview_tag_set (dng_tiff_directory &directory,
const dng_raw_preview &preview,
const dng_ifd &ifd)
: dng_preview_tag_set (directory, preview, ifd)
, fOpcodeList2Tag (tcOpcodeList2,
ttUndefined,
0,
NULL)
, fWhiteLevelTag (tcWhiteLevel,
fWhiteLevelData,
preview.fImage->Planes ())
, fBlackLevelTag (tcBlackLevel,
fBlackLevelData,
preview.fImage->Planes ())
{
if (preview.fOpcodeList2Data.Get ())
{
fOpcodeList2Tag.SetData (preview.fOpcodeList2Data->Buffer ());
fOpcodeList2Tag.SetCount (preview.fOpcodeList2Data->LogicalSize ());
directory.Add (&fOpcodeList2Tag);
}
if (preview.fImage->PixelType () == ttFloat)
{
for (uint32 j = 0; j < kMaxColorPlanes; j++)
{
fWhiteLevelData [j] = 32768;
}
directory.Add (&fWhiteLevelTag);
}
else
{
bool nonZeroBlack = false;
for (uint32 j = 0; j < preview.fImage->Planes (); j++)
{
fBlackLevelData [j].Set_real64 (preview.fBlackLevel [j], 1);
nonZeroBlack = nonZeroBlack || (preview.fBlackLevel [j] != 0.0);
}
if (nonZeroBlack)
{
directory.Add (&fBlackLevelTag);
}
}
}
/*****************************************************************************/
dng_raw_preview_tag_set::~dng_raw_preview_tag_set ()
{
}
/*****************************************************************************/
dng_raw_preview::dng_raw_preview ()
: fImage ()
, fOpcodeList2Data ()
, fCompressionQuality (-1)
, fIFD ()
{
for (uint32 n = 0; n < kMaxSamplesPerPixel; n++)
{
fBlackLevel [n] = 0.0;
}
}
/*****************************************************************************/
dng_raw_preview::~dng_raw_preview ()
{
}
/*****************************************************************************/
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_raw_preview::WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const
{
writer.WriteImage (host,
fIFD,
basic,
stream,
*fImage.Get ());
}
/*****************************************************************************/
dng_mask_preview::dng_mask_preview ()
: fImage ()
, fCompressionQuality (-1)
, fIFD ()
{
}
/*****************************************************************************/
dng_mask_preview::~dng_mask_preview ()
{
}
/*****************************************************************************/
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);
}
/*****************************************************************************/
void dng_mask_preview::WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const
{
writer.WriteImage (host,
fIFD,
basic,
stream,
*fImage.Get ());
}
/*****************************************************************************/
dng_depth_preview::dng_depth_preview ()
: fImage ()
, fCompressionQuality (-1)
, fFullResolution (false)
, fIFD ()
{
}
/*****************************************************************************/
dng_depth_preview::~dng_depth_preview ()
{
}
/*****************************************************************************/
dng_basic_tag_set * dng_depth_preview::AddTagSet (dng_tiff_directory &directory) const
{
fIFD.fNewSubFileType = fFullResolution ? sfDepthMap
: sfPreviewDepthMap;
fIFD.fImageWidth = fImage->Width ();
fIFD.fImageLength = fImage->Height ();
fIFD.fSamplesPerPixel = 1;
fIFD.fPhotometricInterpretation = piDepth;
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);
}
/*****************************************************************************/
void dng_depth_preview::WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const
{
writer.WriteImage (host,
fIFD,
basic,
stream,
*fImage.Get ());
}
/*****************************************************************************/
dng_preview_list::dng_preview_list ()
: fCount (0)
{
}
/*****************************************************************************/
dng_preview_list::~dng_preview_list ()
{
}
/*****************************************************************************/
void dng_preview_list::Append (AutoPtr<dng_preview> &preview)
{
if (preview.Get ())
{
DNG_ASSERT (fCount < kMaxDNGPreviews, "DNG preview list overflow");
if (fCount < kMaxDNGPreviews)
{
fPreview [fCount++] . Reset (preview.Release ());
}
}
}
/*****************************************************************************/

@ -0,0 +1,241 @@
/*****************************************************************************/
// Copyright 2007-2019 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.
/*****************************************************************************/
#ifndef __dng_preview__
#define __dng_preview__
/*****************************************************************************/
#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_ifd.h"
#include "dng_opcode_list.h"
#include "dng_point.h"
#include "dng_sdk_limits.h"
#include "dng_uncopyable.h"
/*****************************************************************************/
class dng_preview: private dng_uncopyable
{
public:
dng_preview_info fInfo;
protected:
dng_preview ();
public:
virtual ~dng_preview ();
virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const = 0;
virtual void WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const = 0;
};
/*****************************************************************************/
class dng_image_preview: public dng_preview
{
public:
AutoPtr<dng_image> fImage;
private:
mutable dng_ifd fIFD;
public:
dng_image_preview ();
virtual ~dng_image_preview ();
virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const;
virtual void WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const;
};
/*****************************************************************************/
class dng_jpeg_preview: public dng_preview
{
public:
dng_point fPreviewSize;
uint16 fPhotometricInterpretation;
dng_point fYCbCrSubSampling;
uint16 fYCbCrPositioning;
AutoPtr<dng_memory_block> fCompressedData;
public:
dng_jpeg_preview ();
virtual ~dng_jpeg_preview ();
virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const;
virtual void WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const;
void SpoolAdobeThumbnail (dng_stream &stream) const;
};
/*****************************************************************************/
class dng_raw_preview: public dng_preview
{
public:
AutoPtr<dng_image> fImage;
AutoPtr<dng_memory_block> fOpcodeList2Data;
real64 fBlackLevel [kMaxSamplesPerPixel];
int32 fCompressionQuality;
private:
mutable dng_ifd fIFD;
public:
dng_raw_preview ();
virtual ~dng_raw_preview ();
virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const;
virtual void WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const;
};
/*****************************************************************************/
class dng_depth_preview: public dng_preview
{
public:
AutoPtr<dng_image> fImage;
int32 fCompressionQuality;
bool fFullResolution;
private:
mutable dng_ifd fIFD;
public:
dng_depth_preview ();
virtual ~dng_depth_preview ();
virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const;
virtual void WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const;
};
/*****************************************************************************/
class dng_mask_preview: public dng_preview
{
public:
AutoPtr<dng_image> fImage;
int32 fCompressionQuality;
private:
mutable dng_ifd fIFD;
public:
dng_mask_preview ();
virtual ~dng_mask_preview ();
virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const;
virtual void WriteData (dng_host &host,
dng_image_writer &writer,
dng_basic_tag_set &basic,
dng_stream &stream) const;
};
/*****************************************************************************/
class dng_preview_list
{
private:
uint32 fCount;
AutoPtr<dng_preview> fPreview [kMaxDNGPreviews];
public:
dng_preview_list ();
~dng_preview_list ();
uint32 Count () const
{
return fCount;
}
const dng_preview & Preview (uint32 index) const
{
return *(fPreview [index]);
}
void Append (AutoPtr<dng_preview> &preview);
};
/*****************************************************************************/
#endif
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,250 @@
/*****************************************************************************/
// Copyright 2002-2019 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.
/*****************************************************************************/
#ifndef DNG_PTHREAD
#define DNG_PTHREAD
/*****************************************************************************/
#include "dng_flags.h"
/*****************************************************************************/
#if qDNGThreadSafe
/*****************************************************************************/
#if !qWinOS
/*****************************************************************************/
/* Try generic POSIX compile */
#include <errno.h>
#include <pthread.h>
#define dng_pthread_disassociate()
#define dng_pthread_terminate()
/*****************************************************************************/
#else
/*****************************************************************************/
#include <stdlib.h>
#if _MSC_VER >= 1600
// Get this included so ETIMEDOUT is predefined.
#include <errno.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************/
#define DNG_ETIMEDOUT 60 /* Operation timed out */
struct dng_timespec {
long tv_sec;
long tv_nsec;
};
typedef unsigned long dng_pthread_t;
typedef struct dng_pthread_mutex_impl *dng_pthread_mutex_t;
typedef struct dng_pthread_cond_impl *dng_pthread_cond_t;
typedef unsigned long dng_pthread_key_t;
#define DNG_PTHREAD_MUTEX_INITIALIZER ((struct dng_pthread_mutex_impl *)-1)
#define DNG_PTHREAD_COND_INITIALIZER ((struct dng_pthread_cond_impl *)-1)
struct _dng_pthread_once_t {
int inited;
long semaphore;
};
typedef struct _dng_pthread_once_t dng_pthread_once_t;
#define DNG_PTHREAD_ONCE_INIT { 0, -1 }
#define dng_pthread_equal(t1, t2) ((t1) == (t2))
typedef struct dng_pthread_attr_impl *dng_pthread_attr_t;
int dng_pthread_attr_init(dng_pthread_attr_t *attr);
int dng_pthread_attr_destroy(dng_pthread_attr_t *attr);
int dng_pthread_attr_setstacksize(dng_pthread_attr_t *attr, size_t stacksize);
int dng_pthread_attr_getstacksize(const dng_pthread_attr_t *attr, size_t *stacksize);
int dng_pthread_create(dng_pthread_t *thread, const dng_pthread_attr_t * /* attrs */, void * (*func)(void *), void *arg);
int dng_pthread_detach(dng_pthread_t thread);
int dng_pthread_join(dng_pthread_t thread, void **result);
dng_pthread_t dng_pthread_self();
void dng_pthread_exit(void *result);
#define DNG_PTHREAD_MUTEX_RECURSIVE 0
typedef unsigned long dng_pthread_mutexattr_t;
int dng_pthread_mutexattr_init(dng_pthread_mutexattr_t *mutexattr);
int dng_pthread_mutexattr_settype(dng_pthread_mutexattr_t *mutexattr, int /*the options*/);
int dng_pthread_mutex_init(dng_pthread_mutex_t *mutex, void * /* attrs */);
int dng_pthread_mutex_destroy(dng_pthread_mutex_t *mutex);
int dng_pthread_mutex_lock(dng_pthread_mutex_t *mutex);
int dng_pthread_mutex_unlock(dng_pthread_mutex_t *mutex);
int dng_pthread_cond_init(dng_pthread_cond_t *cond, void * /* attrs */);
int dng_pthread_cond_destroy(dng_pthread_cond_t *cond);
int dng_pthread_cond_wait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex);
int dng_pthread_cond_timedwait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex, struct dng_timespec *latest_time);
int dng_pthread_cond_signal(dng_pthread_cond_t *cond);
int dng_pthread_cond_broadcast(dng_pthread_cond_t *cond);
int dng_pthread_once(dng_pthread_once_t *once, void (*init_func)());
int dng_pthread_key_create(dng_pthread_key_t * key, void (*destructor) (void *));
int dng_pthread_key_delete(dng_pthread_key_t key);
int dng_pthread_setspecific(dng_pthread_key_t key, const void *value);
void *dng_pthread_getspecific(dng_pthread_key_t key);
typedef struct dng_pthread_rwlock_impl *dng_pthread_rwlock_t;
typedef void *pthread_rwlockattr1_t;
int dng_pthread_rwlock_destroy(dng_pthread_rwlock_t * rwlock);
int dng_pthread_rwlock_init(dng_pthread_rwlock_t * rwlock, const pthread_rwlockattr1_t * attrs);
int dng_pthread_rwlock_rdlock(dng_pthread_rwlock_t * rwlock);
int dng_pthread_rwlock_tryrdlock(dng_pthread_rwlock_t * rwlock);
int dng_pthread_rwlock_trywrlock(dng_pthread_rwlock_t * rwlock);
int dng_pthread_rwlock_unlock(dng_pthread_rwlock_t * rwlock);
int dng_pthread_rwlock_wrlock(dng_pthread_rwlock_t * rwlock);
// dng_pthread may maintain per-thread global state. This routine frees that global state.
// there is no need to call this for threads created by dng_pthread and one can call
// dng_pthread routines of a thread after dng_pthread_disassociate as the global state will
// be recreated as necessary. However dng_pthread_disassociate will need to be called again
// and there is a slight performance cost. Do not call this routine while holding a mutex, etc.
void dng_pthread_disassociate();
void dng_pthread_terminate();
/*****************************************************************************/
// Map symbols back to plain pthread names. This whole mechanism is so the DNG pthreads library
// symbols do not collide with another pthread emulation library
// that may be in use in the same linked entity. However if that is the case, it would be far better
// to have the DNG code use the same pthread library as the rest of the code.
//HERWIG#define pthread_t dng_pthread_t
//HERWIG#define pthread_mutex_t dng_pthread_mutex_t
//HERWIG#define pthread_cond_t dng_pthread_cond_t
//HERWIG#define pthread_once_t dng_pthread_once_t
//HERWIG#define pthread_key_t dng_pthread_key_t
#undef PTHREAD_MUTEX_INITIALIZER
#define PTHREAD_MUTEX_INITIALIZER DNG_PTHREAD_MUTEX_INITIALIZER
#undef PTHREAD_COND_INITIALIZER
#define PTHREAD_COND_INITIALIZER DNG_PTHREAD_COND_INITIALIZER
#undef PTHREAD_ONCE_INIT
#define PTHREAD_ONCE_INIT DNG_PTHREAD_ONCE_INIT
#if _MSC_VER < 1900
#define timespec dng_timespec
#endif
/* If it is defined on Windows, it probably has the wrong value... */
#if defined(WIN32) || !defined(ETIMEDOUT)
#undef ETIMEDOUT
#define ETIMEDOUT DNG_ETIMEDOUT
#endif
//HERWIG#define pthread_equal dng_pthread_equal
//HERWIG#define pthread_attr_t dng_pthread_attr_t
//HERWIG#define pthread_attr_init dng_pthread_attr_init
//HERWIG#define pthread_attr_destroy dng_pthread_attr_destroy
//HERWIG#define pthread_attr_setstacksize dng_pthread_attr_setstacksize
//HERWIG#define pthread_attr_getstacksize dng_pthread_attr_getstacksize
//HERWIG#define pthread_create dng_pthread_create
//HERWIG#define pthread_detach dng_pthread_detach
//HERWIG#define pthread_join dng_pthread_join
//HERWIG#define pthread_self dng_pthread_self
#define pthread_exit dng_pthread_exit
//HERWIG#define pthread_mutex_init dng_pthread_mutex_init
//HERWIG#define pthread_mutex_destroy dng_pthread_mutex_destroy
//HERWIG#define pthread_mutex_lock dng_pthread_mutex_lock
//HERWIG#define pthread_mutex_unlock dng_pthread_mutex_unlock
//HERWIG#define pthread_cond_init dng_pthread_cond_init
//HERWIG#define pthread_cond_destroy dng_pthread_cond_destroy
//HERWIG#define pthread_cond_wait dng_pthread_cond_wait
//HERWIG#define pthread_cond_timedwait dng_pthread_cond_timedwait
//HERWIG#define pthread_cond_signal dng_pthread_cond_signal
//HERWIG#define pthread_cond_broadcast dng_pthread_cond_broadcast
//HERWIG#define pthread_once dng_pthread_once
//HERWIG#define pthread_key_create dng_pthread_key_create
//HERWIG#define pthread_key_delete dng_pthread_key_delete
//HERWIG#define pthread_setspecific dng_pthread_setspecific
//HERWIG#define pthread_getspecific dng_pthread_getspecific
//HERWIG#define pthread_rwlock_t dng_pthread_rwlock_t
//HERWIG#define pthread_rwlock_destroy dng_pthread_rwlock_destroy
//HERWIG#define pthread_rwlock_init dng_pthread_rwlock_init
//HERWIG#define pthread_rwlock_rdlock dng_pthread_rwlock_rdlock
//HERWIG#define pthread_rwlock_tryrdlock dng_pthread_rwlock_tryrdlock
//HERWIG#define pthread_rwlock_trywrlock dng_pthread_rwlock_trywrlock
//HERWIG#define pthread_rwlock_unlock dng_pthread_rwlock_unlock
//HERWIG#define pthread_rwlock_wrlock dng_pthread_rwlock_wrlock
/*****************************************************************************/
#ifdef __cplusplus
}
#endif
/*****************************************************************************/
#endif
/*****************************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif
int dng_pthread_now (struct timespec *now);
#ifdef __cplusplus
}
#endif
/*****************************************************************************/
#endif // qDNGThreadSafe
/*****************************************************************************/
#endif
/*****************************************************************************/

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save