| // Copyright 2025 The Wuffs Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| // |
| // SPDX-License-Identifier: Apache-2.0 OR MIT |
| |
| package lowleveljpeg |
| |
| // ifElse is like C's (condition ? whenTrue : whenFalse) expression. |
| func ifElse(condition bool, whenTrue int64, whenFalse int64) int64 { |
| if condition { |
| return whenTrue |
| } |
| return whenFalse |
| } |
| |
| const ( |
| fmtHex = "0123456789ABCDEF" |
| fmtSep = " \n" // 7 spaces and then a new line. |
| fmtS16 = " \n" // 15 spaces and then a new line. |
| ) |
| |
| const ( |
| // BlockU8NeutralValue is the neutral value for a BlockU8, which holds |
| // unsigned uint8 values in the range [0x00, 0xFF]. |
| BlockU8NeutralValue = 0x80 |
| |
| // BlockI16NeutralValue is the neutral value for a BlockI16, which holds |
| // signed int16 values in the range [-0x8000, +0x7FFF]. |
| BlockI16NeutralValue = 0 |
| ) |
| |
| // BlockU8 is an 8×8 block of uint8 values, such as a block of red, green, blue |
| // or gray pixel values. |
| // |
| // It is indexed in XY (not DCT) space. If b is a BlockU8 then b[0] is the |
| // top-left corner and b[8] is one pixel below that. |
| type BlockU8 [64]uint8 |
| |
| // String returns b in human-readable form. |
| func (b BlockU8) String() string { |
| buf := [64 * 3]byte{} |
| for i, value := range b { |
| buf[(3*i)+0] = fmtHex[15&(value>>0x04)] |
| buf[(3*i)+1] = fmtHex[15&(value>>0x00)] |
| buf[(3*i)+2] = fmtSep[7&i] |
| } |
| return string(buf[:]) |
| } |
| |
| // SetToNeutral sets each element to BlockU8NeutralValue. |
| func (b *BlockU8) SetToNeutral() { |
| if b == nil { |
| return |
| } |
| for i := range b { |
| b[i] = BlockU8NeutralValue |
| } |
| } |
| |
| // ForwardDCT returns the FDCT (Forward Discrete Cosine Transform) of b. |
| func (b *BlockU8) ForwardDCT() (ret BlockI16) { |
| ret.ForwardDCTFrom(b) |
| return ret |
| } |
| |
| // ForwardDCTFrom sets *dst to src.ForwardDCT(). |
| func (dst *BlockI16) ForwardDCTFrom(src *BlockU8) { |
| if dst == nil { |
| return |
| } else if src == nil { |
| dst.SetToNeutral() |
| return |
| } |
| |
| // Convert from uint8 to int64, applying an 0x80 bias. |
| srcI64 := [64]int64{} |
| for i, v := range src { |
| srcI64[i] = int64(v) - 0x80 |
| } |
| |
| // Iterate in DCT space (outer) and XY space (inner). |
| for v := 0; v < 8; v++ { |
| halfAlphaV16 := ifElse(v == 0, fixedPointInv2Sqrt2, fixedPointHalf) |
| for u := 0; u < 8; u++ { |
| halfAlphaU16 := ifElse(u == 0, fixedPointInv2Sqrt2, fixedPointHalf) |
| // alphas32 is two 16.16 fixed point values multiplied together, as |
| // a 32.32 fixed point value. |
| alphas32 := halfAlphaV16 * halfAlphaU16 |
| sum32 := int64(0) |
| |
| for y := 0; y < 8; y++ { |
| for x := 0; x < 8; x++ { |
| // c32 is two 16.16 fixed point values multiplied together, |
| // as a 32.32 fixed point value. |
| // |
| // sum32 accumulates a 32.32 fixed point value. |
| c32 := int64(cosines[(((2*x)+1)*u)&31]) * |
| int64(cosines[(((2*y)+1)*v)&31]) |
| sum32 += srcI64[(8*y)+x] * c32 |
| } |
| } |
| |
| // Calculate alphasSum32 as 32.32 fixed point. |
| alphas16 := (alphas32 + (1 << 15)) >> 16 |
| sum16 := (sum32 + (1 << 15)) >> 16 |
| alphasSum32 := alphas16 * sum16 |
| |
| // Store alphasSum32 as 16.0 fixed point. |
| result0 := (alphasSum32 + (1 << 31)) >> 32 |
| dst[(8*v)+u] = int16(result0) |
| } |
| } |
| } |
| |
| // BlockI16 is an 8×8 block of int16 values, such as a block of JPEG coefficients. |
| // |
| // It is indexed in DCT (not XY) space. If b is a BlockI16 then b[0] is the DC |
| // coefficient and every other element is an AC coefficient. |
| // |
| // The horizontal-only AC coefficients are b[1], b[2], ..., b[7], in order from |
| // low-frequency to high-frequency. |
| // |
| // The vertical-only AC coefficients are b[8], b[16], ..., b[56], in order from |
| // low-frequency to high-frequency. |
| type BlockI16 [64]int16 |
| |
| // String returns b in human-readable form. |
| func (b BlockI16) String() string { |
| buf := [64 * 5]byte{} |
| for i, value := range b { |
| buf[(5*i)+0] = fmtHex[15&(value>>0x0C)] |
| buf[(5*i)+1] = fmtHex[15&(value>>0x08)] |
| buf[(5*i)+2] = fmtHex[15&(value>>0x04)] |
| buf[(5*i)+3] = fmtHex[15&(value>>0x00)] |
| buf[(5*i)+4] = fmtSep[7&i] |
| } |
| return string(buf[:]) |
| } |
| |
| // Abs returns the elementwise absolute value of b. |
| func (b *BlockI16) Abs() (ret BlockI16) { |
| if b == nil { |
| return ret |
| } |
| for i, v := range b { |
| if v < 0 { |
| ret[i] = -v |
| } else { |
| ret[i] = +v |
| } |
| } |
| return ret |
| } |
| |
| // SetToNeutral sets each element to BlockI16NeutralValue. |
| func (b *BlockI16) SetToNeutral() { |
| if b == nil { |
| return |
| } |
| for i := range b { |
| b[i] = BlockI16NeutralValue |
| } |
| } |
| |
| // InverseDCT returns the IDCT (Inverse Discrete Cosine Transform) of b. |
| func (b *BlockI16) InverseDCT() (ret BlockU8) { |
| ret.InverseDCTFrom(b) |
| return ret |
| } |
| |
| // InverseDCTFrom sets *dst to src.InverseDCT(). |
| func (dst *BlockU8) InverseDCTFrom(src *BlockI16) { |
| if dst == nil { |
| return |
| } else if src == nil { |
| dst.SetToNeutral() |
| return |
| } |
| |
| // Convert from int16 to int64. |
| srcI64 := [64]int64{} |
| for i, v := range src { |
| srcI64[i] = int64(v) |
| } |
| |
| // Iterate in XY space (outer) and DCT space (inner). |
| for y := 0; y < 8; y++ { |
| for x := 0; x < 8; x++ { |
| alphasSum32 := int64(0) |
| |
| for v := 0; v < 8; v++ { |
| halfAlphaV16 := ifElse(v == 0, fixedPointInv2Sqrt2, fixedPointHalf) |
| for u := 0; u < 8; u++ { |
| halfAlphaU16 := ifElse(u == 0, fixedPointInv2Sqrt2, fixedPointHalf) |
| // alphas16 is two 16.16 fixed point values multiplied |
| // together, as a 48.16 fixed point value. |
| alphas16 := ((halfAlphaV16 * halfAlphaU16) + (1 << 15)) >> 16 |
| |
| // c32 is two 16.16 fixed point values multiplied together, |
| // as a 32.32 fixed point value. |
| // |
| // c16 is c32 as a 48.16 fixed point value. |
| // |
| // alphasSum32 accumulates a 32.32 fixed point value. |
| c32 := int64(cosines[(((2*x)+1)*u)&31]) * |
| int64(cosines[(((2*y)+1)*v)&31]) |
| c16 := (c32 + (1 << 15)) >> 16 |
| alphasSum32 += srcI64[(8*v)+u] * (alphas16 * c16) |
| } |
| } |
| |
| // Store alphasSum32, biased and clamped, as 8.0 fixed point. |
| result0 := (alphasSum32 + (1 << 31)) >> 32 |
| dst[(8*y)+x] = biasAndClamp[result0&1023] |
| } |
| } |
| } |
| |
| // IsValid returns whether b does not contain unexpectedly extreme values for |
| // an 8-bit-depth JPEG - one that is invalid to pass to AddN. ForwardDCT or |
| // ForwardDCTFrom always returns or sets a BlockI16 that IsValid. |
| // |
| // Specifically: |
| // - a DC element is out of range when outside [-1024, +1023]. |
| // - an AC element is out of range when outside [-1023, +1023]. |
| // |
| // A BlockI16 is valid when none of its elements are out of range. |
| func (b *BlockI16) IsValid() bool { |
| if b == nil { |
| return false |
| } |
| if (b[0] < -1024) || (+1023 < b[0]) { |
| return false |
| } |
| for _, v := range b[1:] { |
| if (v < -1023) || (+1023 < v) { |
| return false |
| } |
| } |
| return true |
| } |
| |
| // QuadBlockU8 is like a BlockU8 but it is 16×16 instead of 8×8. |
| // |
| // It is indexed in XY (not DCT) space. If b is a QuadBlockU8 then b[0] is the |
| // top-left corner and b[16] is one pixel below that. |
| type QuadBlockU8 [256]uint8 |
| |
| // String returns b in human-readable form. |
| func (b QuadBlockU8) String() string { |
| buf := [256 * 3]byte{} |
| for i, value := range b { |
| buf[(3*i)+0] = fmtHex[15&(value>>0x04)] |
| buf[(3*i)+1] = fmtHex[15&(value>>0x00)] |
| buf[(3*i)+2] = fmtS16[15&i] |
| } |
| return string(buf[:]) |
| } |
| |
| // SetToNeutral sets each element to BlockU8NeutralValue. |
| func (b *QuadBlockU8) SetToNeutral() { |
| if b == nil { |
| return |
| } |
| for i := range b { |
| b[i] = BlockU8NeutralValue |
| } |
| } |
| |
| // These are "1 / 2" and "1 / (2 * √2)" as 16.16 fixed point values. |
| const ( |
| fixedPointHalf = +0x8000 |
| fixedPointInv2Sqrt2 = +0x5A82 |
| ) |
| |
| // cosines is a cosine table as 16.16 fixed point values. |
| var cosines = [32]int32{ |
| +0x10000, // cos(π/16 * 0) |
| +0x0FB14, // cos(π/16 * 1) |
| +0x0EC83, // cos(π/16 * 2) |
| +0x0D4DB, // cos(π/16 * 3) |
| +0x0B504, // cos(π/16 * 4) |
| +0x08E39, // cos(π/16 * 5) |
| +0x061F7, // cos(π/16 * 6) |
| +0x031F1, // cos(π/16 * 7) |
| |
| +0x00000, // cos(π/16 * 8) |
| -0x031F1, // cos(π/16 * 9) |
| -0x061F7, // cos(π/16 * 10) |
| -0x08E39, // cos(π/16 * 11) |
| -0x0B504, // cos(π/16 * 12) |
| -0x0D4DB, // cos(π/16 * 13) |
| -0x0EC83, // cos(π/16 * 14) |
| -0x0FB14, // cos(π/16 * 15) |
| |
| -0x10000, // cos(π/16 * 16) |
| -0x0FB14, // cos(π/16 * 17) |
| -0x0EC83, // cos(π/16 * 18) |
| -0x0D4DB, // cos(π/16 * 19) |
| -0x0B504, // cos(π/16 * 20) |
| -0x08E39, // cos(π/16 * 21) |
| -0x061F7, // cos(π/16 * 22) |
| -0x031F1, // cos(π/16 * 23) |
| |
| +0x00000, // cos(π/16 * 24) |
| +0x031F1, // cos(π/16 * 25) |
| +0x061F7, // cos(π/16 * 26) |
| +0x08E39, // cos(π/16 * 27) |
| +0x0B504, // cos(π/16 * 28) |
| +0x0D4DB, // cos(π/16 * 29) |
| +0x0EC83, // cos(π/16 * 30) |
| +0x0FB14, // cos(π/16 * 31) |
| } |
| |
| // biasAndClamp[x & 1023] is (x + 0x80), clamped to the range [0x00, 0xFF], for |
| // a signed integer x in the range [-512, +511]. |
| var biasAndClamp = [1024]uint8{ |
| 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, |
| 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, |
| 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, |
| 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, |
| 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, |
| 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, |
| 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, |
| 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, |
| |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, |
| 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, |
| 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, |
| 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, |
| 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, |
| 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, |
| 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, |
| } |