diff --git a/setup.py b/setup.py index da390ab..05ed181 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ with open("README.md", "r") as fh: setuptools.setup( name="tiffexplore", packages=["tiffexplore"], - version="2021.06.0", + version="2021.06.1", author="Wim Pomp", author_email="wimpomp@gmail.com", description="Explore a tiff structure.", diff --git a/tiffexplore/__init__.py b/tiffexplore/__init__.py index 9a70d65..760547e 100644 --- a/tiffexplore/__init__.py +++ b/tiffexplore/__init__.py @@ -33,11 +33,13 @@ class UiMainWindow(object): self.middlecolumn = QtWidgets.QVBoxLayout(self.middlecolumnWidget) self.middlecolumn.setContentsMargins(0, 0, 0, 0) self.properties = QtWidgets.QTextEdit(self.centralwidget) + self.properties.setReadOnly(True) self.middlecolumn.addWidget(self.properties) self.rightcolumnWidget = QtWidgets.QWidget() self.rightcolumn = QtWidgets.QVBoxLayout(self.rightcolumnWidget) self.rightcolumn.setContentsMargins(0, 0, 0, 0) self.binary = QtWidgets.QTextEdit(self.rightcolumnWidget) + self.binary.setReadOnly(True) self.rightcolumn.addWidget(self.binary) self.image = QtWidgets.QLabel(self.rightcolumnWidget) self.image.setMinimumWidth(200) @@ -165,24 +167,27 @@ class Bar(PaintBox): text.append('') text.append(f'Adresses: {addr[0]} - {sum(addr)}') text.append(f'Length: {addr[1]}') - text.append('') if key[0].lower() == 'header': - text.append(f'File size: {len(self.tiff)}') + text.append(f'\nFile size: {len(self.tiff)}') text.append(f'Byte order: {self.tiff.byteorder}') text.append(f'Big tiff: {self.tiff.bigtiff}') text.append(f'Tag size: {self.tiff.tagsize}') text.append(f'Tag number format: {self.tiff.tagnoformat}') text.append(f'Offset size: {self.tiff.offsetsize}') text.append(f'Offset format: {self.tiff.offsetformat}') - text.append(f'First ifd offset: {self.tiff.offset}') + text.append(f'First ifd offset: {self.tiff.offsets[0]}') if key[0].lower() == 'ifd': - text.extend([f'{k}: {v}' for k, v in self.tiff.tags[key[1]].items()]) - if key[1] < self.tiff.nifds-1: - text.append(f'Next ifd offset: {self.tiff.addresses[("ifd", key[1] + 1)][0]}') + text.append(f'Number of tags: {self.tiff.nTags[key[1]]}\n') + text.extend([self.tiff.fmt_tag(k, v)+'\n' for k, v in self.tiff.tags[key[1]].items()]) + if key[1] < len(self.tiff.offsets) - 1: + text.append(f'Next ifd offset: {self.tiff.offsets[key[1] + 1]}') if key[0].lower() == 'tagdata': - text.append(f'{key[2]}: {self.tiff.tags[key[1]][key[2]]}') + text.append('\n' + self.tiff.fmt_tag(key[2], self.tiff.tags[key[1]][key[2]])) if key[0].lower() == 'image': - self.parent.setImage(key[1], key[2]) + im = self.tiff.asarray(key[1], key[2]) + text.append(f'\nStrip size: {im.shape}') + text.append(f'Data type: {im.dtype}') + self.parent.setImage(im) else: self.parent.setImage() self.parent.properties.setText('\n'.join(text)) @@ -204,9 +209,9 @@ class App(QtWidgets.QMainWindow, UiMainWindow): def setImage(self, *args): if len(args): - im = self.tiff.asarray(*args) + im = args[0] if im.ndim == 3: - im = im[0] + im = im.transpose(2, 0, 1).reshape((im.shape[0]*im.shape[2], im.shape[1])) if im.max() - im.min() > 0: im = (255 * ((im - im.min()) / (im.max() - im.min()))).astype('uint8') shape = im.shape diff --git a/tiffexplore/tiffread.py b/tiffexplore/tiffread.py index 85f17a7..9a44dbf 100644 --- a/tiffexplore/tiffread.py +++ b/tiffexplore/tiffread.py @@ -1,6 +1,7 @@ import struct import tifffile import numpy as np +from traceback import format_exc class tiff(): @@ -11,16 +12,31 @@ class tiff(): self.tags = [] self.get_file_len() self.addresses = assignments(len(self)) - nifd = self.read_header() - i = 0 - while nifd: - nifd = self.read_ifd(nifd, i) - i += 1 - self.nifds = i - for i, tags in enumerate(self.tags): - if 273 in tags and 279 in tags: - for j, a in enumerate(zip(tags[273][-1], tags[279][-1])): - self.addresses[('image', i, j)] = a + self.offsets = [] + self.nTags = [] + try: + self.offsets = [self.read_header()] + i = 0 + while 0 < self.offsets[-1] < len(self): + self.offsets.append(self.read_ifd(self.offsets[-1], i)) + i += 1 + for i, tags in enumerate(self.tags): + if 273 in tags and 279 in tags: + for j, a in enumerate(zip(tags[273][-1], tags[279][-1])): + self.addresses[('image', i, j)] = a + except Exception: + print(format_exc()) + + @staticmethod + def fmt_tag(code, value): + text = [f'Code: {code}'] + if code in tifffile.TIFF.TAGS: + text[-1] += f'; {tifffile.TIFF.TAGS[code]}' + text.append(f'data format: {value[0]}; {tifffile.TIFF.DATA_FORMATS.get(value[0])}') + text.append(f'address: {value[1]}') + text.append(f'count: {value[2]}') + text.append(f'value: {value[3]}') + return '\n'.join(text) def get_file_len(self): self.fh.seek(0, 2) @@ -58,49 +74,50 @@ class tiff(): """ self.fh.seek(offset) nTags = struct.unpack(self.byteorder + self.tagnoformat, self.fh.read(struct.calcsize(self.tagnoformat)))[0] - # print('Found {} tags'.format(nTags)) + self.nTags.append(nTags) + self.tags.append({}) assert nTags < 4096, 'Too many tags' length = 8 if self.bigtiff else 2 length += nTags * self.tagsize + self.offsetsize - tags = {} for i in range(nTags): - pos = offset + struct.calcsize(self.tagnoformat) + self.tagsize * i - self.fh.seek(pos) + code, ttype, caddr, dtypelen, count, value = 0, 0, 0, 0, 0, [0] + try: + self.fh.seek(offset + struct.calcsize(self.tagnoformat) + self.tagsize * i) - code, ttype = struct.unpack(self.byteorder + 'HH', self.fh.read(4)) - count = struct.unpack(self.byteorder + self.offsetformat, self.fh.read(self.offsetsize))[0] - dtype = tifffile.TIFF.DATA_FORMATS[ttype] - dtypelen = struct.calcsize(dtype) + code, ttype = struct.unpack(self.byteorder + 'HH', self.fh.read(4)) + count = struct.unpack(self.byteorder + self.offsetformat, self.fh.read(self.offsetsize))[0] + dtype = tifffile.TIFF.DATA_FORMATS[ttype] + dtypelen = struct.calcsize(dtype) - toolong = struct.calcsize(dtype) * count > self.offsetsize - if toolong: - caddr = struct.unpack(self.byteorder + self.offsetformat, self.fh.read(self.offsetsize))[0] - self.addresses[('tagdata', idx, code)] = (caddr, dtypelen * count) - cp = self.fh.tell() - self.fh.seek(caddr) - else: - caddr = self.fh.tell() + toolong = struct.calcsize(dtype) * count > self.offsetsize + if toolong: + caddr = struct.unpack(self.byteorder + self.offsetformat, self.fh.read(self.offsetsize))[0] + self.addresses[('tagdata', idx, code)] = (caddr, dtypelen * count) + cp = self.fh.tell() + self.fh.seek(caddr) + else: + caddr = self.fh.tell() - if ttype == 1: - value = self.fh.read(count) - elif ttype == 2: - value = self.fh.read(count).decode('ascii').rstrip('\x00') - elif ttype == 5: - value = [struct.unpack(self.byteorder + dtype, self.fh.read(dtypelen)) for _ in range(count)] - else: - value = [struct.unpack(self.byteorder + dtype, self.fh.read(dtypelen))[0] for _ in range(count)] + if ttype == 1: + value = self.fh.read(count) + elif ttype == 2: + value = self.fh.read(count).decode('ascii').rstrip('\x00') + elif ttype == 5: + value = [struct.unpack(self.byteorder + dtype, self.fh.read(dtypelen)) for _ in range(count)] + else: + value = [struct.unpack(self.byteorder + dtype, self.fh.read(dtypelen))[0] for _ in range(count)] - if toolong: - self.fh.seek(cp) + if toolong: + self.fh.seek(cp) + except Exception: + print(format_exc()) + self.tags[-1][code] = (ttype, caddr, dtypelen*count, value) - tags[code] = (ttype, caddr, dtypelen*count, value) - - nifd = struct.unpack(self.byteorder + self.tagnoformat, self.fh.read(struct.calcsize(self.tagnoformat)))[0] - self.fh.seek(offset) + self.fh.seek(offset + struct.calcsize(self.tagnoformat) + self.tagsize * nTags) + nifd = struct.unpack(self.byteorder + self.offsetformat, self.fh.read(self.offsetsize))[0] self.addresses[('ifd', idx)] = (offset, 2 * struct.calcsize(self.tagnoformat) + nTags * self.tagsize) - self.tags.append(tags) return nifd def __getitem__(self, item):