40 #include "compose.hpp"
49 using std::shared_ptr;
51 using std::runtime_error;
54 using boost::optional;
71 auto ptr = j2k->data();
72 auto end = ptr + j2k->size();
74 map<string, uint8_t> markers = {
89 auto marker_name_from_id = [&markers](uint8_t b) -> optional<string> {
90 for (
auto const& i: markers) {
98 auto require_marker = [&](
string name) {
99 if (ptr == end || *ptr != 0xff) {
103 if (ptr == end || *ptr != markers[name]) {
116 auto get_16 = [&]() {
117 if (ptr >= (end - 1)) {
120 auto const a = *ptr++;
121 auto const b = *ptr++;
125 auto get_32 = [&]() -> uint32_t {
126 if (ptr >= (end - 3)) {
129 auto const a = *ptr++;
130 auto const b = *ptr++;
131 auto const c = *ptr++;
132 auto const d = *ptr++;
133 return d | (c << 8) | (b << 16) | (a << 24);
136 auto require_8 = [&](uint8_t value,
string note) {
143 auto require_16 = [&](uint16_t value,
string note) {
150 auto require_32 = [&](uint32_t value,
string note) {
157 require_marker (
"SOC");
158 require_marker (
"SIZ");
159 auto L_siz = get_16();
165 auto const image_width = get_32();
166 auto const image_height = get_32();
167 auto const fourk = image_width > 2048;
168 require_32 (0,
"invalid top-left image x coordinate %1");
169 require_32 (0,
"invalid top-left image y coordinate %1");
170 auto const tile_width = get_32();
171 auto const tile_height = get_32();
172 if (tile_width != image_width || tile_height != image_height) {
173 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_TILE_SIZE });
175 require_32 (0,
"invalid tile anchor x coordinate %1");
176 require_32 (0,
"invalid tile anchor y coordinate %1");
177 require_16 (3,
"invalid component count %1");
178 for (
auto i = 0; i < 3; ++i) {
179 require_8 (12 - 1,
"invalid bit depth %1");
180 require_8 (1,
"invalid horizontal subsampling factor %1");
181 require_8 (1,
"invalid vertical subsampling factor %1");
187 auto num_POC_in_main = 0;
189 auto num_POC_after_main = 0;
190 bool main_header_finished =
false;
195 require_8(0xff,
"missing marker start byte");
196 auto marker_id = get_8();
197 auto marker_name = marker_name_from_id (marker_id);
200 snprintf (buffer, 16,
"%2x", marker_id);
202 }
else if (*marker_name ==
"SOT") {
203 require_16(10,
"invalid SOT size %1");
207 auto tile_parts = get_8();
208 if (!fourk && tile_parts != 3) {
209 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_TILE_PARTS_FOR_2K, raw_convert<string>(tile_parts) });
211 if (fourk && tile_parts != 6) {
212 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_TILE_PARTS_FOR_4K, raw_convert<string>(tile_parts) });
214 main_header_finished =
true;
215 }
else if (*marker_name ==
"SOD") {
216 while (ptr < (end - 1) && (ptr[0] != 0xff || ptr[1] < 0x90)) {
219 }
else if (*marker_name ==
"SIZ") {
221 }
else if (*marker_name ==
"COD") {
224 require_8(1,
"invalid coding style %1");
225 require_8(4,
"invalid progression order %1");
226 require_16(1,
"invalid quality layers count %1");
227 require_8(1,
"invalid multi-component transform flag %1");
228 require_8(fourk ? 6 : 5,
"invalid number of transform levels %1");
229 auto log_code_block_width = get_8();
230 if (log_code_block_width != 3) {
231 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_CODE_BLOCK_WIDTH, raw_convert<string>(4 * (2 << log_code_block_width)) });
233 auto log_code_block_height = get_8();
234 if (log_code_block_height != 3) {
235 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_CODE_BLOCK_HEIGHT, raw_convert<string>(4 * (2 << log_code_block_height)) });
237 require_8(0,
"invalid mode variations");
238 require_8(0,
"invalid wavelet transform type %1");
239 require_8(0x77,
"invalid precinct size %1");
240 require_8(0x88,
"invalid precinct size %1");
241 require_8(0x88,
"invalid precinct size %1");
242 require_8(0x88,
"invalid precinct size %1");
243 require_8(0x88,
"invalid precinct size %1");
244 require_8(0x88,
"invalid precinct size %1");
246 require_8(0x88,
"invalid precinct size %1");
248 }
else if (*marker_name ==
"QCD") {
250 auto const L_qcd = get_16();
251 auto quantization_style = get_8();
252 int guard_bits = (quantization_style >> 5) & 7;
253 if (fourk && guard_bits != 2) {
254 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_4K, raw_convert<string>(guard_bits) });
256 if (!fourk && guard_bits != 1) {
257 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, raw_convert<string>(guard_bits) });
260 }
else if (*marker_name ==
"COC") {
262 require_8(0,
"invalid COC component number");
263 require_8(1,
"invalid coding style %1");
264 require_8(5,
"invalid number of transform levels %1");
265 require_8(3,
"invalid code block width exponent %1");
266 require_8(3,
"invalid code block height exponent %1");
267 require_8(0,
"invalid mode variations");
268 require_8(0x77,
"invalid precinct size %1");
269 require_8(0x88,
"invalid precinct size %1");
270 require_8(0x88,
"invalid precinct size %1");
271 require_8(0x88,
"invalid precinct size %1");
272 require_8(0x88,
"invalid precinct size %1");
273 require_8(0x88,
"invalid precinct size %1");
274 }
else if (*marker_name ==
"TLM") {
275 auto const len = get_16();
278 }
else if (*marker_name ==
"QCC" || *marker_name ==
"COM") {
279 auto const len = get_16();
281 }
else if (*marker_name ==
"POC") {
282 if (main_header_finished) {
283 num_POC_after_main++;
288 auto require_8_poc = [&](uint16_t value,
string note) {
289 if (get_8() != value) {
290 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER, String::compose(note, value) });
294 auto require_16_poc = [&](uint16_t value,
string note) {
295 if (get_16() != value) {
296 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER, String::compose(note, value) });
300 require_16_poc(16,
"invalid length %1");
301 require_8_poc(0,
"invalid RSpoc %1");
302 require_8_poc(0,
"invalid CSpoc %1");
303 require_16_poc(1,
"invalid LYEpoc %1");
304 require_8_poc(6,
"invalid REpoc %1");
305 require_8_poc(3,
"invalid CEpoc %1");
306 require_8_poc(4,
"invalid Ppoc %1");
307 require_8_poc(6,
"invalid RSpoc %1");
308 require_8_poc(0,
"invalid CSpoc %1");
309 require_16_poc(1,
"invalid LYEpoc %1");
310 require_8_poc(7,
"invalid REpoc %1");
311 require_8_poc(3,
"invalid CEpoc %1");
312 require_8_poc(4,
"invalid Ppoc %1");
328 if (num_POC_in_main != 0 && !fourk) {
329 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER_COUNT_FOR_2K, raw_convert<string>(num_POC_in_main) });
331 if (num_POC_in_main != 1 && fourk) {
332 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER_COUNT_FOR_4K, raw_convert<string>(num_POC_in_main) });
334 if (num_POC_after_main != 0) {
335 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_POC_MARKER_LOCATION });
338 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_JPEG200_TLM_MARKER });
343 notes.push_back ({VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string(e.what()) });
void verify_j2k(std::shared_ptr< const Data > data, std::vector< VerificationNote > ¬es)
P raw_convert(Q, int precision=16, bool fixed=false)
Methods for conversion to/from string.
dcp::verify() method and associated code
Verification that JPEG2000 files meet requirements.