/src/libjxl/lib/jxl/icc_codec_common.cc
Line | Count | Source (jump to first uncovered line) |
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 <array> |
9 | | #include <cstddef> |
10 | | #include <cstdint> |
11 | | #include <tuple> |
12 | | |
13 | | #include "lib/jxl/base/byte_order.h" |
14 | | #include "lib/jxl/base/status.h" |
15 | | #include "lib/jxl/padded_bytes.h" |
16 | | |
17 | | namespace jxl { |
18 | | namespace { |
19 | 3.75M | uint8_t ByteKind1(uint8_t b) { |
20 | 3.75M | if ('a' <= b && b <= 'z') return 0; |
21 | 3.74M | if ('A' <= b && b <= 'Z') return 0; |
22 | 3.70M | if ('0' <= b && b <= '9') return 1; |
23 | 3.70M | if (b == '.' || b == ',') return 1; |
24 | 3.69M | if (b == 0) return 2; |
25 | 540k | if (b == 1) return 3; |
26 | 494k | if (b < 16) return 4; |
27 | 134k | if (b == 255) return 6; |
28 | 130k | if (b > 240) return 5; |
29 | 121k | return 7; |
30 | 130k | } |
31 | | |
32 | 3.75M | uint8_t ByteKind2(uint8_t b) { |
33 | 3.75M | if ('a' <= b && b <= 'z') return 0; |
34 | 3.74M | if ('A' <= b && b <= 'Z') return 0; |
35 | 3.70M | if ('0' <= b && b <= '9') return 1; |
36 | 3.70M | if (b == '.' || b == ',') return 1; |
37 | 3.69M | if (b < 16) return 2; |
38 | 134k | if (b > 240) return 3; |
39 | 121k | return 4; |
40 | 134k | } |
41 | | |
42 | | template <typename T> |
43 | 96.3k | T PredictValue(T p1, T p2, T p3, int order) { |
44 | 96.3k | if (order == 0) return p1; |
45 | 77.4k | if (order == 1) return 2 * p1 - p2; |
46 | 6.78k | if (order == 2) return 3 * p1 - 3 * p2 + p3; |
47 | 0 | return 0; |
48 | 6.78k | } icc_codec_common.cc:unsigned char jxl::(anonymous namespace)::PredictValue<unsigned char>(unsigned char, unsigned char, unsigned char, int) Line | Count | Source | 43 | 9.89k | T PredictValue(T p1, T p2, T p3, int order) { | 44 | 9.89k | if (order == 0) return p1; | 45 | 7.20k | if (order == 1) return 2 * p1 - p2; | 46 | 4.43k | if (order == 2) return 3 * p1 - 3 * p2 + p3; | 47 | 0 | return 0; | 48 | 4.43k | } |
icc_codec_common.cc:unsigned short jxl::(anonymous namespace)::PredictValue<unsigned short>(unsigned short, unsigned short, unsigned short, int) Line | Count | Source | 43 | 79.0k | T PredictValue(T p1, T p2, T p3, int order) { | 44 | 79.0k | if (order == 0) return p1; | 45 | 68.0k | if (order == 1) return 2 * p1 - p2; | 46 | 2.11k | if (order == 2) return 3 * p1 - 3 * p2 + p3; | 47 | 0 | return 0; | 48 | 2.11k | } |
icc_codec_common.cc:unsigned int jxl::(anonymous namespace)::PredictValue<unsigned int>(unsigned int, unsigned int, unsigned int, int) Line | Count | Source | 43 | 7.41k | T PredictValue(T p1, T p2, T p3, int order) { | 44 | 7.41k | if (order == 0) return p1; | 45 | 2.17k | if (order == 1) return 2 * p1 - p2; | 46 | 248 | if (order == 2) return 3 * p1 - 3 * p2 + p3; | 47 | 0 | return 0; | 48 | 248 | } |
|
49 | | } // namespace |
50 | | |
51 | 22.2k | uint32_t DecodeUint32(const uint8_t* data, size_t size, size_t pos) { |
52 | 22.2k | return pos + 4 > size ? 0 : LoadBE32(data + pos); |
53 | 22.2k | } |
54 | | |
55 | 21.9k | Status AppendUint32(uint32_t value, PaddedBytes* data) { |
56 | 21.9k | size_t pos = data->size(); |
57 | 21.9k | JXL_RETURN_IF_ERROR(data->resize(pos + 4)); |
58 | 21.9k | StoreBE32(value, data->data() + pos); |
59 | 21.9k | return true; |
60 | 21.9k | } |
61 | | |
62 | 590 | Tag DecodeKeyword(const uint8_t* data, size_t size, size_t pos) { |
63 | 590 | if (pos + 4 > size) return {{' ', ' ', ' ', ' '}}; |
64 | 590 | return {{data[pos], data[pos + 1], data[pos + 2], data[pos + 3]}}; |
65 | 590 | } |
66 | | |
67 | 0 | void EncodeKeyword(const Tag& keyword, uint8_t* data, size_t size, size_t pos) { |
68 | 0 | if (keyword.size() != 4 || pos + 3 >= size) return; |
69 | 0 | for (size_t i = 0; i < 4; ++i) data[pos + i] = keyword[i]; |
70 | 0 | } |
71 | | |
72 | 11.5k | Status AppendKeyword(const Tag& keyword, PaddedBytes* data) { |
73 | 11.5k | static_assert(std::tuple_size<Tag>{} == 4, "Tag should be 4-bytes"); |
74 | 11.5k | return data->append(keyword); |
75 | 11.5k | } |
76 | | |
77 | | // Checks if a + b > size, taking possible integer overflow into account. |
78 | 8.42k | Status CheckOutOfBounds(uint64_t a, uint64_t b, uint64_t size) { |
79 | 8.42k | uint64_t pos = a + b; |
80 | 8.42k | if (pos > size) return JXL_FAILURE("Out of bounds"); |
81 | 8.32k | if (pos < a) return JXL_FAILURE("Out of bounds"); // overflow happened |
82 | 8.32k | return true; |
83 | 8.32k | } |
84 | | |
85 | 21.1k | Status CheckIs32Bit(uint64_t v) { |
86 | 21.1k | static constexpr const uint64_t kUpper32 = ~static_cast<uint64_t>(0xFFFFFFFF); |
87 | 21.1k | if ((v & kUpper32) != 0) return JXL_FAILURE("32-bit value expected"); |
88 | 21.0k | return true; |
89 | 21.1k | } |
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 | 617 | std::array<uint8_t, kICCHeaderSize> ICCInitialHeaderPrediction(uint32_t size) { |
103 | 617 | std::array<uint8_t, kICCHeaderSize> copy(kIccInitialHeaderPrediction); |
104 | 617 | StoreBE32(size, copy.data()); |
105 | 617 | return copy; |
106 | 617 | } |
107 | | |
108 | | void ICCPredictHeader(const uint8_t* icc, size_t size, uint8_t* header, |
109 | 58.4k | size_t pos) { |
110 | 58.4k | if (pos == 8 && size >= 8) { |
111 | 481 | header[80] = icc[4]; |
112 | 481 | header[81] = icc[5]; |
113 | 481 | header[82] = icc[6]; |
114 | 481 | header[83] = icc[7]; |
115 | 481 | } |
116 | 58.4k | if (pos == 41 && size >= 41) { |
117 | 461 | if (icc[40] == 'A') { |
118 | 3 | header[41] = 'P'; |
119 | 3 | header[42] = 'P'; |
120 | 3 | header[43] = 'L'; |
121 | 3 | } |
122 | 461 | if (icc[40] == 'M') { |
123 | 2 | header[41] = 'S'; |
124 | 2 | header[42] = 'F'; |
125 | 2 | header[43] = 'T'; |
126 | 2 | } |
127 | 461 | } |
128 | 58.4k | if (pos == 42 && size >= 42) { |
129 | 461 | if (icc[40] == 'S' && icc[41] == 'G') { |
130 | 0 | header[42] = 'I'; |
131 | 0 | header[43] = ' '; |
132 | 0 | } |
133 | 461 | if (icc[40] == 'S' && icc[41] == 'U') { |
134 | 0 | header[42] = 'N'; |
135 | 0 | header[43] = 'W'; |
136 | 0 | } |
137 | 461 | } |
138 | 58.4k | } |
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 | 96.3k | size_t stride, size_t width, int order) { |
147 | 96.3k | size_t pos = start + i; |
148 | 96.3k | if (width == 1) { |
149 | 9.89k | uint8_t p1 = data[pos - stride]; |
150 | 9.89k | uint8_t p2 = data[pos - stride * 2]; |
151 | 9.89k | uint8_t p3 = data[pos - stride * 3]; |
152 | 9.89k | return PredictValue(p1, p2, p3, order); |
153 | 86.4k | } else if (width == 2) { |
154 | 79.0k | size_t p = start + (i & ~1); |
155 | 79.0k | uint16_t p1 = (data[p - stride * 1] << 8) + data[p - stride * 1 + 1]; |
156 | 79.0k | uint16_t p2 = (data[p - stride * 2] << 8) + data[p - stride * 2 + 1]; |
157 | 79.0k | uint16_t p3 = (data[p - stride * 3] << 8) + data[p - stride * 3 + 1]; |
158 | 79.0k | uint16_t pred = PredictValue(p1, p2, p3, order); |
159 | 79.0k | return (i & 1) ? (pred & 255) : ((pred >> 8) & 255); |
160 | 79.0k | } else { |
161 | 7.41k | size_t p = start + (i & ~3); |
162 | 7.41k | uint32_t p1 = DecodeUint32(data, pos, p - stride); |
163 | 7.41k | uint32_t p2 = DecodeUint32(data, pos, p - stride * 2); |
164 | 7.41k | uint32_t p3 = DecodeUint32(data, pos, p - stride * 3); |
165 | 7.41k | uint32_t pred = PredictValue(p1, p2, p3, order); |
166 | 7.41k | unsigned shiftbytes = 3 - (i & 3); |
167 | 7.41k | return (pred >> (shiftbytes * 8)) & 255; |
168 | 7.41k | } |
169 | 96.3k | } |
170 | | |
171 | 3.88M | size_t ICCANSContext(size_t i, size_t b1, size_t b2) { |
172 | 3.88M | if (i <= 128) return 0; |
173 | 3.75M | return 1 + ByteKind1(b1) + ByteKind2(b2) * 8; |
174 | 3.88M | } |
175 | | |
176 | | } // namespace jxl |