/* RawSpeed - RAW file decoder. Copyright (C) 2009-2014 Klaus Post Copyright (C) 2014 Pedro CĂ´rte-Real Copyright (C) 2017 Roman Lebedev This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "decompressors/KodakDecompressor.h" #include "common/Point.h" // for iPoint2D #include "common/RawImage.h" // for RawImage, RawImageData #include "decoders/RawDecoderException.h" // for ThrowRDE #include "decompressors/HuffmanTable.h" // for HuffmanTable #include "io/ByteStream.h" // for ByteStream #include // for min #include // for array #include // for assert #include // for move namespace rawspeed { constexpr int KodakDecompressor::segment_size; KodakDecompressor::KodakDecompressor(const RawImage& img, ByteStream bs, int bps_, bool uncorrectedRawValues_) : mRaw(img), input(std::move(bs)), bps(bps_), uncorrectedRawValues(uncorrectedRawValues_) { if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 || mRaw->getBpp() != 2) ThrowRDE("Unexpected component count / data type"); if (mRaw->dim.x == 0 || mRaw->dim.y == 0 || mRaw->dim.x % 4 != 0 || mRaw->dim.x > 4516 || mRaw->dim.y > 3012) ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x, mRaw->dim.y); if (bps != 10 && bps != 12) ThrowRDE("Unexpected bits per sample: %i", bps); // Lower estimate: this decompressor requires *at least* half a byte // per output pixel input.check(mRaw->dim.area() / 2ULL); } KodakDecompressor::segment KodakDecompressor::decodeSegment(const uint32 bsize) { assert(bsize > 0); assert(bsize % 4 == 0); assert(bsize <= segment_size); segment out; static_assert(out.size() == segment_size, "Wrong segment size"); #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) // We are to produce only bsize pixels. __sanitizer_annotate_contiguous_container(out.begin(), out.end(), out.end(), out.begin() + bsize); #endif std::array blen; uint64 bitbuf = 0; uint32 bits = 0; for (uint32 i = 0; i < bsize; i += 2) { // One byte per two pixels blen[i] = input.peekByte() & 15; blen[i + 1] = input.getByte() >> 4; } if ((bsize & 7) == 4) { bitbuf = (static_cast(input.getByte())) << 8UL; bitbuf += (static_cast(input.getByte())); bits = 16; } for (uint32 i = 0; i < bsize; i++) { uint32 len = blen[i]; assert(len < 16); if (bits < len) { for (uint32 j = 0; j < 32; j += 8) { bitbuf += static_cast(static_cast(input.getByte())) << (bits + (j ^ 8)); } bits += 32; } uint32 diff = static_cast(bitbuf) & (0xffff >> (16 - len)); bitbuf >>= len; bits -= len; out[i] = len != 0 ? HuffmanTable::signExtended(diff, len) : int(diff); } return out; } void KodakDecompressor::decompress() { uchar8* data = mRaw->getData(); uint32 pitch = mRaw->pitch; uint32 random = 0; for (auto y = 0; y < mRaw->dim.y; y++) { auto* dest = reinterpret_cast(&data[y * pitch]); for (auto x = 0; x < mRaw->dim.x; x += segment_size) { const uint32 len = std::min(segment_size, mRaw->dim.x - x); const segment buf = decodeSegment(len); std::array pred; pred.fill(0); for (uint32 i = 0; i < len; i++) { pred[i & 1] += buf[i]; int value = pred[i & 1]; if (unsigned(value) >= (1U << bps)) ThrowRDE("Value out of bounds %d (bps = %i)", value, bps); if (uncorrectedRawValues) dest[x + i] = value; else mRaw->setWithLookUp(value, reinterpret_cast(&dest[x + i]), &random); } } } } } // namespace rawspeed