1647 lines
55 KiB
Odin
1647 lines
55 KiB
Odin
package pdf
|
|
|
|
import "core:mem"
|
|
|
|
// DCTDecode: a JPEG decoder (ISO/IEC 10918-1), sufficient for what PDF
|
|
// producers actually emit.
|
|
//
|
|
// ISO 32000-2, 7.4.8 defines DCTDecode by reference to the JPEG specification
|
|
// and then says almost nothing else, so the interesting question is which of
|
|
// JPEG's many modes turn up inside PDFs. In practice: baseline and extended
|
|
// sequential Huffman (SOF0/SOF1), progressive Huffman (SOF2 -- ordinary once a
|
|
// document is assembled out of web assets), one, three and four components,
|
|
// and the Adobe APP14 marker that tells CMYK from YCCK. Those are all
|
|
// implemented here. Arithmetic coding (SOF9-SOF11), the lossless mode (SOF3)
|
|
// and the hierarchical modes are not: no producer emits them into a PDF, and
|
|
// there is nothing sensible to substitute.
|
|
//
|
|
// The decoder is written to survive damage. A JPEG inside a PDF has usually
|
|
// been through at least one recompressor, and truncated scans, restart markers
|
|
// at the wrong interval and missing EOI are all routine. Every one of those
|
|
// yields as much of the image as could be decoded rather than an error.
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Public surface
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Jpeg_Image is one decoded JPEG. `data` belongs to the caller.
|
|
Jpeg_Image :: struct {
|
|
width, height: int,
|
|
// 1 (grey), 3 (RGB, after the YCbCr inverse transform) or 4 (CMYK, after
|
|
// the YCCK inverse transform when the Adobe marker asks for one). Two
|
|
// components is not a real JPEG colour model but does occur; it is passed
|
|
// through untransformed.
|
|
components: int,
|
|
// Bits per sample in `data`, always 8. A 12-bit JPEG -- rare, and rarer
|
|
// still in a PDF -- is decoded and scaled down so that `data` stays one
|
|
// byte per sample; `jpeg_info` reports the precision the file declares for
|
|
// a caller that wants to know.
|
|
bits: int,
|
|
// Samples, `components` per pixel, row-major, no padding between rows.
|
|
data: []byte,
|
|
// The Adobe APP14 colour transform: 0 none, 1 YCbCr, 2 YCCK; -1 when the
|
|
// marker is absent.
|
|
//
|
|
// This is reported rather than acted on beyond the inverse transform
|
|
// itself, because Adobe writes the CMYK JPEGs it embeds in PDFs with every
|
|
// sample inverted, and the inversion is expressed in the image
|
|
// dictionary's /Decode array, not in the JPEG. Inverting here as well
|
|
// would double-apply it. image.odin owns that decision.
|
|
adobe_transform: int,
|
|
}
|
|
|
|
// An image larger than anything that can be rendered is not worth decoding,
|
|
// so this is the rasteriser's own limit from document.odin.
|
|
@(private) MAX_JPEG_PIXELS :: MAX_BITMAP_PIXELS
|
|
// Bytes one decode may allocate in total, across coefficient buffers, sample
|
|
// planes and the output. Every dimension in a JPEG header is attacker
|
|
// controlled and none of them can be checked against the compressed size --
|
|
// a uniform image compresses without limit -- so a fixed cap is the only
|
|
// defence there is.
|
|
@(private) MAX_JPEG_ALLOC :: 1 << 30
|
|
// Marker segments before the decoder gives up. A real file has a few dozen;
|
|
// this only bounds a stream of well-formed but empty ones.
|
|
@(private) MAX_JPEG_SEGMENTS :: 1 << 16
|
|
// Scans decoded before the decoder stops and keeps what it has. This is a
|
|
// separate bound from MAX_JPEG_SEGMENTS because a scan is not cheap per byte:
|
|
// one EOB run skips up to 32767 blocks for 18 bits, so a few hundred bytes of
|
|
// entropy data drives the MCU loop across the whole component. Bounding only
|
|
// the segment count leaves 65536 sweeps of a frame that may hold 2^22 blocks
|
|
// -- about 2.7e11 block visits, which is minutes to an hour of CPU from a
|
|
// stream of a megabyte or two. libjpeg-turbo's D_MAX_SCANS is the same 100,
|
|
// and it costs nothing real: no producer emits more than a few dozen, and the
|
|
// worst file in this project's corpus has ten.
|
|
@(private) MAX_JPEG_SCANS :: 100
|
|
|
|
// jpeg_decode decodes a complete JPEG datastream.
|
|
//
|
|
// `img.data` is allocated with `allocator` and is the caller's to free;
|
|
// everything else the decoder needs is scratch taken from `context.allocator`
|
|
// and released before returning.
|
|
//
|
|
// A truncated or damaged scan is not an error: the image comes back with the
|
|
// blocks that were decoded and mid-grey everywhere else, which is what every
|
|
// other reader shows. An error means there was nothing to hand back at all --
|
|
// no SOI, no frame header, impossible dimensions, or a coding mode this
|
|
// decoder does not implement.
|
|
jpeg_decode :: proc(data: []byte, allocator := context.allocator) -> (img: Jpeg_Image, err: Error) {
|
|
d, alloc_err := new(Jpeg_Decoder, context.allocator)
|
|
if alloc_err != nil {
|
|
return {}, .Out_Of_Memory
|
|
}
|
|
defer free(d, context.allocator)
|
|
|
|
d.scratch = context.allocator
|
|
d.adobe_transform = -1
|
|
defer jpeg_release(d)
|
|
|
|
if perr := jpeg_run(d, data); perr != .None {
|
|
return {}, perr
|
|
}
|
|
|
|
out := jpeg_emit(d, allocator) or_return
|
|
return Jpeg_Image{
|
|
width = d.width,
|
|
height = d.height,
|
|
components = d.ncomp,
|
|
bits = 8,
|
|
data = out,
|
|
adobe_transform = d.saw_adobe ? d.adobe_transform : -1,
|
|
}, .None
|
|
}
|
|
|
|
// jpeg_info reads the frame header only. It allocates nothing and does not
|
|
// touch the entropy-coded data, so it is cheap enough to call on every image
|
|
// in a document.
|
|
//
|
|
// `bits` is the precision the file declares (8, or 12 for the rare deep
|
|
// image), not the precision of what `jpeg_decode` hands back.
|
|
jpeg_info :: proc(data: []byte) -> (width, height, components, bits: int, err: Error) {
|
|
pos, found := jpeg_find_soi(data)
|
|
if !found {
|
|
return 0, 0, 0, 0, .Bad_Jpeg_Data
|
|
}
|
|
|
|
for _ in 0 ..< MAX_JPEG_SEGMENTS {
|
|
marker, next, ok := jpeg_next_marker(data, pos)
|
|
if !ok { break }
|
|
pos = next
|
|
|
|
switch marker {
|
|
case JPEG_SOI, JPEG_TEM, JPEG_RST0, JPEG_RST0 + 1, JPEG_RST0 + 2, JPEG_RST0 + 3,
|
|
JPEG_RST0 + 4, JPEG_RST0 + 5, JPEG_RST0 + 6, JPEG_RST0 + 7:
|
|
continue
|
|
case JPEG_EOI:
|
|
return 0, 0, 0, 0, .Bad_Jpeg_Data
|
|
}
|
|
|
|
payload, after, pok := jpeg_segment(data, pos)
|
|
if !pok { break }
|
|
pos = after
|
|
|
|
switch marker {
|
|
case JPEG_SOF0, JPEG_SOF1, JPEG_SOF2, JPEG_SOF3, JPEG_SOF5, JPEG_SOF6, JPEG_SOF7,
|
|
JPEG_SOF9, JPEG_SOF10, JPEG_SOF11, JPEG_SOF13, JPEG_SOF14, JPEG_SOF15:
|
|
if len(payload) < 6 {
|
|
return 0, 0, 0, 0, .Bad_Jpeg_Data
|
|
}
|
|
bits = int(payload[0])
|
|
height = int(payload[1]) << 8 | int(payload[2])
|
|
width = int(payload[3]) << 8 | int(payload[4])
|
|
components = int(payload[5])
|
|
if height == 0 {
|
|
// A frame header may leave the height at zero and supply it in
|
|
// a DNL marker after the first scan (ISO/IEC 10918-1, B.2.2).
|
|
if dnl, dok := jpeg_find_dnl(data, pos); dok {
|
|
height = dnl
|
|
}
|
|
}
|
|
if width <= 0 || height <= 0 || components <= 0 || components > 4 {
|
|
return width, height, components, bits, .Bad_Jpeg_Data
|
|
}
|
|
return width, height, components, bits, .None
|
|
case JPEG_SOS:
|
|
// Entropy data before a frame header: nothing to report.
|
|
return 0, 0, 0, 0, .Bad_Jpeg_Data
|
|
}
|
|
}
|
|
return 0, 0, 0, 0, .Bad_Jpeg_Data
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Markers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(private) JPEG_SOF0 :: 0xC0
|
|
@(private) JPEG_SOF1 :: 0xC1
|
|
@(private) JPEG_SOF2 :: 0xC2
|
|
@(private) JPEG_SOF3 :: 0xC3
|
|
@(private) JPEG_DHT :: 0xC4
|
|
@(private) JPEG_SOF5 :: 0xC5
|
|
@(private) JPEG_SOF6 :: 0xC6
|
|
@(private) JPEG_SOF7 :: 0xC7
|
|
@(private) JPEG_SOF9 :: 0xC9
|
|
@(private) JPEG_SOF10 :: 0xCA
|
|
@(private) JPEG_SOF11 :: 0xCB
|
|
@(private) JPEG_DAC :: 0xCC
|
|
@(private) JPEG_SOF13 :: 0xCD
|
|
@(private) JPEG_SOF14 :: 0xCE
|
|
@(private) JPEG_SOF15 :: 0xCF
|
|
@(private) JPEG_RST0 :: 0xD0
|
|
@(private) JPEG_SOI :: 0xD8
|
|
@(private) JPEG_EOI :: 0xD9
|
|
@(private) JPEG_SOS :: 0xDA
|
|
@(private) JPEG_DQT :: 0xDB
|
|
@(private) JPEG_DNL :: 0xDC
|
|
@(private) JPEG_DRI :: 0xDD
|
|
@(private) JPEG_APP0 :: 0xE0
|
|
@(private) JPEG_APP14 :: 0xEE
|
|
@(private) JPEG_COM :: 0xFE
|
|
@(private) JPEG_TEM :: 0x01
|
|
|
|
// jpeg_find_soi locates the start-of-image. Junk in front of it -- an HTTP
|
|
// response, an Exif wrapper that a rewriter half-removed, a stray newline --
|
|
// is common enough in embedded streams that starting at byte 0 unconditionally
|
|
// would reject working images.
|
|
@(private)
|
|
jpeg_find_soi :: proc(data: []byte) -> (pos: int, ok: bool) {
|
|
for i := 0; i + 1 < len(data); i += 1 {
|
|
if data[i] == 0xFF && data[i + 1] == JPEG_SOI {
|
|
return i + 2, true
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// jpeg_next_marker scans forward to the next marker, skipping fill bytes,
|
|
// stuffed 0xFF 0x00 pairs and any non-marker bytes in between. Returning the
|
|
// marker code and the offset just past it.
|
|
@(private)
|
|
jpeg_next_marker :: proc(data: []byte, from: int) -> (marker: int, next: int, ok: bool) {
|
|
p := max(from, 0)
|
|
for p + 1 < len(data) {
|
|
if data[p] != 0xFF {
|
|
p += 1
|
|
continue
|
|
}
|
|
q := p + 1
|
|
for q < len(data) && data[q] == 0xFF {
|
|
q += 1
|
|
}
|
|
if q >= len(data) { break }
|
|
if data[q] == 0x00 {
|
|
p = q + 1
|
|
continue
|
|
}
|
|
return int(data[q]), q + 1, true
|
|
}
|
|
return 0, len(data), false
|
|
}
|
|
|
|
// jpeg_segment reads a length-prefixed marker segment starting at `pos` (which
|
|
// points at the two length bytes) and returns its payload.
|
|
//
|
|
// A length that runs off the end of the data is clamped rather than rejected;
|
|
// a truncated final segment still tells us everything up to the truncation.
|
|
@(private)
|
|
jpeg_segment :: proc(data: []byte, pos: int) -> (payload: []byte, next: int, ok: bool) {
|
|
if pos + 2 > len(data) {
|
|
return nil, len(data), false
|
|
}
|
|
seglen := int(data[pos]) << 8 | int(data[pos + 1])
|
|
if seglen < 2 {
|
|
// Nonsense length. Skip the two bytes we read so the caller still
|
|
// makes progress and cannot spin here.
|
|
return nil, pos + 2, true
|
|
}
|
|
end := pos + seglen
|
|
if end > len(data) {
|
|
end = len(data)
|
|
}
|
|
return data[pos + 2:end], end, true
|
|
}
|
|
|
|
// jpeg_find_dnl looks ahead for a define-number-of-lines marker, used when the
|
|
// frame header left the height at zero. The scan is a plain forward search for
|
|
// a well-formed DNL segment; a false positive inside entropy data would need
|
|
// the four bytes FF DC 00 04, which the byte-stuffing rules make impossible
|
|
// for FF DC to be (0xDC is not a stuffed zero and not a restart marker), so
|
|
// this is safe in practice.
|
|
@(private)
|
|
jpeg_find_dnl :: proc(data: []byte, from: int) -> (lines: int, ok: bool) {
|
|
for i := max(from, 0); i + 5 < len(data); i += 1 {
|
|
if data[i] != 0xFF || data[i + 1] != JPEG_DNL { continue }
|
|
if data[i + 2] != 0x00 || data[i + 3] != 0x04 { continue }
|
|
n := int(data[i + 4]) << 8 | int(data[i + 5])
|
|
if n > 0 {
|
|
return n, true
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Decoder state
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(private)
|
|
Jpeg_Transform :: enum u8 {
|
|
None, // components are already in their final colour space
|
|
Ycbcr, // three components, inverse YCbCr
|
|
Ycck, // four components, inverse YCbCr on the first three, then invert
|
|
}
|
|
|
|
@(private)
|
|
Jpeg_Comp :: struct {
|
|
id: int,
|
|
h, v: int, // sampling factors, 1..4
|
|
tq: int, // quantisation table selector
|
|
dc_tbl: int,
|
|
ac_tbl: int,
|
|
dw, dh: int, // component size in samples
|
|
bw, bh: int, // component size in blocks, covering dw x dh
|
|
bw_pad: int, // blocks per line once padded out to whole MCUs
|
|
bh_pad: int,
|
|
pix_w: int, // bw_pad * 8
|
|
pix_h: int, // bh_pad * 8
|
|
coeffs: []i16,
|
|
samples: []byte,
|
|
pred: int, // running DC predictor for the scan in progress
|
|
}
|
|
|
|
@(private)
|
|
Jpeg_Scan :: struct {
|
|
comps: [4]int,
|
|
n: int,
|
|
ss, se: int,
|
|
ah, al: int,
|
|
}
|
|
|
|
@(private)
|
|
Jpeg_Decoder :: struct {
|
|
data: []byte,
|
|
pos: int,
|
|
scratch: mem.Allocator,
|
|
allocated: int,
|
|
|
|
width, height: int,
|
|
precision: int,
|
|
ncomp: int,
|
|
comps: [4]Jpeg_Comp,
|
|
hmax, vmax: int,
|
|
mcux, mcuy: int,
|
|
progressive: bool,
|
|
restart_interval: int,
|
|
|
|
qt: [4][64]u16,
|
|
qt_defined: [4]bool,
|
|
dc: [4]Jpeg_Huff,
|
|
ac: [4]Jpeg_Huff,
|
|
|
|
adobe_transform: int,
|
|
saw_adobe: bool,
|
|
saw_jfif: bool,
|
|
saw_sof: bool,
|
|
transform: Jpeg_Transform,
|
|
|
|
eobrun: int,
|
|
}
|
|
|
|
@(private)
|
|
jpeg_release :: proc(d: ^Jpeg_Decoder) {
|
|
for i in 0 ..< 4 {
|
|
if d.comps[i].coeffs != nil {
|
|
delete(d.comps[i].coeffs, d.scratch)
|
|
d.comps[i].coeffs = nil
|
|
}
|
|
if d.comps[i].samples != nil {
|
|
delete(d.comps[i].samples, d.scratch)
|
|
d.comps[i].samples = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// jpeg_charge reserves `n` bytes against the decode-wide allocation budget.
|
|
@(private)
|
|
jpeg_charge :: proc(d: ^Jpeg_Decoder, n: int) -> bool {
|
|
if n < 0 || n > MAX_JPEG_ALLOC - d.allocated {
|
|
return false
|
|
}
|
|
d.allocated += n
|
|
return true
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Header parsing and the top-level marker loop
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(private)
|
|
jpeg_run :: proc(d: ^Jpeg_Decoder, data: []byte) -> Error {
|
|
d.data = data
|
|
pos, found := jpeg_find_soi(data)
|
|
if !found {
|
|
return .Bad_Jpeg_Data
|
|
}
|
|
d.pos = pos
|
|
|
|
saw_scan := false
|
|
scans := 0
|
|
|
|
for _ in 0 ..< MAX_JPEG_SEGMENTS {
|
|
marker, next, ok := jpeg_next_marker(d.data, d.pos)
|
|
if !ok { break }
|
|
d.pos = next
|
|
|
|
switch marker {
|
|
case JPEG_SOI, JPEG_TEM:
|
|
continue
|
|
case JPEG_RST0, JPEG_RST0 + 1, JPEG_RST0 + 2, JPEG_RST0 + 3,
|
|
JPEG_RST0 + 4, JPEG_RST0 + 5, JPEG_RST0 + 6, JPEG_RST0 + 7:
|
|
// A restart marker outside a scan is leftover damage; step over it.
|
|
continue
|
|
case JPEG_EOI:
|
|
return jpeg_finish(d, saw_scan)
|
|
}
|
|
|
|
payload, after, pok := jpeg_segment(d.data, d.pos)
|
|
if !pok { break }
|
|
d.pos = after
|
|
|
|
switch marker {
|
|
case JPEG_DQT:
|
|
jpeg_read_dqt(d, payload)
|
|
case JPEG_DHT:
|
|
jpeg_read_dht(d, payload)
|
|
case JPEG_DRI:
|
|
if len(payload) >= 2 {
|
|
d.restart_interval = int(payload[0]) << 8 | int(payload[1])
|
|
}
|
|
case JPEG_APP0:
|
|
if len(payload) >= 5 && string(payload[:5]) == "JFIF\x00" {
|
|
d.saw_jfif = true
|
|
}
|
|
case JPEG_APP14:
|
|
// "Adobe", version, flags0, flags1, transform: 12 bytes.
|
|
if len(payload) >= 12 && string(payload[:5]) == "Adobe" {
|
|
d.saw_adobe = true
|
|
d.adobe_transform = int(payload[11])
|
|
}
|
|
case JPEG_DNL:
|
|
if len(payload) >= 2 && d.height == 0 {
|
|
d.height = int(payload[0]) << 8 | int(payload[1])
|
|
}
|
|
case JPEG_SOF0, JPEG_SOF1, JPEG_SOF2:
|
|
if d.saw_sof {
|
|
// A second frame header means a hierarchical or corrupt file.
|
|
// Keep the frame already decoded.
|
|
continue
|
|
}
|
|
d.progressive = marker == JPEG_SOF2
|
|
if ferr := jpeg_read_sof(d, payload); ferr != .None {
|
|
return ferr
|
|
}
|
|
case JPEG_SOF3, JPEG_SOF5, JPEG_SOF6, JPEG_SOF7,
|
|
JPEG_SOF9, JPEG_SOF10, JPEG_SOF11,
|
|
JPEG_SOF13, JPEG_SOF14, JPEG_SOF15, JPEG_DAC:
|
|
// Lossless, differential and arithmetic-coded frames. There is
|
|
// nothing to fall back to, so say so rather than emitting noise --
|
|
// unless a frame has already been decoded, in which case this is a
|
|
// corrupt byte that happened to look like a marker and the image
|
|
// in hand is worth more than the complaint.
|
|
if d.saw_sof {
|
|
continue
|
|
}
|
|
return .Unsupported_Image
|
|
case JPEG_SOS:
|
|
if !d.saw_sof {
|
|
return .Bad_Jpeg_Data
|
|
}
|
|
if scans >= MAX_JPEG_SCANS {
|
|
// Past this the file is spending the decoder's time rather
|
|
// than adding detail, so keep the image built so far and stop.
|
|
// Refinement scans only ever sharpen what is already there, so
|
|
// a legitimate file truncated here still looks right.
|
|
return jpeg_finish(d, saw_scan)
|
|
}
|
|
scan, serr := jpeg_read_sos(d, payload)
|
|
if serr != .None {
|
|
// An unusable scan header is not a reason to throw away the
|
|
// scans already decoded.
|
|
continue
|
|
}
|
|
saw_scan = true
|
|
scans += 1
|
|
jpeg_decode_scan(d, scan)
|
|
case:
|
|
// COM, APPn, JPGn, anything unknown: already stepped over.
|
|
}
|
|
}
|
|
|
|
return jpeg_finish(d, saw_scan)
|
|
}
|
|
|
|
@(private)
|
|
jpeg_finish :: proc(d: ^Jpeg_Decoder, saw_scan: bool) -> Error {
|
|
if !d.saw_sof {
|
|
return .Bad_Jpeg_Data
|
|
}
|
|
// A frame with no scan at all decodes to a uniform mid-grey image, which
|
|
// is more useful to a page than a hole where the image should be, but a
|
|
// file that never reached its first scan is damaged past the point of
|
|
// guessing.
|
|
if !saw_scan {
|
|
return .Bad_Jpeg_Data
|
|
}
|
|
return .None
|
|
}
|
|
|
|
@(private)
|
|
jpeg_read_sof :: proc(d: ^Jpeg_Decoder, payload: []byte) -> Error {
|
|
if len(payload) < 6 {
|
|
return .Bad_Jpeg_Data
|
|
}
|
|
d.precision = int(payload[0])
|
|
d.height = int(payload[1]) << 8 | int(payload[2])
|
|
d.width = int(payload[3]) << 8 | int(payload[4])
|
|
d.ncomp = int(payload[5])
|
|
|
|
if d.height == 0 {
|
|
if lines, ok := jpeg_find_dnl(d.data, d.pos); ok {
|
|
d.height = lines
|
|
}
|
|
}
|
|
if d.width <= 0 || d.height <= 0 {
|
|
return .Bad_Jpeg_Data
|
|
}
|
|
if d.ncomp < 1 || d.ncomp > 4 {
|
|
return .Bad_Jpeg_Data
|
|
}
|
|
if d.width > MAX_JPEG_PIXELS / d.height {
|
|
return .Bitmap_Too_Large
|
|
}
|
|
// 8 and 12 are the only precisions JPEG defines; anything else is damage.
|
|
// Deeper samples are shifted down at dequantisation so the rest of the
|
|
// pipeline stays 8-bit.
|
|
if d.precision < 8 || d.precision > 16 {
|
|
return .Bad_Jpeg_Data
|
|
}
|
|
if len(payload) < 6 + 3 * d.ncomp {
|
|
return .Bad_Jpeg_Data
|
|
}
|
|
|
|
d.hmax, d.vmax = 1, 1
|
|
for i in 0 ..< d.ncomp {
|
|
c := &d.comps[i]
|
|
base := 6 + 3 * i
|
|
c.id = int(payload[base])
|
|
c.h = int(payload[base + 1] >> 4)
|
|
c.v = int(payload[base + 1] & 15)
|
|
c.tq = int(payload[base + 2])
|
|
// Sampling factors outside 1..4 are illegal; clamping keeps the block
|
|
// geometry consistent instead of producing a zero-size plane.
|
|
if c.h < 1 || c.h > 4 { c.h = 1 }
|
|
if c.v < 1 || c.v > 4 { c.v = 1 }
|
|
if c.tq < 0 || c.tq > 3 { c.tq = 0 }
|
|
d.hmax = max(d.hmax, c.h)
|
|
d.vmax = max(d.vmax, c.v)
|
|
}
|
|
|
|
d.mcux = (d.width + 8 * d.hmax - 1) / (8 * d.hmax)
|
|
d.mcuy = (d.height + 8 * d.vmax - 1) / (8 * d.vmax)
|
|
|
|
for i in 0 ..< d.ncomp {
|
|
c := &d.comps[i]
|
|
c.dw = (d.width * c.h + d.hmax - 1) / d.hmax
|
|
c.dh = (d.height * c.v + d.vmax - 1) / d.vmax
|
|
c.bw = (c.dw + 7) / 8
|
|
c.bh = (c.dh + 7) / 8
|
|
c.bw_pad = d.mcux * c.h
|
|
c.bh_pad = d.mcuy * c.v
|
|
c.pix_w = c.bw_pad * 8
|
|
c.pix_h = c.bh_pad * 8
|
|
|
|
nblocks := c.bw_pad * c.bh_pad
|
|
if nblocks <= 0 || nblocks > MAX_JPEG_PIXELS / 64 {
|
|
return .Bitmap_Too_Large
|
|
}
|
|
if !jpeg_charge(d, nblocks * 64 * size_of(i16)) { return .Bitmap_Too_Large }
|
|
if !jpeg_charge(d, c.pix_w * c.pix_h) { return .Bitmap_Too_Large }
|
|
|
|
coef_err, samp_err: mem.Allocator_Error
|
|
c.coeffs, coef_err = make([]i16, nblocks * 64, d.scratch)
|
|
if coef_err != nil { return .Out_Of_Memory }
|
|
c.samples, samp_err = make([]byte, c.pix_w * c.pix_h, d.scratch)
|
|
if samp_err != nil { return .Out_Of_Memory }
|
|
// Undecoded blocks read back as mid-grey rather than black, so a
|
|
// truncated scan degrades into a faded image instead of a dark band.
|
|
for j in 0 ..< len(c.samples) {
|
|
c.samples[j] = 128
|
|
}
|
|
}
|
|
|
|
d.transform = jpeg_pick_transform(d)
|
|
d.saw_sof = true
|
|
return .None
|
|
}
|
|
|
|
// jpeg_pick_transform decides what colour transform to undo, following the
|
|
// same rules libjpeg does -- which is the de-facto standard, because every
|
|
// producer was tested against it.
|
|
@(private)
|
|
jpeg_pick_transform :: proc(d: ^Jpeg_Decoder) -> Jpeg_Transform {
|
|
switch d.ncomp {
|
|
case 3:
|
|
if d.saw_adobe {
|
|
// 0 means the components are already RGB.
|
|
return d.adobe_transform == 0 ? .None : .Ycbcr
|
|
}
|
|
if d.saw_jfif {
|
|
return .Ycbcr
|
|
}
|
|
// No marker to go on: component ids 'R','G','B' mean exactly that,
|
|
// and anything else (usually 1,2,3) is YCbCr.
|
|
if d.comps[0].id == 'R' && d.comps[1].id == 'G' && d.comps[2].id == 'B' {
|
|
return .None
|
|
}
|
|
return .Ycbcr
|
|
case 4:
|
|
if d.saw_adobe && d.adobe_transform == 2 {
|
|
return .Ycck
|
|
}
|
|
return .None
|
|
}
|
|
return .None
|
|
}
|
|
|
|
@(private)
|
|
jpeg_read_dqt :: proc(d: ^Jpeg_Decoder, payload: []byte) {
|
|
p := 0
|
|
for p < len(payload) {
|
|
pq := int(payload[p] >> 4)
|
|
tq := int(payload[p] & 15)
|
|
p += 1
|
|
if tq > 3 {
|
|
// Unusable selector: the rest of the segment cannot be located
|
|
// either, since table sizes depend on it.
|
|
return
|
|
}
|
|
n := pq == 0 ? 64 : 128
|
|
if p + n > len(payload) {
|
|
return
|
|
}
|
|
for k in 0 ..< 64 {
|
|
v: u16
|
|
if pq == 0 {
|
|
v = u16(payload[p + k])
|
|
} else {
|
|
v = u16(payload[p + 2 * k]) << 8 | u16(payload[p + 2 * k + 1])
|
|
}
|
|
// A zero quantiser would erase the coefficient; treat it as 1,
|
|
// which is what a viewer that survives such a file must do.
|
|
if v == 0 { v = 1 }
|
|
d.qt[tq][JPEG_ZIGZAG[k]] = v
|
|
}
|
|
d.qt_defined[tq] = true
|
|
p += n
|
|
}
|
|
}
|
|
|
|
@(private)
|
|
jpeg_read_dht :: proc(d: ^Jpeg_Decoder, payload: []byte) {
|
|
p := 0
|
|
for p + 17 <= len(payload) {
|
|
tc := int(payload[p] >> 4)
|
|
th := int(payload[p] & 15)
|
|
p += 1
|
|
counts := payload[p:p + 16]
|
|
p += 16
|
|
total := 0
|
|
for c in counts {
|
|
total += int(c)
|
|
}
|
|
if total > 256 || p + total > len(payload) {
|
|
return
|
|
}
|
|
vals := payload[p:p + total]
|
|
p += total
|
|
if th > 3 || tc > 1 {
|
|
continue
|
|
}
|
|
table := tc == 0 ? &d.dc[th] : &d.ac[th]
|
|
jpeg_huff_build(table, counts, vals)
|
|
}
|
|
}
|
|
|
|
@(private)
|
|
jpeg_read_sos :: proc(d: ^Jpeg_Decoder, payload: []byte) -> (scan: Jpeg_Scan, err: Error) {
|
|
if len(payload) < 1 {
|
|
return {}, .Bad_Jpeg_Data
|
|
}
|
|
ns := int(payload[0])
|
|
if ns < 1 || ns > 4 || len(payload) < 1 + 2 * ns + 3 {
|
|
return {}, .Bad_Jpeg_Data
|
|
}
|
|
|
|
for i in 0 ..< ns {
|
|
cs := int(payload[1 + 2 * i])
|
|
td := int(payload[2 + 2 * i] >> 4)
|
|
ta := int(payload[2 + 2 * i] & 15)
|
|
|
|
idx := -1
|
|
for j in 0 ..< d.ncomp {
|
|
if d.comps[j].id == cs {
|
|
idx = j
|
|
break
|
|
}
|
|
}
|
|
if idx < 0 {
|
|
// Component selectors that do not match the frame happen when a
|
|
// rewriter renumbers one header and not the other. Positional
|
|
// matching recovers those files.
|
|
if i < d.ncomp {
|
|
idx = i
|
|
} else {
|
|
return {}, .Bad_Jpeg_Data
|
|
}
|
|
}
|
|
scan.comps[i] = idx
|
|
d.comps[idx].dc_tbl = td > 3 ? 0 : td
|
|
d.comps[idx].ac_tbl = ta > 3 ? 0 : ta
|
|
}
|
|
scan.n = ns
|
|
|
|
tail := 1 + 2 * ns
|
|
scan.ss = int(payload[tail])
|
|
scan.se = int(payload[tail + 1])
|
|
scan.ah = int(payload[tail + 2] >> 4)
|
|
scan.al = int(payload[tail + 2] & 15)
|
|
|
|
if !d.progressive {
|
|
// A sequential scan covers the whole block whatever its header says.
|
|
scan.ss, scan.se, scan.ah, scan.al = 0, 63, 0, 0
|
|
} else {
|
|
if scan.ss > 63 { scan.ss = 63 }
|
|
if scan.se > 63 { scan.se = 63 }
|
|
if scan.se < scan.ss { scan.se = scan.ss }
|
|
if scan.al > 13 { scan.al = 13 }
|
|
if scan.ah > 13 { scan.ah = 13 }
|
|
// A DC scan is the only kind that may be interleaved, and it always
|
|
// covers coefficient 0 alone.
|
|
if scan.ss == 0 {
|
|
scan.se = 0
|
|
} else if ns != 1 {
|
|
// An interleaved AC scan is illegal; take its first component.
|
|
scan.n = 1
|
|
}
|
|
}
|
|
return scan, .None
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Bit reader
|
|
//
|
|
// Entropy-coded data is a bit stream with 0xFF escaped as 0xFF 0x00. Anything
|
|
// else after an 0xFF is a marker and ends the segment; from there on the
|
|
// reader hands out zero bits, which lets a truncated scan run to the end of
|
|
// its MCU loop and produce a partial image instead of failing.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(private)
|
|
Jpeg_Bits :: struct {
|
|
data: []byte,
|
|
pos: int,
|
|
buf: u32,
|
|
cnt: int,
|
|
// Set once the reader has stopped at a marker. This is not the same as
|
|
// running out of data: the buffer is topped up several bits ahead of what
|
|
// the block decoders have consumed, so a scan that ends exactly on its
|
|
// last MCU still trips this while decoding perfectly.
|
|
marker_hit: bool,
|
|
marker_pos: int, // offset of the 0xFF that begins the pending marker
|
|
// Set when a request could not be met from real bits and was padded with
|
|
// zeroes. *This* is the "the data ran out" signal, and everything after it
|
|
// in the scan is guesswork.
|
|
starved: bool,
|
|
}
|
|
|
|
@(private)
|
|
jpeg_next_data_byte :: proc(b: ^Jpeg_Bits) -> (c: byte, ok: bool) {
|
|
if b.marker_hit {
|
|
return 0, false
|
|
}
|
|
if b.pos >= len(b.data) {
|
|
b.marker_hit = true
|
|
b.marker_pos = len(b.data)
|
|
return 0, false
|
|
}
|
|
v := b.data[b.pos]
|
|
if v != 0xFF {
|
|
b.pos += 1
|
|
return v, true
|
|
}
|
|
j := b.pos + 1
|
|
for j < len(b.data) && b.data[j] == 0xFF {
|
|
j += 1
|
|
}
|
|
if j >= len(b.data) {
|
|
b.marker_hit = true
|
|
b.marker_pos = b.pos
|
|
return 0, false
|
|
}
|
|
if b.data[j] == 0x00 {
|
|
b.pos = j + 1
|
|
return 0xFF, true
|
|
}
|
|
// Leave pos where it is: the scan loop needs to find this marker.
|
|
b.marker_hit = true
|
|
b.marker_pos = j - 1
|
|
return 0, false
|
|
}
|
|
|
|
// jpeg_fill_soft tops the bit buffer up to `n` bits if it can, and says how
|
|
// many it managed. It never reports starvation, because the Huffman decoder
|
|
// speculatively asks for a whole lookahead window and must not be told the
|
|
// data ran out merely because the last few codes of a scan are shorter than
|
|
// that window.
|
|
@(private)
|
|
jpeg_fill_soft :: proc(b: ^Jpeg_Bits, n: int) -> int {
|
|
for b.cnt < n {
|
|
c, ok := jpeg_next_data_byte(b)
|
|
if !ok { break }
|
|
b.buf = b.buf << 8 | u32(c)
|
|
b.cnt += 8
|
|
}
|
|
return b.cnt
|
|
}
|
|
|
|
// jpeg_get_bits consumes n bits, padding with zeroes and raising `starved`
|
|
// when the entropy data really has run out.
|
|
@(private)
|
|
jpeg_get_bits :: proc(b: ^Jpeg_Bits, n: int) -> i32 {
|
|
if n <= 0 { return 0 }
|
|
nn := min(n, 16)
|
|
if jpeg_fill_soft(b, nn) < nn {
|
|
b.buf <<= uint(nn - b.cnt)
|
|
b.cnt = nn
|
|
b.starved = true
|
|
}
|
|
b.cnt -= nn
|
|
return i32((b.buf >> uint(b.cnt)) & (1 << uint(nn) - 1))
|
|
}
|
|
|
|
// jpeg_take_restart consumes the RSTn marker the stream is sitting on.
|
|
//
|
|
// Only the caller knows when a marker is due, and it must only call this
|
|
// there. "The reader is parked on an FF Dn" is not by itself evidence of a
|
|
// segment boundary: the reader buffers whole bytes ahead of the bits that have
|
|
// been consumed and stops on the marker, so the last few blocks of an interval
|
|
// are routinely decoded while `pos` already points at the marker that follows
|
|
// them. Only the declared restart interval says which of those positions is
|
|
// the real boundary, which is why the DRI is what gates the call.
|
|
//
|
|
// The `cnt >= 8` test is a consistency check, not that evidence: with intact
|
|
// data every whole byte of the segment has been consumed by the time the
|
|
// interval is up, so all that can be left in the buffer is the encoder's
|
|
// byte-alignment padding. More than that means the block decoders and the
|
|
// encoder disagree about this segment, and the caller's forward search for the
|
|
// next marker is the better recovery.
|
|
@(private)
|
|
jpeg_take_restart :: proc(b: ^Jpeg_Bits) -> bool {
|
|
if b.cnt >= 8 {
|
|
return false
|
|
}
|
|
p := b.marker_hit ? b.marker_pos : b.pos
|
|
if p < 0 || p + 1 >= len(b.data) || b.data[p] != 0xFF {
|
|
return false
|
|
}
|
|
q := p + 1
|
|
for q < len(b.data) && b.data[q] == 0xFF {
|
|
q += 1
|
|
}
|
|
if q >= len(b.data) {
|
|
return false
|
|
}
|
|
m := b.data[q]
|
|
if m < JPEG_RST0 || m > JPEG_RST0 + 7 {
|
|
return false
|
|
}
|
|
b.pos = q + 1
|
|
b.marker_hit = false
|
|
b.marker_pos = 0
|
|
b.starved = false
|
|
b.buf = 0
|
|
b.cnt = 0
|
|
return true
|
|
}
|
|
|
|
// jpeg_bits_restart resynchronises at the next RSTn marker.
|
|
//
|
|
// It searches forward rather than insisting the marker is at the current
|
|
// position, because a restart interval that disagrees with the markers
|
|
// actually present is a common form of damage and the whole point of restart
|
|
// markers is that a decoder can find its place again. The search only ever
|
|
// moves forward, so the total cost across a scan stays linear.
|
|
@(private)
|
|
jpeg_bits_restart :: proc(b: ^Jpeg_Bits) -> bool {
|
|
b.buf = 0
|
|
b.cnt = 0
|
|
p := b.pos
|
|
for p + 1 < len(b.data) {
|
|
if b.data[p] != 0xFF {
|
|
p += 1
|
|
continue
|
|
}
|
|
m := b.data[p + 1]
|
|
if m == 0x00 || m == 0xFF {
|
|
p += 1
|
|
continue
|
|
}
|
|
if m >= JPEG_RST0 && m <= JPEG_RST0 + 7 {
|
|
b.pos = p + 2
|
|
b.marker_hit = false
|
|
b.marker_pos = 0
|
|
b.starved = false
|
|
return true
|
|
}
|
|
b.marker_hit = true
|
|
b.marker_pos = p
|
|
return false
|
|
}
|
|
b.pos = len(b.data)
|
|
b.marker_hit = true
|
|
b.marker_pos = len(b.data)
|
|
return false
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Huffman tables
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(private) JPEG_LOOKAHEAD :: 8
|
|
|
|
@(private)
|
|
Jpeg_Huff :: struct {
|
|
// Canonical code bounds per code length, as in ISO/IEC 10918-1 F.2.2.3.
|
|
mincode: [17]i32,
|
|
maxcode: [17]i32, // -1 where no code of that length exists
|
|
valptr: [17]i32,
|
|
vals: [256]byte,
|
|
nvals: int,
|
|
// Codes of JPEG_LOOKAHEAD bits or fewer resolve in one table read; longer
|
|
// ones fall back to the bit-at-a-time loop. Short codes dominate, so this
|
|
// is where nearly all the decoding time goes.
|
|
look_nbits: [1 << JPEG_LOOKAHEAD]u8,
|
|
look_sym: [1 << JPEG_LOOKAHEAD]byte,
|
|
defined: bool,
|
|
}
|
|
|
|
@(private)
|
|
jpeg_huff_build :: proc(h: ^Jpeg_Huff, counts: []byte, vals: []byte) {
|
|
h^ = {}
|
|
if len(counts) < 16 { return }
|
|
|
|
total := 0
|
|
for i in 0 ..< 16 {
|
|
total += int(counts[i])
|
|
}
|
|
if total == 0 || total > 256 || total > len(vals) {
|
|
return
|
|
}
|
|
copy(h.vals[:], vals[:total])
|
|
h.nvals = total
|
|
|
|
code := i32(0)
|
|
p := i32(0)
|
|
for l in 1 ..= 16 {
|
|
n := i32(counts[l - 1])
|
|
h.valptr[l] = p
|
|
h.mincode[l] = code
|
|
code += n
|
|
p += n
|
|
h.maxcode[l] = n == 0 ? -1 : code - 1
|
|
code <<= 1
|
|
}
|
|
|
|
idx := 0
|
|
for l in 1 ..= JPEG_LOOKAHEAD {
|
|
n := int(counts[l - 1])
|
|
for i in 0 ..< n {
|
|
if idx >= total { break }
|
|
base := int(h.mincode[l]) + i
|
|
shift := uint(JPEG_LOOKAHEAD - l)
|
|
lo := base << shift
|
|
hi := lo + (1 << shift)
|
|
// An over-subscribed table (more codes than the length allows)
|
|
// pushes entries past the end of the lookup window; drop those
|
|
// rather than refusing the whole table.
|
|
if lo >= 0 && hi <= 1 << JPEG_LOOKAHEAD {
|
|
for k in lo ..< hi {
|
|
h.look_nbits[k] = u8(l)
|
|
h.look_sym[k] = h.vals[idx]
|
|
}
|
|
}
|
|
idx += 1
|
|
}
|
|
}
|
|
h.defined = true
|
|
}
|
|
|
|
// jpeg_huff_decode reads one Huffman-coded symbol.
|
|
//
|
|
// An undefined table, or a code that no length matches, yields 0. For an AC
|
|
// table 0 is end-of-block and for a DC table it is a zero difference, so
|
|
// corrupt data ends the block quietly instead of running away.
|
|
@(private)
|
|
jpeg_huff_decode :: proc(b: ^Jpeg_Bits, h: ^Jpeg_Huff) -> int {
|
|
if !h.defined {
|
|
return 0
|
|
}
|
|
if jpeg_fill_soft(b, JPEG_LOOKAHEAD) >= JPEG_LOOKAHEAD {
|
|
look := int((b.buf >> uint(b.cnt - JPEG_LOOKAHEAD)) & (1 << JPEG_LOOKAHEAD - 1))
|
|
if nb := int(h.look_nbits[look]); nb != 0 {
|
|
b.cnt -= nb
|
|
return int(h.look_sym[look])
|
|
}
|
|
}
|
|
// Either a code longer than the lookahead window, or the last few bits of
|
|
// a scan. Both fall back to reading a bit at a time.
|
|
code := i32(0)
|
|
for l in 1 ..= 16 {
|
|
code = code << 1 | jpeg_get_bits(b, 1)
|
|
if code <= h.maxcode[l] {
|
|
idx := int(h.valptr[l] + code - h.mincode[l])
|
|
if idx < 0 || idx >= h.nvals {
|
|
return 0
|
|
}
|
|
return int(h.vals[idx])
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// jpeg_extend turns an s-bit magnitude into the signed difference it stands
|
|
// for (ISO/IEC 10918-1 F.2.2.1).
|
|
@(private)
|
|
jpeg_extend :: #force_inline proc "contextless" (v: i32, s: int) -> i32 {
|
|
if s <= 0 { return 0 }
|
|
return v < 1 << uint(s - 1) ? v - (1 << uint(s)) + 1 : v
|
|
}
|
|
|
|
@(private)
|
|
jpeg_receive_extend :: #force_inline proc (b: ^Jpeg_Bits, s: int) -> i32 {
|
|
if s <= 0 || s > 16 { return 0 }
|
|
return jpeg_extend(jpeg_get_bits(b, s), s)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Scan decoding
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(private)
|
|
jpeg_reset_scan_state :: proc(d: ^Jpeg_Decoder, scan: Jpeg_Scan) {
|
|
for i in 0 ..< scan.n {
|
|
d.comps[scan.comps[i]].pred = 0
|
|
}
|
|
d.eobrun = 0
|
|
}
|
|
|
|
@(private)
|
|
jpeg_decode_scan :: proc(d: ^Jpeg_Decoder, scan: Jpeg_Scan) {
|
|
if d.pos >= len(d.data) { return }
|
|
|
|
b := Jpeg_Bits{data = d.data, pos = d.pos}
|
|
jpeg_reset_scan_state(d, scan)
|
|
|
|
mcus_x, mcus_y: int
|
|
if scan.n == 1 {
|
|
c := &d.comps[scan.comps[0]]
|
|
mcus_x, mcus_y = c.bw, c.bh
|
|
} else {
|
|
mcus_x, mcus_y = d.mcux, d.mcuy
|
|
}
|
|
total := mcus_x * mcus_y
|
|
if total <= 0 {
|
|
d.pos = b.pos
|
|
return
|
|
}
|
|
|
|
restart_left := d.restart_interval
|
|
|
|
// `mcu` is stepped by hand rather than with a range so the restart paths
|
|
// can be taken before the block decoders run. It only ever increases, so
|
|
// the loop is bounded by the MCU count whatever the data does.
|
|
for mcu := 0; mcu < total; mcu += 1 {
|
|
// The declared interval, not the bit reader's position, is what says a
|
|
// marker is due. The reader buffers whole bytes ahead of the bits the
|
|
// block decoders have consumed and stops dead on a marker, so from the
|
|
// moment the last byte of a segment is in the buffer it is already
|
|
// "sitting on" the FF Dn while that segment's final blocks are still
|
|
// undecoded -- which for anything low-entropy (a scanned page, or the
|
|
// one-bit-per-block DC refinement scan every progressive file has) is
|
|
// most of the segment. Taking the marker on that evidence resets the
|
|
// DC predictors and the EOB run a block or more early and decodes the
|
|
// rest of the interval out of the next segment's bits.
|
|
due := d.restart_interval > 0 && restart_left <= 0
|
|
if due || b.starved {
|
|
// A marker is due, or the bits ran out mid-segment because the
|
|
// entropy data is corrupt or the DRI disagrees with the markers
|
|
// the file actually carries. Consume the marker where it is due;
|
|
// otherwise search forward for the next one, which is recoverable
|
|
// if any remains. If none does, everything from here stays at
|
|
// zero, which reconstructs as flat mid-grey.
|
|
if !(due && jpeg_take_restart(&b)) {
|
|
if !jpeg_bits_restart(&b) { break }
|
|
}
|
|
jpeg_reset_scan_state(d, scan)
|
|
restart_left = d.restart_interval
|
|
}
|
|
restart_left -= 1
|
|
|
|
my := mcu / mcus_x
|
|
mx := mcu % mcus_x
|
|
|
|
if scan.n == 1 {
|
|
ci := scan.comps[0]
|
|
jpeg_decode_block(d, &b, scan, ci, my, mx)
|
|
} else {
|
|
for i in 0 ..< scan.n {
|
|
ci := scan.comps[i]
|
|
comp := &d.comps[ci]
|
|
for by in 0 ..< comp.v {
|
|
for bx in 0 ..< comp.h {
|
|
jpeg_decode_block(d, &b, scan, ci, my * comp.v + by, mx * comp.h + bx)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
d.pos = b.marker_hit ? b.marker_pos : b.pos
|
|
if d.pos < 0 || d.pos > len(d.data) {
|
|
d.pos = len(d.data)
|
|
}
|
|
}
|
|
|
|
@(private)
|
|
jpeg_decode_block :: proc(d: ^Jpeg_Decoder, b: ^Jpeg_Bits, scan: Jpeg_Scan, ci, brow, bcol: int) {
|
|
comp := &d.comps[ci]
|
|
if brow < 0 || bcol < 0 || brow >= comp.bh_pad || bcol >= comp.bw_pad {
|
|
return
|
|
}
|
|
base := (brow * comp.bw_pad + bcol) * 64
|
|
if base < 0 || base + 64 > len(comp.coeffs) {
|
|
return
|
|
}
|
|
coef := comp.coeffs[base:base + 64]
|
|
|
|
if !d.progressive {
|
|
jpeg_decode_baseline_block(d, b, comp, coef)
|
|
return
|
|
}
|
|
if scan.ss == 0 {
|
|
if scan.ah == 0 {
|
|
jpeg_decode_dc_first(d, b, comp, coef, scan.al)
|
|
} else {
|
|
jpeg_decode_dc_refine(b, coef, scan.al)
|
|
}
|
|
} else {
|
|
if scan.ah == 0 {
|
|
jpeg_decode_ac_first(d, b, comp, coef, scan)
|
|
} else {
|
|
jpeg_decode_ac_refine(d, b, comp, coef, scan)
|
|
}
|
|
}
|
|
}
|
|
|
|
@(private)
|
|
jpeg_store_dc :: #force_inline proc "contextless" (coef: []i16, v: i32) {
|
|
coef[0] = i16(clamp(v, i32(min(i16)), i32(max(i16))))
|
|
}
|
|
|
|
@(private)
|
|
jpeg_decode_baseline_block :: proc(d: ^Jpeg_Decoder, b: ^Jpeg_Bits, comp: ^Jpeg_Comp, coef: []i16) {
|
|
s := jpeg_huff_decode(b, &d.dc[comp.dc_tbl])
|
|
diff := jpeg_receive_extend(b, s)
|
|
comp.pred = int(clamp(i32(comp.pred) + diff, -1 << 20, 1 << 20))
|
|
jpeg_store_dc(coef, i32(comp.pred))
|
|
|
|
ac := &d.ac[comp.ac_tbl]
|
|
k := 1
|
|
for k < 64 {
|
|
rs := jpeg_huff_decode(b, ac)
|
|
r := rs >> 4
|
|
s2 := rs & 15
|
|
if s2 == 0 {
|
|
if r != 15 { break }
|
|
k += 16
|
|
continue
|
|
}
|
|
k += r
|
|
if k > 63 { break }
|
|
coef[JPEG_ZIGZAG[k]] = i16(clamp(jpeg_receive_extend(b, s2), i32(min(i16)), i32(max(i16))))
|
|
k += 1
|
|
}
|
|
}
|
|
|
|
@(private)
|
|
jpeg_decode_dc_first :: proc(
|
|
d: ^Jpeg_Decoder, b: ^Jpeg_Bits, comp: ^Jpeg_Comp, coef: []i16, al: int,
|
|
) {
|
|
s := jpeg_huff_decode(b, &d.dc[comp.dc_tbl])
|
|
diff := jpeg_receive_extend(b, s)
|
|
comp.pred = int(clamp(i32(comp.pred) + diff, -1 << 20, 1 << 20))
|
|
jpeg_store_dc(coef, i32(comp.pred) << uint(al))
|
|
}
|
|
|
|
@(private)
|
|
jpeg_decode_dc_refine :: proc(b: ^Jpeg_Bits, coef: []i16, al: int) {
|
|
if jpeg_get_bits(b, 1) != 0 {
|
|
coef[0] |= i16(1) << uint(al)
|
|
}
|
|
}
|
|
|
|
@(private)
|
|
jpeg_decode_ac_first :: proc(
|
|
d: ^Jpeg_Decoder, b: ^Jpeg_Bits, comp: ^Jpeg_Comp, coef: []i16, scan: Jpeg_Scan,
|
|
) {
|
|
if d.eobrun > 0 {
|
|
d.eobrun -= 1
|
|
return
|
|
}
|
|
ac := &d.ac[comp.ac_tbl]
|
|
k := scan.ss
|
|
for k <= scan.se {
|
|
rs := jpeg_huff_decode(b, ac)
|
|
r := rs >> 4
|
|
s := rs & 15
|
|
if s == 0 {
|
|
if r != 15 {
|
|
d.eobrun = 1 << uint(r)
|
|
if r > 0 {
|
|
d.eobrun += int(jpeg_get_bits(b, r))
|
|
}
|
|
d.eobrun -= 1
|
|
break
|
|
}
|
|
k += 16
|
|
continue
|
|
}
|
|
k += r
|
|
if k > scan.se || k > 63 { break }
|
|
v := jpeg_receive_extend(b, s) << uint(scan.al)
|
|
coef[JPEG_ZIGZAG[k]] = i16(clamp(v, i32(min(i16)), i32(max(i16))))
|
|
k += 1
|
|
}
|
|
}
|
|
|
|
// jpeg_decode_ac_refine appends correction bits to the AC coefficients of one
|
|
// block (ISO/IEC 10918-1 G.1.2.3). This is the fiddliest part of progressive
|
|
// JPEG: the bit stream interleaves newly-nonzero coefficients with correction
|
|
// bits for coefficients that earlier scans already made nonzero, and the run
|
|
// length counts only the ones that are still zero.
|
|
@(private)
|
|
jpeg_decode_ac_refine :: proc(
|
|
d: ^Jpeg_Decoder, b: ^Jpeg_Bits, comp: ^Jpeg_Comp, coef: []i16, scan: Jpeg_Scan,
|
|
) {
|
|
p1 := i16(1) << uint(scan.al)
|
|
m1 := -(i16(1) << uint(scan.al))
|
|
ac := &d.ac[comp.ac_tbl]
|
|
k := scan.ss
|
|
|
|
if d.eobrun == 0 {
|
|
for k <= scan.se {
|
|
rs := jpeg_huff_decode(b, ac)
|
|
r := rs >> 4
|
|
s := rs & 15
|
|
newval := i16(0)
|
|
if s != 0 {
|
|
// The magnitude of a newly nonzero coefficient is always 1 in
|
|
// a refinement scan; a larger one is corrupt, and taking the
|
|
// sign bit anyway keeps the bit stream aligned.
|
|
newval = jpeg_get_bits(b, 1) != 0 ? p1 : m1
|
|
} else if r != 15 {
|
|
d.eobrun = 1 << uint(r)
|
|
if r > 0 {
|
|
d.eobrun += int(jpeg_get_bits(b, r))
|
|
}
|
|
break
|
|
}
|
|
|
|
for {
|
|
pos := int(JPEG_ZIGZAG[k])
|
|
if coef[pos] != 0 {
|
|
if jpeg_get_bits(b, 1) != 0 && coef[pos] & p1 == 0 {
|
|
coef[pos] += coef[pos] >= 0 ? p1 : m1
|
|
}
|
|
} else {
|
|
r -= 1
|
|
if r < 0 { break }
|
|
}
|
|
k += 1
|
|
if k > scan.se { break }
|
|
}
|
|
|
|
if newval != 0 && k <= scan.se {
|
|
coef[JPEG_ZIGZAG[k]] = newval
|
|
}
|
|
k += 1
|
|
}
|
|
}
|
|
|
|
if d.eobrun > 0 {
|
|
for ; k <= scan.se; k += 1 {
|
|
pos := int(JPEG_ZIGZAG[k])
|
|
if coef[pos] != 0 {
|
|
if jpeg_get_bits(b, 1) != 0 && coef[pos] & p1 == 0 {
|
|
coef[pos] += coef[pos] >= 0 ? p1 : m1
|
|
}
|
|
}
|
|
}
|
|
d.eobrun -= 1
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Inverse DCT
|
|
//
|
|
// The accurate integer IDCT from ISO/IEC 10918-1's own reference software,
|
|
// after Loeffler, Ligtenberg and Moschytz: 11 multiplies and 29 adds per
|
|
// one-dimensional pass, in 13-bit fixed point. Two passes, columns then rows.
|
|
// A separable pair of one-dimensional transforms is O(n^3) for the block
|
|
// against the O(n^4) of the definition, and this one is a further constant
|
|
// factor faster again.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(private) JPEG_CONST_BITS :: 13
|
|
@(private) JPEG_PASS1_BITS :: 2
|
|
|
|
@(private) JPEG_FIX_0_298631336 :: 2446
|
|
@(private) JPEG_FIX_0_390180644 :: 3196
|
|
@(private) JPEG_FIX_0_541196100 :: 4433
|
|
@(private) JPEG_FIX_0_765366865 :: 6270
|
|
@(private) JPEG_FIX_0_899976223 :: 7373
|
|
@(private) JPEG_FIX_1_175875602 :: 9633
|
|
@(private) JPEG_FIX_1_501321110 :: 12299
|
|
@(private) JPEG_FIX_1_847759065 :: 15137
|
|
@(private) JPEG_FIX_1_961570560 :: 16069
|
|
@(private) JPEG_FIX_2_053119869 :: 16819
|
|
@(private) JPEG_FIX_2_562915447 :: 20995
|
|
@(private) JPEG_FIX_3_072711026 :: 25172
|
|
|
|
// Dequantised coefficients are clamped to this. Valid 8-bit data never gets
|
|
// near it (the DCT of an 8-bit block bounds every coefficient by 1024), and
|
|
// the clamp is what keeps a corrupt coefficient from overflowing the 32-bit
|
|
// fixed-point arithmetic below into visible noise.
|
|
@(private) JPEG_COEF_LIMIT :: 1 << 14
|
|
|
|
@(private)
|
|
jpeg_descale :: #force_inline proc "contextless" (x: i32, n: uint) -> i32 {
|
|
return (x + (1 << (n - 1))) >> n
|
|
}
|
|
|
|
@(private)
|
|
jpeg_clamp_sample :: #force_inline proc "contextless" (x: i32) -> byte {
|
|
if x < 0 { return 0 }
|
|
if x > 255 { return 255 }
|
|
return byte(x)
|
|
}
|
|
|
|
@(private)
|
|
jpeg_idct_block :: proc(coef: []i16, qt: ^[64]u16, dst: []byte, off, stride: int, shift: uint) {
|
|
dq :: #force_inline proc "contextless" (c: i16, q: u16, sh: uint) -> i32 {
|
|
return clamp((i32(c) * i32(q)) >> sh, -JPEG_COEF_LIMIT, JPEG_COEF_LIMIT)
|
|
}
|
|
|
|
ws: [64]i32
|
|
|
|
for col in 0 ..< 8 {
|
|
if coef[col + 8] == 0 && coef[col + 16] == 0 && coef[col + 24] == 0 &&
|
|
coef[col + 32] == 0 && coef[col + 40] == 0 && coef[col + 48] == 0 &&
|
|
coef[col + 56] == 0 {
|
|
// An all-zero AC column is the common case in flat areas.
|
|
dcval := dq(coef[col], qt[col], shift) << JPEG_PASS1_BITS
|
|
for row in 0 ..< 8 {
|
|
ws[row * 8 + col] = dcval
|
|
}
|
|
continue
|
|
}
|
|
|
|
z2 := dq(coef[col + 16], qt[col + 16], shift)
|
|
z3 := dq(coef[col + 48], qt[col + 48], shift)
|
|
z1 := (z2 + z3) * JPEG_FIX_0_541196100
|
|
tmp2 := z1 + z3 * -JPEG_FIX_1_847759065
|
|
tmp3 := z1 + z2 * JPEG_FIX_0_765366865
|
|
|
|
z2 = dq(coef[col], qt[col], shift)
|
|
z3 = dq(coef[col + 32], qt[col + 32], shift)
|
|
tmp0 := (z2 + z3) << JPEG_CONST_BITS
|
|
tmp1 := (z2 - z3) << JPEG_CONST_BITS
|
|
|
|
tmp10 := tmp0 + tmp3
|
|
tmp13 := tmp0 - tmp3
|
|
tmp11 := tmp1 + tmp2
|
|
tmp12 := tmp1 - tmp2
|
|
|
|
tmp0 = dq(coef[col + 56], qt[col + 56], shift)
|
|
tmp1 = dq(coef[col + 40], qt[col + 40], shift)
|
|
tmp2 = dq(coef[col + 24], qt[col + 24], shift)
|
|
tmp3 = dq(coef[col + 8], qt[col + 8], shift)
|
|
|
|
z1 = tmp0 + tmp3
|
|
z2 = tmp1 + tmp2
|
|
z3 = tmp0 + tmp2
|
|
z4 := tmp1 + tmp3
|
|
z5 := (z3 + z4) * JPEG_FIX_1_175875602
|
|
|
|
tmp0 *= JPEG_FIX_0_298631336
|
|
tmp1 *= JPEG_FIX_2_053119869
|
|
tmp2 *= JPEG_FIX_3_072711026
|
|
tmp3 *= JPEG_FIX_1_501321110
|
|
z1 *= -JPEG_FIX_0_899976223
|
|
z2 *= -JPEG_FIX_2_562915447
|
|
z3 *= -JPEG_FIX_1_961570560
|
|
z4 *= -JPEG_FIX_0_390180644
|
|
z3 += z5
|
|
z4 += z5
|
|
|
|
tmp0 += z1 + z3
|
|
tmp1 += z2 + z4
|
|
tmp2 += z2 + z3
|
|
tmp3 += z1 + z4
|
|
|
|
ws[col] = jpeg_descale(tmp10 + tmp3, JPEG_CONST_BITS - JPEG_PASS1_BITS)
|
|
ws[56 + col] = jpeg_descale(tmp10 - tmp3, JPEG_CONST_BITS - JPEG_PASS1_BITS)
|
|
ws[8 + col] = jpeg_descale(tmp11 + tmp2, JPEG_CONST_BITS - JPEG_PASS1_BITS)
|
|
ws[48 + col] = jpeg_descale(tmp11 - tmp2, JPEG_CONST_BITS - JPEG_PASS1_BITS)
|
|
ws[16 + col] = jpeg_descale(tmp12 + tmp1, JPEG_CONST_BITS - JPEG_PASS1_BITS)
|
|
ws[40 + col] = jpeg_descale(tmp12 - tmp1, JPEG_CONST_BITS - JPEG_PASS1_BITS)
|
|
ws[24 + col] = jpeg_descale(tmp13 + tmp0, JPEG_CONST_BITS - JPEG_PASS1_BITS)
|
|
ws[32 + col] = jpeg_descale(tmp13 - tmp0, JPEG_CONST_BITS - JPEG_PASS1_BITS)
|
|
}
|
|
|
|
for row in 0 ..< 8 {
|
|
w := ws[row * 8:row * 8 + 8]
|
|
out := off + row * stride
|
|
if out < 0 || out + 8 > len(dst) {
|
|
continue
|
|
}
|
|
|
|
z2 := w[2]
|
|
z3 := w[6]
|
|
z1 := (z2 + z3) * JPEG_FIX_0_541196100
|
|
tmp2 := z1 + z3 * -JPEG_FIX_1_847759065
|
|
tmp3 := z1 + z2 * JPEG_FIX_0_765366865
|
|
|
|
tmp0 := (w[0] + w[4]) << JPEG_CONST_BITS
|
|
tmp1 := (w[0] - w[4]) << JPEG_CONST_BITS
|
|
|
|
tmp10 := tmp0 + tmp3
|
|
tmp13 := tmp0 - tmp3
|
|
tmp11 := tmp1 + tmp2
|
|
tmp12 := tmp1 - tmp2
|
|
|
|
tmp0 = w[7]
|
|
tmp1 = w[5]
|
|
tmp2 = w[3]
|
|
tmp3 = w[1]
|
|
|
|
z1 = tmp0 + tmp3
|
|
z2 = tmp1 + tmp2
|
|
z3 = tmp0 + tmp2
|
|
z4 := tmp1 + tmp3
|
|
z5 := (z3 + z4) * JPEG_FIX_1_175875602
|
|
|
|
tmp0 *= JPEG_FIX_0_298631336
|
|
tmp1 *= JPEG_FIX_2_053119869
|
|
tmp2 *= JPEG_FIX_3_072711026
|
|
tmp3 *= JPEG_FIX_1_501321110
|
|
z1 *= -JPEG_FIX_0_899976223
|
|
z2 *= -JPEG_FIX_2_562915447
|
|
z3 *= -JPEG_FIX_1_961570560
|
|
z4 *= -JPEG_FIX_0_390180644
|
|
z3 += z5
|
|
z4 += z5
|
|
|
|
tmp0 += z1 + z3
|
|
tmp1 += z2 + z4
|
|
tmp2 += z2 + z3
|
|
tmp3 += z1 + z4
|
|
|
|
// The level shift of ISO/IEC 10918-1 A.3.1: samples are coded centred
|
|
// on zero and stored centred on 128.
|
|
final :: JPEG_CONST_BITS + JPEG_PASS1_BITS + 3
|
|
dst[out] = jpeg_clamp_sample(jpeg_descale(tmp10 + tmp3, final) + 128)
|
|
dst[out + 7] = jpeg_clamp_sample(jpeg_descale(tmp10 - tmp3, final) + 128)
|
|
dst[out + 1] = jpeg_clamp_sample(jpeg_descale(tmp11 + tmp2, final) + 128)
|
|
dst[out + 6] = jpeg_clamp_sample(jpeg_descale(tmp11 - tmp2, final) + 128)
|
|
dst[out + 2] = jpeg_clamp_sample(jpeg_descale(tmp12 + tmp1, final) + 128)
|
|
dst[out + 5] = jpeg_clamp_sample(jpeg_descale(tmp12 - tmp1, final) + 128)
|
|
dst[out + 3] = jpeg_clamp_sample(jpeg_descale(tmp13 + tmp0, final) + 128)
|
|
dst[out + 4] = jpeg_clamp_sample(jpeg_descale(tmp13 - tmp0, final) + 128)
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Output: inverse DCT, upsampling, colour transform
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(private)
|
|
jpeg_idct_planes :: proc(d: ^Jpeg_Decoder) {
|
|
// Precisions above 8 bits are shifted down here rather than carried
|
|
// through the whole pipeline: the output is bytes either way, and doing it
|
|
// at dequantisation keeps the fixed-point IDCT inside its designed range.
|
|
shift := uint(max(d.precision - 8, 0))
|
|
|
|
for i in 0 ..< d.ncomp {
|
|
c := &d.comps[i]
|
|
qt := &d.qt[c.tq]
|
|
for brow in 0 ..< c.bh_pad {
|
|
for bcol in 0 ..< c.bw_pad {
|
|
base := (brow * c.bw_pad + bcol) * 64
|
|
if base + 64 > len(c.coeffs) { continue }
|
|
jpeg_idct_block(
|
|
c.coeffs[base:base + 64], qt, c.samples,
|
|
brow * 8 * c.pix_w + bcol * 8, c.pix_w, shift,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@(private)
|
|
jpeg_ycc_to_rgb :: #force_inline proc "contextless" (y, cb, cr: i32) -> (r, g, b: byte) {
|
|
// Fixed point at 16 bits, matching the coefficients in ITU-T T.871 (JFIF)
|
|
// 7: R = Y + 1.402 Cr, G = Y - 0.344136 Cb - 0.714136 Cr, B = Y + 1.772 Cb.
|
|
cbv := cb - 128
|
|
crv := cr - 128
|
|
r = jpeg_clamp_sample(y + ((91881 * crv + 32768) >> 16))
|
|
g = jpeg_clamp_sample(y + ((-22554 * cbv - 46802 * crv + 32768) >> 16))
|
|
b = jpeg_clamp_sample(y + ((116130 * cbv + 32768) >> 16))
|
|
return
|
|
}
|
|
|
|
@(private)
|
|
jpeg_emit :: proc(d: ^Jpeg_Decoder, allocator: mem.Allocator) -> (out: []byte, err: Error) {
|
|
w, h, n := d.width, d.height, d.ncomp
|
|
if w <= 0 || h <= 0 || n <= 0 || n > 4 {
|
|
return nil, .Bad_Jpeg_Data
|
|
}
|
|
if w > MAX_JPEG_PIXELS / h {
|
|
return nil, .Bitmap_Too_Large
|
|
}
|
|
total := w * h * n
|
|
if !jpeg_charge(d, total) {
|
|
return nil, .Bitmap_Too_Large
|
|
}
|
|
|
|
jpeg_idct_planes(d)
|
|
|
|
out_err: mem.Allocator_Error
|
|
out, out_err = make([]byte, total, allocator)
|
|
if out_err != nil {
|
|
return nil, .Out_Of_Memory
|
|
}
|
|
|
|
// Component samples are replicated to full resolution rather than
|
|
// interpolated. Box upsampling is what ISO/IEC 10918-1's own informative
|
|
// decoder does; the smoother triangular filter libjpeg defaults to would
|
|
// change every subsampled pixel by a couple of levels and buys nothing at
|
|
// the scales a page is rasterised at.
|
|
if !jpeg_charge(d, w * n * size_of(i32)) {
|
|
delete(out, allocator)
|
|
return nil, .Bitmap_Too_Large
|
|
}
|
|
xmap, xerr := make([]i32, w * n, d.scratch)
|
|
if xerr != nil {
|
|
delete(out, allocator)
|
|
return nil, .Out_Of_Memory
|
|
}
|
|
defer delete(xmap, d.scratch)
|
|
|
|
for ci in 0 ..< n {
|
|
c := &d.comps[ci]
|
|
last := max(c.dw - 1, 0)
|
|
for x in 0 ..< w {
|
|
sx := x * c.h / d.hmax
|
|
xmap[ci * w + x] = i32(min(sx, last))
|
|
}
|
|
}
|
|
|
|
rows: [4][]byte
|
|
o := 0
|
|
for y in 0 ..< h {
|
|
for ci in 0 ..< n {
|
|
c := &d.comps[ci]
|
|
sy := min(y * c.v / d.vmax, max(c.dh - 1, 0))
|
|
start := sy * c.pix_w
|
|
if start < 0 || start + c.pix_w > len(c.samples) {
|
|
start = 0
|
|
}
|
|
rows[ci] = c.samples[start:start + c.pix_w]
|
|
}
|
|
|
|
switch {
|
|
case n == 1:
|
|
r0 := rows[0]
|
|
m0 := xmap[:w]
|
|
for x in 0 ..< w {
|
|
out[o] = r0[m0[x]]
|
|
o += 1
|
|
}
|
|
case n == 3 && d.transform == .Ycbcr:
|
|
r0, r1, r2 := rows[0], rows[1], rows[2]
|
|
m0 := xmap[:w]
|
|
m1 := xmap[w:2 * w]
|
|
m2 := xmap[2 * w:3 * w]
|
|
for x in 0 ..< w {
|
|
cr, cg, cb := jpeg_ycc_to_rgb(i32(r0[m0[x]]), i32(r1[m1[x]]), i32(r2[m2[x]]))
|
|
out[o], out[o + 1], out[o + 2] = cr, cg, cb
|
|
o += 3
|
|
}
|
|
case n == 4 && d.transform == .Ycck:
|
|
r0, r1, r2, r3 := rows[0], rows[1], rows[2], rows[3]
|
|
m0 := xmap[:w]
|
|
m1 := xmap[w:2 * w]
|
|
m2 := xmap[2 * w:3 * w]
|
|
m3 := xmap[3 * w:4 * w]
|
|
for x in 0 ..< w {
|
|
cr, cg, cb := jpeg_ycc_to_rgb(i32(r0[m0[x]]), i32(r1[m1[x]]), i32(r2[m2[x]]))
|
|
// YCCK stores the complement of CMY as if it were RGB, so the
|
|
// inverse transform ends by complementing back. This is not
|
|
// the separate whole-image inversion Adobe applies to the CMYK
|
|
// it puts in PDFs -- that one belongs to /Decode.
|
|
out[o] = 255 - cr
|
|
out[o + 1] = 255 - cg
|
|
out[o + 2] = 255 - cb
|
|
out[o + 3] = r3[m3[x]]
|
|
o += 4
|
|
}
|
|
case:
|
|
for x in 0 ..< w {
|
|
for ci in 0 ..< n {
|
|
out[o] = rows[ci][xmap[ci * w + x]]
|
|
o += 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return out, .None
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Tables
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Zig-zag order to natural (row-major) order, ISO/IEC 10918-1 Figure A.6.
|
|
@(private, rodata)
|
|
JPEG_ZIGZAG := [64]u8{
|
|
0, 1, 8, 16, 9, 2, 3, 10,
|
|
17, 24, 32, 25, 18, 11, 4, 5,
|
|
12, 19, 26, 33, 40, 48, 41, 34,
|
|
27, 20, 13, 6, 7, 14, 21, 28,
|
|
35, 42, 49, 56, 57, 50, 43, 36,
|
|
29, 22, 15, 23, 30, 37, 44, 51,
|
|
58, 59, 52, 45, 38, 31, 39, 46,
|
|
53, 60, 61, 54, 47, 55, 62, 63,
|
|
}
|