icc_codec_common.cc (5747B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include "lib/jxl/icc_codec_common.h" 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <string> 12 #include <vector> 13 14 #include "lib/jxl/base/byte_order.h" 15 #include "lib/jxl/fields.h" 16 #include "lib/jxl/padded_bytes.h" 17 18 namespace jxl { 19 namespace { 20 uint8_t ByteKind1(uint8_t b) { 21 if ('a' <= b && b <= 'z') return 0; 22 if ('A' <= b && b <= 'Z') return 0; 23 if ('0' <= b && b <= '9') return 1; 24 if (b == '.' || b == ',') return 1; 25 if (b == 0) return 2; 26 if (b == 1) return 3; 27 if (b < 16) return 4; 28 if (b == 255) return 6; 29 if (b > 240) return 5; 30 return 7; 31 } 32 33 uint8_t ByteKind2(uint8_t b) { 34 if ('a' <= b && b <= 'z') return 0; 35 if ('A' <= b && b <= 'Z') return 0; 36 if ('0' <= b && b <= '9') return 1; 37 if (b == '.' || b == ',') return 1; 38 if (b < 16) return 2; 39 if (b > 240) return 3; 40 return 4; 41 } 42 43 template <typename T> 44 T PredictValue(T p1, T p2, T p3, int order) { 45 if (order == 0) return p1; 46 if (order == 1) return 2 * p1 - p2; 47 if (order == 2) return 3 * p1 - 3 * p2 + p3; 48 return 0; 49 } 50 } // namespace 51 52 uint32_t DecodeUint32(const uint8_t* data, size_t size, size_t pos) { 53 return pos + 4 > size ? 0 : LoadBE32(data + pos); 54 } 55 56 void EncodeUint32(size_t pos, uint32_t value, PaddedBytes* data) { 57 if (pos + 4 > data->size()) return; 58 StoreBE32(value, data->data() + pos); 59 } 60 61 void AppendUint32(uint32_t value, PaddedBytes* data) { 62 data->resize(data->size() + 4); 63 EncodeUint32(data->size() - 4, value, data); 64 } 65 66 typedef std::array<uint8_t, 4> Tag; 67 68 Tag DecodeKeyword(const uint8_t* data, size_t size, size_t pos) { 69 if (pos + 4 > size) return {{' ', ' ', ' ', ' '}}; 70 return {{data[pos], data[pos + 1], data[pos + 2], data[pos + 3]}}; 71 } 72 73 void EncodeKeyword(const Tag& keyword, uint8_t* data, size_t size, size_t pos) { 74 if (keyword.size() != 4 || pos + 3 >= size) return; 75 for (size_t i = 0; i < 4; ++i) data[pos + i] = keyword[i]; 76 } 77 78 void AppendKeyword(const Tag& keyword, PaddedBytes* data) { 79 JXL_ASSERT(keyword.size() == 4); 80 data->append(keyword); 81 } 82 83 // Checks if a + b > size, taking possible integer overflow into account. 84 Status CheckOutOfBounds(uint64_t a, uint64_t b, uint64_t size) { 85 uint64_t pos = a + b; 86 if (pos > size) return JXL_FAILURE("Out of bounds"); 87 if (pos < a) return JXL_FAILURE("Out of bounds"); // overflow happened 88 return true; 89 } 90 91 Status CheckIs32Bit(uint64_t v) { 92 static constexpr const uint64_t kUpper32 = ~static_cast<uint64_t>(0xFFFFFFFF); 93 if ((v & kUpper32) != 0) return JXL_FAILURE("32-bit value expected"); 94 return true; 95 } 96 97 const uint8_t kIccInitialHeaderPrediction[kICCHeaderSize] = { 98 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 'm', 'n', 't', 'r', 99 'R', 'G', 'B', ' ', 'X', 'Y', 'Z', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 100 0, 0, 0, 0, 'a', 'c', 's', 'p', 0, 0, 0, 0, 0, 0, 0, 0, 101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102 0, 0, 0, 0, 0, 0, 246, 214, 0, 1, 0, 0, 0, 0, 211, 45, 103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106 }; 107 108 Span<const uint8_t> ICCInitialHeaderPrediction() { 109 return Bytes(kIccInitialHeaderPrediction); 110 } 111 112 void ICCPredictHeader(const uint8_t* icc, size_t size, uint8_t* header, 113 size_t pos) { 114 if (pos == 8 && size >= 8) { 115 header[80] = icc[4]; 116 header[81] = icc[5]; 117 header[82] = icc[6]; 118 header[83] = icc[7]; 119 } 120 if (pos == 41 && size >= 41) { 121 if (icc[40] == 'A') { 122 header[41] = 'P'; 123 header[42] = 'P'; 124 header[43] = 'L'; 125 } 126 if (icc[40] == 'M') { 127 header[41] = 'S'; 128 header[42] = 'F'; 129 header[43] = 'T'; 130 } 131 } 132 if (pos == 42 && size >= 42) { 133 if (icc[40] == 'S' && icc[41] == 'G') { 134 header[42] = 'I'; 135 header[43] = ' '; 136 } 137 if (icc[40] == 'S' && icc[41] == 'U') { 138 header[42] = 'N'; 139 header[43] = 'W'; 140 } 141 } 142 } 143 144 // Predicts a value with linear prediction of given order (0-2), for integers 145 // with width bytes and given stride in bytes between values. 146 // The start position is at start + i, and the relevant modulus of i describes 147 // which byte of the multi-byte integer is being handled. 148 // The value start + i must be at least stride * 4. 149 uint8_t LinearPredictICCValue(const uint8_t* data, size_t start, size_t i, 150 size_t stride, size_t width, int order) { 151 size_t pos = start + i; 152 if (width == 1) { 153 uint8_t p1 = data[pos - stride]; 154 uint8_t p2 = data[pos - stride * 2]; 155 uint8_t p3 = data[pos - stride * 3]; 156 return PredictValue(p1, p2, p3, order); 157 } else if (width == 2) { 158 size_t p = start + (i & ~1); 159 uint16_t p1 = (data[p - stride * 1] << 8) + data[p - stride * 1 + 1]; 160 uint16_t p2 = (data[p - stride * 2] << 8) + data[p - stride * 2 + 1]; 161 uint16_t p3 = (data[p - stride * 3] << 8) + data[p - stride * 3 + 1]; 162 uint16_t pred = PredictValue(p1, p2, p3, order); 163 return (i & 1) ? (pred & 255) : ((pred >> 8) & 255); 164 } else { 165 size_t p = start + (i & ~3); 166 uint32_t p1 = DecodeUint32(data, pos, p - stride); 167 uint32_t p2 = DecodeUint32(data, pos, p - stride * 2); 168 uint32_t p3 = DecodeUint32(data, pos, p - stride * 3); 169 uint32_t pred = PredictValue(p1, p2, p3, order); 170 unsigned shiftbytes = 3 - (i & 3); 171 return (pred >> (shiftbytes * 8)) & 255; 172 } 173 } 174 175 size_t ICCANSContext(size_t i, size_t b1, size_t b2) { 176 if (i <= 128) return 0; 177 return 1 + ByteKind1(b1) + ByteKind2(b2) * 8; 178 } 179 180 } // namespace jxl