diff --git a/README.md b/README.md index 29e9ce3..022764b 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ their contents. the JPEG XS file format. Additionally supported flags: ```-C```, ```--ignore-codestream```: Don't parse the Codestream boxes. + ```-B ```, ```--buffer-print-limit (limit)```: Output hex dump of + application boxes larger than the specified size (default 256 bytes) * ```jp2box.py``` diff --git a/icc.py b/icc.py index 6df1868..e64eb20 100755 --- a/icc.py +++ b/icc.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- """ JPEG codestream-parser (All-JPEG Codestream/File Format Parser Tools) @@ -362,13 +364,13 @@ def print_sf32(buf, indent): def print_tag(buf, size, indent): sign = buf[0:4] - print_indent("Tag type: %s" % sign, indent) + print_indent("Tag type: %s" % sign.decode('ascii'), indent) print_indent("Reserved: %d" % ordl(buf[4:8]), indent) if sign == "desc": size = ordl(buf[8:12]) - print_indent("Profile description: %s" % buf[12:12 + size - 1], indent) + print_indent("Profile description: %s" % buf[12:12 + size - 1].decode('ascii'), indent) elif sign == "text": - print_indent("Text: %s" % buf[8:len(buf) - 1], indent) + print_indent("Text: %s" % buf[8:len(buf) - 1].decode('ascii'), indent) elif sign == "XYZ ": count = (len(buf) - 8) // 12 off = 8 @@ -405,21 +407,21 @@ def print_tag(buf, size, indent): def print_desctag(buf, indent): size = ordl(buf[8:12]) - print_indent("Profile description: %s" % buf[12:12 + size]) + print_indent("Profile description: %s" % buf[12:12 + size].decode('ascii')) def parse_icc(indent, buf): indent += 1 print_indent("ICC profile size : %d bytes" % ordl(buf[0:4]), indent) - print_indent("Preferred CMM type : %d" % ordl(buf[0:8]), indent) + print_indent("Preferred CMM type : %d" % ordl(buf[4:8]), indent) print_indent("ICC major version : %d" % ordb(buf[8]), indent) print_indent("ICC minor version : %d" % ordb(buf[9]), indent) - print_indent("Profile class : %s" % buf[12:16], indent) - print_indent("Canonical input space : %s" % buf[16:20], indent) - print_indent("Profile connection space: %s" % buf[20:24], indent) + print_indent("Profile class : %s" % buf[12:16].decode('ascii'), indent) + print_indent("Canonical input space : %s" % buf[16:20].decode('ascii'), indent) + print_indent("Profile connection space: %s" % buf[20:24].decode('ascii'), indent) print_indent("Creation date :", indent) print_datetime(buf[24:36], indent + 1) - print_indent("Profile signature : %s" % buf[36:40], indent) + print_indent("Profile signature : %s" % buf[36:40].decode('ascii'), indent) print_indent("Platform singature : %s" % readsignature(buf[40:44]), indent) print_indent("Profile flags : 0x%08x" % ordl(buf[44:48]), indent) print_indent("Device manufacturer : %s" % readsignature(buf[48:52]), indent) @@ -448,7 +450,9 @@ def parse_icc(indent, buf): for i in range(count): offset = ordl(buf[off + 4:off + 8]) size = ordl(buf[off + 8:off + 12]) - print_indent("ICC tag %s at offset %d size %d:" % (buf[off:off + 4], offset, size), indent + 1) + print_indent("ICC tag %s at offset %d size %d:" % + (buf[off:off + 4].decode('ascii'), offset, size), + indent + 1) print_tag(buf[offset:offset + size], size, indent + 2) off += 12 diff --git a/jp2box.py b/jp2box.py index df4128e..bd32629 100644 --- a/jp2box.py +++ b/jp2box.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- """ JPEG codestream-parser (All-JPEG Codestream/File Format Parser Tools) @@ -34,9 +36,9 @@ def print_versflags(self, buf): def new_box(self, description): if self.indent == 0: - self.print_indent("%-8s: New Box: %s" % (str(self.offset - self.hdrsize), description), False) + self.print_indent("%-8s: New Box: %s " % (str(self.offset - self.hdrsize), description), False) else: - self.print_indent("%-8s: Sub Box: %s" % (str(self.offset - self.hdrsize), description), False) + self.print_indent("%-8s: Sub Box: %s " % (str(self.offset - self.hdrsize), description), False) self.indent += 1 def end_box(self): @@ -89,7 +91,7 @@ def parse_header(self): elif len(length) < 4: raise UnexpectedEOF() length = ordl(length) - id = self.infile.read(4) + id = self.infile.read(4).decode('ascii') if len(id) < 4: raise UnexpectedEOF self.offset += 8 diff --git a/jp2codestream.py b/jp2codestream.py index 93e31d6..4c75ec7 100755 --- a/jp2codestream.py +++ b/jp2codestream.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- """ JPEG codestream-parser (All-JPEG Codestream/File Format Parser Tools) @@ -44,13 +46,13 @@ def parse(self, buf, startpos): self.offset = startpos # Read SOC Marker - if (len(self.buffer) - self.pos < 2) or ordw(self.buffer[self.pos + 0:self.pos + 1]) != 0xff4f: + if (len(self.buffer) - self.pos < 2) or ordw(self.buffer[self.pos + 0:self.pos + 2]) != 0xff4f: raise RequiredMarkerMissing("SOC") self.pos += 2 self.read_SOC() # Read SIZ Marker - if (len(self.buffer) - self.pos < 2) or ordw(self.buffer[self.pos + 0:self.pos + 1]) != 0xff51: + if (len(self.buffer) - self.pos < 2) or ordw(self.buffer[self.pos + 0:self.pos + 2]) != 0xff51: raise RequiredMarkerMissing("SIZ") self.pos += 2 self.read_SIZ() @@ -99,7 +101,7 @@ def parse(self, buf, startpos): self._print_indent("Overhead : %d bytes (%d%%)" % (oh, 100 * oh / l)) def load_marker(self, file, marker): - mrk = ordw(marker[0:1]) + mrk = ordw(marker[0:2]) if 0xff30 <= mrk <= 0xff3f: self.buffer = marker elif mrk in [0xff93, 0xff4f, 0xffd9, 0xff92]: @@ -135,7 +137,7 @@ def stream_parse(self, file, startpos): # Read SOC Marker self.load_buffer(file) - if ordw(self.buffer[self.pos + 0:self.pos + 1]) != 0xff4f: + if ordw(self.buffer[self.pos + 0:self.pos + 2]) != 0xff4f: raise RequiredMarkerMissing("SOC") self.pos += 2 self.read_SOC() @@ -143,7 +145,7 @@ def stream_parse(self, file, startpos): # Read SIZ Marker self.load_buffer(file) - if ordw(self.buffer[self.pos + 0:self.pos + 1]) != 0xff51: + if ordw(self.buffer[self.pos + 0:self.pos + 2]) != 0xff51: raise RequiredMarkerMissing("SIZ") self.pos += 2 self.read_SIZ() @@ -162,7 +164,7 @@ def stream_parse(self, file, startpos): self.load_buffer(file) # Read Tile Parts - while len(self.buffer) >= 2 and ordw(self.buffer[0:1]) == 0xff90: + while len(self.buffer) >= 2 and ordw(self.buffer[0:2]) == 0xff90: self.pos += 2 self.read_SOT() self.offset += len(self.buffer) @@ -331,7 +333,7 @@ def read_SIZ(self): raise InvalidSizedMarker("SIZ") # Read Csiz - components = (size - 38) / 3 + components = (size - 38) // 3 self.csiz = ordw(self.buffer[self.pos + 36:self.pos + 38]) if self.csiz != components: raise InvalidSizedMarker("SIZ") @@ -523,7 +525,7 @@ def read_QCD(self): if sqcd & 0x1f == 1 or sqcd & 0x1f == 2: if subbands % 2 != 0: raise InvalidSizedMarker("QCD") - subbands /= 2 + subbands = int(subbands / 2) for i in range(subbands): mantissa = 1.0 if sqcd & 0x1f == 1 or sqcd & 0x1f == 2: @@ -569,7 +571,7 @@ def read_QCC(self): if sqcc & 0x1f == 1 or sqcc & 0x1f == 2: if subbands % 2 != 0: raise InvalidSizedMarker("QCC") - subbands /= 2 + subbands = int(subbands / 2) for i in range(subbands): mantissa = 1.0 if sqcc & 0x1f == 1 or sqcc & 0x1f == 2: @@ -960,7 +962,7 @@ def read_MCT(self): len -= 2 if len % l != 0: raise InvalidSizedMarker("MCT") - count = len / l + count = int(len / l) self.print_header("Number of entries", str(count)) for i in range(count): if type & 12 == 0: @@ -1092,7 +1094,9 @@ def read_COM(self): s = "unknown" self.print_header("Registration", s) if reg == 1: - self.print_header("Comment", self.buffer[self.pos + 4:self.pos + self.size]) + self.print_header( + "Comment", + self.buffer[self.pos + 4:self.pos + self.size].decode('utf-8')) else: self.print_header("Comment", "...") self._end_marker() diff --git a/jp2file.py b/jp2file.py index fac67cb..99220eb 100755 --- a/jp2file.py +++ b/jp2file.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- """ JPEG codestream-parser (All-JPEG Codestream/File Format Parser Tools) @@ -93,7 +95,7 @@ def parse_rreq_box(box, buf): for i in range(nsf): sf = ordw(buf[off:off + 2]) off += 2 - box.print_indent(" Standard flag :", False) + box.print_indent(" Standard flag : ", False) if sf == 0: print("writer could not fully understand file") elif sf == 1: @@ -334,7 +336,7 @@ def parse_filetype_box(box, buffer): # Print MinV (minor version) box.print_indent("Minor version: %d" % ordl(buffer[4:8])) # Print CL (Compatibility List) - box.print_indent("Compatibility:", False) + box.print_indent("Compatibility: ", False) clsize = (len(buffer) - 8) // 4 for i in range(clsize): offset = i * 4 + 8 @@ -391,12 +393,12 @@ def parse_image_header_box(box, buf): box.print_indent("Components : %d" % ordw(buf[8:10])) box.print_indent("Bits Per Component : %d" % ((ordb(buf[10]) & 0x7f) + 1)) - box.print_indent("Signed Components :", 0) + box.print_indent("Signed Components : ", 0) if ordb(buf[10]) & 0x80: print("yes") else: print("no") - box.print_indent("Compression Type :", 0) + box.print_indent("Compression Type : ", 0) if ordb(buf[11]) == 0: print("uncompressed") elif ordb(buf[11]) == 1: @@ -422,15 +424,15 @@ def parse_image_header_box(box, buf): elif ordb(buf[11]) == 12: print("JPEG XS") else: - print("unknown (%s)" % ordb(buf[11])) - box.print_indent("Unknown Colourspace :", 0) + print("unknown (%d)" % ordb(buf[11])) + box.print_indent("Unknown Colourspace : ", 0) if ordb(buf[12]) == 0: print("no") elif ordb(buf[12]) == 1: print("yes") else: print("invalid value") - box.print_indent("Intellectual Property:", 0) + box.print_indent("Intellectual Property: ", 0) if ordb(buf[13]) == 0: print("no") elif ordb(buf[13]) == 1: @@ -475,7 +477,7 @@ def parse_colorspec_box(box, buffer): else: method = ordb(buffer[0]) offset = 3 - box.print_indent("Colour Specification Method:", 0) + box.print_indent("Colour Specification Method: ", 0) if method == 1: print("enumerated colourspace") elif method == 2: @@ -499,7 +501,7 @@ def parse_colorspec_box(box, buffer): if len(buffer) != 7 and cs != 19 and cs != 14: box.print_indent("invalid box") return - box.print_indent("Colourspace :", 0) + box.print_indent("Colourspace : ", 0) if cs == 16: print("sRGB") elif cs == 17: @@ -938,7 +940,7 @@ def parse_cref_box(box, buf): # size = buffer[4:8] type = buf[8:12] if type == "flst": - box.new_box("\"%s\"" % (type)) + box.new_box("\"%s\"" % type) parse_flst_box(box, buf[12:len(buf)]) box.end_box() else: @@ -960,7 +962,7 @@ def parse_xml_box(box, buf): s = buf if s[len(s) - 1] == "\0": s = s[:len(s) - 2] - box.print_indent(s) + box.print_indent(s.decode('utf-8')) def parse_uuidlist_box(box, buf): @@ -1193,7 +1195,7 @@ def parse_hdlr_box(box, buf): print("Handler reference box") box.print_versflags(buf) - htyp = buf[8:12] + htyp = buf[8:12].decode('ascii') if htyp == "vide": htyp = "video track" elif htyp == "soun": @@ -2106,7 +2108,7 @@ def parse_json_box(box, buf): s = buf if s[len(s) - 1] == "\0": s = s[:len(s) - 2] - box.print_indent(s) + box.print_indent(s.decode('utf-8')) def parse_superbox(box, boxtype): @@ -2135,13 +2137,15 @@ def superbox_hook(box, id, length): else: type = box.infile.read(2) box.infile.seek(box.offset) - if ordw(type[0:1]) == 0x574d: + if ordw(type[0:2]) == 0x574d: jxr = JXRCodestream(box.infile, 1) jxr.parse() - elif ordw(type[0:1]) == 0xffd8: - cs = JPGCodestream(indent=box.indent + 1, hook=superbox_hook) + elif ordw(type[0:2]) == 0xffd8: + cs = JPGCodestream( + indent=box.indent + 1, hook=superbox_hook, + buffer_print_limit=buffer_print_limit) cs.stream_parse(box.infile, box.offset) - elif ordw(type[0:1]) == 0xff10: + elif ordw(type[0:2]) == 0xff10: cs = JXSCodestream(indent=box.indent + 1) cs.stream_parse(box.infile, box.offset) else: @@ -2373,12 +2377,15 @@ def superbox_hook(box, id, length): ignore_codestream = False +buffer_print_limit = 256 if __name__ == "__main__": # Read Arguments - args, files = getopt.getopt(sys.argv[1:], "C", "ignore-codestream") + args, files = getopt.getopt(sys.argv[1:], "CB:", ["ignore-codestream", "buffer-print-limit="]) for (o, a) in args: if o in ("-C", "--ignore-codestream"): ignore_codestream = True + if o in ("-B", "--buffer-print-limit"): + buffer_print_limit = int(a) if len(files) != 1: print("Usage: [OPTIONS] %s FILE" % (sys.argv[0])) @@ -2398,7 +2405,7 @@ def superbox_hook(box, id, length): jp2 = JP2Codestream() jp2.stream_parse(file, 0) elif ordw(type) == 0xffd8: - jpg = JPGCodestream(hook=superbox_hook) + jpg = JPGCodestream(hook=superbox_hook, buffer_print_limit=buffer_print_limit) jpg.stream_parse(file, 0) elif ordw(type) == 0xff10: jxs = JXSCodestream() diff --git a/jp2utils.py b/jp2utils.py index 1bf92e2..bc9f779 100755 --- a/jp2utils.py +++ b/jp2utils.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- """ JPEG codestream-parser (All-JPEG Codestream/File Format Parser Tools) @@ -117,8 +119,8 @@ def convert_hex(buf, indent=0, sec_indent=-1, plain_text=False, single_line=True indent = sec_indent line = "" buff = " " - line += " " * indent - buff += str(buf[i]) if 32 <= ordb(buf[i]) < 127 else "." + line += " " * indent + buff += chr(buf[i]) if 32 <= ordb(buf[i]) < 127 else "." line += "%02x " % (ordb(buf[i])) if plain_text: line += " " * ((16 - (len(buf) % 16)) % 16) + buff @@ -135,7 +137,7 @@ def print_hex(buf, indent=0, sec_indent=-1, plain_text=True): def print_indent(buf, indent=0, nl=True): - print(" " * indent + buf, end='\n' if nl else '') + print(" " * indent + buf, end='\n' if nl else '') def ieee_float_to_float(data): @@ -225,10 +227,16 @@ def seek(self, where): if sys.version_info < (3,): def ordb(buf): return struct.unpack('B', buf)[0] + + def chrb(i): + return i else: def ordb(buf): return buf + def chrb(i): + return struct.pack('B', i) + def ordw(buf): return struct.unpack('>H', buf)[0] diff --git a/jpgcodestream.py b/jpgcodestream.py index 2ba5ecc..6594e04 100755 --- a/jpgcodestream.py +++ b/jpgcodestream.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- """ JPEG codestream-parser (All-JPEG Codestream/File Format Parser Tools) @@ -17,7 +19,7 @@ class JPGCodestream(BaseCodestream): JPEG Codestream class. """ - def __init__(self, indent=0, hook=None, offset=0): + def __init__(self, indent=0, hook=None, offset=0, buffer_print_limit=256): super(JPGCodestream, self).__init__(indent=indent) assert hook is not None self.datacount = 0 @@ -30,6 +32,7 @@ def __init__(self, indent=0, hook=None, offset=0): self.superhook = hook self.buffer = None self.pos = 0 + self.buffer_print_limit = buffer_print_limit def load_marker(self, file, marker): mrk = ordw(marker[0:2]) @@ -255,7 +258,7 @@ def parse_frame(self, file, process): self._end_marker() def parse_APP(self, idx): - if idx == 11 and self.buffer[4:6] == "JP": + if idx == 11 and self.buffer[4:6] == b'JP': self._new_marker("APP11", "JPEG XT Extension Marker") segment = BoxSegment(self.buffer, self.offset) self.boxlist.addBoxSegment(segment) @@ -264,13 +267,13 @@ def parse_APP(self, idx): box.parse(self.superhook) else: self._new_marker(("APP%x" % idx), ("Application marker #%d" % idx)) - if len(self.buffer) < 256: + if len(self.buffer) < self.buffer_print_limit: print_hex(self.buffer) self._end_marker() def parse_COM(self): self._new_marker("COM", "Comment marker") - if len(self.buffer) < 256: + if len(self.buffer) < self.buffer_print_limit: print_hex(self.buffer) self._end_marker() @@ -319,7 +322,7 @@ def parse_table(self): self._end_marker() elif marker >= 0xff01: self._new_marker("???", "Unknown marker %04x" % marker) - if len(self.buffer) < 256: + if len(self.buffer) < self.buffer_print_limit: print_hex(self.buffer) self._end_marker() diff --git a/jpgxtbox.py b/jpgxtbox.py index 1970769..5d188d1 100755 --- a/jpgxtbox.py +++ b/jpgxtbox.py @@ -1,10 +1,12 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- """ JPEG codestream-parser (All-JPEG Codestream/File Format Parser Tools) See LICENCE.txt for copyright and licensing conditions. """ from __future__ import print_function, division -from io import StringIO +from io import BytesIO from jp2utils import ordw, ordl, ordq, chrl, chrq, InvalidBoxSize, BoxSizesInconsistent from jp2box import JP2Box @@ -84,7 +86,7 @@ def toBox(self, segment, indent): # offset = sortedlist[0].offset for seg in sortedlist: buf = buf + seg.buffer - string_stream = StringIO(buf) - box = JP2Box(None, string_stream) + bytes_stream = BytesIO(buf) + box = JP2Box(None, bytes_stream) box.indent = indent return box diff --git a/jxrfile.py b/jxrfile.py index d895480..ee7a02a 100755 --- a/jxrfile.py +++ b/jxrfile.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- """ JPEG codestream-parser (All-JPEG Codestream/File Format Parser Tools) @@ -1362,13 +1364,13 @@ def parse(self): type = file.read(2) file.seek(0) try: - if ordw(type[0:1]) == 0x574d: + if ordw(type[0:2]) == 0x574d: jxr = JXRCodestream(file, 0) jxr.parse() - elif ordw(type[0:1]) == 0x4949: + elif ordw(type[0:2]) == 0x4949: jxr = JXRFile(file, 0) jxr.parse() - elif ordw(type[0:1]) == 0x4d4d: + elif ordw(type[0:2]) == 0x4d4d: jxr = JXRFile(file, 1) jxr.parse() else: diff --git a/jxscodestream.py b/jxscodestream.py index d9d66a2..5741fd7 100755 --- a/jxscodestream.py +++ b/jxscodestream.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- """ JPEG codestream-parser (All-JPEG Codestream/File Format Parser Tools) @@ -93,7 +95,7 @@ def decode_Level(level): # class JXSCodestream(BaseCodestream): - def __init__(self, indent=0, offset=0): + def __init__(self, indent=0, offset=0, buffer_print_limit=256): super(JXSCodestream, self).__init__(indent=indent) self.datacount = 0 self.bytecount = 0 @@ -129,6 +131,7 @@ def __init__(self, indent=0, offset=0): self.nlt = "None" self.extent = "Unspecified" self.indent = 0 + self.buffer_print_limit = buffer_print_limit def load_marker(self, file, marker): mrk = ordw(marker) @@ -920,7 +923,7 @@ def stream_parse(self, file, startpos): self.parse_CAP() else: self._new_marker("???", "Unknown marker %04x" % marker_value) - if len(self.buffer) < 256: + if len(self.buffer) < self.buffer_print_limit: print_hex(self.buffer) self._end_marker() self.load_buffer(file)