#include "../../internal/libraw_cxx_defs.h"
#if defined (USE_GPRSDK) && !defined(USE_DNGSDK)
#error GPR (GoPro) SDK should be used with Adobe DNG SDK
#endif
#ifdef USE_DNGSDK
#include "dng_read_image.h"
#endif
#ifdef USE_GPRSDK
#include "gpr_read_image.h"
#endif
#ifdef USE_DNGSDK
static dng_ifd* search_single_ifd(const std::vector <dng_ifd *>& v, uint64 offset, int& idx, dng_stream& stream)
{
idx = -1;
for (int i = 0; i < v.size(); i++)
{
if (!v[i]) continue;
if (v[i]->fTileOffsetsOffset == offset)
{
idx = i;
return v[i];
}
else if (v[i]->fTileOffsetsCount == 1 && v[i]->fTileOffset[0] == offset)
{
idx = i;
return v[i];
}
else if (v[i]->fTileOffsetsCount > dng_ifd::kMaxTileInfo)
{
uint64 p = stream.Position();
stream.SetReadPosition(v[i]->fTileOffsetsOffset);
int32 oo = stream.TagValue_uint32(v[i]->fTileOffsetsType);
stream.SetReadPosition(p);
if (oo == offset)
{
idx = i;
return v[i];
}
}
}
return NULL;
}
static dng_ifd* search_for_ifd(const dng_info& info, uint64 offset, ushort w, ushort h, int& ifdIndex, dng_stream& stream)
{
dng_ifd *ret = 0;
ret = search_single_ifd(info.fIFD, offset, ifdIndex, stream);
int dummy;
if (!ret) ret = search_single_ifd(info.fChainedIFD, offset, dummy, stream);
if (!ret)
{
for (int c = 0; !ret && c < info.fChainedSubIFD.size(); c++)
ret = search_single_ifd(info.fChainedSubIFD[c], offset, dummy, stream);
}
if (ret && (ret->fImageLength == h) && ret->fImageWidth == w)
return ret;
ifdIndex = -1;
return 0;
}
#endif
int LibRaw::valid_for_dngsdk()
{
#ifndef USE_DNGSDK
return 0;
#else
if (!imgdata.idata.dng_version)
return 0;
if (libraw_internal_data.unpacker_data.tiff_compress == 34892
&& libraw_internal_data.unpacker_data.tiff_bps == 8
&& libraw_internal_data.unpacker_data.tiff_samples == 3
&& load_raw == &LibRaw::lossy_dng_load_raw
)
{
if (!dnghost)
return 0;
dng_host *host = static_cast<dng_host *>(dnghost);
libraw_dng_stream stream(libraw_internal_data.internal_data.input);
AutoPtr<dng_negative> negative;
negative.Reset(host->Make_dng_negative());
dng_info info;
info.Parse(*host, stream);
info.PostParse(*host);
if (!info.IsValidDNG())
return 0;
negative->Parse(*host, stream, info);
negative->PostParse(*host, stream, info);
int ifdindex = -1;
dng_ifd *rawIFD = search_for_ifd(info, libraw_internal_data.unpacker_data.data_offset, imgdata.sizes.raw_width, imgdata.sizes.raw_height, ifdindex,stream);
if (rawIFD && ifdindex >= 0 && ifdindex == info.fMainIndex)
return 1;
return 0;
}
#ifdef USE_GPRSDK
if (load_raw == &LibRaw::vc5_dng_load_raw_placeholder) return 1;
#endif
if (!imgdata.params.use_dngsdk)
return 0;
if (load_raw == &LibRaw::lossy_dng_load_raw) return 0;
if (load_raw ==
&LibRaw::float_dng_load_raw_placeholder) return 1;
if (is_floating_point() && (imgdata.params.use_dngsdk & LIBRAW_DNG_FLOAT))
return 1;
if (!imgdata.idata.filters && (imgdata.params.use_dngsdk & LIBRAW_DNG_LINEAR))
return 1;
if (libraw_internal_data.unpacker_data.tiff_bps == 8 &&
(imgdata.params.use_dngsdk & LIBRAW_DNG_8BIT))
return 1;
if (libraw_internal_data.unpacker_data.tiff_compress == 8 &&
(imgdata.params.use_dngsdk & LIBRAW_DNG_DEFLATE))
return 1;
if (libraw_internal_data.unpacker_data.tiff_samples == 2)
return 0; if (imgdata.idata.filters == 9 &&
(imgdata.params.use_dngsdk & LIBRAW_DNG_XTRANS))
return 1;
if (is_fuji_rotated())
return 0; if (imgdata.params.use_dngsdk & LIBRAW_DNG_OTHER)
return 1;
return 0;
#endif
}
int LibRaw::try_dngsdk()
{
#ifdef USE_DNGSDK
if (!dnghost)
return LIBRAW_UNSPECIFIED_ERROR;
dng_host *host = static_cast<dng_host *>(dnghost);
try
{
libraw_dng_stream stream(libraw_internal_data.internal_data.input);
AutoPtr<dng_negative> negative;
negative.Reset(host->Make_dng_negative());
dng_info info;
info.Parse(*host, stream);
info.PostParse(*host);
if (!info.IsValidDNG())
{
return LIBRAW_DATA_ERROR;
}
negative->Parse(*host, stream, info);
negative->PostParse(*host, stream, info);
int ifdindex;
dng_ifd *rawIFD = search_for_ifd(info,libraw_internal_data.unpacker_data.data_offset,imgdata.sizes.raw_width,imgdata.sizes.raw_height,ifdindex,stream);
if(!rawIFD)
return LIBRAW_DATA_ERROR;
AutoPtr<dng_simple_image> stage2;
bool stage23used = false;
bool zerocopy = false;
if (((libraw_internal_data.unpacker_data.tiff_compress == 34892
&& libraw_internal_data.unpacker_data.tiff_bps == 8
&& libraw_internal_data.unpacker_data.tiff_samples == 3
&& load_raw == &LibRaw::lossy_dng_load_raw) ||
(imgdata.params.raw_processing_options & (LIBRAW_PROCESSING_DNG_STAGE2| LIBRAW_PROCESSING_DNG_STAGE3)))
&& ifdindex >= 0)
{
if (info.fMainIndex != ifdindex)
info.fMainIndex = ifdindex;
negative->ReadStage1Image(*host, stream, info);
negative->BuildStage2Image(*host);
imgdata.process_warnings |= LIBRAW_WARN_DNG_STAGE2_APPLIED;
if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNG_STAGE3)
{
negative->BuildStage3Image(*host);
stage2.Reset((dng_simple_image*)negative->Stage3Image());
imgdata.process_warnings |= LIBRAW_WARN_DNG_STAGE3_APPLIED;
}
else
stage2.Reset((dng_simple_image*)negative->Stage2Image());
stage23used = true;
}
else
{
stage2.Reset(new dng_simple_image(rawIFD->Bounds(), rawIFD->fSamplesPerPixel, rawIFD->PixelType(), host->Allocator()));
#ifdef USE_GPRSDK
if (libraw_internal_data.unpacker_data.tiff_compress == 9)
{
gpr_allocator allocator;
allocator.Alloc = ::malloc;
allocator.Free = ::free;
gpr_buffer_auto vc5_image_obj(allocator.Alloc, allocator.Free);
gpr_read_image reader(&vc5_image_obj);
reader.Read(*host, *rawIFD, stream, *stage2.Get(), NULL, NULL);
}
else
#endif
{
dng_read_image reader;
reader.Read(*host, *rawIFD, stream, *stage2.Get(), NULL, NULL);
}
}
if (stage2->Bounds().W() != S.raw_width ||
stage2->Bounds().H() != S.raw_height)
{
if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNG_ALLOWSIZECHANGE)
{
S.raw_width = S.width = stage2->Bounds().W();
S.left_margin = 0;
S.raw_height = S.height = stage2->Bounds().H();
S.top_margin = 0;
}
else
{
stage2.Release(); return LIBRAW_DATA_ERROR;
}
}
if (stage23used)
{
if (stage2->Planes() > 1)
{
imgdata.idata.filters = 0;
imgdata.idata.colors = stage2->Planes();
}
imgdata.color.black = 0;
memset(imgdata.color.cblack, 0, sizeof(imgdata.color.cblack));
imgdata.color.maximum = 0xffff;
}
int pplanes = stage2->Planes();
int ptype = stage2->PixelType();
dng_pixel_buffer buffer;
stage2->GetPixelBuffer(buffer);
int pixels = stage2->Bounds().H() * stage2->Bounds().W() * pplanes;
if (ptype == ttShort && !stage23used && !is_curve_linear())
{
imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ptype));
ushort *src = (ushort *)buffer.fData;
ushort *dst = (ushort *)imgdata.rawdata.raw_alloc;
for (int i = 0; i < pixels; i++)
dst[i] = imgdata.color.curve[src[i]];
S.raw_pitch = S.raw_width * pplanes * TagTypeSize(ptype);
}
else if (ptype == ttByte)
{
imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ttShort));
unsigned char *src = (unsigned char *)buffer.fData;
ushort *dst = (ushort *)imgdata.rawdata.raw_alloc;
if (is_curve_linear())
{
for (int i = 0; i < pixels; i++)
dst[i] = src[i];
}
else
{
for (int i = 0; i < pixels; i++)
dst[i] = imgdata.color.curve[src[i]];
}
S.raw_pitch = S.raw_width * pplanes * TagTypeSize(ttShort);
}
else
{
if ((imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNGSDK_ZEROCOPY) && !stage23used)
{
zerocopy = true;
}
else
{
imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ptype));
memmove(imgdata.rawdata.raw_alloc, buffer.fData,
pixels * TagTypeSize(ptype));
}
S.raw_pitch = S.raw_width * pplanes * TagTypeSize(ptype);
}
if (stage23used)
stage2.Release();
if (zerocopy)
{
switch (ptype)
{
case ttFloat:
if (pplanes == 1)
imgdata.rawdata.float_image = (float *)buffer.fData;
else if (pplanes == 3)
imgdata.rawdata.float3_image = (float(*)[3])buffer.fData;
else if (pplanes == 4)
imgdata.rawdata.float4_image = (float(*)[4])buffer.fData;
break;
case ttShort:
if (pplanes == 1)
imgdata.rawdata.raw_image = (ushort *)buffer.fData;
else if (pplanes == 3)
imgdata.rawdata.color3_image = (ushort(*)[3])buffer.fData;
else if (pplanes == 4)
imgdata.rawdata.color4_image = (ushort(*)[4])buffer.fData;
break;
default:
break;
}
}
else
{
switch (ptype)
{
case ttFloat:
if (pplanes == 1)
imgdata.rawdata.float_image = (float *)imgdata.rawdata.raw_alloc;
else if (pplanes == 3)
imgdata.rawdata.float3_image = (float(*)[3])imgdata.rawdata.raw_alloc;
else if (pplanes == 4)
imgdata.rawdata.float4_image = (float(*)[4])imgdata.rawdata.raw_alloc;
break;
case ttByte:
case ttShort:
if (pplanes == 1)
imgdata.rawdata.raw_image = (ushort *)imgdata.rawdata.raw_alloc;
else if (pplanes == 3)
imgdata.rawdata.color3_image =
(ushort(*)[3])imgdata.rawdata.raw_alloc;
else if (pplanes == 4)
imgdata.rawdata.color4_image =
(ushort(*)[4])imgdata.rawdata.raw_alloc;
break;
default:
break;
}
}
if (zerocopy)
{
dng_negative *stolen = negative.Release();
dngnegative = stolen;
dng_simple_image *simage = stage2.Release();
dngimage = simage;
}
}
catch (...)
{
return LIBRAW_UNSPECIFIED_ERROR;
}
return imgdata.rawdata.raw_alloc ? LIBRAW_SUCCESS : LIBRAW_UNSPECIFIED_ERROR;
#else
return LIBRAW_UNSPECIFIED_ERROR;
#endif
}
void LibRaw::set_dng_host(void *p)
{
#ifdef USE_DNGSDK
dnghost = p;
#endif
}