#ifdef USE_X3FTOOLS
#include "../../internal/libraw_cxx_defs.h"
#if defined __sun && defined DS
#undef DS
#endif
#ifdef ID
#undef ID
#endif
#include "../../internal/x3f_tools.h"
#define Sigma_X3F 22
void x3f_clear(void *p) { x3f_delete((x3f_t *)p); }
static void utf2char(utf16_t *str, char *buffer, unsigned bufsz)
{
if (bufsz < 1)
return;
buffer[bufsz - 1] = 0;
char *b = buffer;
while (*str != 0x00 && --bufsz > 0)
{
char *chr = (char *)str;
*b++ = *chr;
str++;
}
*b = 0;
}
static void *lr_memmem(const void *l, size_t l_len, const void *s, size_t s_len)
{
char *cur, *last;
const char *cl = (const char *)l;
const char *cs = (const char *)s;
if (l_len == 0 || s_len == 0)
return NULL;
if (l_len < s_len)
return NULL;
if (s_len == 1)
return (void *)memchr(l, (int)*cs, l_len);
last = (char *)cl + l_len - s_len;
for (cur = (char *)cl; cur <= last; cur++)
if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
return cur;
return NULL;
}
void LibRaw::parse_x3f()
{
x3f_t *x3f = x3f_new_from_file(libraw_internal_data.internal_data.input);
if (!x3f)
return;
_x3f_data = x3f;
x3f_header_t *H = NULL;
H = &x3f->header;
x3f_directory_entry_t *DE = x3f_get_raw(x3f);
if (!DE)
return;
imgdata.sizes.flip = H->rotation;
x3f_directory_entry_header_t *DEH = &DE->header;
x3f_image_data_t *ID = &DEH->data_subsection.image_data;
imgdata.sizes.raw_width = ID->columns;
imgdata.sizes.raw_height = ID->rows;
DE = x3f_get_prop(x3f);
if ((x3f_load_data(x3f, DE) == X3F_OK))
{
DEH = &DE->header;
x3f_property_list_t *PL = &DEH->data_subsection.property_list;
utf16_t *datap = (utf16_t *)PL->data;
uint32_t maxitems = PL->data_size / sizeof(utf16_t);
if (PL->property_table.size != 0)
{
int i;
x3f_property_t *P = PL->property_table.element;
for (i = 0; i < PL->num_properties; i++)
{
char name[100], value[100];
int noffset = (P[i].name - datap);
int voffset = (P[i].value - datap);
if (noffset < 0 || noffset > maxitems || voffset < 0 ||
voffset > maxitems)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
int maxnsize = maxitems - (P[i].name - datap);
int maxvsize = maxitems - (P[i].value - datap);
utf2char(P[i].name, name, MIN(maxnsize, sizeof(name)));
utf2char(P[i].value, value, MIN(maxvsize, sizeof(value)));
if (!strcmp(name, "ISO"))
imgdata.other.iso_speed = atoi(value);
if (!strcmp(name, "CAMMANUF"))
strcpy(imgdata.idata.make, value);
if (!strcmp(name, "CAMMODEL"))
strcpy(imgdata.idata.model, value);
if (!strcmp(name, "CAMSERIAL"))
strcpy(imgdata.shootinginfo.BodySerial, value);
if (!strcmp(name, "WB_DESC"))
strcpy(imgdata.color.model2, value);
if (!strcmp(name, "TIME"))
imgdata.other.timestamp = atoi(value);
if (!strcmp(name, "SHUTTER"))
imgdata.other.shutter = atof(value);
if (!strcmp(name, "APERTURE"))
imgdata.other.aperture = atof(value);
if (!strcmp(name, "FLENGTH"))
imgdata.other.focal_len = atof(value);
if (!strcmp(name, "FLEQ35MM"))
imgdata.lens.makernotes.FocalLengthIn35mmFormat = atof(value);
if (!strcmp(name, "IMAGERTEMP"))
imgdata.makernotes.common.SensorTemperature = atof(value);
if (!strcmp(name, "LENSARANGE"))
{
char *sp;
imgdata.lens.makernotes.MaxAp4CurFocal =
imgdata.lens.makernotes.MinAp4CurFocal = atof(value);
sp = strrchr(value, ' ');
if (sp)
{
imgdata.lens.makernotes.MinAp4CurFocal = atof(sp);
if (imgdata.lens.makernotes.MaxAp4CurFocal >
imgdata.lens.makernotes.MinAp4CurFocal)
my_swap(float, imgdata.lens.makernotes.MaxAp4CurFocal,
imgdata.lens.makernotes.MinAp4CurFocal);
}
}
if (!strcmp(name, "LENSFRANGE"))
{
char *sp;
imgdata.lens.makernotes.MinFocal = imgdata.lens.makernotes.MaxFocal =
atof(value);
sp = strrchr(value, ' ');
if (sp)
{
imgdata.lens.makernotes.MaxFocal = atof(sp);
if ((imgdata.lens.makernotes.MaxFocal + 0.17f) <
imgdata.lens.makernotes.MinFocal)
my_swap(float, imgdata.lens.makernotes.MaxFocal,
imgdata.lens.makernotes.MinFocal);
}
}
if (!strcmp(name, "LENSMODEL"))
{
char *sp;
imgdata.lens.makernotes.LensID =
strtol(value, &sp, 16); if (imgdata.lens.makernotes.LensID)
imgdata.lens.makernotes.LensMount = Sigma_X3F;
}
}
imgdata.idata.raw_count = 1;
load_raw = &LibRaw::x3f_load_raw;
imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 6;
imgdata.idata.is_foveon = 1;
libraw_internal_data.internal_output_params.raw_color =
1; imgdata.color.maximum = 0x3fff; libraw_internal_data.unpacker_data.order = 0x4949;
}
}
else
{
if (imgdata.sizes.raw_width == 5888 || imgdata.sizes.raw_width == 2944 ||
imgdata.sizes.raw_width == 6656 || imgdata.sizes.raw_width == 3328 ||
imgdata.sizes.raw_width == 5504 ||
imgdata.sizes.raw_width == 2752) {
imgdata.idata.raw_count = 1;
load_raw = &LibRaw::x3f_load_raw;
imgdata.sizes.raw_pitch = imgdata.sizes.raw_width * 6;
imgdata.idata.is_foveon = 1;
libraw_internal_data.internal_output_params.raw_color =
1; libraw_internal_data.unpacker_data.order = 0x4949;
strcpy(imgdata.idata.make, "SIGMA");
#if 1
int pos = libraw_internal_data.internal_data.input->tell();
libraw_internal_data.internal_data.input->seek(0, SEEK_SET);
unsigned char buf[2048];
libraw_internal_data.internal_data.input->read(buf, 2048, 1);
libraw_internal_data.internal_data.input->seek(pos, SEEK_SET);
unsigned char *fnd = (unsigned char *)lr_memmem(buf, 2048, "SIGMA dp", 8);
unsigned char *fndsd =
(unsigned char *)lr_memmem(buf, 2048, "sd Quatt", 8);
if (fnd)
{
unsigned char *nm = fnd + 8;
snprintf(imgdata.idata.model, 64, "dp%c Quattro",
*nm <= '9' && *nm >= '0' ? *nm : '2');
}
else if (fndsd)
{
snprintf(imgdata.idata.model, 64, "%s", fndsd);
}
else
#endif
if (imgdata.sizes.raw_width == 6656 ||
imgdata.sizes.raw_width == 3328)
strcpy(imgdata.idata.model, "sd Quattro H");
else
strcpy(imgdata.idata.model, "dp2 Quattro");
}
}
LibRaw_thumbnail_formats format = LIBRAW_THUMBNAIL_UNKNOWN;
if ((DE = x3f_get_thumb_jpeg(x3f)))
{
format = LIBRAW_THUMBNAIL_JPEG;
}
else if ((DE = x3f_get_thumb_plain(x3f)))
{
format = LIBRAW_THUMBNAIL_BITMAP;
}
if (DE)
{
x3f_directory_entry_header_t *DEH = &DE->header;
x3f_image_data_t *ID = &DEH->data_subsection.image_data;
imgdata.thumbnail.twidth = ID->columns;
imgdata.thumbnail.theight = ID->rows;
imgdata.thumbnail.tcolors = 3;
imgdata.thumbnail.tformat = format;
libraw_internal_data.internal_data.toffset = DE->input.offset;
write_thumb = &LibRaw::x3f_thumb_loader;
}
DE = x3f_get_camf(x3f);
if (DE && DE->input.size > 28)
{
libraw_internal_data.unpacker_data.meta_offset = DE->input.offset + 8;
libraw_internal_data.unpacker_data.meta_length = DE->input.size - 28;
}
}
INT64 LibRaw::x3f_thumb_size()
{
try
{
x3f_t *x3f = (x3f_t *)_x3f_data;
if (!x3f)
return -1; x3f_directory_entry_t *DE = x3f_get_thumb_jpeg(x3f);
if (!DE)
DE = x3f_get_thumb_plain(x3f);
if (!DE)
return -1;
int64_t p = x3f_load_data_size(x3f, DE);
if (p < 0 || p > 0xffffffff)
return -1;
return p;
}
catch (...)
{
return -1;
}
}
void LibRaw::x3f_thumb_loader()
{
try
{
x3f_t *x3f = (x3f_t *)_x3f_data;
if (!x3f)
return; x3f_directory_entry_t *DE = x3f_get_thumb_jpeg(x3f);
if (!DE)
DE = x3f_get_thumb_plain(x3f);
if (!DE)
return;
if (X3F_OK != x3f_load_data(x3f, DE))
throw LIBRAW_EXCEPTION_IO_CORRUPT;
x3f_directory_entry_header_t *DEH = &DE->header;
x3f_image_data_t *ID = &DEH->data_subsection.image_data;
imgdata.thumbnail.twidth = ID->columns;
imgdata.thumbnail.theight = ID->rows;
imgdata.thumbnail.tcolors = 3;
if (imgdata.thumbnail.tformat == LIBRAW_THUMBNAIL_JPEG)
{
imgdata.thumbnail.thumb = (char *)malloc(ID->data_size);
merror(imgdata.thumbnail.thumb, "LibRaw::x3f_thumb_loader()");
memmove(imgdata.thumbnail.thumb, ID->data, ID->data_size);
imgdata.thumbnail.tlength = ID->data_size;
}
else if (imgdata.thumbnail.tformat == LIBRAW_THUMBNAIL_BITMAP)
{
imgdata.thumbnail.tlength = ID->columns * ID->rows * 3;
imgdata.thumbnail.thumb = (char *)malloc(ID->columns * ID->rows * 3);
merror(imgdata.thumbnail.thumb, "LibRaw::x3f_thumb_loader()");
char *src0 = (char *)ID->data;
for (int row = 0; row < ID->rows; row++)
{
int offset = row * ID->row_stride;
if (offset + ID->columns * 3 > ID->data_size)
break;
char *dest = &imgdata.thumbnail.thumb[row * ID->columns * 3];
char *src = &src0[offset];
memmove(dest, src, ID->columns * 3);
}
}
}
catch (...)
{
}
}
static inline uint32_t _clampbits(int x, uint32_t n)
{
uint32_t _y_temp;
if ((_y_temp = x >> n))
x = ~_y_temp >> (32 - n);
return x;
}
void LibRaw::x3f_dpq_interpolate_rg()
{
int w = imgdata.sizes.raw_width / 2;
int h = imgdata.sizes.raw_height / 2;
unsigned short *image = (ushort *)imgdata.rawdata.color3_image;
for (int color = 0; color < 2; color++)
{
for (int y = 2; y < (h - 2); y++)
{
uint16_t *row0 =
&image[imgdata.sizes.raw_width * 3 * (y * 2) + color]; uint16_t row0_3 = row0[3];
uint16_t *row1 =
&image[imgdata.sizes.raw_width * 3 * (y * 2 + 1) + color]; uint16_t row1_3 = row1[3];
for (int x = 2; x < (w - 2); x++)
{
row1[0] = row1[3] = row0[3] = row0[0];
row0 += 6;
row1 += 6;
}
}
}
}
#ifdef _ABS
#undef _ABS
#endif
#define _ABS(a) ((a) < 0 ? -(a) : (a))
#undef CLIP
#define CLIP(value, high) ((value) > (high) ? (high) : (value))
void LibRaw::x3f_dpq_interpolate_af(int xstep, int ystep, int scale)
{
unsigned short *image = (ushort *)imgdata.rawdata.color3_image;
unsigned int rowpitch =
imgdata.rawdata.sizes.raw_pitch / 2; for (int y = 0;
y < imgdata.rawdata.sizes.height + imgdata.rawdata.sizes.top_margin;
y += ystep)
{
if (y < imgdata.rawdata.sizes.top_margin)
continue;
if (y < scale)
continue;
if (y > imgdata.rawdata.sizes.raw_height - scale)
break;
uint16_t *row0 = &image[imgdata.sizes.raw_width * 3 * y]; uint16_t *row_minus =
&image[imgdata.sizes.raw_width * 3 * (y - scale)]; uint16_t *row_plus =
&image[imgdata.sizes.raw_width * 3 * (y + scale)]; for (int x = 0;
x < imgdata.rawdata.sizes.width + imgdata.rawdata.sizes.left_margin;
x += xstep)
{
if (x < imgdata.rawdata.sizes.left_margin)
continue;
if (x < scale)
continue;
if (x > imgdata.rawdata.sizes.raw_width - scale)
break;
uint16_t *pixel0 = &row0[x * 3];
uint16_t *pixel_top = &row_minus[x * 3];
uint16_t *pixel_bottom = &row_plus[x * 3];
uint16_t *pixel_left = &row0[(x - scale) * 3];
uint16_t *pixel_right = &row0[(x + scale) * 3];
uint16_t *pixf = pixel_top;
if (_ABS(pixf[2] - pixel0[2]) > _ABS(pixel_bottom[2] - pixel0[2]))
pixf = pixel_bottom;
if (_ABS(pixf[2] - pixel0[2]) > _ABS(pixel_left[2] - pixel0[2]))
pixf = pixel_left;
if (_ABS(pixf[2] - pixel0[2]) > _ABS(pixel_right[2] - pixel0[2]))
pixf = pixel_right;
int blocal = pixel0[2], bnear = pixf[2];
if (blocal < imgdata.color.black + 16 || bnear < imgdata.color.black + 16)
{
if (pixel0[0] < imgdata.color.black)
pixel0[0] = imgdata.color.black;
if (pixel0[1] < imgdata.color.black)
pixel0[1] = imgdata.color.black;
pixel0[0] = CLIP(
(pixel0[0] - imgdata.color.black) * 4 + imgdata.color.black, 16383);
pixel0[1] = CLIP(
(pixel0[1] - imgdata.color.black) * 4 + imgdata.color.black, 16383);
}
else
{
float multip = float(bnear - imgdata.color.black) /
float(blocal - imgdata.color.black);
if (pixel0[0] < imgdata.color.black)
pixel0[0] = imgdata.color.black;
if (pixel0[1] < imgdata.color.black)
pixel0[1] = imgdata.color.black;
float pixf0 = pixf[0];
if (pixf0 < imgdata.color.black)
pixf0 = imgdata.color.black;
float pixf1 = pixf[1];
if (pixf1 < imgdata.color.black)
pixf1 = imgdata.color.black;
pixel0[0] = CLIP(
((float(pixf0 - imgdata.color.black) * multip +
imgdata.color.black) +
((pixel0[0] - imgdata.color.black) * 3.75 + imgdata.color.black)) /
2,
16383);
pixel0[1] = CLIP(
((float(pixf1 - imgdata.color.black) * multip +
imgdata.color.black) +
((pixel0[1] - imgdata.color.black) * 3.75 + imgdata.color.black)) /
2,
16383);
}
}
}
}
void LibRaw::x3f_dpq_interpolate_af_sd(int xstart, int ystart, int xend,
int yend, int xstep, int ystep,
int scale)
{
unsigned short *image = (ushort *)imgdata.rawdata.color3_image;
unsigned int rowpitch =
imgdata.rawdata.sizes.raw_pitch / 2; for (int y = ystart; y <= yend && y < imgdata.rawdata.sizes.height +
imgdata.rawdata.sizes.top_margin;
y += ystep)
{
uint16_t *row0 = &image[imgdata.sizes.raw_width * 3 * y]; uint16_t *row1 =
&image[imgdata.sizes.raw_width * 3 * (y + 1)]; uint16_t *row_minus =
&image[imgdata.sizes.raw_width * 3 * (y - scale)]; uint16_t *row_plus =
&image[imgdata.sizes.raw_width * 3 *
(y + scale)]; uint16_t *row_minus1 = &image[imgdata.sizes.raw_width * 3 * (y - 1)];
for (int x = xstart; x < xend && x < imgdata.rawdata.sizes.width +
imgdata.rawdata.sizes.left_margin;
x += xstep)
{
uint16_t *pixel00 = &row0[x * 3]; float sumR = 0.f, sumG = 0.f;
float cnt = 0.f;
for (int xx = -scale; xx <= scale; xx += scale)
{
sumR += row_minus[(x + xx) * 3];
sumR += row_plus[(x + xx) * 3];
sumG += row_minus[(x + xx) * 3 + 1];
sumG += row_plus[(x + xx) * 3 + 1];
cnt += 1.f;
if (xx)
{
cnt += 1.f;
sumR += row0[(x + xx) * 3];
sumG += row0[(x + xx) * 3 + 1];
}
}
pixel00[0] = sumR / 8.f;
pixel00[1] = sumG / 8.f;
if (scale == 2)
{
uint16_t *pixel0B = &row0[x * 3 + 3]; uint16_t *pixel1B = &row1[x * 3 + 3]; float sumG0 = 0, sumG1 = 0.f;
float cnt = 0.f;
for (int xx = -scale; xx <= scale; xx += scale)
{
sumG0 += row_minus1[(x + xx) * 3 + 2];
sumG1 += row_plus[(x + xx) * 3 + 2];
cnt += 1.f;
if (xx)
{
sumG0 += row0[(x + xx) * 3 + 2];
sumG1 += row1[(x + xx) * 3 + 2];
cnt += 1.f;
}
}
pixel0B[2] = sumG0 / cnt;
pixel1B[2] = sumG1 / cnt;
}
}
}
}
void LibRaw::x3f_load_raw()
{
int raise_error = 0;
x3f_t *x3f = (x3f_t *)_x3f_data;
if (!x3f)
return; if (X3F_OK == x3f_load_data(x3f, x3f_get_raw(x3f)))
{
x3f_directory_entry_t *DE = x3f_get_raw(x3f);
x3f_directory_entry_header_t *DEH = &DE->header;
x3f_image_data_t *ID = &DEH->data_subsection.image_data;
if (!ID)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
x3f_quattro_t *Q = ID->quattro;
x3f_huffman_t *HUF = ID->huffman;
x3f_true_t *TRU = ID->tru;
uint16_t *data = NULL;
if (ID->rows != S.raw_height || ID->columns != S.raw_width)
{
raise_error = 1;
goto end;
}
if (HUF != NULL)
data = HUF->x3rgb16.data;
if (TRU != NULL)
data = TRU->x3rgb16.data;
if (data == NULL)
{
raise_error = 1;
goto end;
}
size_t datasize = S.raw_height * S.raw_width * 3 * sizeof(unsigned short);
S.raw_pitch = S.raw_width * 3 * sizeof(unsigned short);
if (!(imgdata.rawdata.raw_alloc = malloc(datasize)))
throw LIBRAW_EXCEPTION_ALLOC;
imgdata.rawdata.color3_image = (ushort(*)[3])imgdata.rawdata.raw_alloc;
if (!strcasecmp(P1.make, "Polaroid") && !strcasecmp(P1.model, "x530"))
{
ushort(*src)[3] = (ushort(*)[3])data;
for (int p = 0; p < S.raw_height * S.raw_width; p++)
{
imgdata.rawdata.color3_image[p][0] = src[p][2];
imgdata.rawdata.color3_image[p][1] = src[p][1];
imgdata.rawdata.color3_image[p][2] = src[p][0];
}
}
else if (HUF)
memmove(imgdata.rawdata.raw_alloc, data, datasize);
else if (TRU && (!Q || !Q->quattro_layout))
memmove(imgdata.rawdata.raw_alloc, data, datasize);
else if (TRU && Q)
{
for (int prow = 0; prow < TRU->x3rgb16.rows && prow < S.raw_height / 2;
prow++)
{
ushort(*destrow)[3] =
(unsigned short(*)[3]) &
imgdata.rawdata
.color3_image[prow * 2 * S.raw_pitch / 3 / sizeof(ushort)][0];
ushort(*srcrow)[3] =
(unsigned short(*)[3]) & data[prow * TRU->x3rgb16.row_stride];
for (int pcol = 0;
pcol < TRU->x3rgb16.columns && pcol < S.raw_width / 2; pcol++)
{
destrow[pcol * 2][0] = srcrow[pcol][0];
destrow[pcol * 2][1] = srcrow[pcol][1];
}
}
for (int row = 0; row < Q->top16.rows && row < S.raw_height; row++)
{
ushort(*destrow)[3] =
(unsigned short(*)[3]) &
imgdata.rawdata
.color3_image[row * S.raw_pitch / 3 / sizeof(ushort)][0];
ushort(*srcrow) =
(unsigned short *)&Q->top16.data[row * Q->top16.columns];
for (int col = 0; col < Q->top16.columns && col < S.raw_width; col++)
destrow[col][2] = srcrow[col];
}
}
#if 1
if (TRU && Q &&
(imgdata.params.raw_processing_options &
LIBRAW_PROCESSING_DP2Q_INTERPOLATEAF))
{
if (imgdata.sizes.raw_width == 5888 &&
imgdata.sizes.raw_height == 3672) {
x3f_dpq_interpolate_af(32, 8, 2);
}
else if (imgdata.sizes.raw_width == 5888 &&
imgdata.sizes.raw_height == 3776) {
x3f_dpq_interpolate_af_sd(216, 464, imgdata.sizes.raw_width - 1, 3312,
16, 32, 2);
}
else if (imgdata.sizes.raw_width == 6656 &&
imgdata.sizes.raw_height == 4480) {
x3f_dpq_interpolate_af_sd(232, 592, imgdata.sizes.raw_width - 1, 3920,
16, 32, 2);
}
else if (imgdata.sizes.raw_width == 3328 &&
imgdata.sizes.raw_height == 2240) {
x3f_dpq_interpolate_af_sd(116, 296, imgdata.sizes.raw_width - 1, 2200,
8, 16, 1);
}
else if (imgdata.sizes.raw_width == 5504 &&
imgdata.sizes.raw_height == 3680) {
x3f_dpq_interpolate_af_sd(8, 192, imgdata.sizes.raw_width - 1, 3185, 16,
32, 2);
}
else if (imgdata.sizes.raw_width == 2752 &&
imgdata.sizes.raw_height == 1840) {
x3f_dpq_interpolate_af_sd(4, 96, imgdata.sizes.raw_width - 1, 1800, 8,
16, 1);
}
else if (imgdata.sizes.raw_width == 2944 &&
imgdata.sizes.raw_height == 1836) {
x3f_dpq_interpolate_af(16, 4, 1);
}
else if (imgdata.sizes.raw_width == 2944 &&
imgdata.sizes.raw_height == 1888) {
x3f_dpq_interpolate_af_sd(108, 232, imgdata.sizes.raw_width - 1, 1656,
8, 16, 1);
}
}
#endif
if (TRU && Q && Q->quattro_layout &&
(imgdata.params.raw_processing_options &
LIBRAW_PROCESSING_DP2Q_INTERPOLATERG))
x3f_dpq_interpolate_rg();
}
else
raise_error = 1;
end:
if (raise_error)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
}
#endif