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