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, }