[Git][debian-gis-team/glymur][master] 5 commits: New upstream version 0.13.3
Antonio Valentino (@antonio.valentino)
gitlab at salsa.debian.org
Tue Jul 2 20:05:00 BST 2024
Antonio Valentino pushed to branch master at Debian GIS Project / glymur
Commits:
2c3f3c35 by Antonio Valentino at 2024-07-02T18:47:04+00:00
New upstream version 0.13.3
- - - - -
5695b193 by Antonio Valentino at 2024-07-02T18:47:11+00:00
Update upstream source from tag 'upstream/0.13.3'
Update to upstream version '0.13.3'
with Debian dir 2b174adaeb23f77214eddb0621cabf0a8c13a498
- - - - -
9808a87a by Antonio Valentino at 2024-07-02T18:48:04+00:00
New upstream release
- - - - -
86e60f1a by Antonio Valentino at 2024-07-02T18:52:16+00:00
Drop 0001-Fix-broken-test.patch
- - - - -
252139b7 by Antonio Valentino at 2024-07-02T18:52:33+00:00
Set distribution to unstable
- - - - -
29 changed files:
- CHANGES.txt
- appveyor.yml
- ci/travis-310.yaml
- ci/travis-311-no-gdal.yaml
- ci/travis-311-no-opj.yaml
- ci/travis-311.yaml
- ci/travis-312.yaml
- ci/travis-39.yaml
- debian/changelog
- − debian/patches/0001-Fix-broken-test.patch
- − debian/patches/series
- docs/source/conf.py
- docs/source/how_do_i.rst
- docs/source/whatsnew/0.13.rst
- glymur/codestream.py
- glymur/jp2box.py
- glymur/jp2k.py
- glymur/jp2kr.py
- glymur/version.py
- setup.cfg
- + tests/data/no_jp2c.jp2
- tests/test_codestream.py
- tests/test_jp2box.py
- tests/test_jp2k.py
- tests/test_jp2k_writes.py
- tests/test_jp2kr.py
- tests/test_libtiff.py
- tests/test_set_decoded_components.py
- tests/test_warnings.py
Changes:
=====================================
CHANGES.txt
=====================================
@@ -1,3 +1,10 @@
+June 30, 2024 - v0.13.3
+ Refactor parsing errors and warnings.
+ Update CI configuration for numpy 2.0.
+ Skip psnr doctest for numpy 2.0.
+ Fix test issue on s390x.
+ Refactor code pattern for finding first element.
+
May 07, 2024 - v0.13.2
Improve doctesting, fix broken libtiff doctest
Increase code coverage
=====================================
appveyor.yml
=====================================
@@ -16,42 +16,36 @@ environment:
PYTHON_VERSION: "3.9"
PYTHON_ARCH: "64"
CONDA_PY: "39"
- CONDA_NPY: "23"
USE_PATH_FOR_GDAL_PYTHON: "YES"
- CONDA_ROOT: "C:\\Miniconda3_64"
PYTHON_VERSION: "3.10"
PYTHON_ARCH: "64"
CONDA_PY: "310"
- CONDA_NPY: "23"
USE_PATH_FOR_GDAL_PYTHON: "YES"
- CONDA_ROOT: "C:\\Miniconda3_64"
PYTHON_VERSION: "3.11"
PYTHON_ARCH: "64"
CONDA_PY: "311-no-opj"
- CONDA_NPY: "24"
USE_PATH_FOR_GDAL_PYTHON: "YES"
- CONDA_ROOT: "C:\\Miniconda3_64"
PYTHON_VERSION: "3.11"
PYTHON_ARCH: "64"
CONDA_PY: "311-no-gdal"
- CONDA_NPY: "24"
USE_PATH_FOR_GDAL_PYTHON: "YES"
- CONDA_ROOT: "C:\\Miniconda3_64"
PYTHON_VERSION: "3.11"
PYTHON_ARCH: "64"
CONDA_PY: "311"
- CONDA_NPY: "24"
USE_PATH_FOR_GDAL_PYTHON: "YES"
- CONDA_ROOT: "C:\\Miniconda3_64"
PYTHON_VERSION: "3.12"
PYTHON_ARCH: "64"
CONDA_PY: "312"
- CONDA_NPY: "26"
USE_PATH_FOR_GDAL_PYTHON: "YES"
# We always use a 64-bit machine, but can build x86 distributions
=====================================
ci/travis-310.yaml
=====================================
@@ -6,7 +6,7 @@ dependencies:
- gdal
- libtiff
- lxml
- - numpy
+ - numpy>=1.25,<1.26
- openjpeg
- pytest-xdist
- scikit-image
=====================================
ci/travis-311-no-gdal.yaml
=====================================
@@ -5,7 +5,7 @@ dependencies:
- python=3.11.*
- libtiff
- lxml
- - numpy
+ - numpy>=1.26,<2.0
- openjpeg
- pytest-xdist
- scikit-image
=====================================
ci/travis-311-no-opj.yaml
=====================================
@@ -5,7 +5,7 @@ dependencies:
- python=3.11.*
- gdal
- lxml
- - numpy
+ - numpy>=1.26,<2.0
- pip
- pytest-xdist
- scikit-image
=====================================
ci/travis-311.yaml
=====================================
@@ -6,7 +6,7 @@ dependencies:
- gdal
- libtiff
- lxml
- - numpy
+ - numpy>=1.26,<2.0
- openjpeg
- pytest-xdist
- scikit-image
=====================================
ci/travis-312.yaml
=====================================
@@ -6,7 +6,7 @@ dependencies:
- gdal
- libtiff
- lxml
- - numpy
+ - numpy>=2.0
- openjpeg
- pytest-xdist
- scikit-image
=====================================
ci/travis-39.yaml
=====================================
@@ -5,7 +5,7 @@ dependencies:
- python=3.9.*
- gdal
- lxml
- - numpy
+ - numpy>=1.24,<1.25
- openjpeg
- scikit-image
- libtiff
=====================================
debian/changelog
=====================================
@@ -1,3 +1,11 @@
+glymur (0.13.3-1) unstable; urgency=medium
+
+ * New upstream release.
+ * debian/patches:
+ - Drop 0001-Fix-broken-test.patch, applied upstream.
+
+ -- Antonio Valentino <antonio.valentino at tiscali.it> Tue, 02 Jul 2024 18:52:20 +0000
+
glymur (0.13.2-2) unstable; urgency=medium
* debian/patches:
=====================================
debian/patches/0001-Fix-broken-test.patch deleted
=====================================
@@ -1,35 +0,0 @@
-From: Antonio Valentino <antonio.valentino at tiscali.it>
-Date: Wed, 15 May 2024 05:35:48 +0000
-Subject: Fix broken test
-
-Anytime the TIFF RGBA interface is involved, the endianness must be
-taken into account.
-
-Origin: https://github.com/quintusdias/glymur/commit/a91e861fd477b595c32b495902c4caba30702765
-Forwarded: https://github.com/quintusdias/glymur/issues/654
----
- tests/test_libtiff.py | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/tests/test_libtiff.py b/tests/test_libtiff.py
-index ac4b561..b133a08 100644
---- a/tests/test_libtiff.py
-+++ b/tests/test_libtiff.py
-@@ -1,6 +1,7 @@
- # standard library imports
- import importlib.resources as ir
- import platform
-+import sys
- import unittest
- from unittest.mock import patch
- import warnings
-@@ -119,6 +120,9 @@ class TestSuite(fixtures.TestCommon):
- actual = libtiff.readRGBAImageOriented(fp)
- libtiff.close(fp)
-
-+ # Adjust for big-endian if necessary
-+ actual = np.flip(actual, 2) if sys.byteorder == 'big' else actual
-+
- error = fixtures.skimage.metrics.mean_squared_error(
- actual[:, :, :3], expected
- )
=====================================
debian/patches/series deleted
=====================================
@@ -1 +0,0 @@
-0001-Fix-broken-test.patch
=====================================
docs/source/conf.py
=====================================
@@ -78,7 +78,7 @@ copyright = '2013-2024, John Evans'
# The short X.Y version.
version = '0.13'
# The full version, including alpha/beta/rc tags.
-release = '0.13.2'
+release = '0.13.3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
=====================================
docs/source/how_do_i.rst
=====================================
@@ -248,7 +248,7 @@ We suppress a harmless warning from scikit-image below. ::
>>> for layer in range(4):
... jp2.layer = layer
... psnr.append(skimage.metrics.peak_signal_noise_ratio(truth, jp2[:]))
- >>> print(psnr)
+ >>> print(psnr) # doctest: +SKIP
[inf, 29.90221522329731, 39.71824592284344, 48.381047443043634]
... convert TIFF images to JPEG 2000?
=====================================
docs/source/whatsnew/0.13.rst
=====================================
@@ -2,6 +2,16 @@
Changes in glymur 0.13
######################
+*****************
+Changes in 0.13.3
+*****************
+
+ * Refactor parsing errors and warnings.
+ * Update CI configuration for numpy 2.0.
+ * Skip psnr doctest for numpy 2.0.
+ * Fix test issue on s390x.
+ * Refactor code pattern for finding first element.
+
*****************
Changes in 0.13.2
*****************
=====================================
glymur/codestream.py
=====================================
@@ -767,11 +767,10 @@ class Codestream(object):
num_tiles_y = (xysiz[1] - xyosiz[1]) / (xytsiz[1] - xytosiz[1])
except ZeroDivisionError:
msg = (
- f"Invalid tile specification: "
- f"size of {xytsiz[1]} x {xytsiz[0]}, "
- f"offset of {xytosiz[1]} x {xytsiz[0]}."
+ f"Invalid tile specification in SIZ segment at byte offset "
+ f"{offset}: tile size of {xytsiz[1]} x {xytsiz[0]}."
)
- warnings.warn(msg, UserWarning)
+ raise ZeroDivisionError(msg)
else:
numtiles = np.ceil(num_tiles_x) * np.ceil(num_tiles_y)
if numtiles > 65535:
=====================================
glymur/jp2box.py
=====================================
@@ -71,7 +71,7 @@ _EXIF_UUID = UUID(bytes=b'JpgTiffExif->JP2')
_XMP_UUID = UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')
-class InvalidJp2kWarning(RuntimeError):
+class InvalidJp2kWarning(UserWarning):
"""Issue this warning in case the file is technically invalid but we can
still read the image.
"""
=====================================
glymur/jp2k.py
=====================================
@@ -258,7 +258,7 @@ class Jp2k(Jp2kr):
header box if we were so instructed. This requires a wrapping
operation.
"""
- jp2h = [box for box in self.box if box.box_id == 'jp2h'][0]
+ jp2h = next(filter(lambda x: x.box_id == 'jp2h', self.box), None)
extra_boxes = []
if self._capture_resolution is not None:
@@ -1125,8 +1125,7 @@ class Jp2k(Jp2kr):
def _validate_jp2_colr(self, boxes):
"""Validate JP2 requirements on colour specification boxes."""
- lst = [box for box in boxes if box.box_id == 'jp2h']
- jp2h = lst[0]
+ jp2h = next(filter(lambda x: x.box_id == 'jp2h', boxes), None)
for colr in [box for box in jp2h.box if box.box_id == 'colr']:
if colr.approximation != 0:
msg = (
@@ -1161,19 +1160,21 @@ class Jp2k(Jp2kr):
def _validate_jp2c(self, boxes):
"""Validate the codestream box in relation to other boxes."""
# jp2c must be preceeded by jp2h
- jp2h_lst = [idx for (idx, box) in enumerate(boxes)
- if box.box_id == 'jp2h']
- jp2h_idx = jp2h_lst[0]
- jp2c_lst = [idx for (idx, box) in enumerate(boxes)
- if box.box_id == 'jp2c']
- if len(jp2c_lst) == 0:
+ jp2h_idx, _ = next(
+ filter(lambda x: x[1].box_id == 'jp2h', enumerate(boxes)),
+ (None, None)
+ )
+ jp2c_idx, _ = next(
+ filter(lambda x: x[1].box_id == 'jp2c', enumerate(boxes)),
+ (None, None)
+ )
+ if jp2c_idx is None:
msg = (
"A codestream box must be defined in the outermost list of "
"boxes."
)
raise InvalidJp2kError(msg)
- jp2c_idx = jp2c_lst[0]
if jp2h_idx >= jp2c_idx:
msg = "The codestream box must be preceeded by a jp2 header box."
raise InvalidJp2kError(msg)
@@ -1182,8 +1183,7 @@ class Jp2k(Jp2kr):
"""Validate the JP2 Header box."""
self._check_jp2h_child_boxes(boxes, 'top-level')
- jp2h_lst = [box for box in boxes if box.box_id == 'jp2h']
- jp2h = jp2h_lst[0]
+ jp2h = next(filter(lambda x: x.box_id == 'jp2h', boxes), None)
# 1st jp2 header box cannot be empty.
if len(jp2h.box) == 0:
@@ -1199,20 +1199,18 @@ class Jp2k(Jp2kr):
raise InvalidJp2kError(msg)
# colr must be present in jp2 header box.
- colr_lst = [
- j for (j, box) in enumerate(jp2h.box) if box.box_id == 'colr'
- ]
- if len(colr_lst) == 0:
+ colr = next(filter(lambda x: x.box_id == 'colr', jp2h.box), None)
+ if colr is None:
msg = "The jp2 header box must contain a color definition box."
raise InvalidJp2kError(msg)
- colr = jp2h.box[colr_lst[0]]
self._validate_channel_definition(jp2h, colr)
def _validate_channel_definition(self, jp2h, colr):
"""Validate the channel definition box."""
- cdef_lst = [j for (j, box) in enumerate(jp2h.box)
- if box.box_id == 'cdef']
+ cdef_lst = [
+ idx for (idx, box) in enumerate(jp2h.box) if box.box_id == 'cdef'
+ ]
if len(cdef_lst) > 1:
msg = ("Only one channel definition box is allowed in the "
"JP2 header.")
=====================================
glymur/jp2kr.py
=====================================
@@ -9,11 +9,11 @@ License: MIT
# Standard library imports...
from __future__ import annotations
from contextlib import ExitStack
-from itertools import filterfalse
import ctypes
import pathlib
import re
import struct
+import sys
import warnings
# Third party library imports
@@ -22,7 +22,7 @@ import numpy as np
# Local imports...
from .codestream import Codestream
from . import core, version, get_option
-from .jp2box import Jp2kBox, FileTypeBox, InvalidJp2kError
+from .jp2box import Jp2kBox, FileTypeBox, InvalidJp2kError, InvalidJp2kWarning
from .lib import openjp2 as opj2
@@ -108,8 +108,8 @@ class Jp2kr(Jp2kBox):
num_components = len(cstr.segment[1].xrsiz)
else:
# try to get the image size from the IHDR box
- jp2h = [box for box in self.box if box.box_id == 'jp2h'][0]
- ihdr = [box for box in jp2h.box if box.box_id == 'ihdr'][0]
+ jp2h = next(filter(lambda x: x.box_id == 'jp2h', self.box), None)
+ ihdr = next(filter(lambda x: x.box_id == 'ihdr', jp2h.box), None)
height, width = ihdr.height, ihdr.width
num_components = ihdr.num_components
@@ -189,10 +189,10 @@ class Jp2kr(Jp2kBox):
@layer.setter
def layer(self, layer):
# Set to the indicated value so long as it is valid.
- cod = [
- segment for segment in self.codestream.segment
- if segment.marker_id == 'COD'
- ][0]
+ cod = next(
+ filter(lambda x: x.marker_id == 'COD', self.codestream.segment),
+ None
+ )
if layer < 0 or layer >= cod.layers:
msg = f"Invalid layer number, must be in range [0, {cod.layers})."
raise ValueError(msg)
@@ -355,7 +355,13 @@ class Jp2kr(Jp2kBox):
# Don't bother trying to validate JPX.
return
- jp2h = [box for box in self.box if box.box_id == 'jp2h'][0]
+ jp2h = next(filter(lambda x: x.box_id == 'jp2h', self.box), None)
+ if jp2h is None:
+ msg = (
+ "No JP2 header box was located in the outermost jacket of "
+ "boxes."
+ )
+ raise InvalidJp2kError(msg)
# An IHDR box is required as the first child box of the JP2H box.
if jp2h.box[0].box_id != 'ihdr':
@@ -373,7 +379,7 @@ class Jp2kr(Jp2kBox):
"enumerated colorspace or a restricted ICC profile if the "
"file type box brand is 'jp2 '."
)
- warnings.warn(msg, UserWarning)
+ warnings.warn(msg, InvalidJp2kWarning)
# We need to have one and only one JP2H box if we have a JP2 file.
num_jp2h_boxes = len([box for box in self.box if box.box_id == 'jp2h'])
@@ -382,7 +388,7 @@ class Jp2kr(Jp2kBox):
f"This file has {num_jp2h_boxes} JP2H boxes in the outermost "
"layer of boxes. There should only be one."
)
- warnings.warn(msg)
+ warnings.warn(msg, InvalidJp2kWarning)
# We should have one and only one JP2C box if we have a JP2 file.
num_jp2c_boxes = len([box for box in self.box if box.box_id == 'jp2c'])
@@ -404,10 +410,10 @@ class Jp2kr(Jp2kBox):
ihdr = jp2h.box[0]
ihdr_dims = ihdr.height, ihdr.width, ihdr.num_components
- siz = [
- segment for segment in self.codestream.segment
- if segment.marker_id == 'SIZ'
- ][0]
+ siz = next(
+ filter(lambda x: x.marker_id == 'SIZ', self.codestream.segment),
+ None
+ )
siz_dims = (siz.ysiz, siz.xsiz, len(siz.bitdepth))
if ihdr_dims != siz_dims:
@@ -460,9 +466,9 @@ class Jp2kr(Jp2kBox):
if isinstance(pargs, tuple) and any(isinstance(x, int) for x in pargs):
# Replace the first such integer argument, replace it with a slice.
lst = list(pargs)
- g = filterfalse(lambda x: not isinstance(x[1], int),
- enumerate(pargs))
- idx = next(g)[0]
+ idx, _ = next(
+ filter(lambda x: isinstance(x[1], int), enumerate(lst)), None
+ )
lst[idx] = slice(pargs[idx], pargs[idx] + 1)
newindex = tuple(lst)
@@ -676,10 +682,13 @@ class Jp2kr(Jp2kBox):
# Must check the specified rlevel against the maximum.
if rlevel != 0:
# Must check the specified rlevel against the maximum.
- cod_seg = [
- segment for segment in self.codestream.segment
- if segment.marker_id == 'COD'
- ][0]
+ cod_seg = next(
+ filter(
+ lambda x: x.marker_id == 'COD',
+ self.codestream.segment
+ ),
+ None
+ )
max_rlevel = cod_seg.num_res
if rlevel == -1:
# -1 is shorthand for the largest rlevel
@@ -889,25 +898,45 @@ class Jp2kr(Jp2kBox):
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
"""
with self.path.open('rb') as fptr:
+
+ # if it's just a raw codestream file, it's easy
if self._codec_format == opj2.CODEC_J2K:
- codestream = Codestream(fptr, self.length,
- header_only=header_only)
- else:
- box = [x for x in self.box if x.box_id == 'jp2c']
- fptr.seek(box[0].offset)
+ return self._get_codestream(fptr, self.length, header_only)
+
+ # continue assuming JP2, must seek to the JP2C box and past its
+ # header
+ box = next(filter(lambda x: x.box_id == 'jp2c', self.box), None)
+
+ fptr.seek(box.offset)
+ read_buffer = fptr.read(8)
+ (box_length, _) = struct.unpack('>I4s', read_buffer)
+ if box_length == 0:
+ # The length of the box is presumed to last until the end
+ # of the file. Compute the effective length of the box.
+ box_length = self.path.stat().st_size - fptr.tell() + 8
+ elif box_length == 1:
+ # Seek past the XL field.
read_buffer = fptr.read(8)
- (box_length, _) = struct.unpack('>I4s', read_buffer)
- if box_length == 0:
- # The length of the box is presumed to last until the end
- # of the file. Compute the effective length of the box.
- box_length = self.path.stat().st_size - fptr.tell() + 8
- elif box_length == 1:
- # Seek past the XL field.
- read_buffer = fptr.read(8)
- box_length, = struct.unpack('>Q', read_buffer)
- codestream = Codestream(fptr, box_length - 8,
- header_only=header_only)
+ box_length, = struct.unpack('>Q', read_buffer)
+
+ return self._get_codestream(fptr, box_length - 8, header_only)
+
+ def _get_codestream(self, fptr, length, header_only):
+ """
+ Parsing errors can make for confusing errors sometimes, so catch any
+ such error and add context to it.
+ """
+ try:
+ codestream = Codestream(fptr, length, header_only=header_only)
+ except Exception:
+ _, value, traceback = sys.exc_info()
+ msg = (
+ f'The file is invalid '
+ f'because the codestream could not be parsed: "{value}"'
+ )
+ raise InvalidJp2kError(msg).with_traceback(traceback)
+ else:
return codestream
def _validate_nonzero_image_size(self, nrows, ncols, component_index):
=====================================
glymur/version.py
=====================================
@@ -20,7 +20,7 @@ from .lib import tiff
# Do not change the format of this next line! Doing so risks breaking
# setup.py
-version = "0.13.2"
+version = "0.13.3"
version_tuple = parse(version).release
=====================================
setup.cfg
=====================================
@@ -1,6 +1,6 @@
[metadata]
name = Glymur
-version = 0.13.2
+version = 0.13.3
author = 'John Evans'
author_email = "John Evans" <jevans667cc at proton.me>
license = 'MIT'
=====================================
tests/data/no_jp2c.jp2
=====================================
Binary files /dev/null and b/tests/data/no_jp2c.jp2 differ
=====================================
tests/test_codestream.py
=====================================
@@ -6,18 +6,21 @@ Test suite for codestream oddities
# Standard library imports ...
import importlib.resources as ir
from io import BytesIO
+import pathlib
import struct
+import tempfile
import unittest
import warnings
# Local imports ...
import glymur
-from glymur import Jp2k
+from glymur import Jp2k, Jp2kr
+from glymur.jp2box import InvalidJp2kError
from . import fixtures
class TestSuite(fixtures.TestCommon):
- """Test suite for ICC Profile code."""
+ """Test suite for codestreams."""
def setUp(self):
super().setUp()
@@ -28,6 +31,107 @@ class TestSuite(fixtures.TestCommon):
self.issue142 = ir.files('tests.data').joinpath('issue142.j2k')
self.edf_c2_1178956 = ir.files('tests.data').joinpath('edf_c2_1178956.jp2') # noqa : E501
+ def test_unrecognized_marker(self):
+ """
+ SCENARIO: There is an unrecognized marker just after an SOT marker but
+ before the EOC marker. All markers must have a leading byte value of
+ 0xff.
+
+ EXPECTED RESULT: InvalidJp2kError
+ """
+ with open(self.temp_j2k_filename, mode='wb') as tfile:
+ with open(self.j2kfile, 'rb') as ifile:
+ # Everything up until the SOT marker.
+ read_buffer = ifile.read(98)
+ tfile.write(read_buffer)
+
+ # Write the bad marker 0xd900
+ read_buffer = struct.pack('>H', 0xd900)
+ tfile.write(read_buffer)
+
+ # Get the rest of the input file.
+ read_buffer = ifile.read()
+ tfile.write(read_buffer)
+ tfile.flush()
+
+ with self.assertRaises(InvalidJp2kError):
+ Jp2k(tfile.name).get_codestream(header_only=False)
+
+ def test_bad_tile_part_pointer(self):
+ """
+ SCENARIO: A bad SOT marker segment is encountered (Psot value pointing
+ far beyond the end of the EOC marker) when requesting a fully parsed
+ codestream.
+
+ EXPECTED RESULT: InvalidJp2kError
+ """
+ with open(self.temp_jp2_filename, 'wb') as ofile:
+ with open(self.jp2file, 'rb') as ifile:
+ # Copy up until Psot field.
+ ofile.write(ifile.read(204))
+
+ # Write a bad Psot value.
+ ofile.write(struct.pack('>I', 2000000))
+
+ # copy the rest of the file as-is.
+ ifile.seek(208)
+ ofile.write(ifile.read())
+ ofile.flush()
+
+ j = Jp2kr(self.temp_jp2_filename)
+ with self.assertRaises(InvalidJp2kError):
+ j.get_codestream(header_only=False)
+
+ def test_tile_height_is_zero(self):
+ """
+ Scenario: A tile has height of zero.
+
+ Expected result: ZeroDivisionError
+
+ Original test file was input/nonregression/2539.pdf.SIGFPE.706.1712.jp2
+ """
+ fp = BytesIO()
+
+ buffer = struct.pack('>H', 47) # length
+
+ # kwargs = {'rsiz': 1,
+ # 'xysiz': (1000, 1000),
+ # 'xyosiz': (0, 0),
+ # 'xytsiz': (0, 1000),
+ # 'xytosiz': (0, 0),
+ # 'Csiz': 3,
+ # 'bitdepth': (8, 8, 8),
+ # 'signed': (False, False, False),
+ # 'xyrsiz': ((1, 1, 1), (1, 1, 1)),
+ # 'length': 47,
+ # 'offset': 2}
+ buffer += struct.pack('>HIIIIIIIIH', 1, 1000, 1000, 0, 0, 0, 1000,
+ 0, 0, 3)
+ buffer += struct.pack('>BBBBBBBBB', 7, 1, 1, 7, 1, 1, 7, 1, 1)
+ fp.write(buffer)
+ fp.seek(0)
+
+ with self.assertRaises(ZeroDivisionError):
+ glymur.codestream.Codestream._parse_siz_segment(fp)
+
+ def test_invalid_codestream_past_header(self):
+ """
+ Scenario: the codestream is ok thru the header, but invalid after
+ that. The codestream header for the complete test file ends at byte
+
+ Expected result: InvalidJp2kError
+ """
+ path = ir.files('tests.data').joinpath('p1_06.j2k')
+
+ with tempfile.TemporaryDirectory() as tdir:
+ with open(path, mode='rb') as ifile:
+ with open(pathlib.Path(tdir) / 'tmp.j2k', mode='wb') as ofile:
+ ofile.write(ifile.read(555))
+
+ with self.assertRaises(InvalidJp2kError):
+ j = Jp2k(pathlib.Path(tdir) / 'tmp.j2k')
+ j.get_codestream(header_only=False)
+
def test_tlm_segment(self):
"""
Verify parsing of the TLM segment.
@@ -141,12 +245,14 @@ class TestSuite(fixtures.TestCommon):
def test_626(self):
"""
- Scenario:
+ Scenario: After parsing the SOC and SIZ segments, an unknown segment
+ (probably invalid) is hit, and then the file ends, leaving us trying
+ to interpret EOF as another marker segment.
- Expected result: J2KParseError
+ Expected result: InvalidJp2kError
"""
path = ir.files('tests.data').joinpath('issue626.j2k')
- with self.assertRaises(glymur.codestream.J2KParseError):
+ with self.assertRaises(InvalidJp2kError):
Jp2k(path)
=====================================
tests/test_jp2box.py
=====================================
@@ -1,7 +1,6 @@
"""Test suite specifically targeting JP2 box layout.
"""
# Standard library imports ...
-import doctest
import importlib.resources as ir
from io import BytesIO
import os
@@ -33,20 +32,6 @@ from . import fixtures
from .fixtures import OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG
-def docTearDown(doctest_obj): # pragma: no cover
- glymur.set_option('parse.full_codestream', False)
-
-
-def load_tests(loader, tests, ignore): # pragma: no cover
- """Run doc tests as well."""
- if os.name == "nt":
- # Can't do it on windows, temporary file issue.
- return tests
- tests.addTests(doctest.DocTestSuite('glymur.jp2box',
- tearDown=docTearDown))
- return tests
-
-
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
class TestDataEntryURL(fixtures.TestCommon):
"""Test suite for DataEntryURL boxes."""
@@ -1055,11 +1040,40 @@ class TestJp2Boxes(fixtures.TestCommon):
box._filename = str(self.jp2file)
box.codestream
+ def test_no_jp2h_box(self):
+ """
+ SCENARIO: The JP2/JP2H box is missing
+
+ EXPECTED RESULT: InvalidJp2kError
+ """
+ # Write a new JP2 file that omits the IHDR box.
+ j = Jp2k(self.jp2file)
+ jp2h = [box for box in j.box if box.box_id == 'jp2h'][0]
+ with open(self.temp_jp2_filename, mode='wb') as tfile:
+ numbytes = jp2h.offset
+ with open(self.jp2file, 'rb') as ifile:
+ # Write all the way up to the ihdr box
+ tfile.write(ifile.read(numbytes))
+
+ # Seek past the ihdr box
+ ifile.seek(jp2h.length, os.SEEK_CUR)
+
+ # Write the rest of the JP2 file
+ tfile.write(ifile.read(numbytes))
+
+ tfile.flush()
+
+ with self.assertRaises(InvalidJp2kError):
+ with warnings.catch_warnings():
+ # Lots of things wrong with this file.
+ warnings.simplefilter('ignore')
+ Jp2k(tfile.name)
+
def test_no_ihdr_box(self):
"""
SCENARIO: The JP2/IHDR box cannot be parsed.
- EXPECTED RESULT: An RuntimeError is issued.
+ EXPECTED RESULT: InvalidJp2kError
"""
# Write a new JP2 file that omits the IHDR box.
j = Jp2k(self.jp2file)
@@ -1089,19 +1103,16 @@ class TestJp2Boxes(fixtures.TestCommon):
"""
SCENARIO: The JP2 file has no JP2C box.
- EXPECTED RESULT: An InvalidJp2kError is issued.
+ EXPECTED RESULT: An InvalidJp2kError is issued when the file is
+ parsed.
"""
- # Write a new JP2 file that omits the JP2C box.
- j = Jp2k(self.jp2file)
- jp2c = [box for box in j.box if box.box_id == 'jp2c'][0]
- with open(self.temp_jp2_filename, mode='wb') as tfile:
- numbytes = jp2c.offset
- with open(self.jp2file, 'rb') as ifile:
- tfile.write(ifile.read(numbytes))
- tfile.flush()
+ testfile = ir.files('tests.data').joinpath('no_jp2c.jp2')
+ with warnings.catch_warnings():
+ # Lots of things wrong with this file.
+ warnings.simplefilter('ignore')
with self.assertRaises(InvalidJp2kError):
- Jp2k(tfile.name)
+ Jp2k(testfile)
def test_two_jp2c_boxes(self):
"""
=====================================
tests/test_jp2k.py
=====================================
@@ -262,31 +262,6 @@ class TestJp2k(fixtures.TestCommon):
np.testing.assert_array_equal(rgb, bgr[:, :, [2, 1, 0]])
- def test_bad_tile_part_pointer(self):
- """
- SCENARIO: A bad SOT marker segment is encountered (Psot value pointing
- far beyond the end of the EOC marker) when requesting a fully parsed
- codestream.
-
- EXPECTED RESULT: struct.error
- """
- with open(self.temp_jp2_filename, 'wb') as ofile:
- with open(self.jp2file, 'rb') as ifile:
- # Copy up until Psot field.
- ofile.write(ifile.read(204))
-
- # Write a bad Psot value.
- ofile.write(struct.pack('>I', 2000000))
-
- # copy the rest of the file as-is.
- ifile.seek(208)
- ofile.write(ifile.read())
- ofile.flush()
-
- j = Jp2k(self.temp_jp2_filename)
- with self.assertRaises(struct.error):
- j.get_codestream(header_only=False)
-
def test_read_differing_subsamples(self):
"""
SCENARIO: Attempt to read a file where the components have differing
@@ -393,20 +368,6 @@ class TestJp2k(fixtures.TestCommon):
with self.assertRaises(InvalidJp2kError):
Jp2k(path)
- @unittest.skip("This test may not be appropriate")
- def test_file_does_not_exist(self):
- """
- Scenario: The Jp2k construtor is passed a file that does not exist
- and the intent is reading.
-
- Expected Result: FileNotFoundError
- """
- # Verify that we error out appropriately if not given an existing file
- # at all.
- filename = 'this file does not actually exist on the file system.'
- with self.assertRaises(FileNotFoundError):
- Jp2k(filename)
-
def test_codestream(self):
"""
Verify the markers and segments of a JP2 file codestream.
=====================================
tests/test_jp2k_writes.py
=====================================
@@ -1842,7 +1842,7 @@ class TestSuite(fixtures.TestCommon):
def test_1x1_tile(self):
"""
- SCENARIO: Write an image that is tiled 1x1.
+ SCENARIO: Write by tiles an image that is tiled 1x1.
EXPECTED RESULT: RuntimeError, as this triggers an unresolved
bug, issue586.
@@ -1858,8 +1858,7 @@ class TestSuite(fixtures.TestCommon):
self.temp_j2k_filename, shape=shape, tilesize=tilesize,
)
with self.assertRaises(RuntimeError):
- for tw in j.get_tilewriters():
- tw[:] = j2k_data
+ j.get_tilewriters()
def test_openjpeg_library_too_old_for_tile_writing(self):
"""
=====================================
tests/test_jp2kr.py
=====================================
@@ -205,31 +205,6 @@ class TestJp2kr(fixtures.TestCommon):
rgb_from_idx[r, c] = palette[idx[r, c]]
np.testing.assert_array_equal(rgb, rgb_from_idx)
- def test_bad_tile_part_pointer(self):
- """
- SCENARIO: A bad SOT marker segment is encountered (Psot value pointing
- far beyond the end of the EOC marker) when requesting a fully parsed
- codestream.
-
- EXPECTED RESULT: struct.error
- """
- with open(self.temp_jp2_filename, 'wb') as ofile:
- with open(self.jp2file, 'rb') as ifile:
- # Copy up until Psot field.
- ofile.write(ifile.read(204))
-
- # Write a bad Psot value.
- ofile.write(struct.pack('>I', 2000000))
-
- # copy the rest of the file as-is.
- ifile.seek(208)
- ofile.write(ifile.read())
- ofile.flush()
-
- j = Jp2kr(self.temp_jp2_filename)
- with self.assertRaises(struct.error):
- j.get_codestream(header_only=False)
-
def test_read_differing_subsamples(self):
"""
SCENARIO: Attempt to read a file where the components have differing
=====================================
tests/test_libtiff.py
=====================================
@@ -1,6 +1,7 @@
# standard library imports
import importlib.resources as ir
import platform
+import sys
import unittest
from unittest.mock import patch
import warnings
@@ -119,6 +120,9 @@ class TestSuite(fixtures.TestCommon):
actual = libtiff.readRGBAImageOriented(fp)
libtiff.close(fp)
+ # Adjust for big-endian if necessary
+ actual = np.flip(actual, 2) if sys.byteorder == 'big' else actual
+
error = fixtures.skimage.metrics.mean_squared_error(
actual[:, :, :3], expected
)
=====================================
tests/test_set_decoded_components.py
=====================================
@@ -150,7 +150,6 @@ class TestSuite(unittest.TestCase):
with warnings.catch_warnings():
warnings.simplefilter('error')
j2k.decoded_components = -1
- j2k[:]
def test_same_component_several_times(self):
"""
=====================================
tests/test_warnings.py
=====================================
@@ -78,33 +78,6 @@ class TestSuite(fixtures.TestCommon):
# c = Jp2k(tfile.name).get_codestream(header_only=False)
Jp2k(tfile.name)
- def test_unrecognized_marker(self):
- """
- SCENARIO: There is an unrecognized marker just after an SOT marker but
- before the EOC marker. All markers must have a leading byte value of
- 0xff.
-
- EXPECTED RESULT: The SOT marker is the last one retrieved from the
- codestream.
- """
- with open(self.temp_j2k_filename, mode='wb') as tfile:
- with open(self.j2kfile, 'rb') as ifile:
- # Everything up until the SOT marker.
- read_buffer = ifile.read(98)
- tfile.write(read_buffer)
-
- # Write the bad marker 0xd900
- read_buffer = struct.pack('>H', 0xd900)
- tfile.write(read_buffer)
-
- # Get the rest of the input file.
- read_buffer = ifile.read()
- tfile.write(read_buffer)
- tfile.flush()
-
- with self.assertRaises(ValueError):
- Jp2k(tfile.name).get_codestream(header_only=False)
-
def test_unrecoverable_xml(self):
"""
Bad byte sequence in XML that cannot be parsed.
@@ -123,36 +96,6 @@ class TestSuite(fixtures.TestCommon):
self.assertIsNone(box.xml)
- def test_tile_height_is_zero(self):
- """
- Zero tile height should not cause an exception.
-
- Original test file was input/nonregression/2539.pdf.SIGFPE.706.1712.jp2
- """
- fp = BytesIO()
-
- buffer = struct.pack('>H', 47) # length
-
- # kwargs = {'rsiz': 1,
- # 'xysiz': (1000, 1000),
- # 'xyosiz': (0, 0),
- # 'xytsiz': (0, 1000),
- # 'xytosiz': (0, 0),
- # 'Csiz': 3,
- # 'bitdepth': (8, 8, 8),
- # 'signed': (False, False, False),
- # 'xyrsiz': ((1, 1, 1), (1, 1, 1)),
- # 'length': 47,
- # 'offset': 2}
- buffer += struct.pack('>HIIIIIIIIH', 1, 1000, 1000, 0, 0, 0, 1000,
- 0, 0, 3)
- buffer += struct.pack('>BBBBBBBBB', 7, 1, 1, 7, 1, 1, 7, 1, 1)
- fp.write(buffer)
- fp.seek(0)
-
- with self.assertWarns(UserWarning):
- glymur.codestream.Codestream._parse_siz_segment(fp)
-
def test_invalid_progression_order(self):
"""
Should still be able to parse even if prog order is invalid.
View it on GitLab: https://salsa.debian.org/debian-gis-team/glymur/-/compare/7aa6a22aefc2dd8a845a56bf6fc6cb99bb8873c7...252139b7b3d97af3196ad94df963fc59d7dfa9d9
--
This project does not include diff previews in email notifications.
View it on GitLab: https://salsa.debian.org/debian-gis-team/glymur/-/compare/7aa6a22aefc2dd8a845a56bf6fc6cb99bb8873c7...252139b7b3d97af3196ad94df963fc59d7dfa9d9
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20240702/7763fd6e/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list