From ffdb51e74335772129a0a5650c1806802dd59a95 Mon Sep 17 00:00:00 2001 From: relikd Date: Sun, 26 Sep 2021 23:00:32 +0200 Subject: [PATCH] fix icns type sort order + add html support for png+jp2 --- html/script.js | 67 ++++++++++++++++++++++++++++++++++---------- html/style.css | 5 ++-- icnsutil/IcnsFile.py | 4 +-- icnsutil/IcnsType.py | 4 +-- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/html/script.js b/html/script.js index 14f56f0..4d7c402 100644 --- a/html/script.js +++ b/html/script.js @@ -45,16 +45,20 @@ function is_it32(ext, itype, first4b) { return false; } +function get_length(hex, i) { + return Number('0x'+hex.substring(i, i + 8)); +} + +function as_str(hex, i_start, i_end) { + var str = ''; + for (var u = i_start; u < i_end; u += 2) + str += String.fromCharCode(parseInt(hex.substr(u, 2), 16)); + return str; +} + function* parse_file(hex_str) { - function get_length(hex, i) { return Number('0x'+hex.substring(i, i + 8)); } - function get_str(hex, i, len=8) { - var str = ''; - for (var u = i; u < i + len; u += 2) - str += String.fromCharCode(parseInt(hex.substr(u, 2), 16)); - return str; - } function get_media_ext(itype, idx, len) { - let ext = determine_file_ext(get_str(hex_str, idx, 16)); + let ext = determine_file_ext(as_str(hex_str, idx, idx + 16)); if (ext || !itype) return [ext, idx, idx + len]; return [icns_type(itype), idx, idx + len]; @@ -67,12 +71,12 @@ function* parse_file(hex_str) { yield ['icns', i, num, null]; i += 8 * 2; while (i < hex_str.length) { - let head = get_str(hex_str, i); + let head = as_str(hex_str, i, i + 8); num = get_length(hex_str, i + 8); yield [head, i, num, get_media_ext(head, i + 16, num * 2 - 16)]; i += num * 2; } - } else if (ext[0] == 'argb' || ext[0] == null) { + } else { yield [null, 0, hex_str.length, ext]; } } @@ -225,13 +229,49 @@ function inspect_into(sender, dest) { } function put_images_into(sender, dest) { + function get_image_size(data, ext, i) { + if (ext == 'png') { + let w = get_length(data, i + 16 * 2); + let h = get_length(data, i + 20 * 2); + return [w, h]; + } + if (ext == 'jp2') { + if (data.substring(i, i + 8).toUpperCase() == 'FF4FFF51') { + let w = get_length(data, i + 8 * 2); + let h = get_length(data, i + 12 * 2); + return [w, h]; + } + let len_ftype = get_length(data, i + 12 * 2); + // file header + type box + header box (super box) + image header box + let offset = 12 + len_ftype + 8 + 8; + let h = get_length(data, i + offset * 2); + let w = get_length(data, i + offset * 2 + 8); + return [w, h]; + } + } + function append_img_div(head, typ, w, h) { + let div = document.createElement('div'); + var desc = typ || '?'; + if (w) { desc += ': ' + w + 'x' + h; } + div.innerHTML = `

${head || ''}

${desc}

`; + output.appendChild(div); + return div; + } let src = sender.value.replace(/\s/g, ''); let output = document.getElementById(dest); output.innerHTML = ''; for (let [head, , , ext] of parse_file(src)) { if (!ext) continue; - if (['argb', 'rgb', 'mask', 'iconmask', 'icon1b', null].indexOf(ext[0]) == -1) + if (ext[0] == 'png' || ext[0] == 'jp2') { + let [w, h] = get_image_size(src, ext[0], ext[1]); + let img = append_img_div(head, ext[0], w, h); + img.innerHTML += ``; continue; + } + if (['argb', 'rgb', 'mask', 'iconmask', 'icon1b', null].indexOf(ext[0]) == -1) { + append_img_div(head, ext[0]).innerHTML += `

${(ext[2]-ext[1])/2} Bytes

`; + continue; + } let num_arr = num_arr_from_hex(src.substring(ext[1], ext[2])); let ch; @@ -249,9 +289,6 @@ function put_images_into(sender, dest) { ch = 3; data = expand_rgb(it32 ? num_arr.slice(4) : num_arr); } let [img, w] = make_image(data, ch); - let container = document.createElement('div'); - container.innerHTML = `

${head || ''}

${w}x${w}

` - container.appendChild(img); - output.appendChild(container); + append_img_div(head, ext[0] || 'rgb', w, w).appendChild(img); } } diff --git a/html/style.css b/html/style.css index 2e61755..67ebf07 100644 --- a/html/style.css +++ b/html/style.css @@ -17,15 +17,14 @@ body {margin: 2em; font-family: sans-serif;} white-space: nowrap; } /* image viewer */ -#images {margin-top: 1em;} #images>div { width: max-content; display: inline-block; padding: 0 10px; - margin-right: 10px; + margin: 15px 10px 15px 0; vertical-align: top; border: .5px solid gray; } #images>div>h3 {margin: 7px 0 0;} #images>div>p {font-size: 0.8em; margin: 0 0 7px; color: gray;} -#images>div>canvas {border: .5px solid gray;} +#images>div>canvas, #images>div>img {border: .5px solid gray;} diff --git a/icnsutil/IcnsFile.py b/icnsutil/IcnsFile.py index 6ed4774..61b3526 100755 --- a/icnsutil/IcnsFile.py +++ b/icnsutil/IcnsFile.py @@ -33,7 +33,7 @@ class IcnsFile: # Check whether stored type is an expected file format if not (iType.is_type(ext) if ext else iType.is_binary()): yield 'Unexpected type for key {}: {} != {}'.format( - key, ext or 'binary', list(iType.types)) + key, ext or 'binary', iType.types) if ext in ['png', 'jp2', 'icns', 'plist']: continue @@ -102,7 +102,7 @@ class IcnsFile: try: iType = IcnsType.get(key) if not ext: - ext = list(iType.types)[-1] + ext = iType.types[-1] desc = iType.filename(size_only=True) txt += f', {ext or "binary"}: {desc}\n' except NotImplementedError: diff --git a/icnsutil/IcnsType.py b/icnsutil/IcnsType.py index e3142ad..c4a16a8 100755 --- a/icnsutil/IcnsType.py +++ b/icnsutil/IcnsType.py @@ -22,7 +22,7 @@ class Media: def __init__(self, key, types, size=None, *, ch=None, bits=None, os=None, desc=''): self.key = key - self.types = frozenset(types if type(types) == list else [types]) + self.types = types if type(types) == list else [types] self.size = (size, size) if type(size) == int else size self.availability = os self.desc = desc @@ -104,7 +104,7 @@ class Media: def __repr__(self): return '<{}: {}, {}.{}>'.format(type(self).__name__, self.key, - self.filename(), list(self.types)[0]) + self.filename(), self.types[0]) def __str__(self): T = ''