blob: a13aadaaf9857b021fe741921c92a818a8d18160 [file]
/* -*- C++ -*-
* Copyright 2019-2022 LibRaw LLC (info@libraw.org)
*
* PhaseOne IIQ-Sv2 decoder is inspired by code provided by Daniel Vogelbacher <daniel@chaospixel.com>
*
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 <vector>
#include <algorithm> // for std::sort
void LibRaw::sony_arq_load_raw()
{
int row, col;
if (imgdata.idata.filters || imgdata.idata.colors < 3)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
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
if(imgdata.rawparams.options & LIBRAW_RAWOPTIONS_ARQ_SKIP_CHANNEL_SWAP)
return;
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()
{
size_t alloc_sz = size_t(imgdata.sizes.raw_width) * (size_t(imgdata.sizes.raw_height) + 16) * 4 * sizeof(ushort);
if (INT64(alloc_sz) > INT64(imgdata.rawparams.max_raw_memory_mb) * INT64(1024 * 1024))
throw LIBRAW_EXCEPTION_TOOBIG;
#ifdef LIBRAW_CALLOC_RAWSTORE
ushort *plane = (ushort *)calloc(size_t(imgdata.sizes.raw_width) * size_t(imgdata.sizes.raw_height), sizeof(ushort));
#else
ushort *plane = (ushort *)malloc(size_t(imgdata.sizes.raw_width) *
size_t(imgdata.sizes.raw_height) * sizeof(ushort));
#endif
if (!plane)
throw LIBRAW_EXCEPTION_ALLOC;
#ifdef LIBRAW_CALLOC_RAWSTORE
ushort(*result)[4] = (ushort(*)[4])calloc(alloc_sz,1);
#else
ushort(*result)[4] = (ushort(*)[4])malloc(alloc_sz);
#endif
if(!result)
throw LIBRAW_EXCEPTION_ALLOC;
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.rawparams.p4shot_order[i] >= '0' &&
imgdata.rawparams.p4shot_order[i] <= '3')
{
move_row = ((imgdata.rawparams.p4shot_order[i] - '0') & 2) ? 1 : 0;
move_col = ((imgdata.rawparams.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++;
}
if (imgdata.color.cblack[4] == 2 && imgdata.color.cblack[5] == 2)
for (int c = 0; c < 4; c++)
imgdata.color.cblack[FC(c / 2, c % 2)] +=
imgdata.color.cblack[6 +
c / 2 % imgdata.color.cblack[4] *
imgdata.color.cblack[5] +
c % 2 % imgdata.color.cblack[5]];
imgdata.color.cblack[4] = imgdata.color.cblack[5] = 0;
// 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];
}
static inline void unpack21bytesto12x16_nikon(unsigned char *src, unsigned short (*dest)[4])
{
// bytes 0-6
dest[0][0] = ((src[1] & 0x3f) << 8) | src[0];
dest[0][1] = (src[3] & 0xf) << 10 | (src[2] << 2) | (src[1] >> 6);
dest[0][2] = ((src[5] & 0x3) << 12) | (src[4] << 4) | (src[3] >> 4);
dest[1][0] = (src[6] << 6) | (src[5] >> 2);
// bytes 7-13
dest[1][1] = ((src[8] & 0x3f) << 8) | src[7];
dest[1][2] = (src[10] & 0xf) << 10 | (src[9] << 2) | (src[8] >> 6);
dest[2][0] = ((src[12] & 0x3) << 12) | (src[11] << 4) | (src[10] >> 4);
dest[2][1] = (src[13] << 6) | (src[12] >> 2);
// bytes 14-20
dest[2][2] = ((src[15] & 0x3f) << 8) | src[14];
dest[3][0] = (src[17] & 0xf) << 10 | (src[16] << 2) | (src[15] >> 6);
dest[3][1] = ((src[19] & 0x3) << 12) | (src[18] << 4) | (src[17] >> 4);
dest[3][2] = (src[20] << 6) | (src[19] >> 2);
}
void LibRaw::nikon_14bit_load_raw()
{
int cps = (imgdata.idata.filters == 0 && imgdata.idata.colors == 3) ? 3 : 1;
if (cps == 1 && !imgdata.rawdata.raw_image)
throw LIBRAW_EXCEPTION_DECODE_RAW;
if(cps == 3 && !imgdata.image)
throw LIBRAW_EXCEPTION_DECODE_RAW;
const unsigned linelen =
(unsigned)(ceilf((float)(S.raw_width * cps * 7 / 4) / 16.0f)) *
16; // 14512; // S.raw_width * 7 / 4;
const unsigned pitch = S.raw_pitch ? S.raw_pitch /( (cps>=3)? 8 : 2) : S.raw_width;
unsigned char *buf = (unsigned char *)calloc(linelen,1);
for (int row = 0; row < S.raw_height; row++)
{
unsigned bytesread =
libraw_internal_data.internal_data.input->read(buf, 1, linelen);
if (cps == 1)
{
unsigned short *dest = &imgdata.rawdata.raw_image[pitch * row];
// swab32arr((unsigned *)buf, bytesread / 4);
for (unsigned int sp = 0, dp = 0;
dp < pitch - 3 && sp < linelen - 6 && sp < bytesread - 6;
sp += 7, dp += 4)
unpack7bytesto4x16_nikon(buf + sp, dest + dp);
}
else if (cps == 3)
{
unsigned short (*dest)[4] = &imgdata.image[pitch * row];
// swab32arr((unsigned *)buf, bytesread / 4);
for (unsigned int sp = 0, dp = 0;
dp < pitch - 3 && sp < linelen - 20 && sp < bytesread - 20;
sp += 21, dp += 4)
unpack21bytesto12x16_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 *)calloc(linelen,1);
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 (unsigned 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 (unsigned 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
{
unsigned bytesperrow = (((unsigned(S.raw_width) * 3u / 2u) + 15u) / 16u) * 16u; // bytes per row
// libraw_internal_data.unpacker_data.load_flags -> row byte count
if (bytesperrow < 2000 || bytesperrow > 64000)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
unsigned char *buf =
(unsigned char *)calloc(bytesperrow,1);
for (int row = 0; row < S.raw_height; row++)
{
checkCancel();
int readed = libraw_internal_data.internal_data.input->read(
buf, 1, bytesperrow);
if (readed < (int)bytesperrow)
derror();
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, 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;
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)] =
ushort((bitbuf << (64 - tiff_bps - vbits) >> (64 - tiff_bps)) & 0xffff);
}
vbits -= rbits;
}
}
struct pana_cs6_page_decoder
{
unsigned int pixelbuffer[18], lastoffset, maxoffset;
unsigned char current, *buffer;
pana_cs6_page_decoder(unsigned char *_buffer, unsigned int bsize)
: lastoffset(0), maxoffset(bsize), current(0), buffer(_buffer)
{
}
void read_page(); // will throw IO error if not enough space in buffer
void read_page12(); // 12-bit variant
unsigned int nextpixel() { return current < 14 ? pixelbuffer[current++] : 0; }
unsigned int nextpixel12() { return current < 18 ? pixelbuffer[current++] : 0; }
};
void pana_cs6_page_decoder::read_page()
{
if (!buffer || (maxoffset - lastoffset < 16))
throw LIBRAW_EXCEPTION_IO_EOF;
#define wbuffer(i) ((unsigned short)buffer[lastoffset + 15 - i])
pixelbuffer[0] = (wbuffer(0) << 6) | (wbuffer(1) >> 2); // 14 bit
pixelbuffer[1] = (((wbuffer(1) & 0x3) << 12) | (wbuffer(2) << 4) | (wbuffer(3) >> 4)) & 0x3fff; // 14 bit
pixelbuffer[2] = (wbuffer(3) >> 2) & 0x3; // 2
pixelbuffer[3] = ((wbuffer(3) & 0x3) << 8) | wbuffer(4); // 10
pixelbuffer[4] = (wbuffer(5) << 2) | (wbuffer(6) >> 6); // 10
pixelbuffer[5] = ((wbuffer(6) & 0x3f) << 4) | (wbuffer(7) >> 4); // 10
pixelbuffer[6] = (wbuffer(7) >> 2) & 0x3;
pixelbuffer[7] = ((wbuffer(7) & 0x3) << 8) | wbuffer(8);
pixelbuffer[8] = ((wbuffer(9) << 2) & 0x3fc) | (wbuffer(10) >> 6);
pixelbuffer[9] = ((wbuffer(10) << 4) | (wbuffer(11) >> 4)) & 0x3ff;
pixelbuffer[10] = (wbuffer(11) >> 2) & 0x3;
pixelbuffer[11] = ((wbuffer(11) & 0x3) << 8) | wbuffer(12);
pixelbuffer[12] = (((wbuffer(13) << 2) & 0x3fc) | wbuffer(14) >> 6) & 0x3ff;
pixelbuffer[13] = ((wbuffer(14) << 4) | (wbuffer(15) >> 4)) & 0x3ff;
#undef wbuffer
current = 0;
lastoffset += 16;
}
void pana_cs6_page_decoder::read_page12()
{
if (!buffer || (maxoffset - lastoffset < 16))
throw LIBRAW_EXCEPTION_IO_EOF;
#define wb(i) ((unsigned short)buffer[lastoffset + 15 - i])
pixelbuffer[0] = (wb(0) << 4) | (wb(1) >> 4); // 12 bit: 8/0 + 4 upper bits of /1
pixelbuffer[1] = (((wb(1) & 0xf) << 8) | (wb(2))) & 0xfff; // 12 bit: 4l/1 + 8/2
pixelbuffer[2] = (wb(3) >> 6) & 0x3; // 2; 2u/3, 6 low bits remains in wb(3)
pixelbuffer[3] = ((wb(3) & 0x3f) << 2) | (wb(4) >> 6); // 8; 6l/3 + 2u/4; 6 low bits remains in wb(4)
pixelbuffer[4] = ((wb(4) & 0x3f) << 2) | (wb(5) >> 6); // 8: 6l/4 + 2u/5; 6 low bits remains in wb(5)
pixelbuffer[5] = ((wb(5) & 0x3f) << 2) | (wb(6) >> 6); // 8: 6l/5 + 2u/6, 6 low bits remains in wb(6)
pixelbuffer[6] = (wb(6) >> 4) & 0x3; // 2, 4 low bits remains in wb(6)
pixelbuffer[7] = ((wb(6) & 0xf) << 4) | (wb(7) >> 4); // 8: 4 low bits from wb(6), 4 upper bits from wb(7)
pixelbuffer[8] = ((wb(7) & 0xf) << 4) | (wb(8) >> 4); // 8: 4 low bits from wb7, 4 upper bits from wb8
pixelbuffer[9] = ((wb(8) & 0xf) << 4) | (wb(9) >> 4); // 8: 4 low bits from wb8, 4 upper bits from wb9
pixelbuffer[10] = (wb(9) >> 2) & 0x3; // 2: bits 2-3 from wb9, two low bits remain in wb9
pixelbuffer[11] = ((wb(9) & 0x3) << 6) | (wb(10) >> 2); // 8: 2 bits from wb9, 6 bits from wb10
pixelbuffer[12] = ((wb(10) & 0x3) << 6) | (wb(11) >> 2); // 8: 2 bits from wb10, 6 bits from wb11
pixelbuffer[13] = ((wb(11) & 0x3) << 6) | (wb(12) >> 2); // 8: 2 bits from wb11, 6 bits from wb12
pixelbuffer[14] = wb(12) & 0x3; // 2: low bits from wb12
pixelbuffer[15] = wb(13);
pixelbuffer[16] = wb(14);
pixelbuffer[17] = wb(15);
#undef wb
current = 0;
lastoffset += 16;
}
void LibRaw::panasonicC6_load_raw()
{
const int rowstep = 16;
const bool _12bit = libraw_internal_data.unpacker_data.pana_bpp == 12;
const int pixperblock = _12bit ? 14 : 11;
const int blocksperrow = imgdata.sizes.raw_width / pixperblock;
const int rowbytes = blocksperrow * 16;
const unsigned pixelbase0 = _12bit ? 0x80 : 0x200;
const unsigned pixelbase_compare = _12bit ? 0x800 : 0x2000;
const unsigned spix_compare = _12bit ? 0x3fff : 0xffff;
const unsigned pixel_mask = _12bit ? 0xfff : 0x3fff;
std::vector<unsigned char> iobuf;
try
{
iobuf.resize(rowbytes * rowstep);
}
catch (...)
{
throw LIBRAW_EXCEPTION_ALLOC;
}
for (int row = 0; row < imgdata.sizes.raw_height - rowstep + 1;
row += rowstep)
{
int rowstoread = MIN(rowstep, imgdata.sizes.raw_height - row);
if (libraw_internal_data.internal_data.input->read(
iobuf.data(), rowbytes, rowstoread) != rowstoread)
throw LIBRAW_EXCEPTION_IO_EOF;
pana_cs6_page_decoder page(iobuf.data(), rowbytes * rowstoread);
for (int crow = 0, col = 0; crow < rowstoread; crow++, col = 0)
{
unsigned short *rowptr =
&imgdata.rawdata
.raw_image[(row + crow) * imgdata.sizes.raw_pitch / 2];
for (int rblock = 0; rblock < blocksperrow; rblock++)
{
if (_12bit)
page.read_page12();
else
page.read_page();
unsigned oddeven[2] = {0, 0}, nonzero[2] = {0, 0};
unsigned pmul = 0, pixel_base = 0;
for (int pix = 0; pix < pixperblock; pix++)
{
if (pix % 3 == 2)
{
unsigned base = _12bit ? page.nextpixel12(): page.nextpixel();
if (base > 3)
throw LIBRAW_EXCEPTION_IO_CORRUPT; // not possible b/c of 2-bit
// field, but....
if (base == 3)
base = 4;
pixel_base = pixelbase0 << base;
pmul = 1 << base;
}
unsigned epixel = _12bit ? page.nextpixel12() : page.nextpixel();
if (oddeven[pix % 2])
{
epixel *= pmul;
if (pixel_base < pixelbase_compare && nonzero[pix % 2] > pixel_base)
epixel += nonzero[pix % 2] - pixel_base;
nonzero[pix % 2] = epixel;
}
else
{
oddeven[pix % 2] = epixel;
if (epixel)
nonzero[pix % 2] = epixel;
else
epixel = nonzero[pix % 2];
}
unsigned spix = epixel - 0xf;
if (spix <= spix_compare)
rowptr[col++] = spix & spix_compare;
else
{
epixel = (((signed int)(epixel + 0x7ffffff1)) >> 0x1f);
rowptr[col++] = epixel & pixel_mask;
}
}
}
}
}
}
void LibRaw::panasonicC7_load_raw()
{
const int rowstep = 16;
int pixperblock = libraw_internal_data.unpacker_data.pana_bpp == 14 ? 9 : 10;
int rowbytes = imgdata.sizes.raw_width / pixperblock * 16;
unsigned char *iobuf = (unsigned char *)calloc(rowbytes * rowstep,1);
for (int row = 0; row < imgdata.sizes.raw_height - rowstep + 1;
row += rowstep)
{
int rowstoread = MIN(rowstep, imgdata.sizes.raw_height - row);
if (libraw_internal_data.internal_data.input->read(
iobuf, rowbytes, rowstoread) != rowstoread)
throw LIBRAW_EXCEPTION_IO_EOF;
unsigned char *bytes = iobuf;
for (int crow = 0; crow < rowstoread; crow++)
{
unsigned short *rowptr =
&imgdata.rawdata
.raw_image[(row + crow) * imgdata.sizes.raw_pitch / 2];
for (int col = 0; col < imgdata.sizes.raw_width - pixperblock + 1;
col += pixperblock, bytes += 16)
{
if (libraw_internal_data.unpacker_data.pana_bpp == 14)
{
rowptr[col] = bytes[0] + ((bytes[1] & 0x3F) << 8);
rowptr[col + 1] =
(bytes[1] >> 6) + 4 * (bytes[2]) + ((bytes[3] & 0xF) << 10);
rowptr[col + 2] =
(bytes[3] >> 4) + 16 * (bytes[4]) + ((bytes[5] & 3) << 12);
rowptr[col + 3] = ((bytes[5] & 0xFC) >> 2) + (bytes[6] << 6);
rowptr[col + 4] = bytes[7] + ((bytes[8] & 0x3F) << 8);
rowptr[col + 5] =
(bytes[8] >> 6) + 4 * bytes[9] + ((bytes[10] & 0xF) << 10);
rowptr[col + 6] =
(bytes[10] >> 4) + 16 * bytes[11] + ((bytes[12] & 3) << 12);
rowptr[col + 7] = ((bytes[12] & 0xFC) >> 2) + (bytes[13] << 6);
rowptr[col + 8] = bytes[14] + ((bytes[15] & 0x3F) << 8);
}
else if (libraw_internal_data.unpacker_data.pana_bpp ==
12) // have not seen in the wild yet
{
rowptr[col] = ((bytes[1] & 0xF) << 8) + bytes[0];
rowptr[col + 1] = 16 * bytes[2] + (bytes[1] >> 4);
rowptr[col + 2] = ((bytes[4] & 0xF) << 8) + bytes[3];
rowptr[col + 3] = 16 * bytes[5] + (bytes[4] >> 4);
rowptr[col + 4] = ((bytes[7] & 0xF) << 8) + bytes[6];
rowptr[col + 5] = 16 * bytes[8] + (bytes[7] >> 4);
rowptr[col + 6] = ((bytes[10] & 0xF) << 8) + bytes[9];
rowptr[col + 7] = 16 * bytes[11] + (bytes[10] >> 4);
rowptr[col + 8] = ((bytes[13] & 0xF) << 8) + bytes[12];
rowptr[col + 9] = 16 * bytes[14] + (bytes[13] >> 4);
}
}
}
}
free(iobuf);
}
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.rawparams.shot_select)
{
libraw_internal_data.internal_data.input->seek(-row_size, SEEK_CUR);
base_offset = row_size; // in bytes
}
unsigned char *buffer = (unsigned char *)calloc(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 *)calloc(3 * (imgdata.sizes.raw_width + 2),1);
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.rawparams.specials & LIBRAW_RAWSPECIAL_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.rawparams.specials & LIBRAW_RAWSPECIAL_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.71414f * (Ch3 - 0.5f);
if (g > 1.f)
g = 1.f;
if (g < 0.f)
g = 0.f;
float b = Y + 1.77200f * (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;
}
/*
Each row is decoded independently. Each row starts with a 16 bit prefix.
The hi byte is zero, the lo byte (first 3 bits) indicates a bit_base.
Other bits remain unused.
|0000 0000|0000 0XXX| => XXX is bit_base
After the prefix the pixel data starts. Pixels are grouped into clusters
forming 8 output pixel. Each cluster starts with a variable length of
bits, indicating decompression flags.
*/
#undef MIN
#undef MAX
#undef LIM
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define LIM(x, min, max) MAX(min, MIN(x, max))
struct iiq_bitstream_t
{
uint64_t curr;
uint32_t *input;
uint8_t used;
iiq_bitstream_t(uint32_t *img_input): curr(0),input(img_input),used(0){}
void fill()
{
if (used <= 32)
{
uint64_t bitpump_next = *input++;
curr = (curr << 32) | bitpump_next;
used += 32;
}
}
uint64_t peek(uint8_t len)
{
if (len >= used)
fill();
uint64_t res = curr >> (used - len);
return res & ((1 << (uint8_t)len) - 1);
}
void consume(uint8_t len)
{
peek(len); // fill buffer if needed
used -= len;
}
uint64_t get(char len)
{
uint64_t val = peek(len);
consume(len);
return val;
}
};
void decode_S_type(int32_t out_width, uint32_t *img_input, ushort *outbuf /*, int bit_depth*/)
{
#if 0
if (((bit_depth - 12) & 0xFFFFFFFD) != 0)
return 0;
#endif
iiq_bitstream_t stream(img_input);
const int pix_corr_shift = 2; // 16 - bit_depth;
unsigned int bit_check[2] = { 0, 0 };
const uint8_t used_corr[8] = {
3, 3, 3, 3, 1, 1, 1, 1,
};
const uint8_t extra_bits[8] = {
1, 2, 3, 4, 0, 0, 0, 0,
};
const uint8_t bit_indicator[8 * 4] = {
9, 8, 0, 7, 6, 6, 5, 5, 1, 1, 1, 1, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2,
};
const uint8_t skip_bits[8 * 4] = {5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
int block_count = ((out_width - 8) >> 3) + 1;
int block_total_bytes = 8 * block_count;
int32_t prev_pix_value[2] = { 0, 0 };
uint8_t init_bits = stream.get(16) & 7;
if (out_width - 7 > 0)
{
uint8_t pix_sub_init = 17 - init_bits;
for (int blk_id = 0; blk_id < block_count; ++blk_id)
{
int8_t idx_even = int8_t(stream.peek(7));
stream.consume(2);
if ((unsigned int)idx_even >= 32)
bit_check[0] = ((unsigned int)idx_even >> 5) + bit_check[0] - 2;
else
{
bit_check[0] = bit_indicator[idx_even];
stream.consume(skip_bits[idx_even]);
}
int8_t idx_odd = int8_t(stream.peek(7));
stream.consume(2);
if ((unsigned int)idx_odd >= 32)
bit_check[1] = ((unsigned int)idx_odd >> 5) + bit_check[1] - 2;
else
{
bit_check[1] = bit_indicator[idx_odd];
stream.consume(skip_bits[idx_odd]);
}
uint8_t bidx = uint8_t(stream.peek(3));
stream.consume(used_corr[bidx]);
uint8_t take_bits = init_bits + extra_bits[bidx]; // 11 or less
uint32_t bp_shift[2] = {bit_check[0] - extra_bits[bidx], bit_check[1] - extra_bits[bidx]};
int pix_sub[2] = {0xFFFF >> (pix_sub_init - bit_check[0]), 0xFFFF >> (pix_sub_init - bit_check[1])};
for (int i = 0; i < 8; i++) // MAIN LOOP for pixel decoding
{
int32_t value = 0;
if (bit_check[i & 1] == 9)
value = int32_t(stream.get(14));
else
value = prev_pix_value[i & 1] + ((uint32_t)stream.get(take_bits) << bp_shift[i & 1]) - pix_sub[i & 1];
outbuf[i] = LIM(value << pix_corr_shift, 0, 0xffff);
prev_pix_value[i & 1] = value;
}
outbuf += 8; // always produce 8 pixels from this cluster
}
} // if width > 7 // End main if
// Final block
// maybe fill/unpack extra bytes if width % 8 <> 0?
if (block_total_bytes < out_width)
{
do
{
stream.fill();
uint32_t pix_value = uint32_t(stream.get(14));
++block_total_bytes;
*outbuf++ = pix_value << pix_corr_shift;
} while (block_total_bytes < out_width);
}
}
struct p1_row_info_t
{
unsigned row;
INT64 offset;
p1_row_info_t(): row(0),offset(0){}
p1_row_info_t(const p1_row_info_t& q): row(q.row),offset(q.offset){}
bool operator < (const p1_row_info_t & rhs) const { return offset < rhs.offset; }
};
void LibRaw::phase_one_load_raw_s()
{
if(!libraw_internal_data.unpacker_data.strip_offset || !imgdata.rawdata.raw_image || !libraw_internal_data.unpacker_data.data_offset)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
std::vector<p1_row_info_t> stripes(imgdata.sizes.raw_height+1);
libraw_internal_data.internal_data.input->seek(libraw_internal_data.unpacker_data.strip_offset, SEEK_SET);
for (unsigned row = 0; row < imgdata.sizes.raw_height; row++)
{
stripes[row].row = row;
stripes[row].offset = INT64(get4()) + libraw_internal_data.unpacker_data.data_offset;
}
stripes[imgdata.sizes.raw_height].row = imgdata.sizes.raw_height;
stripes[imgdata.sizes.raw_height].offset = libraw_internal_data.unpacker_data.data_offset + INT64(libraw_internal_data.unpacker_data.data_size);
std::sort(stripes.begin(), stripes.end());
INT64 maxsz = imgdata.sizes.raw_width * 3 + 2; // theor max: 17 bytes per 8 pix + row header
std::vector<uint8_t> datavec(maxsz);
for (unsigned row = 0; row < imgdata.sizes.raw_height; row++)
{
if (stripes[row].row >= imgdata.sizes.raw_height) continue;
ushort *datap = imgdata.rawdata.raw_image + stripes[row].row * imgdata.sizes.raw_width;
libraw_internal_data.internal_data.input->seek(stripes[row].offset, SEEK_SET);
INT64 readsz = stripes[row + 1].offset - stripes[row].offset;
if (readsz > maxsz)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
if(libraw_internal_data.internal_data.input->read(datavec.data(), 1, readsz) != readsz)
derror(); // TODO: check read state
decode_S_type(imgdata.sizes.raw_width, (uint32_t *)datavec.data(), datap /*, 14 */);
}
}
#define ph1_bits(n) ph1_bithuff(n, 0)
#if defined (RAW)
#undef RAW
#endif
#define RAW(row, col) imgdata.rawdata.raw_image[(row)*imgdata.sizes.raw_width + (col)]
void LibRaw::samsung3_load_raw()
{
if(imgdata.sizes.raw_height < 436 || imgdata.sizes.raw_width < 646)
throw LIBRAW_EXCEPTION_IO_CORRUPT; // From Samsung opensource decoder: too small image
libraw_internal_data.unpacker_data.order = 0x4949;
const INT64 maxpixidx = (INT64)imgdata.sizes.raw_width * (INT64)(int)imgdata.sizes.raw_height;
ph1_bits(-1);
ph1_bits(16);
ph1_bits(4);
unsigned bit_depth = ph1_bits(4) + 1;
int datamax = (1 << bit_depth) - 1;
ph1_bits(8);
ph1_bits(16);
ph1_bits(16);
ph1_bits(16);
ph1_bits(4);
unsigned optflags = ph1_bits(4);
ph1_bits(16);
ph1_bits(8);
ph1_bits(2);
ushort init_val = ph1_bits(14);
for (int row = 0; row < (int)imgdata.sizes.raw_height; row++)
{
libraw_internal_data.internal_data.input->seek(
(libraw_internal_data.unpacker_data.data_offset - libraw_internal_data.internal_data.input->tell()) & 15,
SEEK_CUR);
ph1_bits(-1);
INT64 rowstart = (INT64)row * (INT64)imgdata.sizes.raw_width;
unsigned motion = 7;
int scale = 0;
unsigned diff_bits_mode[3][2];
for (int i = 0; i < 3; i++)
diff_bits_mode[i][0] = diff_bits_mode[i][1] = (row < 2) ? 7 : 4;
for (int col = 0; col < (int)imgdata.sizes.raw_width - 15; col += 16)
{
if ((optflags & 4) == 0 && (col & 63) == 0)
{
const int scalevals[3] = {0, -2, 2};
int i = ph1_bits(2);
if (i < 3)
scale += scalevals[i];
else
scale = ph1_bits(12);
}
if (optflags & 2)
motion = ph1_bits(1) ? 3 : 7;
else if (ph1_bits(1) == 0)
motion = ph1_bits(3);
// else => unchanged
if (motion == 7)
for (int i = 0; i < 16; i++)
RAW(row, col + i) = (col == 0) ? init_val : RAW(row, col + i - 2);
else
{
if (row < 2)
throw LIBRAW_EXCEPTION_IO_CORRUPT; // wrong motion mode: previous line lookup on first two lines
const int motion_offset[7] = {-4, -2, -2, 0, 0, 2, 4};
const int motion_average[7] = {0, 0, 1, 0, 1, 0, 0};
for (int i = 0; i < 16; i++)
{
int refrow = ((row + i) & 1) ? row - 2 : row - 1;
int refcol = col + i + motion_offset[motion] + (1 - ((row + i) & 1)) * (1 - 2 * (i & 1));
INT64 refidx = (INT64)refrow * (INT64)imgdata.sizes.raw_width + (INT64)refcol;
if(refidx < 0) // no need to check for >= because refrow is 1-2 rows up and col diffrence is ~+4 pix max
throw LIBRAW_EXCEPTION_IO_CORRUPT;
RAW(row, col + i) =
motion_average[motion] ? (RAW(refrow, refcol) + RAW(refrow, refcol + 2) + 1) >> 1 : RAW(refrow, refcol);
}
}
unsigned diff_bits[4] = {0, 0, 0, 0};
if ((optflags & 1) || ph1_bits(1) == 0)
{
unsigned flags[4];
for (int i = 0; i < 4; i++)
flags[i] = ph1_bits(2);
for (int i = 0; i < 4; i++)
{
unsigned colornum = (row % 2) ? (i >> 1) : ((i >> 1) + 2) % 3;
switch (flags[i])
{
case 0:
diff_bits[i] = diff_bits_mode[colornum][0];
break;
case 1:
diff_bits[i] = diff_bits_mode[colornum][0] + 1;
break;
case 2:
diff_bits[i] = diff_bits_mode[colornum][0] - 1;
break;
case 3:
diff_bits[i] = ph1_bits(4);
break;
}
diff_bits_mode[colornum][0] = diff_bits_mode[colornum][1];
diff_bits_mode[colornum][1] = diff_bits[i];
if (diff_bits[i] > bit_depth + 1)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
}
}
for (int i = 0; i < 16; i++)
{
unsigned len = diff_bits[i >> 2];
int sign_mask = 1 << (len - 1);
int diff = ((ph1_bits(len) ^ sign_mask) - sign_mask) * (scale * 2 + 1) + scale;
int rcol = (row % 2) ? col + ((i & 0x7) << 1) + 1 - (i >> 3) : col + ((i & 0x7) << 1) + (i >> 3);
INT64 bidx = rowstart + (INT64)rcol;
if(bidx <0 || bidx>=maxpixidx)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
int val = RAW(row, rcol) + diff;
RAW(row, rcol) = val < 0 ? 0 : (val > datamax ? datamax : val);
}
}
}
}