Files
pdf-odin-llm/filter_dct_test.odin
T
2026-09-25 23:32:29 +02:00

1535 lines
85 KiB
Odin

package pdf
import "core:slice"
import "core:testing"
import "core:time"
// Test vectors for the DCTDecode filter.
//
// The embedded files were produced with a throwaway Python script during
// development. `grey8`, `grey16`, `greyprog`, `rgb444`, `rgb420`, `rgbprog`,
// `cmyk`, `rst` and `norst` are Pillow (that is, libjpeg-turbo) encodings of
// the synthetic images described beside each one; `dcflat` and `oddsamp` were
// assembled byte by byte by a small encoder in the same script, because no
// ordinary encoder will emit the sampling factors and single-coefficient
// blocks they need. Everything else -- the YCCK file, the DNL file, the wrong
// restart interval, the truncations -- is patched out of those at run time by
// the helpers below, so that what makes each variant malformed is visible in
// the test rather than buried in an opaque blob.
//
// Where a value is asserted exactly it was cross-checked against libjpeg: the
// grey, 4:4:4 and CMYK files decode byte-for-byte identically to Pillow. The
// chroma-subsampled files deliberately do not, because this decoder replicates
// chroma samples where libjpeg interpolates them, so those are checked against
// the source image with a tolerance instead.
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
@(private)
jpeg_t_copy :: proc(src: []byte, extra := 0) -> []byte {
out := make([]byte, len(src) + extra, context.allocator)
copy(out, src)
return out
}
// jpeg_t_seg walks the marker segments and returns the offset of the 0xFF that
// starts the first segment with this marker code, or -1.
@(private)
jpeg_t_seg :: proc(data: []byte, marker: byte) -> int {
p := 2
for p + 3 < len(data) {
if data[p] != 0xFF { return -1 }
m := data[p + 1]
if m == marker { return p }
if m == 0xD8 || m == 0xD9 || (m >= 0xD0 && m <= 0xD7) || m == 0x01 {
p += 2
continue
}
seglen := int(data[p + 2]) << 8 | int(data[p + 3])
if seglen < 2 { return -1 }
if m == 0xDA { return -1 }
p += 2 + seglen
}
return -1
}
@(private)
jpeg_t_decode :: proc(t: ^testing.T, data: []byte, loc := #caller_location) -> Jpeg_Image {
img, err := jpeg_decode(data, context.allocator)
testing.expectf(t, err == .None, "decode failed: %v", err, loc = loc)
return img
}
// jpeg_t_max_dev is the largest absolute difference between two same-length
// sample buffers.
@(private)
jpeg_t_max_dev :: proc(a, b: []byte) -> int {
worst := 0
n := min(len(a), len(b))
for i in 0 ..< n {
d := int(a[i]) - int(b[i])
worst = max(worst, abs(d))
}
return worst
}
// ---------------------------------------------------------------------------
// Frame headers
// ---------------------------------------------------------------------------
@(test)
test_jpeg_info :: proc(t: ^testing.T) {
Case :: struct {
name: string,
data: []byte,
w, h, n, bits: int,
}
cases := []Case{
{"grey8", JPEG_T_GREY8[:], 8, 8, 1, 8},
{"grey16", JPEG_T_GREY16[:], 16, 16, 1, 8},
{"greyprog", JPEG_T_GREYPROG[:], 16, 16, 1, 8},
{"rgb444", JPEG_T_RGB444[:], 16, 16, 3, 8},
{"rgb420", JPEG_T_RGB420[:], 16, 16, 3, 8},
{"rgbprog", JPEG_T_RGBPROG[:], 16, 16, 3, 8},
{"cmyk", JPEG_T_CMYK[:], 16, 16, 4, 8},
{"rst", JPEG_T_RST[:], 32, 16, 1, 8},
{"dcflat", JPEG_T_DCFLAT[:], 8, 8, 1, 8},
{"oddsamp", JPEG_T_ODDSAMP[:], 32, 8, 3, 8},
}
for c in cases {
w, h, n, bits, err := jpeg_info(c.data)
testing.expectf(t, err == .None, "%s: %v", c.name, err)
testing.expectf(t, w == c.w && h == c.h,
"%s: size %dx%d, want %dx%d", c.name, w, h, c.w, c.h)
testing.expectf(t, n == c.n, "%s: %d components, want %d", c.name, n, c.n)
testing.expectf(t, bits == c.bits, "%s: %d bits, want %d", c.name, bits, c.bits)
}
}
// ---------------------------------------------------------------------------
// Baseline sequential
// ---------------------------------------------------------------------------
// A single 8x8 block whose only nonzero coefficient is the DC one, with an
// all-ones quantisation table. The inverse DCT of such a block is flat at
// S00/8 plus the level shift of 128 (ISO/IEC 10918-1, A.3.3 and A.3.1), so
// S00 = 40 must reconstruct as exactly 133 everywhere. This pins the IDCT's
// scaling and rounding against arithmetic rather than against another decoder.
@(test)
test_jpeg_dc_only_block :: proc(t: ^testing.T) {
img := jpeg_t_decode(t, JPEG_T_DCFLAT[:])
defer delete(img.data, context.allocator)
testing.expect(t, img.width == 8 && img.height == 8 && img.components == 1)
testing.expect(t, img.bits == 8)
testing.expect(t, img.adobe_transform == -1)
for v, i in img.data {
testing.expectf(t, v == 133, "sample %d is %d, want 133", i, v)
}
}
// An 8x8 grey ramp. These are the exact bytes libjpeg produces for the same
// file, which they should be: both decoders use the same integer IDCT.
@(test)
test_jpeg_grey_baseline_exact :: proc(t: ^testing.T) {
img := jpeg_t_decode(t, JPEG_T_GREY8[:])
defer delete(img.data, context.allocator)
testing.expect(t, img.width == 8 && img.height == 8 && img.components == 1)
testing.expect(t, len(img.data) == 64)
testing.expect(t, slice.equal(img.data, JPEG_T_GREY8_PIXELS[:]))
}
// 16x16, four blocks, a hard-edged 4x4 checkerboard: plenty of high-frequency
// coefficients, so this exercises the AC path and the ringing around an edge.
@(test)
test_jpeg_grey_baseline_blocks :: proc(t: ^testing.T) {
img := jpeg_t_decode(t, JPEG_T_GREY16[:])
defer delete(img.data, context.allocator)
testing.expect(t, len(img.data) == 256)
worst := 0
for y in 0 ..< 16 {
for x in 0 ..< 16 {
want := (x / 4 + y / 4) % 2 == 0 ? 255 : 0
worst = max(worst, abs(int(img.data[y * 16 + x]) - want))
}
}
// Quality 85 on an image that is nothing but block-aligned edges: the
// measured worst case is 6 levels.
testing.expectf(t, worst <= 8, "worst deviation from the source image is %d", worst)
}
@(test)
test_jpeg_colour_444 :: proc(t: ^testing.T) {
img := jpeg_t_decode(t, JPEG_T_RGB444[:])
defer delete(img.data, context.allocator)
testing.expect(t, img.width == 16 && img.height == 16 && img.components == 3)
// Source: R = 16x, G = 16y, B = 128, encoded at quality 90 with no
// subsampling, so every channel round-trips within a few levels.
worst := 0
for y in 0 ..< 16 {
for x in 0 ..< 16 {
o := (y * 16 + x) * 3
worst = max(worst, abs(int(img.data[o]) - x * 16))
worst = max(worst, abs(int(img.data[o + 1]) - y * 16))
worst = max(worst, abs(int(img.data[o + 2]) - 128))
}
}
testing.expectf(t, worst <= 6, "worst deviation from the source image is %d", worst)
}
@(test)
test_jpeg_colour_420_subsampled :: proc(t: ^testing.T) {
img := jpeg_t_decode(t, JPEG_T_RGB420[:])
defer delete(img.data, context.allocator)
testing.expect(t, img.width == 16 && img.height == 16 && img.components == 3)
worst := 0
for y in 0 ..< 16 {
for x in 0 ..< 16 {
o := (y * 16 + x) * 3
worst = max(worst, abs(int(img.data[o]) - x * 16))
worst = max(worst, abs(int(img.data[o + 1]) - y * 16))
worst = max(worst, abs(int(img.data[o + 2]) - 128))
}
}
// Half-resolution chroma on a 16-levels-per-pixel ramp cannot do better
// than about half a chroma sample of error; measured worst case is 16.
testing.expectf(t, worst <= 20, "worst deviation from the source image is %d", worst)
}
// Sampling factors that no ordinary encoder emits: luma 4x1, one chroma plane
// at 1x1 and the other at 2x1, so the two chroma planes are upsampled by
// different, non-power-of-two-per-axis ratios. Every block carries only a DC
// coefficient, which makes each 8x8 region a flat colour that can be predicted
// from the YCbCr definition alone.
@(test)
test_jpeg_odd_sampling_factors :: proc(t: ^testing.T) {
img := jpeg_t_decode(t, JPEG_T_ODDSAMP[:])
defer delete(img.data, context.allocator)
testing.expect(t, img.width == 32 && img.height == 8 && img.components == 3)
// Luma is flat at 28/108/148/228 across four 8-pixel bands, Cb is flat at
// 108 across the whole row, and Cr is 158 over the left half and 98 over
// the right. Converting with the JFIF coefficients gives:
want := [4][3]byte{
{70, 13, 0}, {150, 93, 73}, {106, 176, 113}, {186, 255, 193},
}
for y in 0 ..< 8 {
for x in 0 ..< 32 {
o := (y * 32 + x) * 3
w := want[x / 8]
testing.expectf(t,
img.data[o] == w[0] && img.data[o + 1] == w[1] && img.data[o + 2] == w[2],
"pixel %d,%d is %d,%d,%d, want %d,%d,%d",
x, y, img.data[o], img.data[o + 1], img.data[o + 2], w[0], w[1], w[2])
}
}
}
// ---------------------------------------------------------------------------
// Progressive
// ---------------------------------------------------------------------------
// A progressive encoding carries the same quantised coefficients as its
// baseline twin, just spread over several scans, so the two must reconstruct
// to identical bytes. That makes this an exact test of spectral selection and
// successive approximation, on both the DC and AC scans, without needing any
// expected pixels of its own.
@(test)
test_jpeg_progressive_matches_baseline :: proc(t: ^testing.T) {
grey_prog := jpeg_t_decode(t, JPEG_T_GREYPROG[:])
defer delete(grey_prog.data, context.allocator)
grey_base := jpeg_t_decode(t, JPEG_T_GREY16[:])
defer delete(grey_base.data, context.allocator)
testing.expect(t, slice.equal(grey_prog.data, grey_base.data),
"progressive grey does not match its baseline twin")
rgb_prog := jpeg_t_decode(t, JPEG_T_RGBPROG[:])
defer delete(rgb_prog.data, context.allocator)
rgb_base := jpeg_t_decode(t, JPEG_T_RGB420[:])
defer delete(rgb_base.data, context.allocator)
testing.expect(t, slice.equal(rgb_prog.data, rgb_base.data),
"progressive colour does not match its baseline twin")
}
// A progressive file cut off after its first scans still has a usable DC pass,
// so it must decode to a recognisable, blocky version of the image rather than
// to an error.
@(test)
test_jpeg_progressive_truncated :: proc(t: ^testing.T) {
full := jpeg_t_decode(t, JPEG_T_GREYPROG[:])
defer delete(full.data, context.allocator)
for cut in 1 ..= 8 {
n := len(JPEG_T_GREYPROG) * cut / 9
img, err := jpeg_decode(JPEG_T_GREYPROG[:n], context.allocator)
defer delete(img.data, context.allocator)
if err != .None {
// Cutting inside the frame header legitimately leaves nothing.
continue
}
testing.expect(t, img.width == 16 && img.height == 16)
testing.expect(t, len(img.data) == 256)
}
}
// ---------------------------------------------------------------------------
// Four components: CMYK and YCCK
// ---------------------------------------------------------------------------
// The source image was CMYK (16x, 16y, 200, 30). Adobe writes the CMYK JPEGs
// it embeds in PDFs with every sample complemented, and the image dictionary
// carries /Decode [1 0 1 0 1 0 1 0] to undo it. The filter must therefore hand
// back the complemented samples untouched -- if it "helpfully" inverted them
// the /Decode array would invert them right back.
@(test)
test_jpeg_cmyk_is_not_inverted :: proc(t: ^testing.T) {
img := jpeg_t_decode(t, JPEG_T_CMYK[:])
defer delete(img.data, context.allocator)
testing.expect(t, img.components == 4)
testing.expectf(t, img.adobe_transform == 0,
"adobe_transform is %d, want 0", img.adobe_transform)
worst := 0
for y in 0 ..< 16 {
for x in 0 ..< 16 {
o := (y * 16 + x) * 4
worst = max(worst, abs(int(img.data[o]) - (255 - x * 16)))
worst = max(worst, abs(int(img.data[o + 1]) - (255 - y * 16)))
worst = max(worst, abs(int(img.data[o + 2]) - 55))
worst = max(worst, abs(int(img.data[o + 3]) - 225))
}
}
testing.expectf(t, worst <= 4, "worst deviation from the stored samples is %d", worst)
}
// The same file with the Adobe transform byte changed from 0 to 2. Nothing
// else about the bit stream changes, so the component samples are identical
// and only the colour transform differs: the first three channels go through
// the inverse YCbCr transform and are then complemented, which is part of the
// YCCK definition and not the separate Adobe inversion above.
@(test)
test_jpeg_ycck :: proc(t: ^testing.T) {
app14 := jpeg_t_seg(JPEG_T_CMYK[:], 0xEE)
testing.expect(t, app14 > 0, "no APP14 segment")
if app14 < 0 { return }
patched := jpeg_t_copy(JPEG_T_CMYK[:])
defer delete(patched, context.allocator)
patched[app14 + 4 + 11] = 2
plain := jpeg_t_decode(t, JPEG_T_CMYK[:])
defer delete(plain.data, context.allocator)
ycck := jpeg_t_decode(t, patched)
defer delete(ycck.data, context.allocator)
testing.expectf(t, ycck.adobe_transform == 2,
"adobe_transform is %d, want 2", ycck.adobe_transform)
testing.expect(t, len(ycck.data) == len(plain.data))
worst := 0
for i := 0; i + 3 < len(plain.data); i += 4 {
y := f64(plain.data[i])
cb := f64(plain.data[i + 1]) - 128
cr := f64(plain.data[i + 2]) - 128
r := 255 - clamp(y + 1.402 * cr, 0, 255)
g := 255 - clamp(y - 0.344136 * cb - 0.714136 * cr, 0, 255)
b := 255 - clamp(y + 1.772 * cb, 0, 255)
worst = max(worst, abs(int(ycck.data[i]) - int(r + 0.5)))
worst = max(worst, abs(int(ycck.data[i + 1]) - int(g + 0.5)))
worst = max(worst, abs(int(ycck.data[i + 2]) - int(b + 0.5)))
// K is never transformed.
testing.expect(t, ycck.data[i + 3] == plain.data[i + 3])
}
testing.expectf(t, worst <= 1, "YCCK transform differs from the definition by %d", worst)
}
// ---------------------------------------------------------------------------
// Restart markers
// ---------------------------------------------------------------------------
// The same image encoded twice at the same quality, once with a restart marker
// after every MCU and once without. Restart markers carry no information, so
// the two must decode identically.
@(test)
test_jpeg_restart_markers :: proc(t: ^testing.T) {
with_rst := jpeg_t_decode(t, JPEG_T_RST[:])
defer delete(with_rst.data, context.allocator)
without := jpeg_t_decode(t, JPEG_T_NORST[:])
defer delete(without.data, context.allocator)
testing.expect(t, jpeg_t_seg(JPEG_T_RST[:], 0xDD) > 0, "test file has no DRI segment")
testing.expect(t, jpeg_t_seg(JPEG_T_NORST[:], 0xDD) < 0, "control file has a DRI segment")
testing.expect(t, slice.equal(with_rst.data, without.data),
"restart markers changed the decoded image")
}
// The same pair again, but over content whose MCUs cost only a few bits each:
// horizontal bars at quality 90, which is what a scanned page of text looks
// like to an encoder. That is the case a decoder gets wrong when it decides a
// restart marker is due from the position of its byte reader instead of from
// the declared interval. The reader buffers whole bytes ahead of the bits the
// block decoders have taken and stops dead on a marker, so once an interval's
// remaining blocks code to fewer than eight bits -- routine here, and certain
// in the one-bit-per-block DC refinement scan that every progressive file has
// -- the marker is already under the reader while blocks of that interval are
// still undecoded. Taking it there resets the DC predictors and the EOB run
// early and decodes the rest of the interval out of the next segment's bits.
//
// Both files decode byte-for-byte identically to libjpeg-turbo; before the
// interval gated the take, the baseline pair differed in 192 of 4096 samples
// and the progressive pair in 960, by up to 190.
@(test)
test_jpeg_restart_low_entropy_mcus :: proc(t: ^testing.T) {
Case :: struct {
name: string,
with, wro: []byte,
}
cases := []Case{
{"baseline", JPEG_T_LOWENT_RST[:], JPEG_T_LOWENT[:]},
{"progressive", JPEG_T_LOWENTP_RST[:], JPEG_T_LOWENTP[:]},
}
for c in cases {
testing.expectf(t, jpeg_t_seg(c.with, 0xDD) > 0, "%s: test file has no DRI segment", c.name)
testing.expectf(t, jpeg_t_seg(c.wro, 0xDD) < 0, "%s: control file has a DRI segment", c.name)
with_rst := jpeg_t_decode(t, c.with)
defer delete(with_rst.data, context.allocator)
without := jpeg_t_decode(t, c.wro)
defer delete(without.data, context.allocator)
testing.expectf(t, with_rst.width == 64 && with_rst.height == 64,
"%s: %dx%d", c.name, with_rst.width, with_rst.height)
testing.expectf(t, slice.equal(with_rst.data, without.data),
"%s: restart markers changed the decoded image (max deviation %d)",
c.name, jpeg_t_max_dev(with_rst.data, without.data))
}
}
// A DRI that disagrees with the markers actually in the stream.
//
// This is damage, and unlike a truncation it is not repairable. The declared
// interval is the only thing that says how many MCUs a segment covers, so once
// it is wrong the decoder cannot tell which of the markers it can see ends the
// segment it is in; believing the markers instead is what breaks every intact
// file with a low-entropy interval. libjpeg does not recover these either --
// patching a real file's DRI from 1 to 3 leaves it reporting "extraneous bytes
// before marker 0xd0" with 92% of its samples wrong.
//
// What is required is that the damage stays damage. The decode terminates,
// hands back an image of the size the frame header declared rather than an
// error, and does not corrupt what it had already decoded correctly: the first
// MCU is ahead of the first restart marker, so no disagreement about the
// interval can reach it.
@(test)
test_jpeg_restart_interval_wrong :: proc(t: ^testing.T) {
dri := jpeg_t_seg(JPEG_T_RST[:], 0xDD)
testing.expect(t, dri > 0)
if dri < 0 { return }
good := jpeg_t_decode(t, JPEG_T_RST[:])
defer delete(good.data, context.allocator)
for claim in ([]int{0, 3, 7, 65535}) {
patched := jpeg_t_copy(JPEG_T_RST[:])
defer delete(patched, context.allocator)
patched[dri + 4] = byte(claim >> 8)
patched[dri + 5] = byte(claim)
img, err := jpeg_decode(patched, context.allocator)
defer delete(img.data, context.allocator)
testing.expectf(t, err == .None, "DRI %d: %v", claim, err)
testing.expectf(t, img.width == 32 && img.height == 16,
"DRI %d: %dx%d", claim, img.width, img.height)
if len(img.data) != len(good.data) { continue }
// The 8x8 block at the origin is MCU 0, decoded before the stream
// reaches any restart marker at all.
for y in 0 ..< 8 {
for x in 0 ..< 8 {
i := y * 32 + x
testing.expectf(t, img.data[i] == good.data[i],
"DRI %d: sample (%d,%d) of the first MCU is %d, want %d",
claim, x, y, img.data[i], good.data[i])
}
}
}
}
// Restart markers are also a recovery point: with the entropy data of one
// segment corrupted, everything after the next marker still decodes.
@(test)
test_jpeg_restart_resync_after_corruption :: proc(t: ^testing.T) {
sos := -1
p := 2
for p + 3 < len(JPEG_T_RST) {
if JPEG_T_RST[p] != 0xFF { break }
m := JPEG_T_RST[p + 1]
seglen := int(JPEG_T_RST[p + 2]) << 8 | int(JPEG_T_RST[p + 3])
if m == 0xDA {
sos = p + 2 + seglen
break
}
p += 2 + seglen
}
testing.expect(t, sos > 0)
if sos < 0 { return }
good := jpeg_t_decode(t, JPEG_T_RST[:])
defer delete(good.data, context.allocator)
patched := jpeg_t_copy(JPEG_T_RST[:])
defer delete(patched, context.allocator)
// Corrupt the first entropy-coded segment only.
patched[sos] = 0x5A
img, err := jpeg_decode(patched, context.allocator)
defer delete(img.data, context.allocator)
testing.expectf(t, err == .None, "%v", err)
testing.expect(t, img.width == 32 && img.height == 16)
// The bottom half of the image comes after several restart markers and
// must be untouched by the damage at the top.
testing.expect(t, slice.equal(img.data[32 * 8:], good.data[32 * 8:]),
"damage in the first restart interval leaked past a restart marker")
}
// ---------------------------------------------------------------------------
// Tolerated malformations
// ---------------------------------------------------------------------------
@(test)
test_jpeg_garbage_before_soi :: proc(t: ^testing.T) {
junk := "HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\n\r\n"
data := make([]byte, len(junk) + len(JPEG_T_GREY8), context.allocator)
defer delete(data, context.allocator)
copy(data, transmute([]byte)junk)
copy(data[len(junk):], JPEG_T_GREY8[:])
img := jpeg_t_decode(t, data)
defer delete(img.data, context.allocator)
testing.expect(t, slice.equal(img.data, JPEG_T_GREY8_PIXELS[:]))
}
@(test)
test_jpeg_missing_eoi :: proc(t: ^testing.T) {
trimmed := JPEG_T_GREY8[:len(JPEG_T_GREY8) - 2]
testing.expect(t, JPEG_T_GREY8[len(JPEG_T_GREY8) - 1] == 0xD9, "test file does not end in EOI")
img := jpeg_t_decode(t, trimmed)
defer delete(img.data, context.allocator)
testing.expect(t, slice.equal(img.data, JPEG_T_GREY8_PIXELS[:]),
"dropping EOI changed the image")
}
// Fill bytes between segments are legal (ISO/IEC 10918-1, B.1.1.2) and
// stray bytes are not, but both turn up. Neither may derail the parse.
@(test)
test_jpeg_extra_bytes_between_markers :: proc(t: ^testing.T) {
sof := jpeg_t_seg(JPEG_T_GREY8[:], 0xC0)
testing.expect(t, sof > 0)
if sof < 0 { return }
data := make([]byte, len(JPEG_T_GREY8) + 4, context.allocator)
defer delete(data, context.allocator)
copy(data, JPEG_T_GREY8[:sof])
data[sof], data[sof + 1], data[sof + 2], data[sof + 3] = 0xFF, 0xFF, 0xFF, 0xFF
copy(data[sof + 4:], JPEG_T_GREY8[sof:])
img := jpeg_t_decode(t, data)
defer delete(img.data, context.allocator)
testing.expect(t, slice.equal(img.data, JPEG_T_GREY8_PIXELS[:]))
}
// A frame header may leave the height at zero and let a DNL marker after the
// first scan supply it (ISO/IEC 10918-1, B.2.2). Rare, but the format allows
// it and a stream that was being generated on the fly may well use it.
@(test)
test_jpeg_dnl_height :: proc(t: ^testing.T) {
sof := jpeg_t_seg(JPEG_T_GREY16[:], 0xC0)
testing.expect(t, sof > 0)
if sof < 0 { return }
n := len(JPEG_T_GREY16)
data := make([]byte, n + 6, context.allocator)
defer delete(data, context.allocator)
copy(data, JPEG_T_GREY16[:n - 2])
hi, lo := data[sof + 5], data[sof + 6]
data[sof + 5], data[sof + 6] = 0, 0
copy(data[n - 2:], []byte{0xFF, 0xDC, 0x00, 0x04, hi, lo, 0xFF, 0xD9})
w, h, _, _, ierr := jpeg_info(data)
testing.expect(t, ierr == .None)
testing.expectf(t, w == 16 && h == 16, "jpeg_info reports %dx%d", w, h)
img := jpeg_t_decode(t, data)
defer delete(img.data, context.allocator)
reference := jpeg_t_decode(t, JPEG_T_GREY16[:])
defer delete(reference.data, context.allocator)
testing.expect(t, img.height == 16)
testing.expect(t, slice.equal(img.data, reference.data))
}
// A quantisation value of zero would erase its coefficient and, in a decoder
// that divided rather than multiplied, divide by it. Treating it as 1 keeps
// the image and cannot fault.
@(test)
test_jpeg_zero_quant_value :: proc(t: ^testing.T) {
dqt := jpeg_t_seg(JPEG_T_GREY8[:], 0xDB)
testing.expect(t, dqt > 0)
if dqt < 0 { return }
patched := jpeg_t_copy(JPEG_T_GREY8[:])
defer delete(patched, context.allocator)
for i in 0 ..< 64 {
patched[dqt + 5 + i] = 0
}
img, err := jpeg_decode(patched, context.allocator)
defer delete(img.data, context.allocator)
testing.expectf(t, err == .None, "%v", err)
testing.expect(t, len(img.data) == 64)
}
// A scan that stops in the middle must yield the part that decoded. The rows
// that were fully covered before the cut have to be bit-exact: a decoder that
// resynchronised by guessing would corrupt them too.
@(test)
test_jpeg_truncated_scan :: proc(t: ^testing.T) {
good := jpeg_t_decode(t, JPEG_T_NORST[:])
defer delete(good.data, context.allocator)
intact_rows := 0
for cut := len(JPEG_T_NORST) - 3; cut > 0; cut -= 1 {
img, err := jpeg_decode(JPEG_T_NORST[:cut], context.allocator)
defer delete(img.data, context.allocator)
if err != .None { continue }
testing.expectf(t, img.width == 32 && img.height == 16,
"cut at %d: %dx%d", cut, img.width, img.height)
testing.expectf(t, len(img.data) == 512, "cut at %d: %d bytes", cut, len(img.data))
rows := 0
for rows < 16 {
lo, hi := rows * 32, (rows + 1) * 32
if !slice.equal(img.data[lo:hi], good.data[lo:hi]) { break }
rows += 1
}
intact_rows = max(intact_rows, rows)
}
// Trimming a byte or two off the end costs at most the last MCU row.
testing.expectf(t, intact_rows >= 8,
"a nearly-complete truncation only reproduced %d rows", intact_rows)
}
// ---------------------------------------------------------------------------
// Refusals
// ---------------------------------------------------------------------------
@(test)
test_jpeg_malformed :: proc(t: ^testing.T) {
Case :: struct {
name: string,
data: []byte,
want: Error,
}
// 12-bit-per-sample and unusual-but-legal headers belong in the tolerated
// set; these are the ones with genuinely nothing to hand back.
cases := []Case{
{"empty", {}, .Bad_Jpeg_Data},
{"no soi", {0x00, 0x01, 0x02, 0x03}, .Bad_Jpeg_Data},
{"soi only", {0xFF, 0xD8}, .Bad_Jpeg_Data},
{"soi eoi", {0xFF, 0xD8, 0xFF, 0xD9}, .Bad_Jpeg_Data},
{"truncated sof", {0xFF, 0xD8, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00}, .Bad_Jpeg_Data},
{"zero size", {0xFF, 0xD8, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xD9}, .Bad_Jpeg_Data},
{"no components", {0xFF, 0xD8, 0xFF, 0xC0, 0x00, 0x08, 0x08, 0x00, 0x08,
0x00, 0x08, 0x00, 0xFF, 0xD9}, .Bad_Jpeg_Data},
{"5 components", {0xFF, 0xD8, 0xFF, 0xC0, 0x00, 0x08, 0x08, 0x00, 0x08,
0x00, 0x08, 0x05, 0xFF, 0xD9}, .Bad_Jpeg_Data},
// 65535 x 65535 is 4.3 gigapixels.
{"absurd size", {0xFF, 0xD8, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0xFF, 0xFF,
0xFF, 0xFF, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xD9}, .Bitmap_Too_Large},
// SOF3 is lossless, SOF9 is arithmetic-coded: implementable, but no
// producer emits either into a PDF.
{"lossless", {0xFF, 0xD8, 0xFF, 0xC3, 0x00, 0x0B, 0x08, 0x00, 0x08,
0x00, 0x08, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xD9}, .Unsupported_Image},
{"arithmetic", {0xFF, 0xD8, 0xFF, 0xC9, 0x00, 0x0B, 0x08, 0x00, 0x08,
0x00, 0x08, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xD9}, .Unsupported_Image},
// A frame header with no scan at all.
{"frame no scan", {0xFF, 0xD8, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x08,
0x00, 0x08, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xD9}, .Bad_Jpeg_Data},
}
for c in cases {
img, err := jpeg_decode(c.data, context.allocator)
defer delete(img.data, context.allocator)
testing.expectf(t, err == c.want, "%s: got %v, want %v", c.name, err, c.want)
testing.expectf(t, img.data == nil, "%s: returned data despite %v", c.name, err)
}
}
// ---------------------------------------------------------------------------
// Scan count
// ---------------------------------------------------------------------------
// jpeg_t_bits is the bit writer the two synthetic files below share. It escapes
// 0xFF the way an encoder must, so the entropy data can never be mistaken for a
// marker.
@(private = "file")
Jpeg_T_Bits :: struct {
out: [dynamic]byte,
acc: u32,
n: uint,
}
@(private = "file")
jpeg_t_put :: proc(w: ^Jpeg_T_Bits, value: u32, count: uint) {
for i := count; i > 0; i -= 1 {
w.acc = w.acc << 1 | (value >> (i - 1)) & 1
w.n += 1
if w.n == 8 {
b := byte(w.acc)
append(&w.out, b)
if b == 0xFF { append(&w.out, 0x00) }
w.acc, w.n = 0, 0
}
}
}
// jpeg_t_flush pads to a byte boundary with 1 bits, which is what ISO/IEC
// 10918-1 F.1.2.3 requires of an encoder.
@(private = "file")
jpeg_t_flush :: proc(w: ^Jpeg_T_Bits) {
for w.n != 0 { jpeg_t_put(w, 1, 1) }
}
@(private = "file")
jpeg_t_seg_append :: proc(out: ^[dynamic]byte, marker: byte, payload: []byte) {
n := len(payload) + 2
append(out, 0xFF, marker, byte(n >> 8), byte(n))
append(out, ..payload)
}
// jpeg_t_dc_scan_file builds a progressive JPEG of a single 8x8 block whose
// scans are all DC-first scans of the same coefficient. Every scan overwrites
// what the one before it wrote, so the sample the block reconstructs to names
// the last scan that actually ran -- which is how the scan limit is observed
// without timing anything.
//
// All the scans but the last code a DC of 8; the last codes 120. With an
// all-ones quantisation table the block reconstructs flat at S00/8 + 128
// (ISO/IEC 10918-1, A.3.3), so the image is 129 everywhere if the last scan was
// refused and 143 everywhere if it ran.
@(private = "file")
jpeg_t_dc_scan_file :: proc(nscans: int, allocator := context.allocator) -> []byte {
out := make([dynamic]byte, allocator)
append(&out, 0xFF, 0xD8)
dqt: [65]byte
for i in 1 ..< 65 { dqt[i] = 1 }
jpeg_t_seg_append(&out, 0xDB, dqt[:])
// SOF2: 8 bits, 8x8, one 1x1 component using quantisation table 0.
jpeg_t_seg_append(&out, 0xC2, []byte{8, 0, 8, 0, 8, 1, 1, 0x11, 0})
// DHT, DC table 0: eight codes of length 4, so magnitude category s is the
// 4-bit code s.
dht: [17]byte
dht[0] = 0x00
dht[4] = 8
tbl := make([]byte, 25, context.temp_allocator)
copy(tbl, dht[:])
for s in 0 ..< 8 { tbl[17 + s] = byte(s) }
jpeg_t_seg_append(&out, 0xC4, tbl)
for i in 0 ..< nscans {
jpeg_t_seg_append(&out, 0xDA, []byte{1, 1, 0x00, 0, 0, 0x00})
w := Jpeg_T_Bits{out = make([dynamic]byte, context.temp_allocator)}
if i == nscans - 1 {
jpeg_t_put(&w, 7, 4) // category 7: 64..127
jpeg_t_put(&w, 120, 7)
} else {
jpeg_t_put(&w, 4, 4) // category 4: 8..15
jpeg_t_put(&w, 8, 4)
}
jpeg_t_flush(&w)
append(&out, ..w.out[:])
}
append(&out, 0xFF, 0xD9)
return out[:]
}
// The scan count is bounded on its own, not just by the segment count.
//
// A progressive scan is not cheap per byte: one EOB run costs 18 bits and skips
// up to 32767 blocks, so a scan whose entropy data is a handful of bytes still
// drives the MCU loop over the whole component. Bounding only the number of
// marker segments therefore bounds the work at 65536 sweeps of a frame that may
// hold millions of blocks, which is minutes of CPU from a stream of a megabyte.
@(test)
test_jpeg_scan_count_is_capped :: proc(t: ^testing.T) {
over := jpeg_t_dc_scan_file(MAX_JPEG_SCANS + 5, context.allocator)
defer delete(over, context.allocator)
img := jpeg_t_decode(t, over)
defer delete(img.data, context.allocator)
testing.expect(t, img.width == 8 && img.height == 8 && img.components == 1)
for v, i in img.data {
testing.expectf(t, v == 129,
"sample %d is %d: a scan past the limit was decoded", i, v)
}
// The same construction inside the limit must decode every scan, so that
// the assertion above is about the limit and not about the file.
under := jpeg_t_dc_scan_file(3, context.allocator)
defer delete(under, context.allocator)
ok := jpeg_t_decode(t, under)
defer delete(ok.data, context.allocator)
for v, i in ok.data {
testing.expectf(t, v == 143, "sample %d is %d: the last scan did not run", i, v)
}
}
// jpeg_t_eob_dos_file is the shape that makes the scan count expensive: a large
// single-component progressive frame whose every scan covers it with EOB runs.
// Nine bytes of entropy data per scan visit 65536 blocks.
@(private = "file")
jpeg_t_eob_dos_file :: proc(side, nscans: int, allocator := context.allocator) -> []byte {
out := make([dynamic]byte, allocator)
append(&out, 0xFF, 0xD8)
dqt: [65]byte
for i in 1 ..< 65 { dqt[i] = 1 }
jpeg_t_seg_append(&out, 0xDB, dqt[:])
jpeg_t_seg_append(&out, 0xC2, []byte{
8, byte(side >> 8), byte(side), byte(side >> 8), byte(side), 1, 1, 0x11, 0,
})
// DHT, AC table 0: two codes of length 4 for the symbols 0x00 (EOB0) and
// 0xE0 (EOB14), so EOB14 is the 4-bit code 0b0001.
dht: [17]byte
dht[0] = 0x10
dht[4] = 2
tbl := make([]byte, 19, context.temp_allocator)
copy(tbl, dht[:])
tbl[17], tbl[18] = 0x00, 0xE0
jpeg_t_seg_append(&out, 0xC4, tbl)
blocks := ((side + 7) / 8) * ((side + 7) / 8)
w := Jpeg_T_Bits{out = make([dynamic]byte, context.temp_allocator)}
for left := blocks; left > 0; {
// EOB14 covers 1<<14 blocks plus its 14 extra bits.
run := min(left, 1 << 14)
jpeg_t_put(&w, 1, 4)
jpeg_t_put(&w, u32(run - (1 << 14)) & 0x3FFF, 14)
left -= run
}
jpeg_t_flush(&w)
body := w.out[:]
for _ in 0 ..< nscans {
jpeg_t_seg_append(&out, 0xDA, []byte{1, 1, 0x00, 1, 63, 0x00})
append(&out, ..body)
}
append(&out, 0xFF, 0xD9)
return out[:]
}
@(test)
test_jpeg_many_scans_terminate :: proc(t: ^testing.T) {
data := jpeg_t_eob_dos_file(2048, 20000, context.allocator)
defer delete(data, context.allocator)
started := time.now()
img, err := jpeg_decode(data, context.allocator)
defer delete(img.data, context.allocator)
ms := time.duration_milliseconds(time.since(started))
testing.expectf(t, err == .None, "%v", err)
testing.expect(t, img.width == 2048 && img.height == 2048)
// Not a performance bound: with the scan count unbounded this same file
// takes about fifteen seconds, and at the largest frame the header may
// declare it is closer to an hour. The limit is loose enough that a loaded
// machine cannot trip it.
testing.expectf(t, ms < 5000, "%d scans took %.0f ms", 20000, ms)
}
// ---------------------------------------------------------------------------
// Fuzz-shaped
// ---------------------------------------------------------------------------
@(private)
jpeg_t_corpus :: proc() -> [10][]byte {
return [10][]byte{
JPEG_T_GREY8[:], JPEG_T_GREY16[:], JPEG_T_GREYPROG[:], JPEG_T_RGB420[:],
JPEG_T_RGBPROG[:], JPEG_T_CMYK[:], JPEG_T_PROGRST[:], JPEG_T_ODDSAMP[:],
JPEG_T_LOWENT_RST[:], JPEG_T_LOWENTP_RST[:],
}
}
// Every prefix of every test file. The decoder must return either an error or
// a correctly-sized image, and must not fault, hang or leak on any of them.
@(test)
test_jpeg_fuzz_truncation :: proc(t: ^testing.T) {
corpus := jpeg_t_corpus()
for src in corpus {
w, h, n, _, ierr := jpeg_info(src)
testing.expect(t, ierr == .None)
for cut in 0 ..= len(src) {
img, err := jpeg_decode(src[:cut], context.allocator)
defer delete(img.data, context.allocator)
if err != .None {
testing.expect(t, img.data == nil)
continue
}
testing.expectf(t, img.width == w && img.height == h && img.components == n,
"cut at %d: %dx%dx%d, want %dx%dx%d",
cut, img.width, img.height, img.components, w, h, n)
testing.expect(t, len(img.data) == w * h * n)
}
}
}
// One flipped bit at every byte offset. Corruption in a header can legitimately
// change the reported size or make the file unreadable; what it must never do
// is produce a buffer whose length disagrees with the header the decoder acted
// on, or take unbounded time.
@(test)
test_jpeg_fuzz_bitflip :: proc(t: ^testing.T) {
corpus := jpeg_t_corpus()
for src in corpus {
scratch := jpeg_t_copy(src)
defer delete(scratch, context.allocator)
for i in 0 ..< len(src) {
for bit in ([]uint{0, 3, 7}) {
scratch[i] = src[i] ~ (1 << bit)
img, err := jpeg_decode(scratch, context.allocator)
if err == .None {
testing.expectf(t,
len(img.data) == img.width * img.height * img.components,
"offset %d bit %d: %d bytes for %dx%dx%d",
i, bit, len(img.data), img.width, img.height, img.components)
testing.expect(t, img.width > 0 && img.height > 0)
testing.expect(t, img.components >= 1 && img.components <= 4)
} else {
testing.expect(t, img.data == nil)
}
delete(img.data, context.allocator)
}
scratch[i] = src[i]
}
}
}
// A single decode of a few-hundred-byte fuzz case that runs longer than this
// has stopped being slow and started being stuck.
@(private = "file")
JPEG_T_FUZZ_HANG_MS :: 5000.0
// Two bytes of a marker segment length turned into something degenerate -- too
// short to hold the segment's own length field, or far longer than the file --
// at every segment in turn. The parser has to clamp to the data it has rather
// than reading past the end of the buffer.
//
// The outcome is not predictable per mutation: a length that swallows the rest
// of the file may still leave a decodable image, and a mangled SOF may not.
// What is predictable is the shape of whatever comes back, so that is what is
// asserted -- an error hands back nothing to free, and a success hands back a
// buffer that matches the dimensions it reports. A decoder that allocated for
// the old header and then wrote for a new one would fail here.
@(test)
test_jpeg_fuzz_segment_lengths :: proc(t: ^testing.T) {
corpus := jpeg_t_corpus()
for src in corpus {
for i := 2; i + 3 < len(src); i += 1 {
if src[i] != 0xFF || src[i + 1] == 0x00 || src[i + 1] == 0xFF { continue }
for value in ([]int{0, 1, 2, 3, 0xFFFF}) {
scratch := jpeg_t_copy(src)
defer delete(scratch, context.allocator)
scratch[i + 2] = byte(value >> 8)
scratch[i + 3] = byte(value)
started := time.now()
img, err := jpeg_decode(scratch, context.allocator)
defer delete(img.data, context.allocator)
// Not a performance bound: the inputs are a few hundred bytes,
// so a decode measured in seconds is a loop whose bound came
// out of the mutated length field. The limit is loose enough
// that a loaded machine cannot trip it.
ms := time.duration_milliseconds(time.since(started))
testing.expectf(t, ms < JPEG_T_FUZZ_HANG_MS,
"offset %d length %#x: decode took %.0f ms", i, value, ms)
if err != .None {
testing.expectf(t, img.data == nil,
"offset %d length %#x: failed decode returned %d bytes",
i, value, len(img.data))
continue
}
// Every dimension the decoder reports has to be one it
// allocated for: this is the check that a segment length is
// never able to make the buffer and the header disagree.
testing.expectf(t,
img.width > 0 && img.height > 0 &&
img.components >= 1 && img.components <= 4,
"offset %d length %#x: decoded %dx%dx%d",
i, value, img.width, img.height, img.components)
testing.expectf(t, img.width <= MAX_JPEG_PIXELS / max(img.height, 1),
"offset %d length %#x: %dx%d is past the pixel cap",
i, value, img.width, img.height)
testing.expectf(t,
len(img.data) == img.width * img.height * img.components,
"offset %d length %#x: %d bytes for %dx%dx%d",
i, value, len(img.data), img.width, img.height, img.components)
testing.expectf(t, img.bits == 8,
"offset %d length %#x: decoded image claims %d bits", i, value, img.bits)
}
}
}
}
// Progressive and restart markers together: a progressive file whose scans are
// each broken into restart intervals. The end-of-band run counter is scan
// state like the DC predictors and has to be cleared at every restart, which
// is the thing this combination catches.
@(test)
test_jpeg_progressive_with_restarts :: proc(t: ^testing.T) {
testing.expect(t, jpeg_t_seg(JPEG_T_PROGRST[:], 0xDD) > 0, "test file has no DRI segment")
img := jpeg_t_decode(t, JPEG_T_PROGRST[:])
defer delete(img.data, context.allocator)
plain := jpeg_t_decode(t, JPEG_T_GREY16[:])
defer delete(plain.data, context.allocator)
testing.expect(t, slice.equal(img.data, plain.data),
"progressive with restarts does not match the baseline encoding")
}
// 12-bit samples. The format allows them; almost nothing produces them, and a
// PDF's /BitsPerComponent has nowhere to say so. `jpeg_info` reports the
// precision the file declares so a caller can complain about it, while
// `jpeg_decode` scales the samples down to the byte-per-sample buffer it
// always returns. The file is one block with DC = 640 against an all-ones
// quantisation table, which after the 4-bit downshift is the same flat 133 as
// the 8-bit version.
@(test)
test_jpeg_12_bit :: proc(t: ^testing.T) {
_, _, _, bits, err := jpeg_info(JPEG_T_BITS12[:])
testing.expect(t, err == .None)
testing.expectf(t, bits == 12, "jpeg_info reports %d bits, want 12", bits)
img := jpeg_t_decode(t, JPEG_T_BITS12[:])
defer delete(img.data, context.allocator)
testing.expectf(t, img.bits == 8, "decoded image claims %d bits", img.bits)
testing.expect(t, len(img.data) == 64)
for v, i in img.data {
testing.expectf(t, v == 133, "sample %d is %d, want 133", i, v)
}
}
// ---------------------------------------------------------------------------
// Embedded files
// ---------------------------------------------------------------------------
@(private)
JPEG_T_GREY8_PIXELS := [64]byte{
20, 45, 71, 94, 121, 145, 170, 195, 22, 48, 73, 97, 124, 147, 173, 198,
26, 51, 77, 100, 127, 151, 176, 201, 29, 54, 80, 103, 130, 154, 179, 204,
31, 57, 82, 106, 133, 156, 182, 207, 34, 60, 85, 109, 135, 159, 185, 210,
38, 63, 89, 112, 139, 163, 188, 213, 40, 66, 91, 115, 141, 165, 191, 216,
}
@(private)
JPEG_T_GREY8 := [341]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03,
0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07,
0x07, 0x06, 0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D,
0x0E, 0x11, 0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F,
0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x08,
0x00, 0x08, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03,
0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00,
0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72,
0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55,
0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2,
0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA,
0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3F, 0x00, 0xC4, 0xFD, 0x86, 0xF4, 0x4F, 0xF9, 0x07, 0xFC,
0xBF, 0xDD, 0xAF, 0xFF, 0xD9,
}
@(private)
JPEG_T_GREY16 := [442]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05,
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B,
0x0B, 0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F, 0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13,
0x14, 0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17,
0x22, 0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x10,
0x00, 0x10, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03,
0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00,
0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72,
0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55,
0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2,
0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA,
0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3F, 0x00, 0x4F, 0xF9, 0x3D, 0x1F, 0xFA, 0x91, 0x3F, 0xE1,
0x0E, 0xFF, 0x00, 0xB8, 0x97, 0xDA, 0xFE, 0xD9, 0xFF, 0x00, 0x7E, 0x7C, 0xBD, 0x9F, 0x65, 0xFF,
0x00, 0x6B, 0x3B, 0xFB, 0x63, 0x93, 0xFE, 0x4F, 0x47, 0xFE, 0xA4, 0x4F, 0xF8, 0x43, 0xBF, 0xEE,
0x25, 0xF6, 0xBF, 0xB6, 0x7F, 0xDF, 0x9F, 0x2F, 0x67, 0xD9, 0x7F, 0xDA, 0xCE, 0xFE, 0xD8, 0xE4,
0xFF, 0x00, 0x93, 0xD1, 0xFF, 0x00, 0xA9, 0x13, 0xFE, 0x10, 0xEF, 0xFB, 0x89, 0x7D, 0xAF, 0xED,
0x9F, 0xF7, 0xE7, 0xCB, 0xD9, 0xF6, 0x5F, 0xF6, 0xB3, 0xBF, 0xB6, 0x39, 0x3F, 0xE4, 0xF4, 0x7F,
0xEA, 0x44, 0xFF, 0x00, 0x84, 0x3B, 0xFE, 0xE2, 0x5F, 0x6B, 0xFB, 0x67, 0xFD, 0xF9, 0xF2, 0xF6,
0x7D, 0x97, 0xFD, 0xAC, 0xEF, 0xED, 0x8E, 0x7F, 0xFF, 0xD9,
}
@(private)
JPEG_T_GREYPROG := [352]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05,
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B,
0x0B, 0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F, 0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13,
0x14, 0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17,
0x22, 0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0xFF, 0xC2, 0x00, 0x0B, 0x08, 0x00, 0x10,
0x00, 0x10, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x15, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xDA, 0x00,
0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x83, 0xFF, 0xC4, 0x00, 0x15, 0x10, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFF,
0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x05, 0x02, 0xB4, 0x5A, 0x2D, 0x16, 0x8F, 0xFF, 0xC4,
0x00, 0x1B, 0x10, 0x00, 0x01, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x12, 0x00, 0x11, 0x14, 0x32, 0x54, 0x83, 0x91, 0xFF, 0xDA, 0x00, 0x08, 0x01,
0x01, 0x00, 0x06, 0x3F, 0x02, 0xC1, 0x87, 0xB0, 0x8F, 0x8D, 0x55, 0x83, 0x0F, 0x61, 0x1F, 0x1A,
0xAB, 0x06, 0x1E, 0xC2, 0x3E, 0x35, 0x56, 0x0C, 0x3D, 0x84, 0x7C, 0x6A, 0xAF, 0xFF, 0xC4, 0x00,
0x18, 0x10, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x31, 0x71, 0xF0, 0xF1, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3F,
0x21, 0xAB, 0x35, 0x36, 0x55, 0x9A, 0x9B, 0x2A, 0xCD, 0x4D, 0x95, 0x66, 0xA6, 0xCF, 0xFF, 0xDA,
0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x10, 0xFF, 0x00, 0xFF, 0xC4, 0x00, 0x18, 0x10, 0x00,
0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
0xF0, 0x21, 0x51, 0x71, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3F, 0x10, 0x7A, 0x8E,
0x95, 0x12, 0xF5, 0x1D, 0x2A, 0x25, 0xEA, 0x3A, 0x54, 0x4B, 0xD4, 0x74, 0xA8, 0x9F, 0xFF, 0xD9,
}
@(private)
JPEG_T_RGB444 := [717]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03,
0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07,
0x07, 0x06, 0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D,
0x0E, 0x11, 0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F,
0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x03, 0x04,
0x04, 0x05, 0x04, 0x05, 0x09, 0x05, 0x05, 0x09, 0x14, 0x0D, 0x0B, 0x0D, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xFF, 0xC0,
0x00, 0x11, 0x08, 0x00, 0x10, 0x00, 0x10, 0x03, 0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11,
0x01, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05,
0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23,
0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5,
0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1,
0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, 0x01, 0x00, 0x03,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x11, 0x00,
0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00,
0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13,
0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15,
0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4,
0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2,
0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
0xFA, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00, 0xF9,
0x57, 0xC2, 0x9F, 0x0A, 0x7E, 0xE7, 0xEE, 0x7F, 0x4A, 0xFD, 0x83, 0x19, 0x9C, 0x6F, 0xA9, 0xE7,
0xF0, 0xDE, 0x7F, 0xF0, 0xFB, 0xC7, 0xB3, 0x78, 0x4F, 0xE1, 0x4F, 0xDC, 0xFD, 0xCF, 0xE9, 0x5F,
0x0D, 0x8C, 0xCE, 0x37, 0xD4, 0xFE, 0xAB, 0xE1, 0xBC, 0xFF, 0x00, 0xE1, 0xF7, 0x8F, 0x62, 0xF0,
0x9F, 0xC2, 0x9F, 0xB9, 0xFB, 0x9F, 0xD2, 0xBE, 0x1F, 0x19, 0x9C, 0x6F, 0xA9, 0xFE, 0x63, 0x70,
0xDE, 0x7D, 0xF0, 0xEA, 0x7B, 0x37, 0x85, 0x3E, 0x14, 0xFD, 0xCF, 0xDC, 0xFE, 0x95, 0xF0, 0xB8,
0xCC, 0xE3, 0x7D, 0x4F, 0xEA, 0xAE, 0x1B, 0xCF, 0xBE, 0x1D, 0x4F, 0xFF, 0xD9,
}
@(private)
JPEG_T_RGB420 := [678]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03,
0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07,
0x07, 0x06, 0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D,
0x0E, 0x11, 0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F,
0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x03, 0x04,
0x04, 0x05, 0x04, 0x05, 0x09, 0x05, 0x05, 0x09, 0x14, 0x0D, 0x0B, 0x0D, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xFF, 0xC0,
0x00, 0x11, 0x08, 0x00, 0x10, 0x00, 0x10, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11,
0x01, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05,
0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23,
0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5,
0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1,
0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, 0x01, 0x00, 0x03,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x11, 0x00,
0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00,
0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13,
0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15,
0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4,
0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2,
0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
0xFA, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00, 0xF9,
0x57, 0xC2, 0x9F, 0x0A, 0x7E, 0xE7, 0xEE, 0x7F, 0x4A, 0xF6, 0x6F, 0x09, 0xFC, 0x29, 0xFB, 0x9F,
0xB9, 0xFD, 0x2B, 0xD8, 0xBC, 0x27, 0xF0, 0xA7, 0xEE, 0x7E, 0xE7, 0xF4, 0xAF, 0x66, 0xF0, 0xA7,
0xC2, 0x9F, 0xB9, 0xFB, 0x9F, 0xD2, 0xBA, 0xF3, 0x9E, 0x30, 0xDF, 0xDE, 0x27, 0xC3, 0x6E, 0x3D,
0xF8, 0x3D, 0xFE, 0xC7, 0xFF, 0xD9,
}
@(private)
JPEG_T_RGBPROG := [556]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03,
0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07,
0x07, 0x06, 0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D,
0x0E, 0x11, 0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F,
0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x03, 0x04,
0x04, 0x05, 0x04, 0x05, 0x09, 0x05, 0x05, 0x09, 0x14, 0x0D, 0x0B, 0x0D, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xFF, 0xC2,
0x00, 0x11, 0x08, 0x00, 0x10, 0x00, 0x10, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11,
0x01, 0xFF, 0xC4, 0x00, 0x15, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x07, 0xFF, 0xC4, 0x00, 0x15, 0x01, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0xFF,
0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x10, 0x03, 0x10, 0x00, 0x00, 0x01, 0x95, 0x33, 0x62,
0xCE, 0xA7, 0xFF, 0xC4, 0x00, 0x16, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01,
0x00, 0x01, 0x05, 0x02, 0x56, 0x50, 0xA4, 0xA1, 0x49, 0x42, 0xB2, 0x8F, 0xFF, 0xC4, 0x00, 0x18,
0x11, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0x06, 0x21, 0x31, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x03, 0x01, 0x01, 0x3F, 0x01,
0x8D, 0xBE, 0xCB, 0x3F, 0xFF, 0xC4, 0x00, 0x17, 0x11, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x61, 0xFF, 0xDA, 0x00,
0x08, 0x01, 0x02, 0x01, 0x01, 0x3F, 0x01, 0x72, 0xC6, 0x9F, 0xFF, 0xC4, 0x00, 0x15, 0x10, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x06, 0x3F, 0x02, 0x88, 0x88, 0xFF, 0xC4, 0x00,
0x15, 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x31, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3F, 0x21, 0x9B, 0x16,
0x2C, 0xDF, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10,
0x0B, 0xFF, 0xC4, 0x00, 0x15, 0x11, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x03, 0x01, 0x01,
0x3F, 0x10, 0x9E, 0xFF, 0xC4, 0x00, 0x15, 0x11, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x02,
0x01, 0x01, 0x3F, 0x10, 0xB1, 0xFF, 0xC4, 0x00, 0x15, 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0xDA, 0x00, 0x08,
0x01, 0x01, 0x00, 0x01, 0x3F, 0x10, 0x94, 0x84, 0x84, 0x94, 0xFF, 0xD9,
}
@(private)
JPEG_T_CMYK := [431]byte{
0xFF, 0xD8, 0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03, 0x03, 0x03,
0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07, 0x07, 0x06,
0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D, 0x0E, 0x11,
0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F, 0x17, 0x18,
0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xC0, 0x00, 0x14, 0x08, 0x00, 0x10, 0x00, 0x10,
0x04, 0x43, 0x11, 0x00, 0x4D, 0x11, 0x00, 0x59, 0x11, 0x00, 0x4B, 0x11, 0x00, 0xFF, 0xC4, 0x00,
0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4,
0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00,
0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13,
0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15,
0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46,
0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86,
0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4,
0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2,
0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA, 0x00, 0x0E, 0x04, 0x43, 0x00, 0x4D, 0x00, 0x59, 0x00,
0x4B, 0x00, 0x00, 0x3F, 0x00, 0xFA, 0xF7, 0xF6, 0x92, 0xFF, 0x00, 0x97, 0xAF, 0xC6, 0xBE, 0xBD,
0xFF, 0x00, 0x86, 0x92, 0xFF, 0x00, 0xA7, 0xAF, 0xFC, 0x7A, 0xBE, 0x3C, 0xAF, 0xD0, 0x3A, 0xFC,
0xAA, 0xFD, 0xA4, 0xBF, 0xE5, 0xEB, 0xF1, 0xA3, 0xFE, 0x1A, 0x4B, 0xFE, 0x9E, 0xBF, 0xF1, 0xEA,
0x28, 0xAF, 0xD5, 0x5F, 0xDA, 0x4B, 0xFE, 0x5E, 0xBF, 0x1A, 0xFC, 0xAA, 0xFF, 0x00, 0x86, 0x92,
0xFF, 0x00, 0xA7, 0xAF, 0xFC, 0x7A, 0x8A, 0x2B, 0xF2, 0xAB, 0xF6, 0x92, 0xFF, 0x00, 0x97, 0xAF,
0xC6, 0x8F, 0xF8, 0x69, 0x2F, 0xFA, 0x7A, 0xFF, 0x00, 0xC7, 0xA8, 0xA2, 0xBF, 0xFF, 0xD9,
}
@(private)
JPEG_T_RST := [410]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05,
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B,
0x0B, 0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F, 0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13,
0x14, 0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17,
0x22, 0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x10,
0x00, 0x20, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03,
0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00,
0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72,
0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55,
0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2,
0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDD,
0x00, 0x04, 0x00, 0x01, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3F, 0x00, 0xF0, 0x5D,
0x07, 0x4D, 0xFB, 0xBF, 0x2D, 0x7F, 0xFF, 0xD0, 0xE1, 0x74, 0x1D, 0x37, 0xEE, 0xFC, 0xB5, 0xFF,
0xD1, 0x9B, 0x41, 0xD3, 0x7E, 0xEF, 0xCB, 0x5F, 0xFF, 0xD2, 0xF4, 0x6D, 0x07, 0x4D, 0xFB, 0xBF,
0x2D, 0x7F, 0xFF, 0xD3, 0xF3, 0x8D, 0x07, 0x4D, 0xFB, 0xBF, 0x2D, 0x7F, 0xFF, 0xD4, 0x83, 0x41,
0xD3, 0x7E, 0xEF, 0xCB, 0x5F, 0xFF, 0xD5, 0xEE, 0x74, 0x1D, 0x37, 0xEE, 0xFC, 0xB5, 0xFF, 0xD6,
0xF7, 0x9D, 0x07, 0x4D, 0xFB, 0xBF, 0x2D, 0x7F, 0xFF, 0xD9,
}
@(private)
JPEG_T_NORST := [388]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05,
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B,
0x0B, 0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F, 0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13,
0x14, 0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17,
0x22, 0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x10,
0x00, 0x20, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03,
0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00,
0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72,
0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55,
0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2,
0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA,
0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3F, 0x00, 0xF0, 0x5D, 0x07, 0x4D, 0xFB, 0xBF, 0x2D, 0x7A,
0x06, 0x83, 0xA6, 0xFD, 0xDF, 0x96, 0xBD, 0x03, 0x41, 0xD3, 0x7E, 0xEF, 0xCB, 0x5E, 0x81, 0xA0,
0xE9, 0xBF, 0x77, 0xE5, 0xAF, 0x9C, 0xB4, 0x1D, 0x37, 0xEE, 0xFC, 0xB5, 0xE8, 0x1A, 0x0E, 0x9B,
0xF7, 0x7E, 0x5A, 0xF4, 0x0D, 0x07, 0x4D, 0xFB, 0xBF, 0x2D, 0x7A, 0x06, 0x83, 0xA6, 0xFD, 0xDF,
0x96, 0xBF, 0xFF, 0xD9,
}
@(private)
JPEG_T_DCFLAT := [153]byte{
0xFF, 0xD8, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x08, 0x00, 0x08,
0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xDA, 0x00, 0x08, 0x01,
0x01, 0x00, 0x00, 0x3F, 0x00, 0xEA, 0x1F, 0xFF, 0xD9,
}
@(private)
JPEG_T_ODDSAMP := [177]byte{
0xFF, 0xD8, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x08, 0x00, 0x20,
0x03, 0x01, 0x41, 0x00, 0x02, 0x11, 0x00, 0x03, 0x21, 0x00, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00,
0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0x14, 0x10,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x3F, 0x00, 0xFE,
0x37, 0xDF, 0xD4, 0x03, 0xF5, 0x01, 0xFD, 0x40, 0x3E, 0x5F, 0x7D, 0xE0, 0xFC, 0x1F, 0x7F, 0xFF,
0xD9,
}
@(private)
JPEG_T_PROGRST := [408]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05,
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B,
0x0B, 0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F, 0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13,
0x14, 0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17,
0x22, 0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0xFF, 0xC2, 0x00, 0x0B, 0x08, 0x00, 0x10,
0x00, 0x10, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xDD, 0x00, 0x04,
0x00, 0x01, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x3F, 0xFF, 0xD0, 0x3F,
0xFF, 0xD1, 0x3F, 0xFF, 0xD2, 0x3F, 0xFF, 0xC4, 0x00, 0x15, 0x10, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xDA, 0x00,
0x08, 0x01, 0x01, 0x00, 0x01, 0x05, 0x02, 0xB4, 0x7F, 0xFF, 0xD0, 0xB4, 0x7F, 0xFF, 0xD1, 0xB4,
0x7F, 0xFF, 0xD2, 0xB4, 0x7F, 0xFF, 0xC4, 0x00, 0x1B, 0x10, 0x00, 0x01, 0x04, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x11, 0x14, 0x32, 0x54,
0x83, 0x91, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x06, 0x3F, 0x02, 0xC1, 0x87, 0xB0, 0x8F,
0x8D, 0x55, 0xFF, 0xD0, 0xC1, 0x87, 0xB0, 0x8F, 0x8D, 0x55, 0xFF, 0xD1, 0xC1, 0x87, 0xB0, 0x8F,
0x8D, 0x55, 0xFF, 0xD2, 0xC1, 0x87, 0xB0, 0x8F, 0x8D, 0x55, 0xFF, 0xC4, 0x00, 0x18, 0x10, 0x00,
0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0x71, 0xF0, 0xF1, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3F, 0x21, 0xAB, 0x35,
0x36, 0x7F, 0xFF, 0xD0, 0xAB, 0x35, 0x36, 0x7F, 0xFF, 0xD1, 0xAB, 0x35, 0x36, 0x7F, 0xFF, 0xD2,
0xAB, 0x35, 0x36, 0x7F, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x10, 0xFF, 0x00,
0xFF, 0xD0, 0xFF, 0x00, 0xFF, 0xD1, 0xFF, 0x00, 0xFF, 0xD2, 0xFF, 0x00, 0xFF, 0xC4, 0x00, 0x18,
0x10, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x11, 0xF0, 0x21, 0x51, 0x71, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3F, 0x10,
0x7A, 0x8E, 0x95, 0x13, 0xFF, 0xD0, 0x7A, 0x8E, 0x95, 0x13, 0xFF, 0xD1, 0x7A, 0x8E, 0x95, 0x13,
0xFF, 0xD2, 0x7A, 0x8E, 0x95, 0x13, 0xFF, 0xD9,
}
@(private)
JPEG_T_BITS12 := [154]byte{
0xFF, 0xD8, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xC0, 0x00, 0x0B, 0x0C, 0x00, 0x08, 0x00, 0x08,
0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xDA, 0x00, 0x08, 0x01,
0x01, 0x00, 0x00, 0x3F, 0x00, 0xFE, 0xA0, 0x1F, 0xFF, 0xD9,
}
// The bars image above encoded four ways: baseline and progressive, each with
// and without restart markers. libjpeg-turbo at quality 90 over 64x64 pixels of
// eight-row bars, which is what a page of text costs an encoder -- a handful of
// bits per MCU. `-restart 3` and `-restart 2` are MCU rows, so the DRI segments
// read 24 and 16.
@(private)
JPEG_T_LOWENT := [392]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03,
0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07,
0x07, 0x06, 0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D,
0x0E, 0x11, 0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F,
0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x40,
0x00, 0x40, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03,
0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00,
0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72,
0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55,
0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2,
0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA,
0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3F, 0x00, 0xFD, 0x10, 0xA2, 0x8A, 0x28, 0xA2, 0x8A, 0x2B,
0xF0, 0x12, 0x8A, 0x28, 0xA2, 0x8A, 0x28, 0xAF, 0xDF, 0xBA, 0x28, 0xA2, 0x8A, 0x28, 0xA2, 0xBF,
0x01, 0x28, 0xA2, 0x8A, 0x28, 0xA2, 0x8A, 0xFD, 0xFB, 0xA2, 0x8A, 0x28, 0xA2, 0x8A, 0x2B, 0xF0,
0x12, 0x8A, 0x28, 0xA2, 0x8A, 0x28, 0xAF, 0xDF, 0xBA, 0x28, 0xA2, 0x8A, 0x28, 0xA2, 0xBF, 0x01,
0x28, 0xA2, 0x8A, 0x28, 0xA2, 0x8A, 0xFF, 0xD9,
}
@(private)
JPEG_T_LOWENT_RST := [403]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03,
0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07,
0x07, 0x06, 0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D,
0x0E, 0x11, 0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F,
0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xC0, 0x00, 0x0B, 0x08, 0x00, 0x40,
0x00, 0x40, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03,
0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00,
0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72,
0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55,
0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2,
0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDD,
0x00, 0x04, 0x00, 0x18, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3F, 0x00, 0xFD, 0x10,
0xA2, 0x8A, 0x28, 0xA2, 0x8A, 0x2B, 0xF0, 0x12, 0x8A, 0x28, 0xA2, 0x8A, 0x28, 0xAF, 0xDF, 0xBA,
0x28, 0xA2, 0x8A, 0x28, 0xA2, 0xBF, 0xFF, 0xD0, 0xF8, 0x52, 0x8A, 0x28, 0xA2, 0x8A, 0x28, 0xAF,
0xDF, 0xBA, 0x28, 0xA2, 0x8A, 0x28, 0xA2, 0xBF, 0x01, 0x28, 0xA2, 0x8A, 0x28, 0xA2, 0x8A, 0xFF,
0xD1, 0xFD, 0x10, 0xA2, 0x8A, 0x28, 0xA2, 0x8A, 0x2B, 0xF0, 0x12, 0x8A, 0x28, 0xA2, 0x8A, 0x28,
0xAF, 0xFF, 0xD9,
}
@(private)
JPEG_T_LOWENTP := [308]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03,
0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07,
0x07, 0x06, 0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D,
0x0E, 0x11, 0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F,
0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xC2, 0x00, 0x0B, 0x08, 0x00, 0x40,
0x00, 0x40, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x15, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xDA, 0x00,
0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x40, 0x20, 0x2F, 0xE0, 0x10, 0x08, 0x0B,
0xF8, 0x04, 0x02, 0x02, 0xFE, 0x01, 0x00, 0x80, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xFF, 0xDA,
0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x05, 0x02, 0x01, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xFF,
0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x06, 0x3F, 0x02, 0x01, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3F, 0x21, 0x01, 0xFF, 0xDA, 0x00, 0x08, 0x01,
0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
0x00, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3F,
0x10, 0x01, 0xFF, 0xD9,
}
@(private)
JPEG_T_LOWENTP_RST := [365]byte{
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03,
0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07,
0x07, 0x06, 0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D,
0x0E, 0x11, 0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F,
0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xC2, 0x00, 0x0B, 0x08, 0x00, 0x40,
0x00, 0x40, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x15, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xDD, 0x00,
0x04, 0x00, 0x10, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x40,
0x20, 0x3F, 0xFF, 0xD0, 0xA2, 0x00, 0x40, 0x20, 0x3F, 0xFF, 0xD1, 0xA2, 0x00, 0x40, 0x20, 0x3F,
0xFF, 0xD2, 0xA2, 0x00, 0x40, 0x20, 0x3F, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xFF, 0xDA, 0x00,
0x08, 0x01, 0x01, 0x00, 0x01, 0x05, 0x02, 0x07, 0xFF, 0xD0, 0x07, 0xFF, 0xD1, 0x07, 0xFF, 0xD2,
0x07, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x06, 0x3F,
0x02, 0x07, 0xFF, 0xD0, 0x07, 0xFF, 0xD1, 0x07, 0xFF, 0xD2, 0x07, 0xFF, 0xC4, 0x00, 0x14, 0x10,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3F, 0x21, 0x07, 0xFF, 0xD0, 0x07, 0xFF,
0xD1, 0x07, 0xFF, 0xD2, 0x07, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
0xFF, 0x00, 0xFF, 0xD0, 0x00, 0xFF, 0x00, 0xFF, 0xD1, 0x00, 0xFF, 0x00, 0xFF, 0xD2, 0x00, 0xFF,
0x00, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3F,
0x10, 0x07, 0xFF, 0xD0, 0x07, 0xFF, 0xD1, 0x07, 0xFF, 0xD2, 0x07, 0xFF, 0xD9,
}