Permalink
Find file Copy path
7020 lines (6539 sloc) 210 KB
/* -*- C++ -*-
* File: libraw_cxx.cpp
* Copyright 2008-2018 LibRaw LLC (info@libraw.org)
* Created: Sat Mar 8 , 2008
*
* LibRaw C++ interface (implementation)
LibRaw is free software; you can redistribute it and/or modify
it under the terms of the one of two licenses as you choose:
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
*/
#include <math.h>
#include <errno.h>
#include <float.h>
#include <new>
#include <exception>
#include <sys/types.h>
#include <sys/stat.h>
#if !defined(_WIN32) && !defined(__MINGW32__)
#include <netinet/in.h>
#else
#include <winsock2.h>
#include <io.h>
#endif
#define LIBRAW_LIBRARY_BUILD
#include "libraw/libraw.h"
#include "internal/defines.h"
#ifdef USE_ZLIB
#include <zlib.h>
#endif
#ifdef USE_RAWSPEED
#include "../RawSpeed/rawspeed_xmldata.cpp"
#include <RawSpeed/StdAfx.h>
#include <RawSpeed/FileMap.h>
#include <RawSpeed/RawParser.h>
#include <RawSpeed/RawDecoder.h>
#include <RawSpeed/CameraMetaData.h>
#include <RawSpeed/ColorFilterArray.h>
#endif
#ifdef USE_DNGSDK
#include "dng_host.h"
#include "dng_negative.h"
#include "dng_simple_image.h"
#include "dng_info.h"
#endif
#include "libraw_fuji_compressed.cpp"
#ifdef __cplusplus
extern "C"
{
#endif
void default_memory_callback(void *, const char *file, const char *where)
{
fprintf(stderr, "%s: Out of memory in %s\n", file ? file : "unknown file", where);
}
void default_data_callback(void *, const char *file, const int offset)
{
if (offset < 0)
fprintf(stderr, "%s: Unexpected end of file\n", file ? file : "unknown file");
else
fprintf(stderr, "%s: data corrupted at %d\n", file ? file : "unknown file", offset);
}
const char *libraw_strerror(int e)
{
enum LibRaw_errors errorcode = (LibRaw_errors)e;
switch (errorcode)
{
case LIBRAW_SUCCESS:
return "No error";
case LIBRAW_UNSPECIFIED_ERROR:
return "Unspecified error";
case LIBRAW_FILE_UNSUPPORTED:
return "Unsupported file format or not RAW file";
case LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE:
return "Request for nonexisting image number";
case LIBRAW_OUT_OF_ORDER_CALL:
return "Out of order call of libraw function";
case LIBRAW_NO_THUMBNAIL:
return "No thumbnail in file";
case LIBRAW_UNSUPPORTED_THUMBNAIL:
return "Unsupported thumbnail format";
case LIBRAW_INPUT_CLOSED:
return "No input stream, or input stream closed";
case LIBRAW_MEMPOOL_OVERFLOW:
return "Libraw internal mempool overflowed";
case LIBRAW_UNSUFFICIENT_MEMORY:
return "Unsufficient memory";
case LIBRAW_DATA_ERROR:
return "Corrupted data or unexpected EOF";
case LIBRAW_IO_ERROR:
return "Input/output error";
case LIBRAW_CANCELLED_BY_CALLBACK:
return "Cancelled by user callback";
case LIBRAW_BAD_CROP:
return "Bad crop box";
case LIBRAW_TOO_BIG:
return "Image too big for processing";
default:
return "Unknown error code";
}
}
#ifdef __cplusplus
}
#endif
#define Sigma_X3F 22
const double LibRaw_constants::xyz_rgb[3][3] = {
{0.4124564, 0.3575761, 0.1804375}, {0.2126729, 0.7151522, 0.0721750}, {0.0193339, 0.1191920, 0.9503041}};
const float LibRaw_constants::d65_white[3] = {0.95047f, 1.0f, 1.08883f};
#define P1 imgdata.idata
#define S imgdata.sizes
#define O imgdata.params
#define C imgdata.color
#define T imgdata.thumbnail
#define IO libraw_internal_data.internal_output_params
#define ID libraw_internal_data.internal_data
#define EXCEPTION_HANDLER(e) \
do \
{ \
/* fprintf(stderr,"Exception %d caught\n",e);*/ \
switch (e) \
{ \
case LIBRAW_EXCEPTION_MEMPOOL: \
recycle(); \
return LIBRAW_MEMPOOL_OVERFLOW; \
case LIBRAW_EXCEPTION_ALLOC: \
recycle(); \
return LIBRAW_UNSUFFICIENT_MEMORY; \
case LIBRAW_EXCEPTION_TOOBIG: \
recycle(); \
return LIBRAW_TOO_BIG; \
case LIBRAW_EXCEPTION_DECODE_RAW: \
case LIBRAW_EXCEPTION_DECODE_JPEG: \
recycle(); \
return LIBRAW_DATA_ERROR; \
case LIBRAW_EXCEPTION_DECODE_JPEG2000: \
recycle(); \
return LIBRAW_DATA_ERROR; \
case LIBRAW_EXCEPTION_IO_EOF: \
case LIBRAW_EXCEPTION_IO_CORRUPT: \
recycle(); \
return LIBRAW_IO_ERROR; \
case LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK: \
recycle(); \
return LIBRAW_CANCELLED_BY_CALLBACK; \
case LIBRAW_EXCEPTION_BAD_CROP: \
recycle(); \
return LIBRAW_BAD_CROP; \
default: \
return LIBRAW_UNSPECIFIED_ERROR; \
} \
} while (0)
const char *LibRaw::version() { return LIBRAW_VERSION_STR; }
int LibRaw::versionNumber() { return LIBRAW_VERSION; }
const char *LibRaw::strerror(int p) { return libraw_strerror(p); }
unsigned LibRaw::capabilities()
{
unsigned ret = 0;
#ifdef USE_RAWSPEED
ret |= LIBRAW_CAPS_RAWSPEED;
#endif
#ifdef USE_DNGSDK
ret |= LIBRAW_CAPS_DNGSDK;
#endif
return ret;
}
unsigned LibRaw::parse_custom_cameras(unsigned limit, libraw_custom_camera_t table[], char **list)
{
if (!list)
return 0;
unsigned index = 0;
for (int i = 0; i < limit; i++)
{
if (!list[i])
break;
if (strlen(list[i]) < 10)
continue;
char *string = (char *)malloc(strlen(list[i]) + 1);
strcpy(string, list[i]);
char *start = string;
memset(&table[index], 0, sizeof(table[0]));
for (int j = 0; start && j < 14; j++)
{
char *end = strchr(start, ',');
if (end)
{
*end = 0;
end++;
} // move to next char
while (isspace(*start) && *start)
start++; // skip leading spaces?
unsigned val = strtol(start, 0, 10);
switch (j)
{
case 0:
table[index].fsize = val;
break;
case 1:
table[index].rw = val;
break;
case 2:
table[index].rh = val;
break;
case 3:
table[index].lm = val;
break;
case 4:
table[index].tm = val;
break;
case 5:
table[index].rm = val;
break;
case 6:
table[index].bm = val;
break;
case 7:
table[index].lf = val;
break;
case 8:
table[index].cf = val;
break;
case 9:
table[index].max = val;
break;
case 10:
table[index].flags = val;
break;
case 11:
strncpy(table[index].t_make, start, sizeof(table[index].t_make) - 1);
break;
case 12:
strncpy(table[index].t_model, start, sizeof(table[index].t_model) - 1);
break;
case 13:
table[index].offset = val;
break;
default:
break;
}
start = end;
}
free(string);
if (table[index].t_make[0])
index++;
}
return index;
}
void LibRaw::derror()
{
if (!libraw_internal_data.unpacker_data.data_error && libraw_internal_data.internal_data.input)
{
if (libraw_internal_data.internal_data.input->eof())
{
if (callbacks.data_cb)
(*callbacks.data_cb)(callbacks.datacb_data, libraw_internal_data.internal_data.input->fname(), -1);
throw LIBRAW_EXCEPTION_IO_EOF;
}
else
{
if (callbacks.data_cb)
(*callbacks.data_cb)(callbacks.datacb_data, libraw_internal_data.internal_data.input->fname(),
libraw_internal_data.internal_data.input->tell());
// throw LIBRAW_EXCEPTION_IO_CORRUPT;
}
}
libraw_internal_data.unpacker_data.data_error++;
}
void LibRaw::dcraw_clear_mem(libraw_processed_image_t *p)
{
if (p)
::free(p);
}
int LibRaw::is_sraw() { return load_raw == &LibRaw::canon_sraw_load_raw || load_raw == &LibRaw::nikon_load_sraw; }
int LibRaw::is_coolscan_nef() { return load_raw == &LibRaw::nikon_coolscan_load_raw; }
int LibRaw::is_jpeg_thumb() { return thumb_load_raw == 0 && write_thumb == &LibRaw::jpeg_thumb; }
int LibRaw::is_nikon_sraw() { return load_raw == &LibRaw::nikon_load_sraw; }
int LibRaw::sraw_midpoint()
{
if (load_raw == &LibRaw::canon_sraw_load_raw)
return 8192;
else if (load_raw == &LibRaw::nikon_load_sraw)
return 2048;
else
return 0;
}
#ifdef USE_RAWSPEED
using namespace RawSpeed;
class CameraMetaDataLR : public CameraMetaData
{
public:
CameraMetaDataLR() : CameraMetaData() {}
CameraMetaDataLR(char *filename) : CameraMetaData(filename) {}
CameraMetaDataLR(char *data, int sz);
};
CameraMetaDataLR::CameraMetaDataLR(char *data, int sz) : CameraMetaData()
{
ctxt = xmlNewParserCtxt();
if (ctxt == NULL)
{
ThrowCME("CameraMetaData:Could not initialize context.");
}
xmlResetLastError();
doc = xmlCtxtReadMemory(ctxt, data, sz, "", NULL, XML_PARSE_DTDVALID);
if (doc == NULL)
{
ThrowCME("CameraMetaData: XML Document could not be parsed successfully. Error was: %s", ctxt->lastError.message);
}
if (ctxt->valid == 0)
{
if (ctxt->lastError.code == 0x5e)
{
// printf("CameraMetaData: Unable to locate DTD, attempting to ignore.");
}
else
{
ThrowCME("CameraMetaData: XML file does not validate. DTD Error was: %s", ctxt->lastError.message);
}
}
xmlNodePtr cur;
cur = xmlDocGetRootElement(doc);
if (xmlStrcmp(cur->name, (const xmlChar *)"Cameras"))
{
ThrowCME("CameraMetaData: XML document of the wrong type, root node is not cameras.");
return;
}
cur = cur->xmlChildrenNode;
while (cur != NULL)
{
if ((!xmlStrcmp(cur->name, (const xmlChar *)"Camera")))
{
Camera *camera = new Camera(doc, cur);
addCamera(camera);
// Create cameras for aliases.
for (unsigned int i = 0; i < camera->aliases.size(); i++)
{
addCamera(new Camera(camera, i));
}
}
cur = cur->next;
}
if (doc)
xmlFreeDoc(doc);
doc = 0;
if (ctxt)
xmlFreeParserCtxt(ctxt);
ctxt = 0;
}
#define RAWSPEED_DATA_COUNT (sizeof(_rawspeed_data_xml) / sizeof(_rawspeed_data_xml[0]))
static CameraMetaDataLR *make_camera_metadata()
{
int len = 0, i;
for (i = 0; i < RAWSPEED_DATA_COUNT; i++)
if (_rawspeed_data_xml[i])
{
len += strlen(_rawspeed_data_xml[i]);
}
char *rawspeed_xml = (char *)calloc(len + 1, sizeof(_rawspeed_data_xml[0][0]));
if (!rawspeed_xml)
return NULL;
int offt = 0;
for (i = 0; i < RAWSPEED_DATA_COUNT; i++)
if (_rawspeed_data_xml[i])
{
int ll = strlen(_rawspeed_data_xml[i]);
if (offt + ll > len)
break;
memmove(rawspeed_xml + offt, _rawspeed_data_xml[i], ll);
offt += ll;
}
rawspeed_xml[offt] = 0;
CameraMetaDataLR *ret = NULL;
try
{
ret = new CameraMetaDataLR(rawspeed_xml, offt);
}
catch (...)
{
// Mask all exceptions
}
free(rawspeed_xml);
return ret;
}
#endif
#define ZERO(a) memset(&a, 0, sizeof(a))
static void cleargps(libraw_gps_info_t *q)
{
for (int i = 0; i < 3; i++)
q->latitude[i] = q->longtitude[i] = q->gpstimestamp[i] = 0.f;
q->altitude = 0.f;
q->altref = q->latref = q->longref = q->gpsstatus = q->gpsparsed = 0;
}
LibRaw::LibRaw(unsigned int flags) : memmgr(1024)
{
double aber[4] = {1, 1, 1, 1};
double gamm[6] = {0.45, 4.5, 0, 0, 0, 0};
unsigned greybox[4] = {0, 0, UINT_MAX, UINT_MAX};
unsigned cropbox[4] = {0, 0, UINT_MAX, UINT_MAX};
#ifdef DCRAW_VERBOSE
verbose = 1;
#else
verbose = 0;
#endif
ZERO(imgdata);
cleargps(&imgdata.other.parsed_gps);
ZERO(libraw_internal_data);
ZERO(callbacks);
_rawspeed_camerameta = _rawspeed_decoder = NULL;
dnghost = NULL;
dngnegative = NULL;
_x3f_data = NULL;
#ifdef USE_RAWSPEED
CameraMetaDataLR *camerameta = make_camera_metadata(); // May be NULL in case of exception in make_camera_metadata()
_rawspeed_camerameta = static_cast<void *>(camerameta);
#endif
callbacks.mem_cb = (flags & LIBRAW_OPIONS_NO_MEMERR_CALLBACK) ? NULL : &default_memory_callback;
callbacks.data_cb = (flags & LIBRAW_OPIONS_NO_DATAERR_CALLBACK) ? NULL : &default_data_callback;
callbacks.exif_cb = NULL; // no default callback
callbacks.pre_identify_cb = NULL;
callbacks.post_identify_cb = NULL;
callbacks.pre_subtractblack_cb = callbacks.pre_scalecolors_cb = callbacks.pre_preinterpolate_cb
= callbacks.pre_interpolate_cb = callbacks.interpolate_bayer_cb = callbacks.interpolate_xtrans_cb
= callbacks.post_interpolate_cb = callbacks.pre_converttorgb_cb = callbacks.post_converttorgb_cb
= NULL;
memmove(&imgdata.params.aber, &aber, sizeof(aber));
memmove(&imgdata.params.gamm, &gamm, sizeof(gamm));
memmove(&imgdata.params.greybox, &greybox, sizeof(greybox));
memmove(&imgdata.params.cropbox, &cropbox, sizeof(cropbox));
imgdata.params.bright = 1;
imgdata.params.use_camera_matrix = 1;
imgdata.params.user_flip = -1;
imgdata.params.user_black = -1;
imgdata.params.user_cblack[0] = imgdata.params.user_cblack[1] = imgdata.params.user_cblack[2] =
imgdata.params.user_cblack[3] = -1000001;
imgdata.params.user_sat = -1;
imgdata.params.user_qual = -1;
imgdata.params.output_color = 1;
imgdata.params.output_bps = 8;
imgdata.params.use_fuji_rotate = 1;
imgdata.params.exp_shift = 1.0;
imgdata.params.auto_bright_thr = LIBRAW_DEFAULT_AUTO_BRIGHTNESS_THRESHOLD;
imgdata.params.adjust_maximum_thr = LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD;
imgdata.params.use_rawspeed = 1;
imgdata.params.use_dngsdk = LIBRAW_DNG_DEFAULT;
imgdata.params.no_auto_scale = 0;
imgdata.params.no_interpolation = 0;
imgdata.params.raw_processing_options = LIBRAW_PROCESSING_DP2Q_INTERPOLATERG | LIBRAW_PROCESSING_DP2Q_INTERPOLATEAF |
LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT;
imgdata.params.sony_arw2_posterization_thr = 0;
imgdata.params.max_raw_memory_mb = LIBRAW_MAX_ALLOC_MB_DEFAULT;
imgdata.params.green_matching = 0;
imgdata.params.custom_camera_strings = 0;
imgdata.params.coolscan_nef_gamma = 1.0f;
imgdata.parent_class = this;
imgdata.progress_flags = 0;
imgdata.color.dng_levels.baseline_exposure = -999.f;
imgdata.color.dng_levels.LinearResponseLimit = 1.0f;
_exitflag = 0;
tls = new LibRaw_TLS;
tls->init();
}
int LibRaw::set_rawspeed_camerafile(char *filename)
{
#ifdef USE_RAWSPEED
try
{
CameraMetaDataLR *camerameta = new CameraMetaDataLR(filename);
if (_rawspeed_camerameta)
{
CameraMetaDataLR *d = static_cast<CameraMetaDataLR *>(_rawspeed_camerameta);
delete d;
}
_rawspeed_camerameta = static_cast<void *>(camerameta);
}
catch (...)
{
// just return error code
return -1;
}
#endif
return 0;
}
LibRaw::~LibRaw()
{
recycle();
delete tls;
#ifdef USE_RAWSPEED
if (_rawspeed_camerameta)
{
CameraMetaDataLR *cmeta = static_cast<CameraMetaDataLR *>(_rawspeed_camerameta);
delete cmeta;
_rawspeed_camerameta = NULL;
}
#endif
}
void *LibRaw::malloc(size_t t)
{
void *p = memmgr.malloc(t);
if (!p)
throw LIBRAW_EXCEPTION_ALLOC;
return p;
}
void *LibRaw::realloc(void *q, size_t t)
{
void *p = memmgr.realloc(q, t);
if (!p)
throw LIBRAW_EXCEPTION_ALLOC;
return p;
}
void *LibRaw::calloc(size_t n, size_t t)
{
void *p = memmgr.calloc(n, t);
if (!p)
throw LIBRAW_EXCEPTION_ALLOC;
return p;
}
void LibRaw::free(void *p) { memmgr.free(p); }
void LibRaw::recycle_datastream()
{
if (libraw_internal_data.internal_data.input && libraw_internal_data.internal_data.input_internal)
{
delete libraw_internal_data.internal_data.input;
libraw_internal_data.internal_data.input = NULL;
}
libraw_internal_data.internal_data.input_internal = 0;
}
void x3f_clear(void *);
void LibRaw::recycle()
{
recycle_datastream();
#define FREE(a) \
do \
{ \
if (a) \
{ \
free(a); \
a = NULL; \
} \
} while (0)
FREE(imgdata.image);
FREE(imgdata.thumbnail.thumb);
FREE(libraw_internal_data.internal_data.meta_data);
FREE(libraw_internal_data.output_data.histogram);
FREE(libraw_internal_data.output_data.oprof);
FREE(imgdata.color.profile);
FREE(imgdata.rawdata.ph1_cblack);
FREE(imgdata.rawdata.ph1_rblack);
FREE(imgdata.rawdata.raw_alloc);
FREE(imgdata.idata.xmpdata);
#undef FREE
ZERO(imgdata.sizes);
imgdata.sizes.raw_crop.cleft = 0xffff;
imgdata.sizes.raw_crop.ctop = 0xffff;
ZERO(imgdata.idata);
ZERO(imgdata.makernotes);
ZERO(imgdata.color);
ZERO(imgdata.other);
ZERO(imgdata.thumbnail);
ZERO(imgdata.rawdata);
imgdata.makernotes.olympus.OlympusCropID = -1;
imgdata.makernotes.sony.raw_crop.cleft = 0xffff;
imgdata.makernotes.sony.raw_crop.ctop = 0xffff;
cleargps(&imgdata.other.parsed_gps);
imgdata.color.dng_levels.baseline_exposure = -999.f;
imgdata.color.dng_levels.LinearResponseLimit = 1.f;
imgdata.makernotes.fuji.FujiExpoMidPointShift = -999.f;
imgdata.makernotes.fuji.FujiDynamicRange = 0xffff;
imgdata.makernotes.fuji.FujiFilmMode = 0xffff;
imgdata.makernotes.fuji.FujiDynamicRangeSetting = 0xffff;
imgdata.makernotes.fuji.FujiDevelopmentDynamicRange = 0xffff;
imgdata.makernotes.fuji.FujiAutoDynamicRange = 0xffff;
imgdata.makernotes.fuji.FocusMode = 0xffff;
imgdata.makernotes.fuji.AFMode = 0xffff;
imgdata.makernotes.fuji.FocusPixel[0] = imgdata.makernotes.fuji.FocusPixel[1] = 0xffff;
imgdata.makernotes.fuji.ImageStabilization[0] = imgdata.makernotes.fuji.ImageStabilization[1] =
imgdata.makernotes.fuji.ImageStabilization[2] = 0xffff;
imgdata.makernotes.samsung.ColorSpace[0] =
imgdata.makernotes.samsung.ColorSpace[1] = -1;
imgdata.makernotes.sony.SonyCameraType = 0xffff;
imgdata.makernotes.sony.real_iso_offset = 0xffff;
imgdata.makernotes.sony.ImageCount3_offset = 0xffff;
imgdata.makernotes.sony.ElectronicFrontCurtainShutter = 0xffff;
imgdata.makernotes.sony.MinoltaCamID = -1;
imgdata.makernotes.sony.RAWFileType = 0xffff;
imgdata.makernotes.sony.AFAreaModeSetting = 0xff;
imgdata.makernotes.sony.FlexibleSpotPosition[0] =
imgdata.makernotes.sony.FlexibleSpotPosition[1] = 0xffff;
imgdata.makernotes.sony.AFPointSelected = 0xff;
imgdata.makernotes.sony.LongExposureNoiseReduction = 0xffffffff;
imgdata.makernotes.sony.Quality = 0xffffffff;
imgdata.makernotes.sony.HighISONoiseReduction = 0xffff;
imgdata.makernotes.sony.SonyRawFileType = 0xffff;
imgdata.makernotes.kodak.BlackLevelTop = 0xffff;
imgdata.makernotes.kodak.BlackLevelBottom = 0xffff;
imgdata.color.dng_color[0].illuminant = imgdata.color.dng_color[1].illuminant = 0xffff;
for (int i = 0; i < 4; i++)
imgdata.color.dng_levels.analogbalance[i] = 1.0f;
ZERO(libraw_internal_data);
ZERO(imgdata.lens);
imgdata.lens.makernotes.CanonFocalUnits = 1;
imgdata.lens.makernotes.LensID = 0xffffffffffffffffULL;
ZERO(imgdata.shootinginfo);
imgdata.shootinginfo.DriveMode = -1;
imgdata.shootinginfo.FocusMode = -1;
imgdata.shootinginfo.MeteringMode = -1;
imgdata.shootinginfo.AFPoint = -1;
imgdata.shootinginfo.ExposureMode = -1;
imgdata.shootinginfo.ExposureProgram = -1;
imgdata.shootinginfo.ImageStabilization = -1;
_exitflag = 0;
#ifdef USE_RAWSPEED
if (_rawspeed_decoder)
{
RawDecoder *d = static_cast<RawDecoder *>(_rawspeed_decoder);
delete d;
}
_rawspeed_decoder = 0;
#endif
#ifdef USE_DNGSDK
if (dngnegative)
{
dng_negative *ng = (dng_negative*)dngnegative;
delete ng;
dngnegative = 0;
}
#endif
if (_x3f_data)
{
x3f_clear(_x3f_data);
_x3f_data = 0;
}
memmgr.cleanup();
imgdata.thumbnail.tformat = LIBRAW_THUMBNAIL_UNKNOWN;
imgdata.progress_flags = 0;
load_raw = thumb_load_raw = 0;
tls->init();
}
const char *LibRaw::unpack_function_name()
{
libraw_decoder_info_t decoder_info;
get_decoder_info(&decoder_info);
return decoder_info.decoder_name;
}
int LibRaw::get_decoder_info(libraw_decoder_info_t *d_info)
{
if (!d_info)
return LIBRAW_UNSPECIFIED_ERROR;
d_info->decoder_name = 0;
d_info->decoder_flags = 0;
if (!load_raw)
return LIBRAW_OUT_OF_ORDER_CALL;
int rawdata = (imgdata.idata.filters || P1.colors == 1);
// dcraw.c names order
if (load_raw == &LibRaw::android_tight_load_raw)
{
d_info->decoder_name = "android_tight_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::android_loose_load_raw)
{
d_info->decoder_name = "android_loose_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::float_dng_load_raw_placeholder)
{
d_info->decoder_name = "float_dng_load_raw_placeholder()";
}
else if (load_raw == &LibRaw::canon_600_load_raw)
{
d_info->decoder_name = "canon_600_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::fuji_compressed_load_raw)
{
d_info->decoder_name = "fuji_compressed_load_raw()";
}
else if (load_raw == &LibRaw::fuji_14bit_load_raw)
{
d_info->decoder_name = "fuji_14bit_load_raw()";
}
else if (load_raw == &LibRaw::canon_load_raw)
{
d_info->decoder_name = "canon_load_raw()";
}
else if (load_raw == &LibRaw::lossless_jpeg_load_raw)
{
d_info->decoder_name = "lossless_jpeg_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_TRYRAWSPEED;
}
else if (load_raw == &LibRaw::canon_sraw_load_raw)
{
d_info->decoder_name = "canon_sraw_load_raw()";
// d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED;
}
else if (load_raw == &LibRaw::lossless_dng_load_raw)
{
d_info->decoder_name = "lossless_dng_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_ADOBECOPYPIXEL;
}
else if (load_raw == &LibRaw::packed_dng_load_raw)
{
d_info->decoder_name = "packed_dng_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_ADOBECOPYPIXEL;
}
else if (load_raw == &LibRaw::pentax_load_raw)
{
d_info->decoder_name = "pentax_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED;
}
else if (load_raw == &LibRaw::nikon_load_raw)
{
d_info->decoder_name = "nikon_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_HASCURVE;
}
else if (load_raw == &LibRaw::nikon_coolscan_load_raw)
{
d_info->decoder_name = "nikon_coolscan_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::nikon_load_sraw)
{
d_info->decoder_name = "nikon_load_sraw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::nikon_yuv_load_raw)
{
d_info->decoder_name = "nikon_load_yuv_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::rollei_load_raw)
{
// UNTESTED
d_info->decoder_name = "rollei_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::phase_one_load_raw)
{
d_info->decoder_name = "phase_one_load_raw()";
}
else if (load_raw == &LibRaw::phase_one_load_raw_c)
{
d_info->decoder_name = "phase_one_load_raw_c()";
}
else if (load_raw == &LibRaw::hasselblad_load_raw)
{
d_info->decoder_name = "hasselblad_load_raw()";
}
else if (load_raw == &LibRaw::leaf_hdr_load_raw)
{
d_info->decoder_name = "leaf_hdr_load_raw()";
}
else if (load_raw == &LibRaw::unpacked_load_raw)
{
d_info->decoder_name = "unpacked_load_raw()";
}
else if (load_raw == &LibRaw::unpacked_load_raw_reversed)
{
d_info->decoder_name = "unpacked_load_raw_reversed()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::sinar_4shot_load_raw)
{
// UNTESTED
d_info->decoder_name = "sinar_4shot_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_SINAR4SHOT;
}
else if (load_raw == &LibRaw::imacon_full_load_raw)
{
d_info->decoder_name = "imacon_full_load_raw()";
}
else if (load_raw == &LibRaw::hasselblad_full_load_raw)
{
d_info->decoder_name = "hasselblad_full_load_raw()";
}
else if (load_raw == &LibRaw::packed_load_raw)
{
d_info->decoder_name = "packed_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED;
}
else if (load_raw == &LibRaw::broadcom_load_raw)
{
// UNTESTED
d_info->decoder_name = "broadcom_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::nokia_load_raw)
{
// UNTESTED
d_info->decoder_name = "nokia_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::canon_rmf_load_raw)
{
// UNTESTED
d_info->decoder_name = "canon_rmf_load_raw()";
}
else if (load_raw == &LibRaw::panasonic_load_raw)
{
d_info->decoder_name = "panasonic_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED;
}
else if (load_raw == &LibRaw::olympus_load_raw)
{
d_info->decoder_name = "olympus_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED;
}
else if (load_raw == &LibRaw::minolta_rd175_load_raw)
{
// UNTESTED
d_info->decoder_name = "minolta_rd175_load_raw()";
}
else if (load_raw == &LibRaw::quicktake_100_load_raw)
{
// UNTESTED
d_info->decoder_name = "quicktake_100_load_raw()";
}
else if (load_raw == &LibRaw::kodak_radc_load_raw)
{
d_info->decoder_name = "kodak_radc_load_raw()";
}
else if (load_raw == &LibRaw::kodak_jpeg_load_raw)
{
// UNTESTED + RBAYER
d_info->decoder_name = "kodak_jpeg_load_raw()";
}
else if (load_raw == &LibRaw::lossy_dng_load_raw)
{
// Check rbayer
d_info->decoder_name = "lossy_dng_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_HASCURVE;
}
else if (load_raw == &LibRaw::kodak_dc120_load_raw)
{
d_info->decoder_name = "kodak_dc120_load_raw()";
}
else if (load_raw == &LibRaw::eight_bit_load_raw)
{
d_info->decoder_name = "eight_bit_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::kodak_c330_load_raw)
{
d_info->decoder_name = "kodak_yrgb_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::kodak_c603_load_raw)
{
d_info->decoder_name = "kodak_yrgb_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::kodak_262_load_raw)
{
d_info->decoder_name = "kodak_262_load_raw()"; // UNTESTED!
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::kodak_65000_load_raw)
{
d_info->decoder_name = "kodak_65000_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE;
}
else if (load_raw == &LibRaw::kodak_ycbcr_load_raw)
{
// UNTESTED
d_info->decoder_name = "kodak_ycbcr_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::kodak_rgb_load_raw)
{
// UNTESTED
d_info->decoder_name = "kodak_rgb_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::sony_load_raw)
{
d_info->decoder_name = "sony_load_raw()";
}
else if (load_raw == &LibRaw::sony_arw_load_raw)
{
d_info->decoder_name = "sony_arw_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED;
}
else if (load_raw == &LibRaw::sony_arw2_load_raw)
{
d_info->decoder_name = "sony_arw2_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_SONYARW2;
}
else if (load_raw == &LibRaw::sony_arq_load_raw)
{
d_info->decoder_name = "sony_arq_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_LEGACY_WITH_MARGINS;
}
else if (load_raw == &LibRaw::samsung_load_raw)
{
d_info->decoder_name = "samsung_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED;
}
else if (load_raw == &LibRaw::samsung2_load_raw)
{
d_info->decoder_name = "samsung2_load_raw()";
}
else if (load_raw == &LibRaw::samsung3_load_raw)
{
d_info->decoder_name = "samsung3_load_raw()";
}
else if (load_raw == &LibRaw::smal_v6_load_raw)
{
// UNTESTED
d_info->decoder_name = "smal_v6_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::smal_v9_load_raw)
{
// UNTESTED
d_info->decoder_name = "smal_v9_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC;
}
else if (load_raw == &LibRaw::redcine_load_raw)
{
d_info->decoder_name = "redcine_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_HASCURVE;
}
else if (load_raw == &LibRaw::x3f_load_raw)
{
d_info->decoder_name = "x3f_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_OWNALLOC | LIBRAW_DECODER_FIXEDMAXC | LIBRAW_DECODER_LEGACY_WITH_MARGINS;
}
else if (load_raw == &LibRaw::pentax_4shot_load_raw)
{
d_info->decoder_name = "pentax_4shot_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_OWNALLOC;
}
else if (load_raw == &LibRaw::deflate_dng_load_raw)
{
d_info->decoder_name = "deflate_dng_load_raw()";
d_info->decoder_flags = LIBRAW_DECODER_OWNALLOC;
}
else if (load_raw == &LibRaw::nikon_load_striped_packed_raw)
{
d_info->decoder_name = "nikon_load_striped_packed_raw()";
}
else if (load_raw == &LibRaw::nikon_load_padded_packed_raw)
{
d_info->decoder_name = "nikon_load_padded_packed_raw()";
}
else if (load_raw == &LibRaw::nikon_14bit_load_raw)
{
d_info->decoder_name = "nikon_14bit_load_raw()";
}
/* -- added 07/02/18 -- */
else if (load_raw == &LibRaw::unpacked_load_raw_fuji_f700s20)
{
d_info->decoder_name = "unpacked_load_raw_fuji_f700s20()";
}
else if (load_raw == &LibRaw::unpacked_load_raw_FujiDBP)
{
d_info->decoder_name = "unpacked_load_raw_FujiDBP()";
}
else
{
d_info->decoder_name = "Unknown unpack function";
d_info->decoder_flags = LIBRAW_DECODER_NOTSET;
}
return LIBRAW_SUCCESS;
}
int LibRaw::adjust_maximum()
{
ushort real_max;
float auto_threshold;
if (O.adjust_maximum_thr < 0.00001)
return LIBRAW_SUCCESS;
else if (O.adjust_maximum_thr > 0.99999)
auto_threshold = LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD;
else
auto_threshold = O.adjust_maximum_thr;
real_max = C.data_maximum;
if (real_max > 0 && real_max < C.maximum && real_max > C.maximum * auto_threshold)
{
C.maximum = real_max;
}
return LIBRAW_SUCCESS;
}
void LibRaw::merror(void *ptr, const char *where)
{
if (ptr)
return;
if (callbacks.mem_cb)
(*callbacks.mem_cb)(
callbacks.memcb_data,
libraw_internal_data.internal_data.input ? libraw_internal_data.internal_data.input->fname() : NULL, where);
throw LIBRAW_EXCEPTION_ALLOC;
}
int LibRaw::open_file(const char *fname, INT64 max_buf_size)
{
#ifndef WIN32
struct stat st;
if (stat(fname, &st))
return LIBRAW_IO_ERROR;
int big = (st.st_size > max_buf_size) ? 1 : 0;
#else
struct _stati64 st;
if (_stati64(fname, &st))
return LIBRAW_IO_ERROR;
int big = (st.st_size > max_buf_size) ? 1 : 0;
#endif
LibRaw_abstract_datastream *stream;
try
{
if (big)
stream = new LibRaw_bigfile_datastream(fname);
else
stream = new LibRaw_file_datastream(fname);
}
catch (std::bad_alloc)
{
recycle();
return LIBRAW_UNSUFFICIENT_MEMORY;
}
if (!stream->valid())
{
delete stream;
return LIBRAW_IO_ERROR;
}
ID.input_internal = 0; // preserve from deletion on error
int ret = open_datastream(stream);
if (ret == LIBRAW_SUCCESS)
{
ID.input_internal = 1; // flag to delete datastream on recycle
}
else
{
delete stream;
ID.input_internal = 0;
}
return ret;
}
#if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310)
int LibRaw::open_file(const wchar_t *fname, INT64 max_buf_size)
{
struct _stati64 st;
if (_wstati64(fname, &st))
return LIBRAW_IO_ERROR;
int big = (st.st_size > max_buf_size) ? 1 : 0;
LibRaw_abstract_datastream *stream;
try
{
if (big)
stream = new LibRaw_bigfile_datastream(fname);
else
stream = new LibRaw_file_datastream(fname);
}
catch (std::bad_alloc)
{
recycle();
return LIBRAW_UNSUFFICIENT_MEMORY;
}
if (!stream->valid())
{
delete stream;
return LIBRAW_IO_ERROR;
}
ID.input_internal = 0; // preserve from deletion on error
int ret = open_datastream(stream);
if (ret == LIBRAW_SUCCESS)
{
ID.input_internal = 1; // flag to delete datastream on recycle
}
else
{
delete stream;
ID.input_internal = 0;
}
return ret;
}
#endif
int LibRaw::open_buffer(void *buffer, size_t size)
{
// this stream will close on recycle()
if (!buffer || buffer == (void *)-1)
return LIBRAW_IO_ERROR;
LibRaw_buffer_datastream *stream;
try
{
stream = new LibRaw_buffer_datastream(buffer, size);
}
catch (std::bad_alloc)
{
recycle();
return LIBRAW_UNSUFFICIENT_MEMORY;
}
if (!stream->valid())
{
delete stream;
return LIBRAW_IO_ERROR;
}
ID.input_internal = 0; // preserve from deletion on error
int ret = open_datastream(stream);
if (ret == LIBRAW_SUCCESS)
{
ID.input_internal = 1; // flag to delete datastream on recycle
}
else
{
delete stream;
ID.input_internal = 0;
}
return ret;
}
int LibRaw::open_bayer(unsigned char *buffer, unsigned datalen, ushort _raw_width, ushort _raw_height,
ushort _left_margin, ushort _top_margin, ushort _right_margin, ushort _bottom_margin,
unsigned char procflags, unsigned char bayer_pattern, unsigned unused_bits, unsigned otherflags,
unsigned black_level)
{
// this stream will close on recycle()
if (!buffer || buffer == (void *)-1)
return LIBRAW_IO_ERROR;
LibRaw_buffer_datastream *stream;
try
{
stream = new LibRaw_buffer_datastream(buffer, datalen);
}
catch (std::bad_alloc)
{
recycle();
return LIBRAW_UNSUFFICIENT_MEMORY;
}
if (!stream->valid())
{
delete stream;
return LIBRAW_IO_ERROR;
}
ID.input = stream;
SET_PROC_FLAG(LIBRAW_PROGRESS_OPEN);
// From identify
initdata();
strcpy(imgdata.idata.make, "BayerDump");
snprintf(imgdata.idata.model, sizeof(imgdata.idata.model) - 1, "%u x %u pixels", _raw_width, _raw_height);
S.flip = procflags >> 2;
libraw_internal_data.internal_output_params.zero_is_bad = procflags & 2;
libraw_internal_data.unpacker_data.data_offset = 0;
S.raw_width = _raw_width;
S.raw_height = _raw_height;
S.left_margin = _left_margin;
S.top_margin = _top_margin;
S.width = S.raw_width - S.left_margin - _right_margin;
S.height = S.raw_height - S.top_margin - _bottom_margin;
imgdata.idata.filters = 0x1010101 * bayer_pattern;
imgdata.idata.colors = 4 - !((imgdata.idata.filters & imgdata.idata.filters >> 1) & 0x5555);
libraw_internal_data.unpacker_data.load_flags = otherflags;
switch (libraw_internal_data.unpacker_data.tiff_bps = (datalen)*8 / (S.raw_width * S.raw_height))
{
case 8:
load_raw = &CLASS eight_bit_load_raw;
break;
case 10:
if ((datalen) / S.raw_height * 3 >= S.raw_width * 4)
{
load_raw = &CLASS android_loose_load_raw;
break;
}
else if (libraw_internal_data.unpacker_data.load_flags & 1)
{
load_raw = &CLASS android_tight_load_raw;
break;
}
case 12:
libraw_internal_data.unpacker_data.load_flags |= 128;
load_raw = &CLASS packed_load_raw;
break;
case 16:
libraw_internal_data.unpacker_data.order = 0x4949 | 0x404 * (libraw_internal_data.unpacker_data.load_flags & 1);
libraw_internal_data.unpacker_data.tiff_bps -= libraw_internal_data.unpacker_data.load_flags >> 4;
libraw_internal_data.unpacker_data.tiff_bps -= libraw_internal_data.unpacker_data.load_flags =
libraw_internal_data.unpacker_data.load_flags >> 1 & 7;
load_raw = &CLASS unpacked_load_raw;
}
C.maximum = (1 << libraw_internal_data.unpacker_data.tiff_bps) - (1 << unused_bits);
C.black = black_level;
S.iwidth = S.width;
S.iheight = S.height;
imgdata.idata.colors = 3;
imgdata.idata.filters |= ((imgdata.idata.filters >> 2 & 0x22222222) | (imgdata.idata.filters << 2 & 0x88888888)) &
imgdata.idata.filters << 1;
imgdata.idata.raw_count = 1;
for (int i = 0; i < 4; i++)
imgdata.color.pre_mul[i] = 1.0;
strcpy(imgdata.idata.cdesc, "RGBG");
ID.input_internal = 1;
SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY);
return LIBRAW_SUCCESS;
}
#ifdef USE_ZLIB
inline unsigned int __DNG_HalfToFloat(ushort halfValue)
{
int sign = (halfValue >> 15) & 0x00000001;
int exponent = (halfValue >> 10) & 0x0000001f;
int mantissa = halfValue & 0x000003ff;
if (exponent == 0)
{
if (mantissa == 0)
{
return (unsigned int)(sign << 31);
}
else
{
while (!(mantissa & 0x00000400))
{
mantissa <<= 1;
exponent -= 1;
}
exponent += 1;
mantissa &= ~0x00000400;
}
}
else if (exponent == 31)
{
if (mantissa == 0)
{
return (unsigned int)((sign << 31) | ((0x1eL + 127 - 15) << 23) | (0x3ffL << 13));
}
else
{
return 0;
}
}
exponent += (127 - 15);
mantissa <<= 13;
return (unsigned int)((sign << 31) | (exponent << 23) | mantissa);
}
inline unsigned int __DNG_FP24ToFloat(const unsigned char *input)
{
int sign = (input[0] >> 7) & 0x01;
int exponent = (input[0]) & 0x7F;
int mantissa = (((int)input[1]) << 8) | input[2];
if (exponent == 0)
{
if (mantissa == 0)
{
return (unsigned int)(sign << 31);
}
else
{
while (!(mantissa & 0x00010000))
{
mantissa <<= 1;
exponent -= 1;
}
exponent += 1;
mantissa &= ~0x00010000;
}
}
else if (exponent == 127)
{
if (mantissa == 0)
{
return (unsigned int)((sign << 31) | ((0x7eL + 128 - 64) << 23) | (0xffffL << 7));
}
else
{
// Nan -- Just set to zero.
return 0;
}
}
exponent += (128 - 64);
mantissa <<= 7;
return (uint32_t)((sign << 31) | (exponent << 23) | mantissa);
}
inline void DecodeDeltaBytes(unsigned char *bytePtr, int cols, int channels)
{
if (channels == 1)
{
unsigned char b0 = bytePtr[0];
bytePtr += 1;
for (uint32_t col = 1; col < cols; ++col)
{
b0 += bytePtr[0];
bytePtr[0] = b0;
bytePtr += 1;
}
}
else if (channels == 3)
{
unsigned char b0 = bytePtr[0];
unsigned char b1 = bytePtr[1];
unsigned char b2 = bytePtr[2];
bytePtr += 3;
for (int col = 1; col < cols; ++col)
{
b0 += bytePtr[0];
b1 += bytePtr[1];
b2 += bytePtr[2];
bytePtr[0] = b0;
bytePtr[1] = b1;
bytePtr[2] = b2;
bytePtr += 3;
}
}
else if (channels == 4)
{
unsigned char b0 = bytePtr[0];
unsigned char b1 = bytePtr[1];
unsigned char b2 = bytePtr[2];
unsigned char b3 = bytePtr[3];
bytePtr += 4;
for (uint32_t col = 1; col < cols; ++col)
{
b0 += bytePtr[0];
b1 += bytePtr[1];
b2 += bytePtr[2];
b3 += bytePtr[3];
bytePtr[0] = b0;
bytePtr[1] = b1;
bytePtr[2] = b2;
bytePtr[3] = b3;
bytePtr += 4;
}
}
else
{
for (int col = 1; col < cols; ++col)
{
for (int chan = 0; chan < channels; ++chan)
{
bytePtr[chan + channels] += bytePtr[chan];
}
bytePtr += channels;
}
}
}
static void DecodeFPDelta(unsigned char *input, unsigned char *output, int cols, int channels, int bytesPerSample)
{
DecodeDeltaBytes(input, cols * bytesPerSample, channels);
int32_t rowIncrement = cols * channels;
if (bytesPerSample == 2)
{
#if LibRawBigEndian
const unsigned char *input0 = input;
const unsigned char *input1 = input + rowIncrement;
#else
const unsigned char *input1 = input;
const unsigned char *input0 = input + rowIncrement;
#endif
for (int col = 0; col < rowIncrement; ++col)
{
output[0] = input0[col];
output[1] = input1[col];
output += 2;
}
}
else if (bytesPerSample == 3)
{
const unsigned char *input0 = input;
const unsigned char *input1 = input + rowIncrement;
const unsigned char *input2 = input + rowIncrement * 2;
for (int col = 0; col < rowIncrement; ++col)
{
output[0] = input0[col];
output[1] = input1[col];
output[2] = input2[col];
output += 3;
}
}
else
{
#if LibRawBigEndian
const unsigned char *input0 = input;
const unsigned char *input1 = input + rowIncrement;
const unsigned char *input2 = input + rowIncrement * 2;
const unsigned char *input3 = input + rowIncrement * 3;
#else
const unsigned char *input3 = input;
const unsigned char *input2 = input + rowIncrement;
const unsigned char *input1 = input + rowIncrement * 2;
const unsigned char *input0 = input + rowIncrement * 3;
#endif
for (int col = 0; col < rowIncrement; ++col)
{
output[0] = input0[col];
output[1] = input1[col];
output[2] = input2[col];
output[3] = input3[col];
output += 4;
}
}
}
static float expandFloats(unsigned char *dst, int tileWidth, int bytesps)
{
float max = 0.f;
if (bytesps == 2)
{
uint16_t *dst16 = (ushort *)dst;
uint32_t *dst32 = (unsigned int *)dst;
float *f32 = (float *)dst;
for (int index = tileWidth - 1; index >= 0; --index)
{
dst32[index] = __DNG_HalfToFloat(dst16[index]);
max = MAX(max, f32[index]);
}
}
else if (bytesps == 3)
{
uint8_t *dst8 = ((unsigned char *)dst) + (tileWidth - 1) * 3;
uint32_t *dst32 = (unsigned int *)dst;
float *f32 = (float *)dst;
for (int index = tileWidth - 1; index >= 0; --index, dst8 -= 3)
{
dst32[index] = __DNG_FP24ToFloat(dst8);
max = MAX(max, f32[index]);
}
}
else if (bytesps == 4)
{
float *f32 = (float *)dst;
for (int index = 0; index < tileWidth; index++)
max = MAX(max, f32[index]);
}
return max;
}
void LibRaw::deflate_dng_load_raw()
{
struct tiff_ifd_t *ifd = &tiff_ifd[0];
while (ifd < &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds] &&
ifd->offset != libraw_internal_data.unpacker_data.data_offset)
++ifd;
if (ifd == &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds])
{
throw LIBRAW_EXCEPTION_DECODE_RAW;
}
float *float_raw_image = 0;
float max = 0.f;
if (ifd->samples != 1 && ifd->samples != 3 && ifd->samples != 4)
throw LIBRAW_EXCEPTION_DECODE_RAW; // Only float deflated supported
if (libraw_internal_data.unpacker_data.tiff_samples != ifd->samples)
throw LIBRAW_EXCEPTION_DECODE_RAW; // Wrong IFD
size_t tilesH = (imgdata.sizes.raw_width + libraw_internal_data.unpacker_data.tile_width - 1) /
libraw_internal_data.unpacker_data.tile_width;
size_t tilesV = (imgdata.sizes.raw_height + libraw_internal_data.unpacker_data.tile_length - 1) /
libraw_internal_data.unpacker_data.tile_length;
size_t tileCnt = tilesH * tilesV;
if (ifd->sample_format == 3)
{ // Floating point data
float_raw_image = (float *)calloc(tileCnt * libraw_internal_data.unpacker_data.tile_length *
libraw_internal_data.unpacker_data.tile_width * ifd->samples,
sizeof(float));
// imgdata.color.maximum = 65535;
// imgdata.color.black = 0;
// memset(imgdata.color.cblack,0,sizeof(imgdata.color.cblack));
}
else
throw LIBRAW_EXCEPTION_DECODE_RAW; // Only float deflated supported
int xFactor;
switch (ifd->predictor)
{
case 3:
default:
xFactor = 1;
break;
case 34894:
xFactor = 2;
break;
case 34895:
xFactor = 4;
break;
}
if (libraw_internal_data.unpacker_data.tile_length < INT_MAX)
{
if (tileCnt < 1 || tileCnt > 1000000)
throw LIBRAW_EXCEPTION_DECODE_RAW;
size_t *tOffsets = (size_t *)malloc(tileCnt * sizeof(size_t));
for (int t = 0; t < tileCnt; ++t)
tOffsets[t] = get4();
size_t *tBytes = (size_t *)malloc(tileCnt * sizeof(size_t));
unsigned long maxBytesInTile = 0;
if (tileCnt == 1)
tBytes[0] = maxBytesInTile = ifd->bytes;
else
{
libraw_internal_data.internal_data.input->seek(ifd->bytes, SEEK_SET);
for (size_t t = 0; t < tileCnt; ++t)
{
tBytes[t] = get4();
maxBytesInTile = MAX(maxBytesInTile, tBytes[t]);
}
}
unsigned tilePixels =
libraw_internal_data.unpacker_data.tile_width * libraw_internal_data.unpacker_data.tile_length;
unsigned pixelSize = sizeof(float) * ifd->samples;
unsigned tileBytes = tilePixels * pixelSize;
unsigned tileRowBytes = libraw_internal_data.unpacker_data.tile_width * pixelSize;
unsigned char *cBuffer = (unsigned char *)malloc(maxBytesInTile);
unsigned char *uBuffer = (unsigned char *)malloc(tileBytes + tileRowBytes); // extra row for decoding
for (size_t y = 0, t = 0; y < imgdata.sizes.raw_height; y += libraw_internal_data.unpacker_data.tile_length)
{
for (size_t x = 0; x < imgdata.sizes.raw_width; x += libraw_internal_data.unpacker_data.tile_width, ++t)
{
libraw_internal_data.internal_data.input->seek(tOffsets[t], SEEK_SET);
libraw_internal_data.internal_data.input->read(cBuffer, 1, tBytes[t]);
unsigned long dstLen = tileBytes;
int err = uncompress(uBuffer + tileRowBytes, &dstLen, cBuffer, tBytes[t]);
if (err != Z_OK)
{
free(tOffsets);
free(tBytes);
free(cBuffer);
free(uBuffer);
throw LIBRAW_EXCEPTION_DECODE_RAW;
return;
}
else
{
int bytesps = ifd->bps >> 3;
size_t rowsInTile = y + libraw_internal_data.unpacker_data.tile_length > imgdata.sizes.raw_height
? imgdata.sizes.raw_height - y
: libraw_internal_data.unpacker_data.tile_length;
size_t colsInTile = x + libraw_internal_data.unpacker_data.tile_width > imgdata.sizes.raw_width
? imgdata.sizes.raw_width - x
: libraw_internal_data.unpacker_data.tile_width;
for (size_t row = 0; row < rowsInTile; ++row) // do not process full tile if not needed
{
unsigned char *dst = uBuffer + row * libraw_internal_data.unpacker_data.tile_width * bytesps * ifd->samples;
unsigned char *src = dst + tileRowBytes;
DecodeFPDelta(src, dst, libraw_internal_data.unpacker_data.tile_width / xFactor, ifd->samples * xFactor,
bytesps);
float lmax = expandFloats(dst, libraw_internal_data.unpacker_data.tile_width * ifd->samples, bytesps);
max = MAX(max, lmax);
unsigned char *dst2 =
(unsigned char *)&float_raw_image[((y + row) * imgdata.sizes.raw_width + x) * ifd->samples];
memmove(dst2, dst, colsInTile * ifd->samples * sizeof(float));
}
}
}
}
free(tOffsets);
free(tBytes);
free(cBuffer);
free(uBuffer);
}
imgdata.color.fmaximum = max;
// Set fields according to data format
imgdata.rawdata.raw_alloc = float_raw_image;
if (ifd->samples == 1)
{
imgdata.rawdata.float_image = float_raw_image;
imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 4;
}
else if (ifd->samples == 3)
{
imgdata.rawdata.float3_image = (float(*)[3])float_raw_image;
imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 12;
}
else if (ifd->samples == 4)
{
imgdata.rawdata.float4_image = (float(*)[4])float_raw_image;
imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 16;
}
if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT)
convertFloatToInt(); // with default settings
}
#else
void LibRaw::deflate_dng_load_raw() { throw LIBRAW_EXCEPTION_DECODE_RAW; }
#endif
void LibRaw::float_dng_load_raw_placeholder()
{
// placeholder only, real decoding implemented in DNG SDK
throw LIBRAW_EXCEPTION_DECODE_RAW;
}
int LibRaw::is_floating_point()
{
struct tiff_ifd_t *ifd = &tiff_ifd[0];
while (ifd < &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds] &&
ifd->offset != libraw_internal_data.unpacker_data.data_offset)
++ifd;
if (ifd == &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds])
return 0;
return ifd->sample_format == 3;
}
int LibRaw::have_fpdata()
{
return imgdata.rawdata.float_image || imgdata.rawdata.float3_image || imgdata.rawdata.float4_image;
}
void LibRaw::convertFloatToInt(float dmin /* =4096.f */, float dmax /* =32767.f */, float dtarget /*= 16383.f */)
{
int samples = 0;
float *data = 0;
if (imgdata.rawdata.float_image)
{
samples = 1;
data = imgdata.rawdata.float_image;
}
else if (imgdata.rawdata.float3_image)
{
samples = 3;
data = (float *)imgdata.rawdata.float3_image;
}
else if (imgdata.rawdata.float4_image)
{
samples = 4;
data = (float *)imgdata.rawdata.float4_image;
}
else
return;
ushort *raw_alloc = (ushort *)malloc(imgdata.sizes.raw_height * imgdata.sizes.raw_width *
libraw_internal_data.unpacker_data.tiff_samples * sizeof(ushort));
float tmax = MAX(imgdata.color.maximum, 1);
float datamax = imgdata.color.fmaximum;
tmax = MAX(tmax, datamax);
tmax = MAX(tmax, 1.f);
float multip = 1.f;
if (tmax < dmin || tmax > dmax)
{
imgdata.rawdata.color.fnorm = imgdata.color.fnorm = multip = dtarget / tmax;
imgdata.rawdata.color.maximum = imgdata.color.maximum = dtarget;
imgdata.rawdata.color.black = imgdata.color.black = (float)imgdata.color.black * multip;
for (int i = 0; i < sizeof(imgdata.color.cblack) / sizeof(imgdata.color.cblack[0]); i++)
if (i != 4 && i != 5)
imgdata.rawdata.color.cblack[i] = imgdata.color.cblack[i] = (float)imgdata.color.cblack[i] * multip;
}
else
imgdata.rawdata.color.fnorm = imgdata.color.fnorm = 0.f;
for (size_t i = 0;
i < imgdata.sizes.raw_height * imgdata.sizes.raw_width * libraw_internal_data.unpacker_data.tiff_samples; ++i)
{
float val = MAX(data[i], 0.f);
raw_alloc[i] = (ushort)(val * multip);
}
if (samples == 1)
{
imgdata.rawdata.raw_alloc = imgdata.rawdata.raw_image = raw_alloc;
imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 2;
}
else if (samples == 3)
{
imgdata.rawdata.raw_alloc = imgdata.rawdata.color3_image = (ushort(*)[3])raw_alloc;
imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 6;
}
else if (samples == 4)
{
imgdata.rawdata.raw_alloc = imgdata.rawdata.color4_image = (ushort(*)[4])raw_alloc;
imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 8;
}
free(data); // remove old allocation
imgdata.rawdata.float_image = 0;
imgdata.rawdata.float3_image = 0;
imgdata.rawdata.float4_image = 0;
}
void LibRaw::sony_arq_load_raw()
{
int row, col;
read_shorts(imgdata.rawdata.raw_image, imgdata.sizes.raw_width * imgdata.sizes.raw_height * 4);
libraw_internal_data.internal_data.input->seek(-2,SEEK_CUR); // avoid wrong eof error
for (row = 0; row < imgdata.sizes.raw_height; row++)
{
unsigned short(*rowp)[4] = (unsigned short(*)[4]) & imgdata.rawdata.raw_image[row * imgdata.sizes.raw_width * 4];
for (col = 0; col < imgdata.sizes.raw_width; col++)
{
unsigned short g2 = rowp[col][2];
rowp[col][2] = rowp[col][3];
rowp[col][3] = g2;
if (((unsigned)(row - imgdata.sizes.top_margin) < imgdata.sizes.height) &&
((unsigned)(col - imgdata.sizes.left_margin) < imgdata.sizes.width) &&
(MAX(MAX(rowp[col][0], rowp[col][1]), MAX(rowp[col][2], rowp[col][3])) > imgdata.color.maximum))
derror();
}
}
}
void LibRaw::pentax_4shot_load_raw()
{
ushort *plane = (ushort *)malloc(imgdata.sizes.raw_width * imgdata.sizes.raw_height * sizeof(ushort));
int alloc_sz = imgdata.sizes.raw_width * (imgdata.sizes.raw_height + 16) * 4 * sizeof(ushort);
ushort(*result)[4] = (ushort(*)[4])malloc(alloc_sz);
struct movement_t
{
int row, col;
} _move[4] = {
{1, 1},
{0, 1},
{0, 0},
{1, 0},
};
int tidx = 0;
for (int i = 0; i < 4; i++)
{
int move_row, move_col;
if (imgdata.params.p4shot_order[i] >= '0' && imgdata.params.p4shot_order[i] <= '3')
{
move_row = (imgdata.params.p4shot_order[i] - '0' & 2) ? 1 : 0;
move_col = (imgdata.params.p4shot_order[i] - '0' & 1) ? 1 : 0;
}
else
{
move_row = _move[i].row;
move_col = _move[i].col;
}
for (; tidx < 16; tidx++)
if (tiff_ifd[tidx].t_width == imgdata.sizes.raw_width && tiff_ifd[tidx].t_height == imgdata.sizes.raw_height &&
tiff_ifd[tidx].bps > 8 && tiff_ifd[tidx].samples == 1)
break;
if (tidx >= 16)
break;
imgdata.rawdata.raw_image = plane;
ID.input->seek(tiff_ifd[tidx].offset, SEEK_SET);
imgdata.idata.filters = 0xb4b4b4b4;
libraw_internal_data.unpacker_data.data_offset = tiff_ifd[tidx].offset;
(this->*pentax_component_load_raw)();
for (int row = 0; row < imgdata.sizes.raw_height - move_row; row++)
{
int colors[2];
for (int c = 0; c < 2; c++)
colors[c] = COLOR(row, c);
ushort *srcrow = &plane[imgdata.sizes.raw_width * row];
ushort(*dstrow)[4] = &result[(imgdata.sizes.raw_width) * (row + move_row) + move_col];
for (int col = 0; col < imgdata.sizes.raw_width - move_col; col++)
dstrow[col][colors[col % 2]] = srcrow[col];
}
tidx++;
}
// assign things back:
imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 8;
imgdata.idata.filters = 0;
imgdata.rawdata.raw_alloc = imgdata.rawdata.color4_image = result;
free(plane);
imgdata.rawdata.raw_image = 0;
}
void LibRaw::hasselblad_full_load_raw()
{
int row, col;
for (row = 0; row < S.height; row++)
for (col = 0; col < S.width; col++)
{
read_shorts(&imgdata.image[row * S.width + col][2], 1); // B
read_shorts(&imgdata.image[row * S.width + col][1], 1); // G
read_shorts(&imgdata.image[row * S.width + col][0], 1); // R
}
}
static inline void unpack7bytesto4x16(unsigned char *src, unsigned short *dest)
{
dest[0] = (src[0] << 6) | (src[1] >> 2);
dest[1] = ((src[1] & 0x3) << 12) | (src[2] << 4) | (src[3] >> 4);
dest[2] = (src[3] & 0xf) << 10 | (src[4] << 2) | (src[5] >> 6);
dest[3] = ((src[5] & 0x3f) << 8) | src[6];
}
static inline void unpack28bytesto16x16ns(unsigned char *src, unsigned short *dest)
{
dest[0] = (src[3] << 6) | (src[2] >> 2);
dest[1] = ((src[2] & 0x3) << 12) | (src[1] << 4) | (src[0] >> 4);
dest[2] = (src[0] & 0xf) << 10 | (src[7] << 2) | (src[6] >> 6);
dest[3] = ((src[6] & 0x3f) << 8) | src[5];
dest[4] = (src[4] << 6) | (src[11] >> 2);
dest[5] = ((src[11] & 0x3) << 12) | (src[10] << 4) | (src[9] >> 4);
dest[6] = (src[9] & 0xf) << 10 | (src[8] << 2) | (src[15] >> 6);
dest[7] = ((src[15] & 0x3f) << 8) | src[14];
dest[8] = (src[13] << 6) | (src[12] >> 2);
dest[9] = ((src[12] & 0x3) << 12) | (src[19] << 4) | (src[18] >> 4);
dest[10] = (src[18] & 0xf) << 10 | (src[17] << 2) | (src[16] >> 6);
dest[11] = ((src[16] & 0x3f) << 8) | src[23];
dest[12] = (src[22] << 6) | (src[21] >> 2);
dest[13] = ((src[21] & 0x3) << 12) | (src[20] << 4) | (src[27] >> 4);
dest[14] = (src[27] & 0xf) << 10 | (src[26] << 2) | (src[25] >> 6);
dest[15] = ((src[25] & 0x3f) << 8) | src[24];
}
#define swab32(x) \
((unsigned int)((((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
(((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \
(((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \
(((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24)))
static inline void swab32arr(unsigned *arr, unsigned len)
{
for (unsigned i = 0; i < len; i++)
arr[i] = swab32(arr[i]);
}
#undef swab32
static inline void unpack7bytesto4x16_nikon(unsigned char *src, unsigned short *dest)
{
dest[3] = (src[6] << 6) | (src[5] >> 2);
dest[2] = ((src[5] & 0x3) << 12) | (src[4] << 4) | (src[3] >> 4);
dest[1] = (src[3] & 0xf) << 10 | (src[2] << 2) | (src[1] >> 6);
dest[0] = ((src[1] & 0x3f) << 8) | src[0];
}
void LibRaw::nikon_14bit_load_raw()
{
const unsigned linelen = (unsigned)(ceilf((float)(S.raw_width * 7 / 4) / 16.0)) * 16; // 14512; // S.raw_width * 7 / 4;
const unsigned pitch = S.raw_pitch ? S.raw_pitch / 2 : S.raw_width;
unsigned char *buf = (unsigned char *)malloc(linelen);
merror(buf, "nikon_14bit_load_raw()");
for (int row = 0; row < S.raw_height; row++)
{
unsigned bytesread = libraw_internal_data.internal_data.input->read(buf, 1, linelen);
unsigned short *dest = &imgdata.rawdata.raw_image[pitch * row];
//swab32arr((unsigned *)buf, bytesread / 4);
for (int sp = 0, dp = 0; dp < pitch - 3 && sp < linelen - 6 && sp < bytesread - 6; sp += 7, dp += 4)
unpack7bytesto4x16_nikon(buf + sp, dest + dp);
}
free(buf);
}
void LibRaw::fuji_14bit_load_raw()
{
const unsigned linelen = S.raw_width * 7 / 4;
const unsigned pitch = S.raw_pitch ? S.raw_pitch / 2 : S.raw_width;
unsigned char *buf = (unsigned char *)malloc(linelen);
merror(buf, "fuji_14bit_load_raw()");
for (int row = 0; row < S.raw_height; row++)
{
unsigned bytesread = libraw_internal_data.internal_data.input->read(buf, 1, linelen);
unsigned short *dest = &imgdata.rawdata.raw_image[pitch * row];
if (bytesread % 28)
{
swab32arr((unsigned *)buf, bytesread / 4);
for (int sp = 0, dp = 0; dp < pitch - 3 && sp < linelen - 6 && sp < bytesread - 6; sp += 7, dp += 4)
unpack7bytesto4x16(buf + sp, dest + dp);
}
else
for (int sp = 0, dp = 0; dp < pitch - 15 && sp < linelen - 27 && sp < bytesread - 27; sp += 28, dp += 16)
unpack28bytesto16x16ns(buf + sp, dest + dp);
}
free(buf);
}
void LibRaw::nikon_load_padded_packed_raw() // 12 bit per pixel, padded to 16 bytes
{
// libraw_internal_data.unpacker_data.load_flags -> row byte count
if(libraw_internal_data.unpacker_data.load_flags < 2000 || libraw_internal_data.unpacker_data.load_flags > 64000) return;
unsigned char *buf = (unsigned char*)malloc(libraw_internal_data.unpacker_data.load_flags);
for (int row = 0; row < S.raw_height; row++)
{
checkCancel();
libraw_internal_data.internal_data.input->read(buf,libraw_internal_data.unpacker_data.load_flags,1);
for (int icol = 0; icol < S.raw_width/2; icol++)
{
imgdata.rawdata.raw_image[(row)*S.raw_width + (icol*2)] = ((buf[icol*3+1] & 0xf) << 8) | buf[icol*3];
imgdata.rawdata.raw_image[(row)*S.raw_width + (icol*2+1)] = buf[icol*3+2] << 4 | ((buf[icol*3+1] & 0xf0)>>4);
}
}
free(buf);
}
void LibRaw::nikon_load_striped_packed_raw()
{
int vbits = 0, bwide, rbits, bite, row, col, val, i;
UINT64 bitbuf = 0;
unsigned load_flags = 24; // libraw_internal_data.unpacker_data.load_flags;
unsigned tiff_bps = libraw_internal_data.unpacker_data.tiff_bps;
int tiff_compress = libraw_internal_data.unpacker_data.tiff_compress;
struct tiff_ifd_t *ifd = &tiff_ifd[0];
while (ifd < &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds] &&
ifd->offset != libraw_internal_data.unpacker_data.data_offset)
++ifd;
if (ifd == &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds])
throw LIBRAW_EXCEPTION_DECODE_RAW;
if (!ifd->rows_per_strip || !ifd->strip_offsets_count)
return; // not unpacked
int stripcnt = 0;
bwide = S.raw_width * tiff_bps / 8;
bwide += bwide & load_flags >> 7;
rbits = bwide * 8 - S.raw_width * tiff_bps;
if (load_flags & 1)
bwide = bwide * 16 / 15;
bite = 8 + (load_flags & 24);
for (row = 0; row < S.raw_height; row++)
{
checkCancel();
if (!(row % ifd->rows_per_strip))
{
if (stripcnt >= ifd->strip_offsets_count)
return; // run out of data
libraw_internal_data.internal_data.input->seek(ifd->strip_offsets[stripcnt], SEEK_SET);
stripcnt++;
}
for (col = 0; col < S.raw_width; col++)
{
for (vbits -= tiff_bps; vbits < 0; vbits += bite)
{
bitbuf <<= bite;
for (i = 0; i < bite; i += 8)
bitbuf |= (unsigned)(libraw_internal_data.internal_data.input->get_char() << i);
}
imgdata.rawdata.raw_image[(row)*S.raw_width + (col)] = bitbuf << (64 - tiff_bps - vbits) >> (64 - tiff_bps);
}
vbits -= rbits;
}
}
struct foveon_data_t
{
const char *make;
const char *model;
const int raw_width, raw_height;
const int white;
const int left_margin, top_margin;
const int width, height;
} foveon_data[] = {
{"Sigma", "SD9", 2304, 1531, 12000, 20, 8, 2266, 1510},
{"Sigma", "SD9", 1152, 763, 12000, 10, 2, 1132, 755},
{"Sigma", "SD10", 2304, 1531, 12000, 20, 8, 2266, 1510},
{"Sigma", "SD10", 1152, 763, 12000, 10, 2, 1132, 755},
{"Sigma", "SD14", 2688, 1792, 14000, 18, 12, 2651, 1767},
{"Sigma", "SD14", 2688, 896, 14000, 18, 6, 2651, 883}, // 2/3
{"Sigma", "SD14", 1344, 896, 14000, 9, 6, 1326, 883}, // 1/2
{"Sigma", "SD15", 2688, 1792, 2900, 18, 12, 2651, 1767},
{"Sigma", "SD15", 2688, 896, 2900, 18, 6, 2651, 883}, // 2/3 ?
{"Sigma", "SD15", 1344, 896, 2900, 9, 6, 1326, 883}, // 1/2 ?
{"Sigma", "DP1", 2688, 1792, 2100, 18, 12, 2651, 1767},
{"Sigma", "DP1", 2688, 896, 2100, 18, 6, 2651, 883}, // 2/3 ?
{"Sigma", "DP1", 1344, 896, 2100, 9, 6, 1326, 883}, // 1/2 ?
{"Sigma", "DP1S", 2688, 1792, 2200, 18, 12, 2651, 1767},
{"Sigma", "DP1S", 2688, 896, 2200, 18, 6, 2651, 883}, // 2/3
{"Sigma", "DP1S", 1344, 896, 2200, 9, 6, 1326, 883}, // 1/2
{"Sigma", "DP1X", 2688, 1792, 3560, 18, 12, 2651, 1767},
{"Sigma", "DP1X", 2688, 896, 3560, 18, 6, 2651, 883}, // 2/3
{"Sigma", "DP1X", 1344, 896, 3560, 9, 6, 1326, 883}, // 1/2
{"Sigma", "DP2", 2688, 1792, 2326, 13, 16, 2651, 1767},
{"Sigma", "DP2", 2688, 896, 2326, 13, 8, 2651, 883}, // 2/3 ??
{"Sigma", "DP2", 1344, 896, 2326, 7, 8, 1325, 883}, // 1/2 ??
{"Sigma", "DP2S", 2688, 1792, 2300, 18, 12, 2651, 1767},
{"Sigma", "DP2S", 2688, 896, 2300, 18, 6, 2651, 883}, // 2/3
{"Sigma", "DP2S", 1344, 896, 2300, 9, 6, 1326, 883}, // 1/2
{"Sigma", "DP2X", 2688, 1792, 2300, 18, 12, 2651, 1767},
{"Sigma", "DP2X", 2688, 896, 2300, 18, 6, 2651, 883}, // 2/3
{"Sigma", "DP2X", 1344, 896, 2300, 9, 6, 1325, 883}, // 1/2
{"Sigma", "SD1", 4928, 3264, 3900, 12, 52, 4807, 3205}, // Full size
{"Sigma", "SD1", 4928, 1632, 3900, 12, 26, 4807, 1603}, // 2/3 size
{"Sigma", "SD1", 2464, 1632, 3900, 6, 26, 2403, 1603}, // 1/2 size
{"Sigma", "SD1 Merrill", 4928, 3264, 3900, 12, 52, 4807, 3205}, // Full size
{"Sigma", "SD1 Merrill", 4928, 1632, 3900, 12, 26, 4807, 1603}, // 2/3 size
{"Sigma", "SD1 Merrill", 2464, 1632, 3900, 6, 26, 2403, 1603}, // 1/2 size
{"Sigma", "DP1 Merrill", 4928, 3264, 3900, 12, 0, 4807, 3205},
{"Sigma", "DP1 Merrill", 2464, 1632, 3900, 12, 0, 2403, 1603}, // 1/2 size
{"Sigma", "DP1 Merrill", 4928, 1632, 3900, 12, 0, 4807, 1603}, // 2/3 size
{"Sigma", "DP2 Merrill", 4928, 3264, 3900, 12, 0, 4807, 3205},
{"Sigma", "DP2 Merrill", 2464, 1632, 3900, 12, 0, 2403, 1603}, // 1/2 size
{"Sigma", "DP2 Merrill", 4928, 1632, 3900, 12, 0, 4807, 1603}, // 2/3 size
{"Sigma", "DP3 Merrill", 4928, 3264, 3900, 12, 0, 4807, 3205},
{"Sigma", "DP3 Merrill", 2464, 1632, 3900, 12, 0, 2403, 1603}, // 1/2 size
{"Sigma", "DP3 Merrill", 4928, 1632, 3900, 12, 0, 4807, 1603}, // 2/3 size
{"Polaroid", "x530", 1440, 1088, 2700, 10, 13, 1419, 1059},
// dp2 Q
{"Sigma", "dp3 Quattro", 5888, 3672, 16383, 204, 24, 5446, 3624}, // full size
{"Sigma", "dp3 Quattro", 2944, 1836, 16383, 102, 12, 2723, 1812}, // half size
{"Sigma", "dp2 Quattro", 5888, 3672, 16383, 204, 24, 5446, 3624}, // full size
{"Sigma", "dp2 Quattro", 2944, 1836, 16383, 102, 12, 2723, 1812}, // half size
{"Sigma", "dp1 Quattro", 5888, 3672, 16383, 204, 24, 5446, 3624}, // full size
{"Sigma", "dp1 Quattro", 2944, 1836, 16383, 102, 12, 2723, 1812}, // half size
{"Sigma", "dp0 Quattro", 5888, 3672, 16383, 204, 24, 5446, 3624}, // full size
{"Sigma", "dp0 Quattro", 2944, 1836, 16383, 102, 12, 2723, 1812}, // half size
// Sigma sd Quattro
{"Sigma", "sd Quattro", 5888, 3776, 16383, 204, 76, 5446, 3624}, // full size
{"Sigma", "sd Quattro", 2944, 1888, 16383, 102, 38, 2723, 1812}, // half size
// Sd Quattro H
{"Sigma", "sd Quattro H", 6656, 4480, 16383, 224, 160, 6208, 4160}, // full size
{"Sigma", "sd Quattro H", 3328, 2240, 16383, 112, 80, 3104, 2080}, // half size
{"Sigma", "sd Quattro H", 5504, 3680, 16383, 0, 4, 5496, 3668}, // full size
{"Sigma", "sd Quattro H", 2752, 1840, 16383, 0, 2, 2748, 1834}, // half size
};
const int foveon_count = sizeof(foveon_data) / sizeof(foveon_data[0]);
int LibRaw::open_datastream(LibRaw_abstract_datastream *stream)
{
if (!stream)
return ENOENT;
if (!stream->valid())
return LIBRAW_IO_ERROR;
recycle();
if(callbacks.pre_identify_cb)
{
int r = (callbacks.pre_identify_cb)(this);
if(r == 1) goto final;
}
try
{
ID.input = stream;
SET_PROC_FLAG(LIBRAW_PROGRESS_OPEN);
identify();
if(callbacks.post_identify_cb)
(callbacks.post_identify_cb)(this);
if (load_raw == &LibRaw::nikon_load_raw)
nikon_read_curve();
#define NIKON_14BIT_SIZE(rw,rh) (((unsigned)(ceilf((float)(rw * 7 / 4) / 16.0)) * 16)*rh)
// Ugly hack, replace with proper data/line size for different cameras/format when available
if (!strcasecmp(imgdata.idata.make, "Nikon") && !strncasecmp(imgdata.idata.model,"Z",1) &&
NIKON_14BIT_SIZE(imgdata.sizes.raw_width,imgdata.sizes.raw_height) == libraw_internal_data.unpacker_data.data_size)
{
load_raw = &LibRaw::nikon_14bit_load_raw;
}
#undef NIKON_14BIT_SIZE
// Linear max from 14-bit camera, but on 12-bit data?
if(( !strcasecmp(imgdata.idata.make, "Sony") /* || !strcasecmp(imgdata.idata.make, "Nikon") */)
&& imgdata.color.maximum > 0 && imgdata.color.linear_max[0] > imgdata.color.maximum
&& imgdata.color.linear_max[0] <= imgdata.color.maximum*4)
for(int c = 0; c<4; c++)
imgdata.color.linear_max[c] /= 4;
if (!strcasecmp(imgdata.idata.make, "Canon") && (load_raw == &LibRaw::canon_sraw_load_raw) &&
imgdata.sizes.raw_width > 0)
{
float ratio = float(imgdata.sizes.raw_height) / float(imgdata.sizes.raw_width);
if ((ratio < 0.57 || ratio > 0.75) && imgdata.makernotes.canon.SensorHeight > 1 &&
imgdata.makernotes.canon.SensorWidth > 1)
{
imgdata.sizes.raw_width = imgdata.makernotes.canon.SensorWidth;
imgdata.sizes.left_margin = imgdata.makernotes.canon.SensorLeftBorder;
imgdata.sizes.iwidth = imgdata.sizes.width =
imgdata.makernotes.canon.SensorRightBorder - imgdata.makernotes.canon.SensorLeftBorder + 1;
imgdata.sizes.raw_height = imgdata.makernotes.canon.SensorHeight;
imgdata.sizes.top_margin = imgdata.makernotes.canon.SensorTopBorder;
imgdata.sizes.iheight = imgdata.sizes.height =
imgdata.makernotes.canon.SensorBottomBorder - imgdata.makernotes.canon.SensorTopBorder + 1;
libraw_internal_data.unpacker_data.load_flags |= 256; // reset width/height in canon_sraw_load_raw()
imgdata.sizes.raw_pitch = 8 * imgdata.sizes.raw_width;
}
else if (imgdata.sizes.raw_width == 4032 && imgdata.sizes.raw_height == 3402 &&
!strcasecmp(imgdata.idata.model, "EOS 80D")) // 80D hardcoded
{
imgdata.sizes.raw_width = 4536;
imgdata.sizes.left_margin = 28;
imgdata.sizes.iwidth = imgdata.sizes.width = imgdata.sizes.raw_width - imgdata.sizes.left_margin;
imgdata.sizes.raw_height = 3024;
imgdata.sizes.top_margin = 8;
imgdata.sizes.iheight = imgdata.sizes.height = imgdata.sizes.raw_height - imgdata.sizes.top_margin;
libraw_internal_data.unpacker_data.load_flags |= 256;
imgdata.sizes.raw_pitch = 8 * imgdata.sizes.raw_width;
}
}
// XTrans Compressed?
if (!imgdata.idata.dng_version && !strcasecmp(imgdata.idata.make, "Fujifilm") &&
(load_raw == &LibRaw::unpacked_load_raw))
{
if (imgdata.sizes.raw_width * imgdata.sizes.raw_height * 2 != libraw_internal_data.unpacker_data.data_size)
{
if (imgdata.sizes.raw_width * imgdata.sizes.raw_height * 7 / 4 == libraw_internal_data.unpacker_data.data_size)
load_raw = &LibRaw::fuji_14bit_load_raw;
else
parse_fuji_compressed_header();
}
if (imgdata.idata.filters == 9)
{
// Adjust top/left margins for X-Trans
int newtm = imgdata.sizes.top_margin % 6 ? (imgdata.sizes.top_margin / 6 + 1) * 6 : imgdata.sizes.top_margin;
int newlm = imgdata.sizes.left_margin % 6 ? (imgdata.sizes.left_margin / 6 + 1) * 6 : imgdata.sizes.left_margin;
if (newtm != imgdata.sizes.top_margin || newlm != imgdata.sizes.left_margin)
{
imgdata.sizes.height -= (newtm - imgdata.sizes.top_margin);
imgdata.sizes.top_margin = newtm;
imgdata.sizes.width -= (newlm - imgdata.sizes.left_margin);
imgdata.sizes.left_margin = newlm;
for (int c1 = 0; c1 < 6; c1++)
for (int c2 = 0; c2 < 6; c2++)
imgdata.idata.xtrans[c1][c2] = imgdata.idata.xtrans_abs[c1][c2];
}
}
}
// Fix DNG white balance if needed
if (imgdata.idata.dng_version && (imgdata.idata.filters == 0) && imgdata.idata.colors > 1 &&
imgdata.idata.colors < 5)
{
float delta[4] = {0.f, 0.f, 0.f, 0.f};
int black[4];
for (int c = 0; c < 4; c++)
black[c] = imgdata.color.dng_levels.dng_black + imgdata.color.dng_levels.dng_cblack[c];
for (int c = 0; c < imgdata.idata.colors; c++)
delta[c] = imgdata.color.dng_levels.dng_whitelevel[c] - black[c];
float mindelta = delta[0], maxdelta = delta[0];
for (int c = 1; c < imgdata.idata.colors; c++)
{
if (mindelta > delta[c])
mindelta = delta[c];
if (maxdelta < delta[c])
maxdelta = delta[c];
}
if (mindelta > 1 && maxdelta < (mindelta * 20)) // safety
{
for (int c = 0; c < imgdata.idata.colors; c++)
{
imgdata.color.cam_mul[c] /= (delta[c] / maxdelta);
imgdata.color.pre_mul[c] /= (delta[c] / maxdelta);
}
imgdata.color.maximum = imgdata.color.cblack[0] + maxdelta;
}
}
if (imgdata.idata.dng_version &&
((!strcasecmp(imgdata.idata.make, "Leica") && !strcasecmp(imgdata.idata.model, "D-LUX (Typ 109)")) ||
(!strcasecmp(imgdata.idata.make, "Panasonic") && !strcasecmp(imgdata.idata.model, "LX100"))))
imgdata.sizes.width = 4288;
if (!strncasecmp(imgdata.idata.make, "Sony", 4) && imgdata.idata.dng_version &&
!(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_USE_DNG_DEFAULT_CROP))
{
if (S.raw_width == 3984)
S.width = 3925;
else if (S.raw_width == 4288)
S.width = S.raw_width - 32;
else if (S.raw_width == 4928 && S.height < 3280)
S.width = S.raw_width - 8;
else if (S.raw_width == 5504)
S.width = S.raw_width - (S.height > 3664 ? 8 : 32);
}
if (!strncasecmp(imgdata.idata.make, "Sony", 4) && !imgdata.idata.dng_version && !strncasecmp(imgdata.idata.model, "ILCE-7RM3", 9) &&
S.raw_width == 5216) // A7RM3 in APS mode
S.width = S.raw_width - 32;
if (!strcasecmp(imgdata.idata.make, "Pentax") &&
/*!strcasecmp(imgdata.idata.model,"K-3 II") &&*/ imgdata.idata.raw_count == 4 &&
(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_PENTAX_PS_ALLFRAMES))
{
imgdata.idata.raw_count = 1;
imgdata.idata.filters = 0;
imgdata.idata.colors = 4;
IO.mix_green = 1;
pentax_component_load_raw = load_raw;
load_raw = &LibRaw::pentax_4shot_load_raw;
}
if (!imgdata.idata.dng_version && !strcmp(imgdata.idata.make, "Leaf") && !strcmp(imgdata.idata.model, "Credo 50"))
{
imgdata.color.pre_mul[0] = 1.f / 0.3984f;
imgdata.color.pre_mul[2] = 1.f / 0.7666f;
imgdata.color.pre_mul[1] = imgdata.color.pre_mul[3] = 1.0;
}
// S3Pro DNG patch
if (imgdata.idata.dng_version && !strcmp(imgdata.idata.make, "Fujifilm") && !strcmp(imgdata.idata.model, "S3Pro") &&
imgdata.sizes.raw_width == 4288)
{
imgdata.sizes.left_margin++;
imgdata.sizes.width--;
}
if (imgdata.idata.dng_version && !strcmp(imgdata.idata.make, "Fujifilm") && !strcmp(imgdata.idata.model, "S5Pro") &&
imgdata.sizes.raw_width == 4288)
{
imgdata.sizes.left_margin++;
imgdata.sizes.width--;
}
if (!imgdata.idata.dng_version && !strcmp(imgdata.idata.make, "Fujifilm") &&
(!strncmp(imgdata.idata.model, "S20Pro", 6) || !strncmp(imgdata.idata.model, "F700", 4)))
{
imgdata.sizes.raw_width /= 2;
load_raw = &LibRaw::unpacked_load_raw_fuji_f700s20;
}
if (load_raw == &LibRaw::packed_load_raw && !strcasecmp(imgdata.idata.make, "Nikon") &&
!libraw_internal_data.unpacker_data.load_flags &&
(!strncasecmp(imgdata.idata.model, "D810", 4) || !strcasecmp(imgdata.idata.model, "D4S")) &&
libraw_internal_data.unpacker_data.data_size * 2 == imgdata.sizes.raw_height * imgdata.sizes.raw_width * 3)
{
libraw_internal_data.unpacker_data.load_flags = 80;
}
// Adjust BL for Sony A900/A850
if (load_raw == &LibRaw::packed_load_raw &&
!strcasecmp(imgdata.idata.make, "Sony")) // 12 bit sony, but metadata may be for 14-bit range
{
if (C.maximum > 4095)
C.maximum = 4095;
if (C.black > 256 || C.cblack[0] > 256)
{
C.black /= 4;
for (int c = 0; c < 4; c++)
C.cblack[c] /= 4;
for (int c = 0; c < C.cblack[4] * C.cblack[5]; c++)
C.cblack[6 + c] /= 4;
}
}
if (load_raw == &LibRaw::nikon_yuv_load_raw) // Is it Nikon sRAW?
{
load_raw = &LibRaw::nikon_load_sraw;
C.black = 0;
memset(C.cblack, 0, sizeof(C.cblack));
imgdata.idata.filters = 0;
libraw_internal_data.unpacker_data.tiff_samples = 3;
imgdata.idata.colors = 3;
double beta_1 = -5.79342238397656E-02;
double beta_2 = 3.28163551282665;
double beta_3 = -8.43136004842678;
double beta_4 = 1.03533181861023E+01;
for (int i = 0; i <= 3072; i++)
{
double x = (double)i / 3072.;
double y = (1. - exp(-beta_1 * x - beta_2 * x * x - beta_3 * x * x * x - beta_4 * x * x * x * x));
if (y < 0.)
y = 0.;
imgdata.color.curve[i] = (y * 16383.);
}
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; j++)
imgdata.color.rgb_cam[i][j] = float(i == j);
}
// Adjust BL for Nikon 12bit
if ((load_raw == &LibRaw::nikon_load_raw
|| load_raw == &LibRaw::packed_load_raw
|| load_raw == &LibRaw::nikon_load_padded_packed_raw
)
&& !strcasecmp(imgdata.idata.make, "Nikon")
&& strncmp(imgdata.idata.model, "COOLPIX", 7)
&& libraw_internal_data.unpacker_data.tiff_bps == 12)
{
C.maximum = 4095;
C.black /= 4;
for (int c = 0; c < 4; c++)
C.cblack[c] /= 4;
for (int c = 0; c < C.cblack[4] * C.cblack[5]; c++)
C.cblack[6 + c] /= 4;
}
// Adjust wb_already_applied
if( load_raw == &LibRaw::nikon_load_sraw)
imgdata.color.as_shot_wb_applied = LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_NIKON_SRAW;
else if(!strcasecmp(imgdata.idata.make,"Canon") && imgdata.makernotes.canon.multishot[0] >= 8
&& imgdata.makernotes.canon.multishot[1] > 0)
imgdata.color.as_shot_wb_applied = LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_CANON;
else if(!strcasecmp(imgdata.idata.make,"Nikon") && imgdata.makernotes.nikon.ExposureMode == 1)
imgdata.color.as_shot_wb_applied = LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_NIKON;
else if(!strcasecmp(imgdata.idata.make,"Pentax") && imgdata.makernotes.pentax.MultiExposure >0)
imgdata.color.as_shot_wb_applied = LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_PENTAX;
else
imgdata.color.as_shot_wb_applied = 0;
// Adjust Highlight Linearity limit
if (C.linear_max[0] < 0)
{
if (imgdata.idata.dng_version)
{
for (int c = 0; c < 4; c++)
C.linear_max[c] = -1 * C.linear_max[c] + imgdata.color.cblack[c + 6];
}
else
{
for (int c = 0; c < 4; c++)
C.linear_max[c] = -1 * C.linear_max[c] + imgdata.color.cblack[c];
}
}
if (!strcasecmp(imgdata.idata.make, "Nikon") && (!C.linear_max[0]) && (C.maximum > 1024) &&
(load_raw != &LibRaw::nikon_load_sraw))
{
C.linear_max[0] = C.linear_max[1] = C.linear_max[2] = C.linear_max[3] = (long)((float)(C.maximum) / 1.07f);
}
// Correct WB for Samsung GX20
if (!strcasecmp(imgdata.idata.make, "Samsung") && !strcasecmp(imgdata.idata.model, "GX20"))
{
C.WB_Coeffs[LIBRAW_WBI_Daylight][2] = (int)((float)(C.WB_Coeffs[LIBRAW_WBI_Daylight][2]) * 2.56f);
C.WB_Coeffs[LIBRAW_WBI_Shade][2] = (int)((float)(C.WB_Coeffs[LIBRAW_WBI_Shade][2]) * 2.56f);
C.WB_Coeffs[LIBRAW_WBI_Cloudy][2] = (int)((float)(C.WB_Coeffs[LIBRAW_WBI_Cloudy][2]) * 2.56f);
C.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = (int)((float)(C.WB_Coeffs[LIBRAW_WBI_Tungsten][2]) * 2.56f);
C.WB_Coeffs[LIBRAW_WBI_FL_D][2] = (int)((float)(C.WB_Coeffs[LIBRAW_WBI_FL_D][2]) * 2.56f);
C.WB_Coeffs[LIBRAW_WBI_FL_N][2] = (int)((float)(C.WB_Coeffs[LIBRAW_WBI_FL_N][2]) * 2.56f);
C.WB_Coeffs[LIBRAW_WBI_FL_W][2] = (int)((float)(C.WB_Coeffs[LIBRAW_WBI_FL_W][2]) * 2.56f);
C.WB_Coeffs[LIBRAW_WBI_Flash][2] = (int)((float)(C.WB_Coeffs[LIBRAW_WBI_Flash][2]) * 2.56f);
for (int c = 0; c < 64; c++)
{
if (imgdata.color.WBCT_Coeffs[c][0] > 0.0f)
{
imgdata.color.WBCT_Coeffs[c][3] *= 2.56f;
}
}
}
// Adjust BL for Panasonic
if (load_raw == &LibRaw::panasonic_load_raw &&
(!strcasecmp(imgdata.idata.make, "Panasonic") || !strcasecmp(imgdata.idata.make, "Leica") ||
!strcasecmp(imgdata.idata.make, "YUNEEC")) &&
ID.pana_black[0] && ID.pana_black[1] && ID.pana_black[2])
{
if(libraw_internal_data.unpacker_data.pana_encoding == 5)
libraw_internal_data.internal_output_params.zero_is_bad = 0;
C.black = 0;
int add = libraw_internal_data.unpacker_data.pana_encoding == 4?15:0;
C.cblack[0] = ID.pana_black[0]+add;
C.cblack[1] = C.cblack[3] = ID.pana_black[1]+add;
C.cblack[2] = ID.pana_black[2]+add;
int i = C.cblack[3];
for (int c = 0; c < 3; c++)
if (i > C.cblack[c])
i = C.cblack[c];
for (int c = 0; c < 4; c++)
C.cblack[c] -= i;
C.black = i;
}
// Adjust sizes for X3F processing
if (load_raw == &LibRaw::x3f_load_raw)
{
for (int i = 0; i < foveon_count; i++)
if (!strcasecmp(imgdata.idata.make, foveon_data[i].make) &&
!strcasecmp(imgdata.idata.model, foveon_data[i].model) &&
imgdata.sizes.raw_width == foveon_data[i].raw_width &&
imgdata.sizes.raw_height == foveon_data[i].raw_height)
{
imgdata.sizes.top_margin = foveon_data[i].top_margin;
imgdata.sizes.left_margin = foveon_data[i].left_margin;
imgdata.sizes.width = imgdata.sizes.iwidth = foveon_data[i].width;
imgdata.sizes.height = imgdata.sizes.iheight = foveon_data[i].height;
C.maximum = foveon_data[i].white;
break;
}
}
#if 0
size_t bytes = ID.input->size()-libraw_internal_data.unpacker_data.data_offset;
float bpp = float(bytes)/float(S.raw_width)/float(S.raw_height);
float bpp2 = float(bytes)/float(S.width)/float(S.height);
printf("RawSize: %dx%d data offset: %d data size:%d bpp: %g bpp2: %g\n",S.raw_width,S.raw_height,libraw_internal_data.unpacker_data.data_offset,bytes,bpp,bpp2);
if(!strcasecmp(imgdata.idata.make,"Hasselblad") && bpp == 6.0f)
{
load_raw = &LibRaw::hasselblad_full_load_raw;
S.width = S.raw_width;
S.height = S.raw_height;
P1.filters = 0;
P1.colors=3;
P1.raw_count=1;
C.maximum=0xffff;
printf("3 channel hassy found\n");
}
#endif
if (C.profile_length)
{
if (C.profile)
free(C.profile);
C.profile = malloc(C.profile_length);
merror(C.profile, "LibRaw::open_file()");
ID.input->seek(ID.profile_offset, SEEK_SET);
ID.input->read(C.profile, C.profile_length, 1);
}
SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY);
}
catch (LibRaw_exceptions err)
{
EXCEPTION_HANDLER(err);
}
catch (std::exception ee)
{
EXCEPTION_HANDLER(LIBRAW_EXCEPTION_IO_CORRUPT);
}
final:;
if (P1.raw_count < 1)
return LIBRAW_FILE_UNSUPPORTED;
write_fun = &LibRaw::write_ppm_tiff;
if (load_raw == &LibRaw::kodak_ycbcr_load_raw)
{
S.height += S.height & 1;
S.width += S.width & 1;
}
IO.shrink = P1.filters && (O.half_size || ((O.threshold || O.aber[0] != 1 || O.aber[2] != 1)));
if (IO.shrink && P1.filters >= 1000)
{
S.width &= 65534;
S.height &= 65534;
}
S.iheight = (S.height + IO.shrink) >> IO.shrink;
S.iwidth = (S.width + IO.shrink) >> IO.shrink;
// Save color,sizes and internal data into raw_image fields
memmove(&imgdata.rawdata.color, &imgdata.color, sizeof(imgdata.color));
memmove(&imgdata.rawdata.sizes, &imgdata.sizes, sizeof(imgdata.sizes));
memmove(&imgdata.rawdata.iparams, &imgdata.idata, sizeof(imgdata.idata));
memmove(&imgdata.rawdata.ioparams, &libraw_internal_data.internal_output_params,
sizeof(libraw_internal_data.internal_output_params));
SET_PROC_FLAG(LIBRAW_PROGRESS_SIZE_ADJUST);
return LIBRAW_SUCCESS;
}
#ifdef USE_RAWSPEED
void LibRaw::fix_after_rawspeed(int bl)
{
if (load_raw == &LibRaw::lossy_dng_load_raw)
C.maximum = 0xffff;
else if (load_raw == &LibRaw::sony_load_raw)
C.maximum = 0x3ff0;
}
#else
void LibRaw::fix_after_rawspeed(int) {}
#endif
void LibRaw::clearCancelFlag()
{
#ifdef WIN32
InterlockedExchange(&_exitflag, 0);
#else
__sync_fetch_and_and(&_exitflag, 0);
#endif
#ifdef RAWSPEED_FASTEXIT
if (_rawspeed_decoder)
{
RawDecoder *d = static_cast<RawDecoder *>(_rawspeed_decoder);
d->resumeProcessing();
}
#endif
}
void LibRaw::setCancelFlag()
{
#ifdef WIN32
InterlockedExchange(&_exitflag, 1);
#else
__sync_fetch_and_add(&_exitflag, 1);
#endif
#ifdef RAWSPEED_FASTEXIT
if (_rawspeed_decoder)
{
RawDecoder *d = static_cast<RawDecoder *>(_rawspeed_decoder);
d->cancelProcessing();
}
#endif
}
void LibRaw::checkCancel()
{
#ifdef WIN32
if (InterlockedExchange(&_exitflag, 0))
throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK;
#else
if (__sync_fetch_and_and(&_exitflag, 0))
throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK;
#endif
}
int LibRaw::try_rawspeed()
{
#ifdef USE_RAWSPEED
int ret = LIBRAW_SUCCESS;
int rawspeed_ignore_errors = 0;
if (imgdata.idata.dng_version && imgdata.idata.colors == 3 &&
!strcasecmp(imgdata.idata.software, "Adobe Photoshop Lightroom 6.1.1 (Windows)"))
rawspeed_ignore_errors = 1;
// RawSpeed Supported,
INT64 spos = ID.input->tell();
void *_rawspeed_buffer = 0;
try
{
// printf("Using rawspeed\n");
ID.input->seek(0, SEEK_SET);
INT64 _rawspeed_buffer_sz = ID.input->size() + 32;
_rawspeed_buffer = malloc(_rawspeed_buffer_sz);
if (!_rawspeed_buffer)
throw LIBRAW_EXCEPTION_ALLOC;
ID.input->read(_rawspeed_buffer, _rawspeed_buffer_sz, 1);
FileMap map((uchar8 *)_rawspeed_buffer, _rawspeed_buffer_sz);
RawParser t(&map);
RawDecoder *d = 0;
CameraMetaDataLR *meta = static_cast<CameraMetaDataLR *>(_rawspeed_camerameta);
d = t.getDecoder();
if (!d)
throw "Unable to find decoder";
try
{
d->checkSupport(meta);
}
catch (const RawDecoderException &e)
{
imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_UNSUPPORTED;
throw e;
}
d->interpolateBadPixels = FALSE;
d->applyStage1DngOpcodes = FALSE;
_rawspeed_decoder = static_cast<void *>(d);
d->decodeRaw();
d->decodeMetaData(meta);
RawImage r = d->mRaw;
if (r->errors.size() > 0 && !rawspeed_ignore_errors)
{
delete d;
_rawspeed_decoder = 0;
throw 1;
}
if (r->isCFA)
{
imgdata.rawdata.raw_image = (ushort *)r->getDataUncropped(0, 0);
}
else if (r->getCpp() == 4)
{
imgdata.rawdata.color4_image = (ushort(*)[4])r->getDataUncropped(0, 0);
if (r->whitePoint > 0 && r->whitePoint < 65536)
C.maximum = r->whitePoint;
}
else if (r->getCpp() == 3)
{
imgdata.rawdata.color3_image = (ushort(*)[3])r->getDataUncropped(0, 0);
if (r->whitePoint > 0 && r->whitePoint < 65536)
C.maximum = r->whitePoint;
}
else
{
delete d;
_rawspeed_decoder = 0;
ret = LIBRAW_UNSPECIFIED_ERROR;
}
if (_rawspeed_decoder)
{
// set sizes
iPoint2D rsdim = r->getUncroppedDim();
S.raw_pitch = r->pitch;
S.raw_width = rsdim.x;
S.raw_height = rsdim.y;
// C.maximum = r->whitePoint;
fix_after_rawspeed(r->blackLevel);
}
free(_rawspeed_buffer);
_rawspeed_buffer = 0;
imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_PROCESSED;
}
catch (const RawDecoderException &RDE)
{
imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_PROBLEM;
if (_rawspeed_buffer)
{
free(_rawspeed_buffer);
_rawspeed_buffer = 0;
}
const char *p = RDE.what();
if (!strncmp(RDE.what(), "Decoder canceled", strlen("Decoder canceled")))
throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK;
ret = LIBRAW_UNSPECIFIED_ERROR;
}
catch (...)
{
// We may get here due to cancellation flag
imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_PROBLEM;
if (_rawspeed_buffer)
{
free(_rawspeed_buffer);
_rawspeed_buffer = 0;
}
ret = LIBRAW_UNSPECIFIED_ERROR;
}
ID.input->seek(spos, SEEK_SET);
return ret;
#else
return LIBRAW_NOT_IMPLEMENTED;
#endif
}
int LibRaw::valid_for_dngsdk()
{
#ifndef USE_DNGSDK
return 0;
#else
if (!imgdata.idata.dng_version)
return 0;
if (!imgdata.params.use_dngsdk)
return 0;
if (load_raw == &LibRaw::lossy_dng_load_raw) // WHY??
return 0;
if (load_raw == &LibRaw::float_dng_load_raw_placeholder) // regardless of flags!
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; // Always deny 2-samples (old fuji superccd)
if (imgdata.idata.filters == 9 && (imgdata.params.use_dngsdk & LIBRAW_DNG_XTRANS))
return 1;
if (is_fuji_rotated())
return 0; // refuse
if (imgdata.params.use_dngsdk & LIBRAW_DNG_OTHER)
return 1;
return 0;
#endif
}
int LibRaw::is_curve_linear()
{
for (int i = 0; i < 0x10000; i++)
if (imgdata.color.curve[i] != i)
return 0;
return 1;
}
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);
negative->ReadStage1Image(*host, stream, info);
dng_simple_image *stage2 = (dng_simple_image *)negative->Stage1Image();
if (stage2->Bounds().W() != S.raw_width || stage2->Bounds().H() != S.raw_height)
{
return LIBRAW_DATA_ERROR;
}
int pplanes = stage2->Planes();
int ptype = stage2->PixelType();
dng_pixel_buffer buffer;
stage2->GetPixelBuffer(buffer);
int pixels = stage2->Bounds().H() * stage2->Bounds().W() * pplanes;
bool zerocopy = false;
if (ptype == ttShort && !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
{
// Alloc
if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNGSDK_ZEROCOPY)
{
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 (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:
/* do nothing */
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:
/* do nothing */
break;
}
}
if (zerocopy)
{
dng_negative *stolen = negative.Release();
dngnegative = stolen;
}
}
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
}
int LibRaw::unpack(void)
{
CHECK_ORDER_HIGH(LIBRAW_PROGRESS_LOAD_RAW);
CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY);
try
{
if (!libraw_internal_data.internal_data.input)
return LIBRAW_INPUT_CLOSED;
RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW, 0, 2);
if (O.shot_select >= P1.raw_count)
return LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE;
if (!load_raw)
return LIBRAW_UNSPECIFIED_ERROR;
// already allocated ?
if (imgdata.image)
{
free(imgdata.image);
imgdata.image = 0;
}
if (imgdata.rawdata.raw_alloc)
{
free(imgdata.rawdata.raw_alloc);
imgdata.rawdata.raw_alloc = 0;
}
if (libraw_internal_data.unpacker_data.meta_length)
{
libraw_internal_data.internal_data.meta_data = (char *)malloc(libraw_internal_data.unpacker_data.meta_length);
merror(libraw_internal_data.internal_data.meta_data, "LibRaw::unpack()");
}
libraw_decoder_info_t decoder_info;
get_decoder_info(&decoder_info);
int save_iwidth = S.iwidth, save_iheight = S.iheight, save_shrink = IO.shrink;
int rwidth = S.raw_width, rheight = S.raw_height;
if (!IO.fuji_width)
{
// adjust non-Fuji allocation
if (rwidth < S.width + S.left_margin)
rwidth = S.width + S.left_margin;
if (rheight < S.height + S.top_margin)
rheight = S.height + S.top_margin;
}
if (rwidth > 65535 || rheight > 65535) // No way to make image larger than 64k pix
throw LIBRAW_EXCEPTION_IO_CORRUPT;
imgdata.rawdata.raw_image = 0;
imgdata.rawdata.color4_image = 0;
imgdata.rawdata.color3_image = 0;
imgdata.rawdata.float_image = 0;
imgdata.rawdata.float3_image = 0;
#ifdef USE_DNGSDK
if (imgdata.idata.dng_version && dnghost && imgdata.idata.raw_count == 1 && valid_for_dngsdk() &&
load_raw != &LibRaw::pentax_4shot_load_raw)
{
// Data size check
INT64 pixcount = INT64(MAX(S.width, S.raw_width)) * INT64(MAX(S.height, S.raw_height));
INT64 planecount = (imgdata.idata.filters || P1.colors == 1)?1: LIM(P1.colors,3,4);
INT64 samplesize = is_floating_point()?4:2;
INT64 bytes = pixcount * planecount * samplesize;
if(bytes > INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024)) throw LIBRAW_EXCEPTION_TOOBIG;
// find ifd to check sample
int rr = try_dngsdk();
}
#endif
#ifdef USE_RAWSPEED
if (!raw_was_read())
{
int rawspeed_enabled = 1;
if (imgdata.idata.dng_version && libraw_internal_data.unpacker_data.tiff_samples == 2)
rawspeed_enabled = 0;
if(imgdata.other.is_NikonTransfer)
rawspeed_enabled = 0;
if(libraw_internal_data.unpacker_data.pana_encoding == 5)
rawspeed_enabled = 0;
if (imgdata.idata.raw_count > 1)
rawspeed_enabled = 0;
if (!strncasecmp(imgdata.idata.software, "Magic", 5))
rawspeed_enabled = 0;
// Disable rawspeed for double-sized Oly files
if (!strncasecmp(imgdata.idata.make, "Olympus", 7) &&
((imgdata.sizes.raw_width > 6000) || !strncasecmp(imgdata.idata.model, "SH-2", 4) ||
!strncasecmp(imgdata.idata.model, "SH-3", 4) || !strncasecmp(imgdata.idata.model, "TG-4", 4) ||
!strncasecmp(imgdata.idata.model, "TG-5", 4)))
rawspeed_enabled = 0;
if (!strncasecmp(imgdata.idata.make, "Canon", 5) && !strcasecmp(imgdata.idata.model, "EOS 6D Mark II"))
rawspeed_enabled = 0;
if (imgdata.idata.dng_version && imgdata.idata.filters == 0 &&
libraw_internal_data.unpacker_data.tiff_bps == 8) // Disable for 8 bit
rawspeed_enabled = 0;
if (load_raw == &LibRaw::packed_load_raw && !strncasecmp(imgdata.idata.make, "Nikon", 5) &&
(!strncasecmp(imgdata.idata.model, "E", 1) || !strncasecmp(imgdata.idata.model, "COOLPIX B", 9) ||!strncasecmp(imgdata.idata.model, "COOLPIX P1000", 13)))
rawspeed_enabled = 0;
if (load_raw == &LibRaw::nikon_load_raw && !strncasecmp(imgdata.idata.make, "Nikon", 5) && !strncasecmp(imgdata.idata.model, "Z", 1))
rawspeed_enabled = 0;
// RawSpeed Supported,
if (O.use_rawspeed && rawspeed_enabled &&
!(is_sraw() &&
(O.raw_processing_options & (LIBRAW_PROCESSING_SRAW_NO_RGB | LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE))) &&
(decoder_info.decoder_flags & LIBRAW_DECODER_TRYRAWSPEED) && _rawspeed_camerameta)
{
INT64 pixcount = INT64(MAX(S.width, S.raw_width)) * INT64(MAX(S.height, S.raw_height));
INT64 planecount = (imgdata.idata.filters || P1.colors == 1)?1: LIM(P1.colors,3,4);
INT64 bytes = pixcount * planecount * 2; // sample size is always 2 for rawspeed
if(bytes > INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024)) throw LIBRAW_EXCEPTION_TOOBIG;
int rr = try_rawspeed();
}
}
#endif
if (!raw_was_read()) // RawSpeed failed or not run
{
// Not allocated on RawSpeed call, try call LibRaow
int zero_rawimage = 0;
if (decoder_info.decoder_flags & LIBRAW_DECODER_OWNALLOC)
{
// x3f foveon decoder and DNG float
// Do nothing! Decoder will allocate data internally
}
if (decoder_info.decoder_flags & LIBRAW_DECODER_SINAR4SHOT)
{
if(imgdata.params.shot_select) // single image extract
{
if (INT64(rwidth) * INT64(rheight + 8) * sizeof(imgdata.rawdata.raw_image[0]) >
INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024))
throw LIBRAW_EXCEPTION_TOOBIG;
imgdata.rawdata.raw_alloc = malloc(rwidth * (rheight + 8) * sizeof(imgdata.rawdata.raw_image[0]));
imgdata.rawdata.raw_image = (ushort *)imgdata.rawdata.raw_alloc;
if (!S.raw_pitch)
S.raw_pitch = S.raw_width * 2; // Bayer case, not set before
}
else // Full image extract
{
if (INT64(rwidth) * INT64(rheight + 8) * sizeof(imgdata.rawdata.raw_image[0]) * 4 >
INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024))
throw LIBRAW_EXCEPTION_TOOBIG;
S.raw_pitch = S.raw_width * 8;
imgdata.rawdata.raw_alloc = 0;
imgdata.image = (ushort(*)[4])calloc(
unsigned(MAX(S.width, S.raw_width)) * unsigned(MAX(S.height, S.raw_height)+8), sizeof(*imgdata.image));
}
}
else if (decoder_info.decoder_flags & LIBRAW_DECODER_3CHANNEL)
{
if (INT64(rwidth) * INT64(rheight + 8) * sizeof(imgdata.rawdata.raw_image[0]) * 3 >
INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024))
throw LIBRAW_EXCEPTION_TOOBIG;
imgdata.rawdata.raw_alloc = malloc(rwidth * (rheight + 8) * sizeof(imgdata.rawdata.raw_image[0]) * 3);
imgdata.rawdata.color3_image = (ushort(*)[3])imgdata.rawdata.raw_alloc;
if (!S.raw_pitch)
S.raw_pitch = S.raw_width * 6;
}
else if (imgdata.idata.filters || P1.colors == 1) // Bayer image or single color -> decode to raw_image
{
if (INT64(rwidth) * INT64(rheight + 8) * sizeof(imgdata.rawdata.raw_image[0]) >
INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024))
throw LIBRAW_EXCEPTION_TOOBIG;
imgdata.rawdata.raw_alloc = malloc(rwidth * (rheight + 8) * sizeof(imgdata.rawdata.raw_image[0]));
imgdata.rawdata.raw_image = (ushort *)imgdata.rawdata.raw_alloc;
if (!S.raw_pitch)
S.raw_pitch = S.raw_width * 2; // Bayer case, not set before
}
else // NO LEGACY FLAG if (decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY)
{
if (decoder_info.decoder_flags & LIBRAW_DECODER_ADOBECOPYPIXEL)
{
S.raw_pitch = S.raw_width * 8;
}
else
{
S.iwidth = S.width;
S.iheight = S.height;
IO.shrink = 0;
if (!S.raw_pitch)
S.raw_pitch =
(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY_WITH_MARGINS) ? S.raw_width * 8 : S.width * 8;
}
// sRAW and old Foveon decoders only, so extra buffer size is just 1/4
// allocate image as temporary buffer, size
if (INT64(MAX(S.width, S.raw_width)) * INT64(MAX(S.height, S.raw_height)+8) * sizeof(*imgdata.image) >
INT64(imgdata.params.max_raw_memory_mb) * INT64(1024 * 1024))
throw LIBRAW_EXCEPTION_TOOBIG;
imgdata.rawdata.raw_alloc = 0;
imgdata.image = (ushort(*)[4])calloc(
unsigned(MAX(S.width, S.raw_width)) * unsigned(MAX(S.height, S.raw_height)+8), sizeof(*imgdata.image));
if (!(decoder_info.decoder_flags & LIBRAW_DECODER_ADOBECOPYPIXEL))
{
imgdata.rawdata.raw_image = (ushort *)imgdata.image;
zero_rawimage = 1;
}
}
ID.input->seek(libraw_internal_data.unpacker_data.data_offset, SEEK_SET);
unsigned m_save = C.maximum;
if (load_raw == &LibRaw::unpacked_load_raw && !strcasecmp(imgdata.idata.make, "Nikon"))
C.maximum = 65535;
(this->*load_raw)();
if (zero_rawimage)
imgdata.rawdata.raw_image = 0;
if (load_raw == &LibRaw::unpacked_load_raw && !strcasecmp(imgdata.idata.make, "Nikon"))
C.maximum = m_save;
if (decoder_info.decoder_flags & LIBRAW_DECODER_OWNALLOC)
{
// x3f foveon decoder only: do nothing
}
else if (decoder_info.decoder_flags & LIBRAW_DECODER_SINAR4SHOT && imgdata.params.shot_select == 0)
{
imgdata.rawdata.raw_alloc = imgdata.image;
imgdata.rawdata.color4_image = (ushort(*)[4])imgdata.rawdata.raw_alloc;
imgdata.image = 0;
}
else if (!(imgdata.idata.filters || P1.colors == 1)) // legacy decoder, ownalloc handled above
{
// successfully decoded legacy image, attach image to raw_alloc
imgdata.rawdata.raw_alloc = imgdata.image;
imgdata.rawdata.color4_image = (ushort(*)[4])imgdata.rawdata.raw_alloc;
imgdata.image = 0;
// Restore saved values. Note: Foveon have masked frame
// Other 4-color legacy data: no borders
if (!(libraw_internal_data.unpacker_data.load_flags & 256) &&
!(decoder_info.decoder_flags & LIBRAW_DECODER_ADOBECOPYPIXEL) &&
!(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY_WITH_MARGINS))
{
S.raw_width = S.width;
S.left_margin = 0;
S.raw_height = S.height;
S.top_margin = 0;
}
}
}
if (imgdata.rawdata.raw_image)
crop_masked_pixels(); // calculate black levels
// recover image sizes
S.iwidth = save_iwidth;
S.iheight = save_iheight;
IO.shrink = save_shrink;
// adjust black to possible maximum
unsigned int i = C.cblack[3];
unsigned int c;
for (c = 0; c < 3; c++)
if (i > C.cblack[c])
i = C.cblack[c];
for (c = 0; c < 4; c++)
C.cblack[c] -= i;
C.black += i;
// Save color,sizes and internal data into raw_image fields
memmove(&imgdata.rawdata.color, &imgdata.color, sizeof(imgdata.color));
memmove(&imgdata.rawdata.sizes, &imgdata.sizes, sizeof(imgdata.sizes));
memmove(&imgdata.rawdata.iparams, &imgdata.idata, sizeof(imgdata.idata));
memmove(&imgdata.rawdata.ioparams, &libraw_internal_data.internal_output_params,
sizeof(libraw_internal_data.internal_output_params));
SET_PROC_FLAG(LIBRAW_PROGRESS_LOAD_RAW);
RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW, 1, 2);
return 0;
}
catch (LibRaw_exceptions err)
{
EXCEPTION_HANDLER(err);
}
catch (std::exception ee)
{
EXCEPTION_HANDLER(LIBRAW_EXCEPTION_IO_CORRUPT);
}
}
void LibRaw::unpacked_load_raw_fuji_f700s20()
{
int base_offset = 0;
int row_size = imgdata.sizes.raw_width * 2; // in bytes
if (imgdata.idata.raw_count == 2 && imgdata.params.shot_select)
{
libraw_internal_data.internal_data.input->seek(-row_size, SEEK_CUR);
base_offset = row_size; // in bytes
}
unsigned char *buffer = (unsigned char *)malloc(row_size * 2);
for (int row = 0; row < imgdata.sizes.raw_height; row++)
{
read_shorts((ushort *)buffer, imgdata.sizes.raw_width * 2);
memmove(&imgdata.rawdata.raw_image[row * imgdata.sizes.raw_pitch / 2], buffer + base_offset, row_size);
}
free(buffer);
}
void LibRaw::nikon_load_sraw()
{
// We're already seeked to data!
unsigned char *rd = (unsigned char *)malloc(3 * (imgdata.sizes.raw_width + 2));
if (!rd)
throw LIBRAW_EXCEPTION_ALLOC;
try
{
int row, col;
for (row = 0; row < imgdata.sizes.raw_height; row++)
{
checkCancel();
libraw_internal_data.internal_data.input->read(rd, 3, imgdata.sizes.raw_width);
for (col = 0; col < imgdata.sizes.raw_width - 1; col += 2)
{
int bi = col * 3;
ushort bits1 = (rd[bi + 1] & 0xf) << 8 | rd[bi]; // 3,0,1
ushort bits2 = rd[bi + 2] << 4 | ((rd[bi + 1] >> 4) & 0xf); // 452
ushort bits3 = ((rd[bi + 4] & 0xf) << 8) | rd[bi + 3]; // 967
ushort bits4 = rd[bi + 5] << 4 | ((rd[bi + 4] >> 4) & 0xf); // ab8
imgdata.image[row * imgdata.sizes.raw_width + col][0] = bits1;
imgdata.image[row * imgdata.sizes.raw_width + col][1] = bits3;
imgdata.image[row * imgdata.sizes.raw_width + col][2] = bits4;
imgdata.image[row * imgdata.sizes.raw_width + col + 1][0] = bits2;
imgdata.image[row * imgdata.sizes.raw_width + col + 1][1] = 2048;
imgdata.image[row * imgdata.sizes.raw_width + col + 1][2] = 2048;
}
}
}
catch (...)
{
free(rd);
throw;
}
free(rd);
C.maximum = 0xfff; // 12 bit?
if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE)
{
return; // no CbCr interpolation
}
// Interpolate CC channels
int row, col;
for (row = 0; row < imgdata.sizes.raw_height; row++)
{
checkCancel(); // will throw out
for (col = 0; col < imgdata.sizes.raw_width; col += 2)
{
int col2 = col < imgdata.sizes.raw_width - 2 ? col + 2 : col;
imgdata.image[row * imgdata.sizes.raw_width + col + 1][1] =
(unsigned short)(int(imgdata.image[row * imgdata.sizes.raw_width + col][1] +
imgdata.image[row * imgdata.sizes.raw_width + col2][1]) /
2);
imgdata.image[row * imgdata.sizes.raw_width + col + 1][2] =
(unsigned short)(int(imgdata.image[row * imgdata.sizes.raw_width + col][2] +
imgdata.image[row * imgdata.sizes.raw_width + col2][2]) /
2);
}
}
if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_RGB)
return;
for (row = 0; row < imgdata.sizes.raw_height; row++)
{
checkCancel(); // will throw out
for (col = 0; col < imgdata.sizes.raw_width; col++)
{
float Y = float(imgdata.image[row * imgdata.sizes.raw_width + col][0]) / 2549.f;
float Ch2 = float(imgdata.image[row * imgdata.sizes.raw_width + col][1] - 1280) / 1536.f;
float Ch3 = float(imgdata.image[row * imgdata.sizes.raw_width + col][2] - 1280) / 1536.f;
if (Y > 1.f)
Y = 1.f;
if (Y > 0.803f)
Ch2 = Ch3 = 0.5f;
float r = Y + 1.40200f * (Ch3 - 0.5f);
if (r < 0.f)
r = 0.f;
if (r > 1.f)
r = 1.f;
float g = Y - 0.34414f * (Ch2 - 0.5f) - 0.71414 * (Ch3 - 0.5f);
if (g > 1.f)
g = 1.f;
if (g < 0.f)
g = 0.f;
float b = Y + 1.77200 * (Ch2 - 0.5f);
if (b > 1.f)
b = 1.f;
if (b < 0.f)
b = 0.f;
imgdata.image[row * imgdata.sizes.raw_width + col][0] = imgdata.color.curve[int(r * 3072.f)];
imgdata.image[row * imgdata.sizes.raw_width + col][1] = imgdata.color.curve[int(g * 3072.f)];
imgdata.image[row * imgdata.sizes.raw_width + col][2] = imgdata.color.curve[int(b * 3072.f)];
}
}
C.maximum = 16383;
}
void LibRaw::free_image(void)
{
if (imgdata.image)
{
free(imgdata.image);
imgdata.image = 0;
imgdata.progress_flags = LIBRAW_PROGRESS_START | LIBRAW_PROGRESS_OPEN | LIBRAW_PROGRESS_IDENTIFY |
LIBRAW_PROGRESS_SIZE_ADJUST | LIBRAW_PROGRESS_LOAD_RAW;
}
}
void LibRaw::raw2image_start()
{
// restore color,sizes and internal data into raw_image fields
memmove(&imgdata.color, &imgdata.rawdata.color, sizeof(imgdata.color));
memmove(&imgdata.sizes, &imgdata.rawdata.sizes, sizeof(imgdata.sizes));
memmove(&imgdata.idata, &imgdata.rawdata.iparams, sizeof(imgdata.idata));
memmove(&libraw_internal_data.internal_output_params, &imgdata.rawdata.ioparams,
sizeof(libraw_internal_data.internal_output_params));
if (O.user_flip >= 0)
S.flip = O.user_flip;
switch ((S.flip + 3600) % 360)
{
case 270:
S.flip = 5;
break;
case 180:
S.flip = 3;
break;
case 90:
S.flip = 6;
break;
}
// adjust for half mode!
IO.shrink = P1.filters && (O.half_size || ((O.threshold || O.aber[0] != 1 || O.aber[2] != 1)));
S.iheight = (S.height + IO.shrink) >> IO.shrink;
S.iwidth = (S.width + IO.shrink) >> IO.shrink;
}
int LibRaw::is_phaseone_compressed()
{
return (load_raw == &LibRaw::phase_one_load_raw_c || load_raw == &LibRaw::phase_one_load_raw);
}
int LibRaw::is_canon_600() { return load_raw == &LibRaw::canon_600_load_raw; }
int LibRaw::raw2image(void)
{
CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);
try
{
raw2image_start();
if (is_phaseone_compressed() && imgdata.rawdata.raw_alloc)
{
phase_one_allocate_tempbuffer();
int rc = phase_one_subtract_black((ushort *)imgdata.rawdata.raw_alloc, imgdata.rawdata.raw_image);
if (rc == 0)
rc = phase_one_correct();
if (rc != 0)
{
phase_one_free_tempbuffer();
return rc;
}
}
// free and re-allocate image bitmap
if (imgdata.image)
{
imgdata.image = (ushort(*)[4])realloc(imgdata.image, S.iheight * S.iwidth * sizeof(*imgdata.image));
memset(imgdata.image, 0, S.iheight * S.iwidth * sizeof(*imgdata.image));
}
else
imgdata.image = (ushort(*)[4])calloc(S.iheight * S.iwidth, sizeof(*imgdata.image));
merror(imgdata.image, "raw2image()");
libraw_decoder_info_t decoder_info;
get_decoder_info(&decoder_info);
// Move saved bitmap to imgdata.image
if ((imgdata.idata.filters || P1.colors == 1)
&& imgdata.rawdata.raw_image)
{
if (IO.fuji_width)
{
unsigned r, c;
int row, col;
for (row = 0; row < S.raw_height - S.top_margin * 2; row++)
{
for (col = 0; col < IO.fuji_width << !libraw_internal_data.unpacker_data.fuji_layout; col++)
{
if (libraw_internal_data.unpacker_data.fuji_layout)
{
r = IO.fuji_width - 1 - col + (row >> 1);
c = col + ((row + 1) >> 1);
}
else
{
r = IO.fuji_width - 1 + row - (col >> 1);
c = row + ((col + 1) >> 1);
}
if (r < S.height && c < S.width)
imgdata.image[((r) >> IO.shrink) * S.iwidth + ((c) >> IO.shrink)][FC(r, c)] =
imgdata.rawdata.raw_image[(row + S.top_margin) * S.raw_pitch / 2 + (col + S.left_margin)];
}
}
}
else
{
int row, col;
for (row = 0; row < S.height; row++)
for (col = 0; col < S.width; col++)
imgdata.image[((row) >> IO.shrink) * S.iwidth + ((col) >> IO.shrink)][fcol(row, col)] =
imgdata.rawdata.raw_image[(row + S.top_margin) * S.raw_pitch / 2 + (col + S.left_margin)];
}
}
else // if(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY)
{
if (imgdata.rawdata.color4_image)
{
if (S.width * 8 == S.raw_pitch)
memmove(imgdata.image, imgdata.rawdata.color4_image, S.width * S.height * sizeof(*imgdata.image));
else
{
for (int row = 0; row < S.height; row++)
memmove(&imgdata.image[row * S.width],
&imgdata.rawdata.color4_image[(row + S.top_margin) * S.raw_pitch / 8 + S.left_margin],
S.width * sizeof(*imgdata.image));
}
}
else if (imgdata.rawdata.color3_image)
{
unsigned char *c3image = (unsigned char *)imgdata.rawdata.color3_image;
for (int row = 0; row < S.height; row++)
{
ushort(*srcrow)[3] = (ushort(*)[3]) & c3image[(row + S.top_margin) * S.raw_pitch];
ushort(*dstrow)[4] = (ushort(*)[4]) & imgdata.image[row * S.width];
for (int col = 0; col < S.width; col++)
{
for (int c = 0; c < 3; c++)
dstrow[col][c] = srcrow[S.left_margin + col][c];
dstrow[col][3] = 0;
}
}
}
else
{
// legacy decoder, but no data?
throw LIBRAW_EXCEPTION_DECODE_RAW;
}
}
// Free PhaseOne separate copy allocated at function start
if (is_phaseone_compressed())
{
phase_one_free_tempbuffer();
}
// hack - clear later flags!
if (load_raw == &CLASS canon_600_load_raw && S.width < S.raw_width)
{
canon_600_correct();
}
imgdata.progress_flags = LIBRAW_PROGRESS_START | LIBRAW_PROGRESS_OPEN | LIBRAW_PROGRESS_RAW2_IMAGE |
LIBRAW_PROGRESS_IDENTIFY | LIBRAW_PROGRESS_SIZE_ADJUST | LIBRAW_PROGRESS_LOAD_RAW;
return 0;
}
catch (LibRaw_exceptions err)
{
EXCEPTION_HANDLER(err);
}
}
void LibRaw::phase_one_allocate_tempbuffer()
{
// Allocate temp raw_image buffer
imgdata.rawdata.raw_image = (ushort *)malloc(S.raw_pitch * S.raw_height);
merror(imgdata.rawdata.raw_image, "phase_one_prepare_to_correct()");
}
void LibRaw::phase_one_free_tempbuffer()
{
free(imgdata.rawdata.raw_image);
imgdata.rawdata.raw_image = (ushort *)imgdata.rawdata.raw_alloc;
}
int LibRaw::phase_one_subtract_black(ushort *src, ushort *dest)
{
try
{
if (O.user_black < 0 && O.user_cblack[0] <= -1000000 && O.user_cblack[1] <= -1000000 &&
O.user_cblack[2] <= -1000000 && O.user_cblack[3] <= -1000000)
{
if (!imgdata.rawdata.ph1_cblack || !imgdata.rawdata.ph1_rblack)
{
register int bl = imgdata.color.phase_one_data.t_black;
for (int row = 0; row < S.raw_height; row++)
{
checkCancel();
for (int col = 0; col < S.raw_width; col++)
{
int idx = row * S.raw_width + col;
int val = int(src[idx]) - bl;
dest[idx] = val > 0 ? val : 0;
}
}
}
else
{
register int bl = imgdata.color.phase_one_data.t_black;
for (int row = 0; row < S.raw_height; row++)
{
checkCancel();
for (int col = 0; col < S.raw_width; col++)
{
int idx = row * S.raw_width + col;
int val = int(src[idx]) - bl +
imgdata.rawdata.ph1_cblack[row][col >= imgdata.rawdata.color.phase_one_data.split_col] +
imgdata.rawdata.ph1_rblack[col][row >= imgdata.rawdata.color.phase_one_data.split_row];
dest[idx] = val > 0 ? val : 0;
}
}
}
}
else // black set by user interaction
{
// Black level in cblack!
for (int row = 0; row < S.raw_height; row++)
{
checkCancel();
unsigned short cblk[16];
for (int cc = 0; cc < 16; cc++)
cblk[cc] = C.cblack[fcol(row, cc)];
for (int col = 0; col < S.raw_width; col++)
{
int idx = row * S.raw_width + col;
ushort val = src[idx];
ushort bl = cblk[col & 0xf];
dest[idx] = val > bl ? val - bl : 0;
}
}
}
return 0;
}
catch (LibRaw_exceptions err)
{
return LIBRAW_CANCELLED_BY_CALLBACK;
}
}
void LibRaw::copy_fuji_uncropped(unsigned short cblack[4], unsigned short *dmaxp)
{
int row;
#if defined(LIBRAW_USE_OPENMP)
#pragma omp parallel for default(shared)
#endif
for (row = 0; row < S.raw_height - S.top_margin * 2; row++)
{
int col;
unsigned short ldmax = 0;
for (col = 0; col < IO.fuji_width << !libraw_internal_data.unpacker_data.fuji_layout; col++)
{
unsigned r, c;
if (libraw_internal_data.unpacker_data.fuji_layout)
{
r = IO.fuji_width - 1 - col + (row >> 1);
c = col + ((row + 1) >> 1);
}
else
{
r = IO.fuji_width - 1 + row - (col >> 1);
c = row + ((col + 1) >> 1);
}
if (r < S.height && c < S.width)
{
unsigned short val = imgdata.rawdata.raw_image[(row + S.top_margin) * S.raw_pitch / 2 + (col + S.left_margin)];
int cc = FC(r, c);
if (val > cblack[cc])
{
val -= cblack[cc];
if (val > ldmax)
ldmax = val;
}
else
val = 0;