| /* -*- 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(); |
| } |