8afe44cd0 Snapshot 202502 29d9785c2 Do not apply canon metadata crop to DNG files 015b27fff Changelog updated d1a27c26e Merge branch 'master' of git.lexa.ru:LibRaw ca1368d8e check split_col/split_row values in phase_one_correct fb23332a9 UINT32=>unsigned as defined in structure declaration 354bc2907 Revert "build: add handling of openmp library" 797ac1934 Merge pull request #680 from ssssota/remove-duplicated-camera 52421b19e fix: remove duplicated supported camera ca57a1103 Merge pull request #679 from dlemstra/fix-profile-length 25bb86fe7 Merge pull request #678 from clan/openmp 591239482 Changelog updated 42fce9f8e Make sure the profile_length is the same size as the allocated memory. f767a2fbe prevent OOB reads in phase_one_correct 638154a5b build: add handling of openmp library bdd9e3436 Prevent out-of-bounds read in fuji 0xf00c tag parser 59cfa8b8a Prevent out-of-bounds read in fuji 0xf00c tag parser 3240fb21f Merge pull request #677 from ssssota/windows-makefile-invalid-indent 416912f43 build: fix indentation (8 spaces -> tab) bf7a0346d Merge pull request #676 from lance5/master 6a0ef2483 [fix] use LIBRAW_OWN_SWAB control swab 816ab359b [feature] support android NDK 21 cc118c1c1 H265 and JPEG-XL thumbnails support for dcraw_make_mem_thumb 9bcb8a1d9 LIBRAW_CALLOC_RAWSTORE; replace for w/ memmove in dng_sdk glue bf1a9140e panasonic decoder: limit load_flags to 0x4000 77a46b319 panasonic loader: zero buf to avoid uninitalized data leak 4f5a4cfb3 null-terminate xmp block f9bb7d126 small allocations: replace malloc with calloc 70f511871 define NOMINMAX before including winsock2 in public header file => do not provide min/max maco 3772d1be2 Merge pull request #661 from nekopsykose/end f2d1070f7 fix endian detection for ppc64le 47c7a2394 Ignore vendor crops for Fuji S6000/6500 17f16837e Prevent Sony-LJPEG decoder buffer overrun 9c9c04b44 Ensure SR2 block is fully read from file d3cbbd0e9 4-component DNG-JPEG support 891630152 additional check for imgdata.color.WB_Coeffs index range 54c6af90b prevent possible imgdata.color.WBCT_Coeffs overrun 158e635e5 X100V color updated w/ actual data; X-T4 and X-Pro3 typo fixed 393dc925d Fuji X-T3x colormatrix: fixed typo 66a81c333 removed extra Pentax KP colordata 6475fd04b pass all images with wrong bayer filter data to vng_interpolate fe2a7e2b7 Refuse images with colors==2 c2e8a908d additional offset checks in Sony metadata parser c9facb4b7 Clean wrong aber values; allocate extra data to image to avoid overrun on specially crafted test images 83bf3ad5e Merge pull request #640 from Calandracas606/fix-clback-docs c294e7075 fix the docs to properly reflect the size of cblack[LIBRAW_CBLACK_SIZE] 072eeaeb4 fixed integer overflow in largest frame selection code e58e8e43a additional checked_buffer_t offset checks 73d6daa05 Check for negatife offset checked_buffer_t 0d011198b Oops. Forgot to increase version a625a7d53 Merge pull request #633 from thesamesam/openmp b396d92d8 README.md: removed unprintable symbols 9893eb825 README.md: update policy actualized to match libraw.org site 54fbe8f47 libraw_adjust_to_raw_inset_crop 2f75ef793 m4: update ax_openmp.m4 from autoconf-archive (8->14) git-subtree-dir: rtengine/libraw git-subtree-split: 8afe44cd0e96611ba3cb73779b83ad05e945634c
293 lines
7.2 KiB
C++
293 lines
7.2 KiB
C++
/* -*- C++ -*-
|
|
* File: huffmandec.h
|
|
* Copyright (C) 2024 Alex Tutubalin, LibRaw LLC
|
|
*
|
|
Lossless JPEG decoder
|
|
|
|
Code partially backported from DNGLab's rust code
|
|
DNGLab was originally created in 2021 by Daniel Vogelbacher.
|
|
|
|
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).
|
|
|
|
*/
|
|
#pragma once
|
|
#include <stdint.h>
|
|
#include <vector>
|
|
|
|
struct BitPump // generic bit source
|
|
{
|
|
virtual uint32_t peek(uint32_t num) = 0;
|
|
virtual void consume(uint32_t num) = 0;
|
|
|
|
uint32_t get(uint32_t num)
|
|
{
|
|
if(num == 0) { return 0u; }
|
|
uint32_t val = peek(num);
|
|
consume(num);
|
|
return val;
|
|
}
|
|
};
|
|
|
|
struct ByteStreamBE // Jpeg is always big endian
|
|
{
|
|
enum Exceptions
|
|
{
|
|
OK = 0,
|
|
EndOfBuffer = 1
|
|
};
|
|
|
|
uint8_t *buffer;
|
|
unsigned size, pos;
|
|
ByteStreamBE(uint8_t *b, unsigned s) : buffer(b), size(s), pos(0) {}
|
|
ByteStreamBE() : buffer(0),size(0),pos(0){}
|
|
bool skip_to_marker();
|
|
|
|
uint8_t get_u8()
|
|
{
|
|
if (pos >= size)
|
|
throw EndOfBuffer;
|
|
uint8_t ret = buffer[pos];
|
|
pos++;
|
|
return ret;
|
|
}
|
|
uint16_t get_u16()
|
|
{
|
|
if (pos + 2 > size)
|
|
throw EndOfBuffer;
|
|
uint8_t r1 = buffer[pos];
|
|
uint8_t r2 = buffer[pos + 1];
|
|
pos += 2;
|
|
return (r1 << 8) | r2;
|
|
}
|
|
};
|
|
|
|
struct BitPumpJpeg : public BitPump
|
|
{
|
|
uint8_t *buffer;
|
|
unsigned size, pos;
|
|
uint64_t bits;
|
|
uint32_t nbits;
|
|
bool finished;
|
|
|
|
void consume(uint32_t num)
|
|
{
|
|
if (num <= nbits)
|
|
{
|
|
nbits -= num;
|
|
bits &= (uint64_t(1) << nbits) - 1UL;
|
|
}
|
|
}
|
|
uint32_t peek(uint32_t num)
|
|
{
|
|
if (num > nbits && !finished)
|
|
{
|
|
if ((size >= 4) && pos < size && buffer[pos] != 0xff && buffer[pos + 1] != 0xff && buffer[pos + 2] != 0xff &&
|
|
buffer[pos + 3] != 0xff)
|
|
{
|
|
uint64_t inbits = (uint32_t(buffer[pos]) << 24) | (uint32_t(buffer[pos + 1]) << 16) |
|
|
(uint32_t(buffer[pos + 2]) << 8) | (uint32_t(buffer[pos + 3]));
|
|
bits = (bits << 32) | inbits;
|
|
pos += 4;
|
|
nbits += 32;
|
|
}
|
|
else
|
|
{
|
|
int read_bytes = 0;
|
|
while (read_bytes < 4 && !finished)
|
|
{
|
|
uint8_t byte = 0;
|
|
if (pos >= size)
|
|
finished = true;
|
|
else
|
|
{
|
|
uint8_t nextbyte = buffer[pos];
|
|
if (nextbyte != 0xff)
|
|
byte = nextbyte;
|
|
else if (buffer[pos + 1] == 0x00)
|
|
{
|
|
pos += 1;
|
|
byte = nextbyte;
|
|
}
|
|
else
|
|
finished = true;
|
|
};
|
|
bits = (bits << 8) | uint64_t(byte);
|
|
pos += 1;
|
|
nbits += 8;
|
|
read_bytes += 1;
|
|
}
|
|
}
|
|
}
|
|
if(num > nbits && finished)
|
|
{
|
|
bits <<= 32;
|
|
nbits += 32;
|
|
}
|
|
return uint32_t(bits >> (nbits - num));
|
|
}
|
|
|
|
BitPumpJpeg(ByteStreamBE& s): buffer(s.buffer+s.pos),size(s.size-s.pos),pos(0),bits(0),nbits(0),finished(false){}
|
|
};
|
|
|
|
|
|
const uint32_t LIBRAW_DECODE_CACHE_BITS = 13;
|
|
const uint64_t LIBRAW_CACHE_PRESENT_FLAG = 0x100000000L;
|
|
|
|
struct HuffTable
|
|
{
|
|
uint32_t bits[17];
|
|
uint32_t huffval[256];
|
|
uint32_t shiftval[256];
|
|
bool dng_bug;
|
|
bool disable_cache;
|
|
uint32_t nbits;
|
|
std::vector<uint32_t> hufftable; // len:8 << 16| huffval:8 << 8 | shift:8
|
|
std::vector<uint64_t> decodecache;
|
|
bool initialized;
|
|
HuffTable();
|
|
void initval(uint32_t bits[17], uint32_t huffval[256], bool dng_bug);
|
|
|
|
int32_t decode(BitPump& pump)
|
|
{
|
|
uint64_t cached = disable_cache ? 0 : decodecache[pump.peek(LIBRAW_DECODE_CACHE_BITS)];
|
|
if (cached & LIBRAW_CACHE_PRESENT_FLAG)
|
|
{
|
|
uint32_t _bits = (cached >> 16) & 0xff;
|
|
int16_t val = int16_t(cached & 0xffff);
|
|
if (val == -32768 && dng_bug)
|
|
{
|
|
if (_bits > 16)
|
|
pump.consume(_bits - 16);
|
|
}
|
|
else
|
|
pump.consume(_bits);
|
|
return val;
|
|
}
|
|
else
|
|
return decode_slow1(pump);
|
|
}
|
|
|
|
int32_t decode_slow1(BitPump &pump)
|
|
{
|
|
int32_t _diff = diff(pump, len(pump));
|
|
return _diff;
|
|
}
|
|
|
|
int32_t decode_slow2(BitPump & pump, uint32_t& outlen) // output: (len+shift):8, code:16
|
|
{
|
|
uint32_t _len = len(pump);
|
|
int32_t _diff = diff(pump, _len);
|
|
uint8_t bits8 = (_len >> 16) & 0xff;
|
|
uint8_t len8 = (_len >> 8) & 0xff;
|
|
outlen = bits8 + len8;
|
|
return _diff;
|
|
}
|
|
|
|
uint32_t len(BitPump & pump) //bits:8, len:8, shift:8
|
|
{
|
|
uint32_t code = pump.peek(nbits);
|
|
uint32_t huffdata = hufftable[code];
|
|
uint32_t _bits = (huffdata >> 16) & 0xff;
|
|
pump.consume(_bits);
|
|
return huffdata;
|
|
}
|
|
|
|
int32_t diff(BitPump & pump, uint32_t hentry) // input: bits:8, len:8, shift:8; output: diff:i32
|
|
{
|
|
uint32_t len = (hentry >> 8) & 0xff;
|
|
if (len == 0)
|
|
return 0;
|
|
if (len == 16)
|
|
{
|
|
if (dng_bug)
|
|
pump.get(16);
|
|
return -32768;
|
|
}
|
|
uint32_t shift = hentry & 0xff;
|
|
uint32_t fulllen = len + shift;
|
|
uint32_t _bits = pump.get(len);
|
|
int32_t diff = ((_bits << 1) + 1) << shift >> 1;
|
|
if ((diff & (1 << (fulllen - 1))) == 0)
|
|
{
|
|
diff -= int32_t((1 << fulllen) - ((shift == 0)));
|
|
}
|
|
return diff;
|
|
}
|
|
};
|
|
|
|
struct LibRaw_JpegComponentInfo
|
|
{
|
|
unsigned id;
|
|
unsigned index;
|
|
unsigned dc_tbl;
|
|
unsigned subsample_h, subsample_v;
|
|
LibRaw_JpegComponentInfo() : id(0), index(0), dc_tbl(0), subsample_h(0), subsample_v(0) {};
|
|
LibRaw_JpegComponentInfo(unsigned _id, unsigned _index, unsigned _dcn, unsigned _sh, unsigned _sv)
|
|
: id(_id), index(_index), dc_tbl(_dcn), subsample_h(_sh), subsample_v(_sv){};
|
|
LibRaw_JpegComponentInfo(const LibRaw_JpegComponentInfo& q): id(q.id), index(q.index), dc_tbl(q.dc_tbl),
|
|
subsample_h(q.subsample_h),subsample_v(q.subsample_v){}
|
|
};
|
|
|
|
struct LibRaw_SOFInfo
|
|
{
|
|
unsigned width, height;
|
|
unsigned cps, precision;
|
|
std::vector<LibRaw_JpegComponentInfo> components;
|
|
bool csfix;
|
|
LibRaw_SOFInfo(): width(0),height(0),cps(0),precision(0),csfix(false){}
|
|
bool parse_sof(ByteStreamBE&); // true => OK, false => not OK
|
|
uint32_t parse_sos(ByteStreamBE&); // returns (predictor << 8 | point transform); if above 0xffff => error
|
|
};
|
|
|
|
struct LibRaw_LjpegDecompressor
|
|
{
|
|
ByteStreamBE buffer;
|
|
LibRaw_SOFInfo sof;
|
|
uint32_t predictor, point_transform;
|
|
uint32_t datastart;
|
|
std::vector<HuffTable> dhts;
|
|
LibRaw_LjpegDecompressor(uint8_t *b, unsigned s);
|
|
LibRaw_LjpegDecompressor(uint8_t *b, unsigned bs, bool dngbug, bool csfix);
|
|
void initialize(bool dngbug, bool csfix);
|
|
uint8_t next_marker(bool allowskip);
|
|
bool parse_dht(bool init[4], uint32_t dht_bits[4][17], uint32_t dht_huffval[4][256]); // return true on OK;
|
|
bool decode_ljpeg_422(std::vector<uint16_t> &dest, int width, int height);
|
|
|
|
struct State {
|
|
enum States
|
|
{
|
|
OK = 0,
|
|
NotInited = 1,
|
|
NoSOI = 2,
|
|
IncorrectPrecision = 3,
|
|
EOIReached = 4,
|
|
InvalidDHT = 5,
|
|
InvalidSOF = 6,
|
|
InvalidSOS = 7,
|
|
DQTPresent = 8
|
|
};
|
|
|
|
};
|
|
struct Marker {
|
|
enum Markers {
|
|
Stuff = 0x00,
|
|
SOF3 = 0xc3, // lossless
|
|
DHT = 0xc4, // huffman tables
|
|
SOI = 0xd8, // start of image
|
|
EOI = 0xd9, // end of image
|
|
SOS = 0xda, // start of scan
|
|
DQT = 0xdb, // quantization tables
|
|
Fill = 0xff,
|
|
};
|
|
};
|
|
enum State::States state;
|
|
};
|
|
|