blob: 639860e0e4e1dc5d7e4b968b85c49d3d6528b043 [file]
/* -*- C++ -*-
* Copyright 2019-2025 LibRaw LLC (info@libraw.org)
*
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 "third_party/libraw/internal/libraw_cxx_defs.h"
#include "third_party/libraw/internal/libraw_cameraids.h"
#ifndef LIBRAW_NO_IOSTREAMS_DATASTREAM
int LibRaw::open_file(const char *fname, INT64 max_buf_size)
{
int big = 0;
if (max_buf_size == LIBRAW_OPEN_BIGFILE)
big = 1;
else if (max_buf_size == LIBRAW_OPEN_FILE)
big = 0;
else
{
#ifndef LIBRAW_WIN32_CALLS
struct stat st;
if (stat(fname, &st))
return LIBRAW_IO_ERROR;
big = (st.st_size > max_buf_size) ? 1 : 0;
#else
struct _stati64 st;
if (_stati64(fname, &st))
return LIBRAW_IO_ERROR;
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 (const 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(_WIN32)
#ifndef LIBRAW_WIN32_UNICODEPATHS
int LibRaw::open_file(const wchar_t *, INT64)
{
return LIBRAW_NOT_IMPLEMENTED;
}
#else
int LibRaw::open_file(const wchar_t *fname, INT64 max_buf_size)
{
int big = 0;
if (max_buf_size == LIBRAW_OPEN_BIGFILE)
big = 1;
else if (max_buf_size == LIBRAW_OPEN_FILE)
big = 0;
else
{
struct _stati64 st;
if (_wstati64(fname, &st))
return LIBRAW_IO_ERROR;
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 (const 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
#endif
#else /* LIBRAW_NO_IOSTREAMS_DATASTREAM*/
int LibRaw::libraw_openfile_tail(LibRaw_abstract_datastream *stream)
{
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_file(const char *fname)
{
LibRaw_abstract_datastream *stream;
try
{
#ifdef LIBRAW_WIN32_CALLS
stream = new LibRaw_bigfile_buffered_datastream(fname);
#else
stream = new LibRaw_bigfile_datastream(fname);
#endif
}
catch (const std::bad_alloc&)
{
recycle();
return LIBRAW_UNSUFFICIENT_MEMORY;
}
if ((stream->size() > (INT64)LIBRAW_MAX_NONDNG_RAW_FILE_SIZE)
&& (stream->size() > (INT64)LIBRAW_MAX_DNG_RAW_FILE_SIZE)
&& (stream->size() > (INT64)LIBRAW_MAX_CR3_RAW_FILE_SIZE)
)
{
delete stream;
return LIBRAW_TOO_BIG;
}
return libraw_openfile_tail(stream);
}
#if defined(WIN32) || defined(_WIN32)
#ifndef LIBRAW_WIN32_UNICODEPATHS
int LibRaw::open_file(const wchar_t *)
{
return LIBRAW_NOT_IMPLEMENTED;
}
#else
int LibRaw::open_file(const wchar_t *fname)
{
LibRaw_abstract_datastream *stream;
try
{
#ifdef LIBRAW_WIN32_CALLS
stream = new LibRaw_bigfile_buffered_datastream(fname);
#else
stream = new LibRaw_bigfile_datastream(fname);
#endif
}
catch (const std::bad_alloc&)
{
recycle();
return LIBRAW_UNSUFFICIENT_MEMORY;
}
if ((stream->size() > (INT64)LIBRAW_MAX_DNG_RAW_FILE_SIZE)
&& (stream->size() > (INT64)LIBRAW_MAX_NONDNG_RAW_FILE_SIZE) &&
(stream->size() > (INT64)LIBRAW_MAX_CR3_RAW_FILE_SIZE)
)
{
delete stream;
return LIBRAW_TOO_BIG;
}
return libraw_openfile_tail(stream);
}
#endif
#endif
#endif
int LibRaw::open_buffer(const void *buffer, size_t size)
{
// this stream will close on recycle()
if (!buffer || buffer == (const void *)-1)
return LIBRAW_IO_ERROR;
if ((size > (INT64)LIBRAW_MAX_DNG_RAW_FILE_SIZE)
&& (size > (INT64)LIBRAW_MAX_NONDNG_RAW_FILE_SIZE)
&& (size > (INT64)LIBRAW_MAX_CR3_RAW_FILE_SIZE)
)
return LIBRAW_TOO_BIG;
LibRaw_buffer_datastream *stream;
try
{
stream = new LibRaw_buffer_datastream(buffer, size);
}
catch (const 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(const 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 == (const void *)-1)
return LIBRAW_IO_ERROR;
LibRaw_buffer_datastream *stream;
try
{
stream = new LibRaw_buffer_datastream(buffer, datalen);
}
catch (const 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 = &LibRaw::eight_bit_load_raw;
break;
case 10:
if ((datalen) / S.raw_height * 3u >= S.raw_width * 4u)
{
load_raw = &LibRaw::android_loose_load_raw;
break;
}
else if (libraw_internal_data.unpacker_data.load_flags & 1)
{
load_raw = &LibRaw::android_tight_load_raw;
break;
}
case 12:
libraw_internal_data.unpacker_data.load_flags |= 128;
load_raw = &LibRaw::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 = &LibRaw::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;
}
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, 3776, 16383, 204, 76, 5446,
3624}, // full size, new fw ??
{"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", "dp3 Quattro", 2944, 1888, 16383, 102, 38, 2723,
1812}, // half size, new fw??
{"Sigma", "dp2 Quattro", 5888, 3776, 16383, 204, 76, 5446,
3624}, // full size, new fw
{"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", "dp2 Quattro", 2944, 1888, 16383, 102, 38, 2723,
1812}, // half size, new fw
{"Sigma", "dp1 Quattro", 5888, 3776, 16383, 204, 76, 5446,
3624}, // full size, new fw??
{"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", "dp1 Quattro", 2944, 1888, 16383, 102, 38, 2723,
1812}, // half size, new fw
{"Sigma", "dp0 Quattro", 5888, 3776, 16383, 204, 76, 5446,
3624}, // full size, new fw??
{"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", "dp0 Quattro", 2944, 1888, 16383, 102, 38, 2723,
1812}, // half size, new fw
// 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, 4000, 224, 160, 6208,
4160}, // full size
{"Sigma", "sd Quattro H", 3328, 2240, 4000, 112, 80, 3104,
2080}, // half size
{"Sigma", "sd Quattro H", 5504, 3680, 4000, 0, 4, 5496, 3668}, // full size
{"Sigma", "sd Quattro H", 2752, 1840, 4000, 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;
if ((stream->size() > (INT64)LIBRAW_MAX_DNG_RAW_FILE_SIZE)
&& (stream->size() > (INT64)LIBRAW_MAX_NONDNG_RAW_FILE_SIZE) &&
(stream->size() > (INT64)LIBRAW_MAX_CR3_RAW_FILE_SIZE)
)
return LIBRAW_TOO_BIG;
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();
// Fuji layout files: either DNG or unpacked_load_raw should be used
if (libraw_internal_data.internal_output_params.fuji_width || libraw_internal_data.unpacker_data.fuji_layout)
{
if (!imgdata.idata.dng_version && load_raw != &LibRaw::unpacked_load_raw
&& load_raw != &LibRaw::unpacked_load_raw_FujiDBP
&& load_raw != &LibRaw::unpacked_load_raw_fuji_f700s20
)
return LIBRAW_FILE_UNSUPPORTED;
}
// Remove unsupported Nikon thumbnails
if (makeIs(LIBRAW_CAMERAMAKER_Nikon) &&
(!strncasecmp(imgdata.idata.model, "Z 8", 3) || !strcasecmp(imgdata.idata.model, "Z f")
|| !strncasecmp(imgdata.idata.model, "Z6_3", 4))
&&
imgdata.thumbs_list.thumbcount > 1)
{
int tgtidx = 0;
for (int idx = 0; idx < imgdata.thumbs_list.thumbcount && idx < LIBRAW_THUMBNAIL_MAXCOUNT; idx++)
{
int bps = imgdata.thumbs_list.thumblist[idx].tmisc & 0x1f;
if (bps > 8) // remove high-bit thumbs
{
// nothing: just skip this item
}
else
{
if (tgtidx < idx)
{
memmove(&imgdata.thumbs_list.thumblist[tgtidx], &imgdata.thumbs_list.thumblist[idx],
sizeof(imgdata.thumbs_list.thumblist[idx]));
tgtidx++;
}
else // same index, just assign next tgtidx
tgtidx = idx + 1;
}
}
if (tgtidx > 0 && tgtidx < imgdata.thumbs_list.thumbcount)
{
int selidx = 0;
INT64 maximgbits = INT64(imgdata.thumbs_list.thumblist[0].twidth) *
INT64(imgdata.thumbs_list.thumblist[0].theight) * INT64(imgdata.thumbs_list.thumblist[0].tmisc & 0x1f);
for (int i = 1; i < tgtidx; i++)
{
INT64 imgbits = INT64(imgdata.thumbs_list.thumblist[i].twidth) *
INT64(imgdata.thumbs_list.thumblist[i].theight) *
INT64(imgdata.thumbs_list.thumblist[i].tmisc & 0x1f);
if (imgbits > maximgbits)
{
selidx = i;
maximgbits = imgbits;
}
}
libraw_internal_data.internal_data.toffset = imgdata.thumbs_list.thumblist[selidx].toffset;
imgdata.thumbnail.tlength = imgdata.thumbs_list.thumblist[selidx].tlength;
libraw_internal_data.unpacker_data.thumb_format = imgdata.thumbs_list.thumblist[selidx].tformat;
imgdata.thumbnail.twidth = imgdata.thumbs_list.thumblist[selidx].twidth;
imgdata.thumbnail.theight = imgdata.thumbs_list.thumblist[selidx].theight;
libraw_internal_data.unpacker_data.thumb_misc = imgdata.thumbs_list.thumblist[selidx].tmisc;
// find another largest thumb and copy it to single thumbnail data
}
imgdata.thumbs_list.thumbcount = tgtidx > 0 ? tgtidx : 1;
}
// promote the old single thumbnail to the thumbs_list if not present already
if (imgdata.thumbs_list.thumbcount < LIBRAW_THUMBNAIL_MAXCOUNT)
{
bool already = false;
if (imgdata.thumbnail.tlength || libraw_internal_data.internal_data.toffset)
for (int i = 0; i < imgdata.thumbs_list.thumbcount; i++)
if (imgdata.thumbs_list.thumblist[i].toffset == libraw_internal_data.internal_data.toffset
&& imgdata.thumbs_list.thumblist[i].tlength == imgdata.thumbnail.tlength)
{
already = true;
break;
}
if (!already)
{
int idx = imgdata.thumbs_list.thumbcount;
imgdata.thumbs_list.thumblist[idx].toffset = libraw_internal_data.internal_data.toffset;
imgdata.thumbs_list.thumblist[idx].tlength = imgdata.thumbnail.tlength;
imgdata.thumbs_list.thumblist[idx].tflip = 0xffff;
imgdata.thumbs_list.thumblist[idx].tformat = libraw_internal_data.unpacker_data.thumb_format;
imgdata.thumbs_list.thumblist[idx].tmisc = libraw_internal_data.unpacker_data.thumb_misc;
// promote if set
imgdata.thumbs_list.thumblist[idx].twidth = imgdata.thumbnail.twidth;
imgdata.thumbs_list.thumblist[idx].theight = imgdata.thumbnail.theight;
imgdata.thumbs_list.thumbcount++;
}
}
imgdata.lens.Lens[sizeof(imgdata.lens.Lens) - 1] = 0; // make sure lens is 0-terminated
if (callbacks.post_identify_cb)
(callbacks.post_identify_cb)(this);
#define isRIC imgdata.sizes.raw_inset_crops[0]
if (!imgdata.idata.dng_version && makeIs(LIBRAW_CAMERAMAKER_Fujifilm)
&& (!strcmp(imgdata.idata.normalized_model, "S3Pro")
|| !strcmp(imgdata.idata.normalized_model, "S5Pro")
|| !strcmp(imgdata.idata.normalized_model, "S2Pro")))
{
isRIC.cleft = isRIC.ctop = 0xffff;
isRIC.cwidth = isRIC.cheight = 0;
}
// Wipe out canon incorrect in-camera crop
if (!imgdata.idata.dng_version && makeIs(LIBRAW_CAMERAMAKER_Canon)
&& isRIC.cleft == 0 && isRIC.ctop == 0 // non symmetric!
&& isRIC.cwidth < (imgdata.sizes.raw_width * 4 / 5)) // less than 80% of sensor width
{
isRIC.cleft = isRIC.ctop = 0xffff;
isRIC.cwidth = isRIC.cheight = 0;
}
// Wipe out non-standard WB
if (!imgdata.idata.dng_version &&
(makeIs(LIBRAW_CAMERAMAKER_Sony) && !strcmp(imgdata.idata.normalized_model, "DSC-F828"))
&& !(imgdata.rawparams.options & LIBRAW_RAWOPTIONS_PROVIDE_NONSTANDARD_WB))
{
for (int i = 0; i < 4; i++) imgdata.color.cam_mul[i] = (i == 1);
memset(imgdata.color.WB_Coeffs, 0, sizeof(imgdata.color.WB_Coeffs));
memset(imgdata.color.WBCT_Coeffs, 0, sizeof(imgdata.color.WBCT_Coeffs));
}
if (load_raw == &LibRaw::nikon_load_raw)
nikon_read_curve();
if (load_raw == &LibRaw::lossless_jpeg_load_raw &&
MN.canon.RecordMode && makeIs(LIBRAW_CAMERAMAKER_Kodak) &&
/* Not normalized models here, it is intentional */
(!strncasecmp(imgdata.idata.model, "EOS D2000", 9) || // if we want something different for B&W cameras,
!strncasecmp(imgdata.idata.model, "EOS D6000", 9))) // it's better to compare with CamIDs
{
imgdata.color.black = 0;
imgdata.color.maximum = 4501;
memset(imgdata.color.cblack, 0, sizeof(imgdata.color.cblack));
memset(imgdata.sizes.mask, 0, sizeof(imgdata.sizes.mask));
imgdata.sizes.mask[0][3] = 1; // to skip mask re-calc
libraw_internal_data.unpacker_data.load_flags |= 512;
}
if (load_raw == &LibRaw::panasonic_load_raw)
{
if (libraw_internal_data.unpacker_data.pana_encoding == 6 ||
libraw_internal_data.unpacker_data.pana_encoding == 7 ||
libraw_internal_data.unpacker_data.pana_encoding == 8)
{
for (int i = 0; i < 3; i++)
imgdata.color.cblack[i] =
libraw_internal_data.internal_data.pana_black[i];
imgdata.color.cblack[3] = imgdata.color.cblack[1];
imgdata.color.cblack[4] = imgdata.color.cblack[5] = 0;
imgdata.color.black = 0;
imgdata.color.maximum =
MAX(imgdata.color.linear_max[0],
MAX(imgdata.color.linear_max[1], imgdata.color.linear_max[2]));
}
if (libraw_internal_data.unpacker_data.pana_encoding == 6)
{
int rowbytes11 = imgdata.sizes.raw_width / 11 * 16;
int rowbytes14 = imgdata.sizes.raw_width / 14 * 16;
INT64 ds = INT64(libraw_internal_data.unpacker_data.data_size);
if (!ds)
ds = libraw_internal_data.internal_data.input->size() - libraw_internal_data.unpacker_data.data_offset;
if ((imgdata.sizes.raw_width % 11) == 0 &&
(INT64(imgdata.sizes.raw_height) * rowbytes11 == ds))
load_raw = &LibRaw::panasonicC6_load_raw;
else if ((imgdata.sizes.raw_width % 14) == 0 &&
(INT64(imgdata.sizes.raw_height) * rowbytes14 == ds))
load_raw = &LibRaw::panasonicC6_load_raw;
else
imgdata.idata.raw_count = 0; // incorrect size
}
else if (libraw_internal_data.unpacker_data.pana_encoding == 7)
{
int pixperblock =
libraw_internal_data.unpacker_data.pana_bpp == 14 ? 9 : 10;
int rowbytes = imgdata.sizes.raw_width / pixperblock * 16;
if ((imgdata.sizes.raw_width % pixperblock) == 0 &&
(INT64(imgdata.sizes.raw_height) * rowbytes ==
INT64(libraw_internal_data.unpacker_data.data_size)))
load_raw = &LibRaw::panasonicC7_load_raw;
else
imgdata.idata.raw_count = 0; // incorrect size
}
else if (libraw_internal_data.unpacker_data.pana_encoding == 8)
{
if (libraw_internal_data.unpacker_data.pana8.stripe_count > 0)
load_raw = &LibRaw::panasonicC8_load_raw;
else
imgdata.idata.raw_count = 0; // incorrect stripes count
}
}
#define NIKON_14BIT_SIZE(rw, rh) \
(((unsigned)(ceilf((float)(rw * 7 / 4) / 16.f)) * 16) * rh)
#define NIKON_14BIT_SIZE3COLOR(rw, rh) ( ceilf(float(rw * 21 / 4)/16.f) * 16 * rh)
// Ugly hack, replace with proper data/line size for different
// cameras/format when available
if (makeIs(LIBRAW_CAMERAMAKER_Nikon)
&& (!strncasecmp(imgdata.idata.model, "Z", 1) || !strcasecmp(imgdata.idata.model, "D6"))
)
{
if (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;
}
if (NIKON_14BIT_SIZE3COLOR(imgdata.sizes.raw_width, imgdata.sizes.raw_height) ==
libraw_internal_data.unpacker_data.data_size)
{
load_raw = &LibRaw::nikon_14bit_load_raw;
imgdata.idata.filters = 0; // 3-color nefx image
}
}
#undef NIKON_14BIT_SIZE
#undef NIKON_14BIT_SIZE3COLOR
// Linear max from 14-bit camera, but on 12-bit data?
if (makeIs(LIBRAW_CAMERAMAKER_Sony) &&
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 (makeIs(LIBRAW_CAMERAMAKER_Canon))
{
if (!imgdata.idata.dng_version && (MN.canon.DefaultCropAbsolute.l != -1)) // tag 0x00e0 SensorInfo was parsed
{
if (imgdata.sizes.raw_aspect != LIBRAW_IMAGE_ASPECT_UNKNOWN)
{ // tag 0x009a AspectInfo was parsed
isRIC.cleft += MN.canon.DefaultCropAbsolute.l;
isRIC.ctop += MN.canon.DefaultCropAbsolute.t;
}
else
{
isRIC.cleft = MN.canon.DefaultCropAbsolute.l;
isRIC.ctop = MN.canon.DefaultCropAbsolute.t;
isRIC.cwidth = MN.canon.DefaultCropAbsolute.r - MN.canon.DefaultCropAbsolute.l + 1;
isRIC.cheight = MN.canon.DefaultCropAbsolute.b - MN.canon.DefaultCropAbsolute.t + 1;
}
}
else
{
if (imgdata.sizes.raw_aspect != LIBRAW_IMAGE_ASPECT_UNKNOWN)
{
}
else
{ // Canon PowerShot S2 IS
}
}
#undef isRIC
if (imgdata.color.raw_bps < 14 && !imgdata.idata.dng_version && load_raw != &LibRaw::canon_sraw_load_raw)
{
int xmax = (1 << imgdata.color.raw_bps) - 1;
if (MN.canon.SpecularWhiteLevel > xmax) // Adjust 14-bit metadata to real bps
{
int div = 1 << (14 - imgdata.color.raw_bps);
for (int c = 0; c < 4; c++) imgdata.color.linear_max[c] /= div;
for (int c = 0; c < 4; c++) MN.canon.ChannelBlackLevel[c] /= div;
MN.canon.AverageBlackLevel /= div;
MN.canon.SpecularWhiteLevel /= div;
MN.canon.NormalWhiteLevel /= div;
}
}
}
if (makeIs(LIBRAW_CAMERAMAKER_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) &&
MN.canon.SensorHeight > 1 &&
MN.canon.SensorWidth > 1)
{
imgdata.sizes.raw_width = MN.canon.SensorWidth;
imgdata.sizes.left_margin = MN.canon.DefaultCropAbsolute.l;
imgdata.sizes.iwidth = imgdata.sizes.width =
MN.canon.DefaultCropAbsolute.r - MN.canon.DefaultCropAbsolute.l + 1;
imgdata.sizes.raw_height = MN.canon.SensorHeight;
imgdata.sizes.top_margin = MN.canon.DefaultCropAbsolute.t;
imgdata.sizes.iheight = imgdata.sizes.height =
MN.canon.DefaultCropAbsolute.b - MN.canon.DefaultCropAbsolute.t + 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;
}
}
#ifdef USE_DNGSDK
if (imgdata.idata.dng_version
&&libraw_internal_data.unpacker_data.tiff_compress == 34892
&& libraw_internal_data.unpacker_data.tiff_bps == 8
&& libraw_internal_data.unpacker_data.tiff_samples == 3
&& load_raw == &LibRaw::lossy_dng_load_raw)
{
// Data should be linearized by DNG SDK
C.black = 0;
memset(C.cblack, 0, sizeof(C.cblack));
}
#endif
// XTrans Compressed?
if (!imgdata.idata.dng_version &&
makeIs(LIBRAW_CAMERAMAKER_Fujifilm) &&
(load_raw == &LibRaw::unpacked_load_raw))
{
if (imgdata.sizes.raw_width * (imgdata.sizes.raw_height * 2ul) !=
libraw_internal_data.unpacker_data.data_size)
{
if ((imgdata.sizes.raw_width * (imgdata.sizes.raw_height * 7ul)) / 4 ==
libraw_internal_data.unpacker_data.data_size)
load_raw = &LibRaw::fuji_14bit_load_raw;
else
parse_fuji_compressed_header();
}
else if (!strcmp(imgdata.idata.normalized_model, "X-H2S")
&& libraw_internal_data.internal_data.input->size()
< (libraw_internal_data.unpacker_data.data_size + libraw_internal_data.unpacker_data.data_offset))
{
parse_fuji_compressed_header(); // try to use compressed header: X-H2S may record wrong data size
}
}
// set raw_inset_crops[1] via raw_aspect
if (imgdata.sizes.raw_aspect >= LIBRAW_IMAGE_ASPECT_MINIMAL_REAL_ASPECT_VALUE
&& imgdata.sizes.raw_aspect <= LIBRAW_IMAGE_ASPECT_MAXIMAL_REAL_ASPECT_VALUE
/* crops[0] is valid*/
&& (imgdata.sizes.raw_inset_crops[0].cleft < 0xffff)
&& (imgdata.sizes.raw_inset_crops[0].cleft + imgdata.sizes.raw_inset_crops[0].cwidth <= imgdata.sizes.raw_width)
&& (imgdata.sizes.raw_inset_crops[0].ctop < 0xffff)
&& (imgdata.sizes.raw_inset_crops[0].ctop + imgdata.sizes.raw_inset_crops[0].cheight <= imgdata.sizes.raw_height)
&& imgdata.sizes.raw_inset_crops[0].cwidth > 0 && imgdata.sizes.raw_inset_crops[0].cheight >0
/* crops[1] is not set*/
&& (imgdata.sizes.raw_inset_crops[1].cleft == 0xffff)
&& (imgdata.sizes.raw_inset_crops[1].ctop == 0xffff)
)
{
float c0_ratio = float(imgdata.sizes.raw_inset_crops[0].cwidth) / float(imgdata.sizes.raw_inset_crops[0].cheight);
float c1_ratio = float(imgdata.sizes.raw_aspect) / 1000.f;
if (c0_ratio / c1_ratio < 0.98 || c0_ratio / c1_ratio > 1.02) // set crops[1]
{
if (c1_ratio > c0_ratio) // requested image is wider, cut from top/bottom
{
int newheight = int(imgdata.sizes.raw_inset_crops[0].cwidth / c1_ratio);
int dtop = (imgdata.sizes.raw_inset_crops[0].cheight - newheight) / 2;
imgdata.sizes.raw_inset_crops[1].ctop = imgdata.sizes.raw_inset_crops[0].ctop + dtop;
imgdata.sizes.raw_inset_crops[1].cheight = newheight;
imgdata.sizes.raw_inset_crops[1].cleft = imgdata.sizes.raw_inset_crops[0].cleft;
imgdata.sizes.raw_inset_crops[1].cwidth = imgdata.sizes.raw_inset_crops[0].cwidth;
}
else
{
int newwidth = int(imgdata.sizes.raw_inset_crops[0].cheight * c1_ratio);
int dleft = (imgdata.sizes.raw_inset_crops[0].cwidth - newwidth) / 2;
imgdata.sizes.raw_inset_crops[1].cleft = imgdata.sizes.raw_inset_crops[0].cleft + dleft;
imgdata.sizes.raw_inset_crops[1].cwidth = newwidth;
imgdata.sizes.raw_inset_crops[1].ctop = imgdata.sizes.raw_inset_crops[0].ctop;
imgdata.sizes.raw_inset_crops[1].cheight = imgdata.sizes.raw_inset_crops[0].cheight;
}
}
}
int adjust_margins = 0;
if (makeIs(LIBRAW_CAMERAMAKER_Fujifilm) && (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];
}
adjust_margins = 6;
}
else if (!libraw_internal_data.internal_output_params.fuji_width
&& imgdata.idata.filters >= 1000)
{
if ((imgdata.sizes.top_margin % 2) || (imgdata.sizes.left_margin % 2))
{
int crop[2] = { 0,0 };
unsigned filt;
int c;
if (imgdata.sizes.top_margin % 2)
{
imgdata.sizes.top_margin += 1;
imgdata.sizes.height -= 1;
crop[1] = 1;
}
if (imgdata.sizes.left_margin % 2)
{
imgdata.sizes.left_margin += 1;
imgdata.sizes.width -= 1;
crop[0] = 1;
}
for (filt = c = 0; c < 16; c++)
filt |= FC((c >> 1) + (crop[1]), (c & 1) + (crop[0])) << c * 2;
imgdata.idata.filters = filt;
}
adjust_margins = 2;
}
if(adjust_margins) // adjust crop_inset margins
for (int i = 0; i < 2; i++)
{
if (imgdata.sizes.raw_inset_crops[i].cleft && imgdata.sizes.raw_inset_crops[i].cleft < 0xffff
&& imgdata.sizes.raw_inset_crops[i].cwidth && imgdata.sizes.raw_inset_crops[i].cwidth < 0xffff
&& (imgdata.sizes.raw_inset_crops[i].cleft%adjust_margins)
&& (imgdata.sizes.raw_inset_crops[i].cwidth > adjust_margins))
{
int newleft = ((imgdata.sizes.raw_inset_crops[i].cleft / adjust_margins) + 1) * adjust_margins;
int diff = newleft - imgdata.sizes.raw_inset_crops[i].cleft;
if (diff > 0)
{
imgdata.sizes.raw_inset_crops[i].cleft += diff;
imgdata.sizes.raw_inset_crops[i].cwidth -= diff;
}
}
if (imgdata.sizes.raw_inset_crops[i].ctop && imgdata.sizes.raw_inset_crops[i].ctop < 0xffff
&& imgdata.sizes.raw_inset_crops[i].cheight && imgdata.sizes.raw_inset_crops[i].cheight < 0xffff
&& (imgdata.sizes.raw_inset_crops[i].ctop%adjust_margins)
&& (imgdata.sizes.raw_inset_crops[i].cheight > adjust_margins))
{
int newtop = ((imgdata.sizes.raw_inset_crops[i].ctop / adjust_margins) + 1) * adjust_margins;
int diff = newtop - imgdata.sizes.raw_inset_crops[i].ctop;
if (diff > 0)
{
imgdata.sizes.raw_inset_crops[i].ctop += diff;
imgdata.sizes.raw_inset_crops[i].cheight -= diff;
}
}
}
#ifdef USE_DNGSDK
if (
imgdata.rawparams.use_dngsdk &&
!(imgdata.rawparams.options & (LIBRAW_RAWOPTIONS_DNG_STAGE2 | LIBRAW_RAWOPTIONS_DNG_STAGE3 | LIBRAW_RAWOPTIONS_DNG_DISABLEWBADJUST)))
#endif
{
// Fix DNG white balance if needed: observed only for Kalpanika X3F tools produced DNGs
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] = float(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 = unsigned(imgdata.color.cblack[0] + maxdelta);
}
}
}
if (imgdata.idata.dng_version &&
makeIs(LIBRAW_CAMERAMAKER_Panasonic)
&& !strcasecmp(imgdata.idata.normalized_model, "DMC-LX100"))
imgdata.sizes.width = 4288;
if (imgdata.idata.dng_version && makeIs(LIBRAW_CAMERAMAKER_Leica))
{
if (!strcasecmp(imgdata.idata.normalized_model, "SL2"))
imgdata.sizes.height -= 16;
else if (!strcasecmp(imgdata.idata.normalized_model, "SL3"))
{
if (imgdata.sizes.raw_width == 9536)
imgdata.sizes.width -= 12;
else if (imgdata.sizes.raw_width == 7424)
imgdata.sizes.width -= 14;
else if (imgdata.sizes.raw_width == 5312)
imgdata.sizes.width -= 18;
}
}
if (makeIs(LIBRAW_CAMERAMAKER_Sony) &&
imgdata.idata.dng_version)
{
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 (makeIs(LIBRAW_CAMERAMAKER_Sony) &&
!imgdata.idata.dng_version)
{
if(load_raw ==&LibRaw::sony_arq_load_raw)
{
if(S.raw_width > 12000) // A7RM4 16x, both APS-C and APS
S.width = S.raw_width - 64;
else // A7RM3/M4 4x merge
S.width = S.raw_width - 32;
}
if (((!strncasecmp(imgdata.idata.model, "ILCE-7RM", 8) ||
!strcasecmp(imgdata.idata.model, "ILCA-99M2")) &&
(S.raw_width == 5216 || S.raw_width == 6304)) // A7RM2/M3/A99M2 in APS mode; A7RM4 in APS-C
||
(!strcasecmp(imgdata.idata.model, "ILCE-7R") && S.raw_width >= 4580 &&
S.raw_width < 5020) // A7R in crop mode, no samples, so size est.
|| (!strcasecmp(imgdata.idata.model, "ILCE-7") &&
S.raw_width == 3968) // A7 in crop mode
||
((!strncasecmp(imgdata.idata.model, "ILCE-7M", 7) ||
!strcasecmp(imgdata.idata.model, "ILCE-9") ||
#if 0
!strcasecmp(imgdata.idata.model,
"SLT-A99V")) // Does SLT-A99 also have APS-C mode??
#endif
(mnCamID == SonyID_SLT_A99)) // 2 reasons: some cameras are SLT-A99, no 'V'; some are Hasselblad HV
&& S.raw_width > 3750 &&
S.raw_width < 4120) // A7M2, A7M3, AA9, most likely APS-C raw_width
// is 3968 (same w/ A7), but no samples, so guess
|| (!strncasecmp(imgdata.idata.model, "ILCE-7S", 7) &&
S.raw_width == 2816) // A7S2=> exact, hope it works for A7S-I too
)
S.width = S.raw_width - 32;
}
// FIXME: it is possible that DNG contains 4x main frames + some previews; in this case imgdata.idata.raw_count will be greater than 4
if (makeIs(LIBRAW_CAMERAMAKER_Pentax) &&
/*!strcasecmp(imgdata.idata.model,"K-3 II") &&*/
imgdata.idata.raw_count == 4 &&
(imgdata.rawparams.options & LIBRAW_RAWOPTIONS_PENTAX_PS_ALLFRAMES))
{
imgdata.idata.raw_count = 1;
imgdata.idata.filters = 0;
imgdata.idata.colors = 4;
imgdata.sizes.top_margin+=2;
imgdata.sizes.left_margin+=2;
imgdata.sizes.width-=4;
imgdata.sizes.height-=4;
IO.mix_green = 1;
pentax_component_load_raw = load_raw;
load_raw = &LibRaw::pentax_4shot_load_raw;
}
if (!imgdata.idata.dng_version && makeIs(LIBRAW_CAMERAMAKER_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;
}
if (!imgdata.idata.dng_version && makeIs(LIBRAW_CAMERAMAKER_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 &&
makeIs(LIBRAW_CAMERAMAKER_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 * 2u ==
imgdata.sizes.raw_height * imgdata.sizes.raw_width * 3u)
{
libraw_internal_data.unpacker_data.load_flags = 80;
}
// Adjust BL for Sony A900/A850
if (load_raw == &LibRaw::packed_load_raw &&
makeIs(LIBRAW_CAMERAMAKER_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 (unsigned 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] = ushort(y * 16383.f);
}
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) &&
makeIs(LIBRAW_CAMERAMAKER_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 (unsigned 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 (makeIs(LIBRAW_CAMERAMAKER_Canon) &&
MN.canon.multishot[0] >= 8 &&
MN.canon.multishot[1] > 0)
imgdata.color.as_shot_wb_applied =
LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_CANON;
else if (makeIs(LIBRAW_CAMERAMAKER_Nikon) &&
MN.nikon.ExposureMode == 1)
imgdata.color.as_shot_wb_applied =
LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_NIKON;
else if (makeIs(LIBRAW_CAMERAMAKER_Pentax) &&
((MN.pentax.MultiExposure & 0x01) == 1))
imgdata.color.as_shot_wb_applied =
LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_PENTAX;
else if (makeIs(LIBRAW_CAMERAMAKER_Sony) && load_raw == &LibRaw::sony_ycbcr_load_raw)
imgdata.color.as_shot_wb_applied = LIBRAW_ASWB_APPLIED | LIBRAW_ASWB_SONY;
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 (makeIs(LIBRAW_CAMERAMAKER_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 (
#if 0
/* GX20 should be corrected, but K20 is not */
makeIs(LIBRAW_CAMERAMAKER_Pentax) &&
!strcasecmp(imgdata.idata.normalized_model, "K20D")
#endif
#if 0
!strcasecmp(imgdata.idata.make, "Samsung") &&
!strcasecmp(imgdata.idata.model, "GX20")
#endif
makeIs(LIBRAW_CAMERAMAKER_Pentax) &&
(mnCamID == PentaxID_GX20) // Samsung rebranding
)
{
for (int cnt = LIBRAW_WBI_Unknown; cnt <= LIBRAW_WBI_StudioTungsten; cnt++) {
if (C.WB_Coeffs[cnt][1]) {
C.WB_Coeffs[cnt][0] = (int)((float)(C.WB_Coeffs[cnt][0]) * 1.0503f);
C.WB_Coeffs[cnt][2] = (int)((float)(C.WB_Coeffs[cnt][2]) * 2.2867f);
}
}
for (int cnt = 0; cnt < 64; cnt++) {
if (C.WBCT_Coeffs[cnt][0] > 0.0f) {
C.WBCT_Coeffs[cnt][1] *= 1.0503f;
C.WBCT_Coeffs[cnt][3] *= 2.2867f;
}
}
for(int cnt = 0; cnt < 4; cnt++)
imgdata.color.pre_mul[cnt] =
float(C.WB_Coeffs[LIBRAW_WBI_Daylight][cnt]);
}
// Adjust BL for Panasonic
if (load_raw == &LibRaw::panasonic_load_raw &&
makeIs(LIBRAW_CAMERAMAKER_Panasonic) &&
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;
unsigned 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
#ifdef USE_X3FTOOLS
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;
}
}
#endif
#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);
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;
}
#endif
if (C.profile_length)
{
if (C.profile)
free(C.profile);
INT64 profile_sz = MIN(INT64(C.profile_length), ID.input->size() - ID.profile_offset);
if (profile_sz > 0LL && profile_sz < LIBRAW_MAX_PROFILE_SIZE_MB * 1024LL * 1024LL)
{
C.profile = calloc(size_t(profile_sz),1);
C.profile_length = unsigned(profile_sz);
ID.input->seek(ID.profile_offset, SEEK_SET);
ID.input->read(C.profile, size_t(profile_sz), 1);
}
else
C.profile = NULL;
}
SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY);
}
catch (const std::bad_alloc&)
{
EXCEPTION_HANDLER(LIBRAW_EXCEPTION_ALLOC);
}
catch (const LibRaw_exceptions& err)
{
EXCEPTION_HANDLER(err);
}
catch (const std::exception& )
{
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;
}