blob: 5b35dc4e277965d272d4ee98762897be33d87af8 [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"
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 (int 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 (int 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;
}
}
}
#ifdef USE_ZLIB
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;
}
}
}
#endif
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;
}
struct tile_stripe_data_t
{
bool tiled, striped;
int tileCnt;
unsigned tileWidth, tileHeight, tilesH, tilesV;
INT64 maxBytesInTile;
std::vector<INT64> tOffsets, tBytes;
tile_stripe_data_t() : tiled(false), striped(false),tileCnt(0),
tileWidth(0),tileHeight(0),tilesH(0),tilesV(0),
maxBytesInTile(0){}
void init(tiff_ifd_t *ifd, const libraw_image_sizes_t&, const unpacker_data_t&,
short _order,
LibRaw_abstract_datastream *stream);
};
static unsigned static_get4(LibRaw_abstract_datastream *stream, short _order)
{
uchar str[4] = { 0xff, 0xff, 0xff, 0xff };
stream->read(str, 1, 4);
return libraw_sget4_static(_order, str);
}
void tile_stripe_data_t::init(tiff_ifd_t *ifd, const libraw_image_sizes_t& sizes,
const unpacker_data_t& unpacker_data, short _order, LibRaw_abstract_datastream *stream)
{
tiled = (unpacker_data.tile_width <= sizes.raw_width) && (unpacker_data.tile_length <= sizes.raw_height);
striped = (ifd->rows_per_strip > 0 && ifd->rows_per_strip < sizes.raw_height) && ifd->strip_byte_counts_count > 0;
tileWidth = tiled ? unpacker_data.tile_width : sizes.raw_width;
tileHeight = tiled ? unpacker_data.tile_length :(striped ? ifd->rows_per_strip : sizes.raw_height);
tilesH = tiled ? (sizes.raw_width + tileWidth - 1) / tileWidth : 1;
tilesV = tiled ? (sizes.raw_height + tileHeight - 1) / tileHeight :
(striped ? ((sizes.raw_height + ifd->rows_per_strip - 1) / ifd->rows_per_strip) : 1);
tileCnt = tilesH * tilesV;
if (tileCnt < 1 || tileCnt > 1000000)
throw LIBRAW_EXCEPTION_DECODE_RAW;
tOffsets = std::vector<INT64>(tileCnt,0);
tBytes = std::vector <INT64>(tileCnt,0);
if (tiled)
for (int t = 0; t < tileCnt; ++t)
tOffsets[t] = static_get4(stream, _order);
else if (striped)
for (int t = 0; t < tileCnt && t < ifd->strip_offsets_count; ++t)
tOffsets[t] = ifd->strip_offsets[t];
else
tOffsets[0] = ifd->offset;
maxBytesInTile = 0;
if (tileCnt == 1 || (!tiled && !striped))
tBytes[0] = maxBytesInTile = ifd->bytes;
else if (tiled)
{
// ifd->bytes points to tile size table if more than 1 tile exists
stream->seek(ifd->bytes, SEEK_SET);
for (int t = 0; t < tileCnt; ++t)
{
tBytes[t] = static_get4(stream, _order); ;
maxBytesInTile = MAX(maxBytesInTile, tBytes[t]);
}
}
else if (striped)
for (int t = 0; t < tileCnt && t < ifd->strip_byte_counts_count; ++t)
{
tBytes[t] = ifd->strip_byte_counts[t];
maxBytesInTile = MAX(maxBytesInTile, tBytes[t]);
}
}
#ifdef USE_ZLIB
void LibRaw::deflate_dng_load_raw()
{
int iifd = find_ifd_by_offset(libraw_internal_data.unpacker_data.data_offset);
if(iifd < 0 || iifd > (int)libraw_internal_data.identify_data.tiff_nifds)
throw LIBRAW_EXCEPTION_DECODE_RAW;
struct tiff_ifd_t *ifd = &tiff_ifd[iifd];
float *float_raw_image = 0;
float max = 0.f;
if (ifd->samples != 1 && ifd->samples != 3 && ifd->samples != 4)
throw LIBRAW_EXCEPTION_DECODE_RAW;
if (libraw_internal_data.unpacker_data.tiff_samples != (unsigned)ifd->samples)
throw LIBRAW_EXCEPTION_DECODE_RAW; // Wrong IFD
if (imgdata.idata.filters && ifd->samples > 1)
throw LIBRAW_EXCEPTION_DECODE_RAW;
tile_stripe_data_t tiles;
tiles.init(ifd, imgdata.sizes, libraw_internal_data.unpacker_data, libraw_internal_data.unpacker_data.order,
libraw_internal_data.internal_data.input);
if (tiles.tBytes.size() < 1)
throw LIBRAW_EXCEPTION_IO_CORRUPT;
// Ensure less then 2GB per compressed tile
INT64 maxcomprlen = tiles.tBytes[0];
for (int i = 1; i < tiles.tBytes.size(); i++)
maxcomprlen = MAX(maxcomprlen, tiles.tBytes[i]);
if(maxcomprlen >= (1LL << 31) || maxcomprlen < 0)
throw LIBRAW_EXCEPTION_TOOBIG;
// Max bytes: 2^16 raw width * 2^2 bytes/pixel * 2^2 channels = 2^20, so check against 2^22
INT64 rowbytes = INT64(MAX(tiles.tileWidth, imgdata.sizes.raw_width)) * 4ULL * INT64(ifd->samples);
if (rowbytes > (1LL << 22))
throw LIBRAW_EXCEPTION_TOOBIG;
if (ifd->sample_format == 3)
{
INT64 raw_bytes = INT64(tiles.tileCnt) * INT64(tiles.tileWidth) * INT64(tiles.tileHeight) * INT64(ifd->samples) * sizeof(float);
if (raw_bytes > INT64(imgdata.rawparams.max_raw_memory_mb) * INT64(1024 * 1024))
throw LIBRAW_EXCEPTION_TOOBIG;
float_raw_image = (float *)calloc(raw_bytes, 1);
}
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;
}
INT64 tilePixels = INT64(tiles.tileWidth) * INT64(tiles.tileHeight);
unsigned pixelSize = sizeof(float) * ifd->samples;
INT64 tileBytes = tilePixels * INT64(pixelSize);
INT64 tileRowBytes = INT64(tiles.tileWidth) * INT64(pixelSize);
if(INT64(tiles.maxBytesInTile) > INT64(imgdata.rawparams.max_raw_memory_mb) * 1024LL * 1024LL )
throw LIBRAW_EXCEPTION_TOOBIG;
if (tileBytes + tileRowBytes > INT64(imgdata.rawparams.max_raw_memory_mb) * 1024LL * 1024LL)
throw LIBRAW_EXCEPTION_TOOBIG;
std::vector<uchar> cBuffer(tiles.maxBytesInTile,0);
std::vector<uchar> uBuffer(tileBytes + tileRowBytes,0); // extra row for decoding
for (size_t y = 0, t = 0; y < imgdata.sizes.raw_height; y += tiles.tileHeight)
{
for (size_t x = 0; x < imgdata.sizes.raw_width; x += tiles.tileWidth, ++t)
{
libraw_internal_data.internal_data.input->seek(tiles.tOffsets[t], SEEK_SET);
int bytesread = libraw_internal_data.internal_data.input->read(cBuffer.data(), 1, tiles.tBytes[t]);
if (bytesread < tiles.tBytes[t])
derror();
unsigned long dstLen = tileBytes;
int err =
uncompress(uBuffer.data() + tileRowBytes, &dstLen, cBuffer.data(), (unsigned long)tiles.tBytes[t]);
if (err != Z_OK)
{
throw LIBRAW_EXCEPTION_DECODE_RAW;
return;
}
else
{
int bytesps = ifd->bps >> 3;
size_t rowsInTile = y + tiles.tileHeight > imgdata.sizes.raw_height ? imgdata.sizes.raw_height - y : tiles.tileHeight;
size_t colsInTile = x + tiles.tileWidth > imgdata.sizes.raw_width ? imgdata.sizes.raw_width - x : tiles.tileWidth;
for (size_t row = 0; row < rowsInTile; ++row) // do not process full tile if not needed
{
unsigned char *dst = uBuffer.data() + row * tiles.tileWidth * bytesps * ifd->samples;
unsigned char *src = dst + tileRowBytes;
DecodeFPDelta(src, dst, tiles.tileWidth / xFactor, ifd->samples * xFactor, bytesps);
float lmax = expandFloats(dst, tiles.tileWidth * 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));
}
}
}
}
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.rawparams.options & LIBRAW_RAWOPTIONS_CONVERTFLOAT_TO_INT)
convertFloatToInt(); // with default settings
}
#else
void LibRaw::deflate_dng_load_raw() { throw LIBRAW_EXCEPTION_DECODE_RAW; }
#endif
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;
void *orawalloc = imgdata.rawdata.raw_alloc;
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 = float(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 = unsigned(dtarget);
imgdata.rawdata.color.black = imgdata.color.black =
unsigned((float)imgdata.color.black * multip);
for (int i = 0;
i < int(sizeof(imgdata.color.cblack)/sizeof(imgdata.color.cblack[0]));
i++)
if (i != 4 && i != 5)
imgdata.rawdata.color.cblack[i] = imgdata.color.cblack[i] =
unsigned((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;
}
if(orawalloc)
free(orawalloc); // remove old allocation
imgdata.rawdata.float_image = 0;
imgdata.rawdata.float3_image = 0;
imgdata.rawdata.float4_image = 0;
}
static
#if (defined(_MSC_VER) && !defined(__clang__))
_forceinline
#else
inline
#endif
void libraw_swap24(uchar *data, int len)
{
for (int i = 0; i < len - 2; i += 3)
{
uchar t = data[i];
data[i] = data[i + 2];
data[i + 2] = t;
}
}
static
#if (defined(_MSC_VER) && !defined(__clang__))
_forceinline
#else
inline
#endif
void libraw_swap32(uchar *data, int len)
{
unsigned *d = (unsigned*)data;
for (int i = 0; i < len / 4; i++)
{
unsigned x = d[i];
d[i] = (x << 24) + ((x << 8) & 0x00FF0000) +
((x >> 8) & 0x0000FF00) + (x >> 24);
}
}
void LibRaw::uncompressed_fp_dng_load_raw()
{
int iifd = find_ifd_by_offset(libraw_internal_data.unpacker_data.data_offset);
if (iifd < 0 || iifd > (int)libraw_internal_data.identify_data.tiff_nifds)
throw LIBRAW_EXCEPTION_DECODE_RAW;
struct tiff_ifd_t *ifd = &tiff_ifd[iifd];
float *float_raw_image = 0;
if (ifd->samples != 1 && ifd->samples != 3 && ifd->samples != 4)
throw LIBRAW_EXCEPTION_DECODE_RAW;
if(imgdata.idata.filters && ifd->samples > 1)
throw LIBRAW_EXCEPTION_DECODE_RAW;
if ((int)libraw_internal_data.unpacker_data.tiff_samples != ifd->samples)
throw LIBRAW_EXCEPTION_DECODE_RAW; // Wrong IFD
int bytesps = (ifd->bps + 7) >> 3; // round to upper value
if(bytesps < 1 || bytesps > 4)
throw LIBRAW_EXCEPTION_DECODE_RAW;
tile_stripe_data_t tiles;
tiles.init(ifd, imgdata.sizes, libraw_internal_data.unpacker_data, libraw_internal_data.unpacker_data.order,
libraw_internal_data.internal_data.input);
// Max bytes: 2^16 raw width * 2^2 bytes/pixel * 2^2 channels = 2^20, so check against 2^22
INT64 rowbytes = INT64(MAX(tiles.tileWidth, imgdata.sizes.raw_width)) * INT64(MAX(bytesps,4)) * INT64(ifd->samples);
if(rowbytes > (1LL << 22))
throw LIBRAW_EXCEPTION_TOOBIG;
INT64 allocsz = INT64(tiles.tileCnt) * INT64(tiles.tileWidth) * INT64(tiles.tileHeight) * INT64(ifd->samples) * INT64(sizeof(float));
if (allocsz > INT64(imgdata.rawparams.max_raw_memory_mb) * INT64(1024 * 1024))
throw LIBRAW_EXCEPTION_TOOBIG;
if (ifd->sample_format == 3)
float_raw_image = (float *)calloc(allocsz,1);
else
throw LIBRAW_EXCEPTION_DECODE_RAW; // Only float supported
bool difford = (libraw_internal_data.unpacker_data.order == 0x4949) == (ntohs(0x1234) == 0x1234);
float max = 0.f;
std::vector<uchar> rowbuf(tiles.tileWidth *sizeof(float) * ifd->samples,0); // line buffer for last tile in tile row
for (size_t y = 0, t = 0; y < imgdata.sizes.raw_height; y += tiles.tileHeight)
{
for (unsigned x = 0; x < imgdata.sizes.raw_width && t < (unsigned)tiles.tileCnt; x += tiles.tileWidth, ++t)
{
libraw_internal_data.internal_data.input->seek(tiles.tOffsets[t], SEEK_SET);
size_t rowsInTile = y + tiles.tileHeight > imgdata.sizes.raw_height ? imgdata.sizes.raw_height - y : tiles.tileHeight;
size_t colsInTile = x + tiles.tileWidth > imgdata.sizes.raw_width ? imgdata.sizes.raw_width - x : tiles.tileWidth;
// inrowbytes is less then 2^22 (see above) so conversion to int is safe
size_t inrowbytes = colsInTile * bytesps * ifd->samples;
int fullrowbytes = tiles.tileWidth *bytesps * ifd->samples;
size_t outrowbytes = colsInTile * sizeof(float) * ifd->samples;
for (size_t row = 0; row < rowsInTile; ++row) // do not process full tile if not needed
{
unsigned char *dst = fullrowbytes > int(inrowbytes) ? rowbuf.data(): // last tile in row, use buffer
(unsigned char *)&float_raw_image
[((y + row) * imgdata.sizes.raw_width + x) * ifd->samples];
int bytesread = libraw_internal_data.internal_data.input->read(dst, 1, fullrowbytes);
if (bytesread < fullrowbytes)
derror();
if (bytesps == 2 && difford)
libraw_swab(dst, fullrowbytes);
else if (bytesps == 3 && (libraw_internal_data.unpacker_data.order == 0x4949)) // II-16bit
libraw_swap24(dst, fullrowbytes);
if (bytesps == 4 && difford)
libraw_swap32(dst, fullrowbytes);
float lmax = expandFloats(
dst,
tiles.tileWidth * ifd->samples,
bytesps);
if (fullrowbytes > int(inrowbytes)) // last tile in row: copy buffer to destination
memmove(&float_raw_image[((y + row) * imgdata.sizes.raw_width + x) * ifd->samples], dst, outrowbytes);
max = MAX(max, lmax);
}
}
}
imgdata.color.fmaximum = max;
// setup outpuf fields
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.rawparams.options & LIBRAW_RAWOPTIONS_CONVERTFLOAT_TO_INT)
convertFloatToInt();
}