Skip to content
Commits on Source (5)
......@@ -11,10 +11,6 @@ matrix:
env:
- JOB_NAME "27_latest"
- JOB_TAG=latest
- python: 3.4
env:
- JOB_NAME "34_latest"
- JOB_TAG=latest
- python: 3.5
env:
- JOB_NAME "35_latest"
......
April 24, 2019 - v0.8.18
Fix geotiff UUID corner coordinate string representation.
Improve warning and error messages.
Correct improperly raised exception types.
Remove build/test for Python 3.4 (EOL).
Fix read-the-docs requirements.
February 19, 2019 - v0.8.17
Add support for ICC profile raw data.
Fix parsing of negative resolution box exponents.
......
Metadata-Version: 1.1
Name: Glymur
Version: 0.8.17
Version: 0.8.18
Summary: Tools for accessing JPEG2000 files
Home-page: https://github.com/quintusdias/glymur
Author: John Evans
......
......@@ -5,6 +5,7 @@ LICENSE.txt
MANIFEST.in
README.md
appveyor.yml
notes.txt
setup.cfg
setup.py
thang.txt
......
Metadata-Version: 1.1
Name: Glymur
Version: 0.8.17
Version: 0.8.18
Summary: Tools for accessing JPEG2000 files
Home-page: https://github.com/quintusdias/glymur
Author: John Evans
......
......@@ -12,11 +12,17 @@ environment:
matrix:
- CONDA_ROOT: "C:\\Miniconda3_64"
PYTHON_VERSION: "3.7"
PYTHON_ARCH: "64"
CONDA_PY: "37"
CONDA_NPY: "115"
- CONDA_ROOT: "C:\\Miniconda3_64"
PYTHON_VERSION: "3.6"
PYTHON_ARCH: "64"
CONDA_PY: "36"
CONDA_NPY: "112"
CONDA_NPY: "115"
- CONDA_ROOT: "C:\\Miniconda3_64"
PYTHON_VERSION: "2.7"
......@@ -28,7 +34,7 @@ environment:
PYTHON_VERSION: "3.5"
PYTHON_ARCH: "64"
CONDA_PY: "35"
CONDA_NPY: "111"
CONDA_NPY: "115"
# We always use a 64-bit machine, but can build x86 distributions
......
importlib_resources
numpy
openjpeg=2.3.0
lxml
......
glymur (0.8.17-1) UNRELEASED; urgency=medium
glymur (0.8.18-1) unstable; urgency=medium
* Team upload.
[ Bas Couwenberg ]
* Update gbp.conf to use --source-only-changes by default.
-- Bas Couwenberg <sebastic@debian.org> Sun, 07 Jul 2019 08:05:48 +0200
[ Antonio Valentino ]
* New upstream release.
* debian/rules:
- fix override_dh_auto_test rule
-- Antonio Valentino <antonio.valentino@tiscali.it> Sun, 07 Jul 2019 16:00:46 +0000
glymur (0.8.17-1) unstable; urgency=medium
......
......@@ -13,6 +13,10 @@ override_dh_auto_clean:
$(RM) -r *.egg-info
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
touch tests/data/__init__.py
PYBUILD_SYSTEM=custom \
PYBUILD_TEST_ARGS="env PYTHONPATH={build_dir} python{version} -m unittest -v" \
PYBUILD_TEST_ARGS="env PYTHONPATH={build_dir} python{version} -m unittest discover -v" \
dh_auto_test
$(RM) tests/data/__init__.py
endif
......@@ -78,7 +78,7 @@ copyright = u'2013, John Evans'
# The short X.Y version.
version = '0.8'
# The full version, including alpha/beta/rc tags.
release = '0.8.16'
release = '0.8.18'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......
......@@ -5,10 +5,11 @@ How do I...?
... read images?
================
Jp2k implements slicing via the :py:meth:`__getitem__` method, meaning that
multiple resolution imagery in a JPEG 2000 file can
easily be accessed via array-style slicing. For example here's how to
retrieve a full resolution and first lower-resolution image ::
Jp2k implements slicing via the :py:meth:`__getitem__` method and
hooks it into the multiple resolution property of JPEG 2000 imagery.
This means that lower-resolution imagery can be accessed via
array-style slicing that utilizes strides. For example here's how
to retrieve a full resolution and first lower-resolution image ::
>>> import glymur
>>> jp2file = glymur.data.nemo() # just a path to a JPEG2000 file
......@@ -24,7 +25,7 @@ retrieve a full resolution and first lower-resolution image ::
=========================================================
If you have glymur 0.8.13 or higher
and OpenJPEG 2.2.0 or higher,
you can make use of OpenJPEG's thread support to speed up read operations ::
you can make use of OpenJPEG's thread support to speed-up read operations ::
>>> import glymur
>>> import time
......@@ -387,6 +388,33 @@ As to the question of which method you should use, :py:meth:`append` or
produces a new JP2 file, while :py:meth:`append` modifies an existing file and
is currently limited to XML and UUID boxes.
... work with ICC profiles?
===========================
A detailed answer is beyond my capabilities. What I can tell you is how to
gain access to ICC profiles that JPEG 2000 images may or may not provide for
you. If there is an ICC profile, it will be provided in a ColourSpecification
box, but only if the :py:attr:`colorspace` attribute is None. Here is an example
of how you can access an ICC profile in an `example JPX file
<https://github.com/uclouvain/openjpeg-data/blob/master/input/nonregression/text_GBR.jp2?raw=true>`_.
Basically what is done is that the raw bytes corresponding to the ICC profile
are wrapped in a BytesIO object, which is fed to the most-excellent Pillow package.
::
>>> from glymur import Jp2k
>>> from PIL import ImageCms
>>> from io import BytesIO
>>> # This next step produces a harmless warning that has nothing to do with ICC profiles.
>>> j = Jp2k('text_GBR.jp2')
>>> # The 2nd sub box of the 4th box is a ColourSpecification box.
>>> print(j.box[3].box[1].colorspace)
None
>>> b = BytesIO(j.box[3].box[1].icc_profile_data)
>>> icc = ImageCms.ImageCmsProfile(b)
To go any further with this, you will want to consult
`the Pillow documentation <https://pillow.readthedocs.io/en/stable/>`_.
... create an image with an alpha layer?
========================================
......@@ -396,7 +424,7 @@ as such. In order to do so, we need to re-wrap such an image in a
set of boxes that includes a channel definition box.
This example is based on SciPy example code found at
http://scipy-lectures.github.io/advanced/image_processing/#basic-manipulations .
http://scipy-lectures.org/advanced/image_processing/#basic-manipulations .
Instead of a circular mask we'll make it an ellipse since the source
image isn't square. ::
......
......@@ -17,7 +17,7 @@ Glymur will look to use **lxml** when processing boxes with XML content, but can
fall back upon the standard library's **ElementTree** if **lxml** is not
available.
Glymur works on Python versions 2.7, 3.4, 3.5, 3.6, and 3.7.
Glymur works on Python versions 2.7, 3.5, 3.6, and 3.7.
For more information about OpenJPEG, please consult http://www.openjpeg.org.
......
......@@ -2,15 +2,20 @@
Changes in glymur 0.8
=====================
Changes in 0.8.18
=================
* Fix geotiff UUID corner coordinate string representation.
* Improve parsing warning and error messages.
* Correct improperly raised exception types.
* Remove build/test for Python 3.4 (EOL).
* Fix read-the-docs requirements, improved examples.
Changes in 0.8.17
=================
* Fix parsing of resolution box with negative exponents.
* Add support for ICC profile buffers. The undecoded ICC profile
can be accessed via the "icc_profile_data" member of a
ColourSpecification box. In version 0.9.0, this will change to
"icc_profile" to store the raw data, and the old dictionary
for ICC profile metadata will be accessed as
"icc_profile_header".
ColourSpecification box.
Changes in 0.8.16
=================
......
......@@ -8,6 +8,7 @@ These document the changes between minor (or major) versions of glymur.
.. toctree::
0.9
0.8
0.7
0.6
......
......@@ -21,13 +21,15 @@ def tiff_header(read_buffer):
# big endian
endian = '>'
else:
msg = ("The byte order indication in the TIFF header ({byte_order}) "
msg = (
"The byte order indication in the TIFF header ({byte_order}) "
"is invalid. It should be either {little_endian} or "
"{big_endian}.")
msg = msg.format(byte_order=read_buffer[6:8],
"{big_endian}."
)
msg = msg.format(byte_order=read_buffer[0:2],
little_endian=bytes([73, 73]),
big_endian=bytes([77, 77]))
raise IOError(msg)
raise RuntimeError(msg)
_, offset = struct.unpack(endian + 'HI', read_buffer[2:8])
......@@ -36,6 +38,14 @@ def tiff_header(read_buffer):
return exif.processed_ifd
class BadTiffTagDatatype(RuntimeError):
"""
This exception exists soley to better communicate up the stack that the
problem exists.
"""
pass
class Ifd(object):
"""
Attributes
......@@ -95,7 +105,7 @@ class Ifd(object):
payload_size = self.datatype2fmt[dtype][1] * count
except KeyError:
msg = 'Invalid TIFF tag datatype ({0}).'.format(dtype)
raise IOError(msg)
raise BadTiffTagDatatype(msg)
if payload_size <= 4:
# Interpret the payload from the 4 bytes in the tag entry.
......
......@@ -4,7 +4,6 @@ The module contains classes used to store information parsed from JPEG 2000
codestreams.
"""
import math
import struct
import sys
import warnings
......@@ -47,18 +46,6 @@ _CAPABILITIES_DISPLAY = {
_PROFILE_4: 'Cinema 4K',
}
# Need a catch-all list of valid markers.
# See table A-1 in ISO/IEC FCD15444-1.
_VALID_MARKERS = [0xff00, 0xff01, 0xfffe]
for _marker in range(0xffc0, 0xffe0):
_VALID_MARKERS.append(_marker)
for _marker in range(0xfff0, 0xfff9):
_VALID_MARKERS.append(_marker)
for _marker in range(0xff4f, 0xff70):
_VALID_MARKERS.append(_marker)
for _marker in range(0xff90, 0xff94):
_VALID_MARKERS.append(_marker)
class Codestream(object):
"""Container for codestream information.
......@@ -102,9 +89,18 @@ class Codestream(object):
Supplying False may impose a large performance penalty.
"""
# Map each of the known markers to a method that processes them.
process_marker_segment = {
0xff00: self._parse_reserved_segment,
0xff01: self._parse_reserved_segment,
#
# Some markers are listed in table table A-1 in ISO/IEC FCD15444-1 as
# being defined in other standards such as
#
# ITU-T Rec. T.81
# ITU-T Rec. T.84
# ITU-T Rec. T.87
#
# These segments are handled as if they are reserved segments.
parse_marker_segment_fcn = {
# Reserved markers according to table A-1 in ISO/IEC FCD15444-1.
0xff30: self._parse_reserved_marker,
0xff31: self._parse_reserved_marker,
0xff32: self._parse_reserved_marker,
......@@ -121,7 +117,8 @@ class Codestream(object):
0xff3d: self._parse_reserved_marker,
0xff3e: self._parse_reserved_marker,
0xff3f: self._parse_reserved_marker,
0xff4f: self._parse_reserved_segment,
# 0xff4f: SOC (already encountered by the time we get here)
0xff50: self._parse_reserved_segment,
0xff51: self._parse_siz_segment,
0xff52: self._parse_cod_segment,
......@@ -154,12 +151,9 @@ class Codestream(object):
0xff6d: self._parse_reserved_segment,
0xff6e: self._parse_reserved_segment,
0xff6f: self._parse_reserved_segment,
0xff79: self._parse_unrecognized_segment,
0xff90: self._parse_sot_segment,
0xff91: self._parse_unrecognized_segment,
0xff92: self._parse_unrecognized_segment,
0xff93: self._parse_sod_segment,
0xffd9: self._parse_eoc_segment
0xffd9: self._parse_eoc_marker,
}
self.offset = fptr.tell()
......@@ -178,14 +172,18 @@ class Codestream(object):
while True:
read_buffer = fptr.read(2)
try:
self._marker_id, = struct.unpack('>H', read_buffer)
except struct.error:
if self._marker_id < 0xff00:
offset = fptr.tell() - 2
msg = ('Invalid codestream, expected to find a marker '
'at byte position {offset}.')
msg = msg.format(offset=offset)
raise IOError(msg)
msg = (
'Invalid codestream marker at byte offset {offset}. It '
'must be must be greater than 0xff00, but '
'found 0x{marker:04x} instead. Codestream parsing '
'will cease.'
)
msg = msg.format(offset=offset, marker=self._marker_id)
warnings.warn(msg, UserWarning)
break
self._offset = fptr.tell() - 2
......@@ -195,19 +193,14 @@ class Codestream(object):
break
try:
segment = process_marker_segment[self._marker_id](fptr)
segment = parse_marker_segment_fcn[self._marker_id](fptr)
except KeyError:
msg = ('Invalid marker ID 0x{marker_id:x} encountered at byte '
'{offset:d}.')
msg = msg.format(offset=self._offset,
marker_id=self._marker_id)
warnings.warn(msg, UserWarning)
break
segment = self._parse_reserved_marker_segment(fptr)
self.segment.append(segment)
if self._marker_id == 0xffd9:
# end of codestream, should break.
# end of codestream, we are done
break
if self._marker_id == 0xff93:
......@@ -221,13 +214,9 @@ class Codestream(object):
new_offset = self._tile_offset[-1] + self._tile_length[-1]
fptr.seek(new_offset)
def _parse_unrecognized_segment(self, fptr):
"""Looks like a valid marker, but not sure from reading the specs.
def _parse_reserved_marker_segment(self, fptr):
"""We have a marker, but it's not defined by the specs.
"""
msg = ("Unrecognized codestream marker 0x{marker_id:x} encountered at "
"byte offset {offset}.")
msg = msg.format(marker_id=self._marker_id, offset=fptr.tell())
warnings.warn(msg, UserWarning)
cpos = fptr.tell()
read_buffer = fptr.read(2)
next_item, = struct.unpack('>H', read_buffer)
......@@ -235,7 +224,8 @@ class Codestream(object):
if ((next_item & 0xff00) >> 8) == 255:
# No segment associated with this marker, so reset
# to two bytes after it.
segment = Segment(id='0x{0:x}'.format(self._marker_id),
marker_id = '0x{0:x}'.format(self._marker_id)
segment = Segment(marker_id=marker_id,
offset=self._offset, length=0)
else:
segment = self._parse_reserved_segment(fptr)
......@@ -430,8 +420,8 @@ class Codestream(object):
return CRGsegment(xcrg, ycrg, length, offset)
def _parse_eoc_segment(self, fptr):
"""Parse the EOC (end-of-codestream) marker segment.
def _parse_eoc_marker(self, fptr):
"""Parse the EOC (end-of-codestream) marker.
Parameters
----------
......@@ -714,7 +704,7 @@ class Codestream(object):
col_offset=xytosiz[0])
warnings.warn(msg, UserWarning)
else:
numtiles = math.ceil(num_tiles_x) * math.ceil(num_tiles_y)
numtiles = np.ceil(num_tiles_x) * np.ceil(num_tiles_y)
if numtiles > 65535:
msg = "Invalid number of tiles: ({numtiles})."
msg = msg.format(numtiles=numtiles)
......@@ -925,8 +915,7 @@ class COCsegment(Segment):
self.scoc = scoc
self.spcoc = spcoc
self.code_block_size = (4 * math.pow(2, self.spcoc[2]),
4 * math.pow(2, self.spcoc[1]))
self.code_block_size = 4 * 2 ** self.spcoc[2], 4 * 2 ** self.spcoc[1]
if len(self.spcoc) > 5:
self.precinct_size = _parse_precinct_size(self.spcoc[5:])
......@@ -1031,10 +1020,7 @@ class CODsegment(Segment):
msg = msg.format(xform=xform)
warnings.warn(msg, UserWarning)
cblk_width = 4 * math.pow(2, xcb)
cblk_height = 4 * math.pow(2, ycb)
code_block_size = (cblk_height, cblk_width)
self.code_block_size = code_block_size
self.code_block_size = 4 * 2 ** ycb, 4 * 2 ** xcb
if precinct_size is None:
self.precinct_size = ((2 ** 15, 2 ** 15))
......
......@@ -14,7 +14,6 @@ References
# Standard library imports ...
import codecs
import io
import math
import os
import pprint
import struct
......@@ -26,7 +25,7 @@ import warnings
# Third party library imports ...
try:
import lxml.etree as ET
except ImportError:
except ImportError: # pragma: no cover
import xml.etree.ElementTree as ET
import numpy as np
try:
......@@ -34,7 +33,7 @@ try:
import osr
_HAVE_GDAL = True
gdal.UseExceptions()
except ImportError:
except ImportError: # pragma: no cover
_HAVE_GDAL = False
......@@ -44,7 +43,7 @@ from .core import (_COLORSPACE_MAP_DISPLAY, _COLOR_TYPE_MAP_DISPLAY,
SRGB, GREYSCALE, YCC,
ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE,
ANY_ICC_PROFILE, VENDOR_COLOR_METHOD)
from ._tiff import tiff_header
from ._tiff import tiff_header, BadTiffTagDatatype
from . import get_option
from ._iccprofile import _ICCProfile
......@@ -71,6 +70,13 @@ _EXIF_UUID = UUID(bytes=b'JpgTiffExif->JP2')
_XMP_UUID = UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')
class InvalidJp2kError(RuntimeError):
"""
Raise this exception in case we cannot parse a valid JP2 file.
"""
pass
class Jp2kBox(object):
"""Superclass for JPEG 2000 boxes.
......@@ -103,7 +109,7 @@ class Jp2kBox(object):
JP2 files. If reading, then we should be more lenient and just warn.
"""
if writing:
raise IOError(msg)
raise InvalidJp2kError(msg)
else:
warnings.warn(msg)
......@@ -351,22 +357,46 @@ class ColourSpecificationBox(Jp2kBox):
"creating a ColourSpecificationBox.")
self._dispatch_validation_error(msg, writing=writing)
if self.method not in _COLORSPACE_METHODS.keys():
if self.method not in _COLORSPACE_METHODS:
msg = "Invalid colorspace method value ({method})."
msg = msg.format(method=self.method)
if writing:
raise IOError(msg)
raise InvalidJp2kError(msg)
else:
warnings.warn(msg, UserWarning)
if self.approximation not in _APPROXIMATION_MEASURES.keys():
msg = "Invalid colr approximation value ({approx})."
msg = msg.format(approx=self.approximation)
if self.approximation not in _APPROXIMATION_MEASURES:
msg = (
"An unrecognized color approximation value "
"({approx}) was encountered in a ColourSpecificationBox at "
"byte offset {offset}. Permitted approximation mappings "
"include {allowed}."
)
msg = msg.format(approx=self.approximation,
offset=self.offset,
allowed=_APPROXIMATION_MEASURES)
if not writing:
# Don't bother to check this for the case of writing=True
# because it's already handles in the wrapping code.
warnings.warn(msg, UserWarning)
if (
self.icc_profile_data is None
and self.colorspace is not None
and self.colorspace not in _COLORSPACE_MAP_DISPLAY
):
msg = (
"An unrecognized colorspace value ({colorspace}) was "
"encountered in a ColourSpecificationBox at byte offset "
"{offset}. The supported colorspace mappings are "
"{mappings}."
)
msg = msg.format(colorspace=self.colorspace,
offset=self.offset,
mappings=_COLORSPACE_MAP_DISPLAY)
warnings.warn(msg, UserWarning)
def _write_validate(self):
"""In addition to constructor validation steps, run validation steps
for writing."""
......@@ -484,10 +514,6 @@ class ColourSpecificationBox(Jp2kBox):
if method == 1:
# enumerated colour space
colorspace, = struct.unpack_from('>I', read_buffer, offset=3)
if colorspace not in _COLORSPACE_MAP_DISPLAY.keys():
msg = "Unrecognized colorspace ({colorspace})."
msg = msg.format(colorspace=colorspace)
warnings.warn(msg, UserWarning)
icc_profile = None
icc_profile_data = None
......@@ -496,9 +522,13 @@ class ColourSpecificationBox(Jp2kBox):
colorspace = None
icc_profile = None
if (num_bytes - 3) < 128:
msg = ("ICC profile header is corrupt, length is "
"only {length} when it should be at least 128.")
warnings.warn(msg.format(length=num_bytes - 3), UserWarning)
msg = (
"An ICC profile header in a ColourSpecificationBox at "
"byte offset {offset} is corrupt, the length is only "
"{length} when it should be at least 128."
)
msg = msg.format(length=num_bytes - 3, offset=offset)
warnings.warn(msg, UserWarning)
icc_profile_data = None
else:
icc_profile_data = read_buffer[3:]
......@@ -1273,7 +1303,7 @@ class FileTypeBox(Jp2kBox):
"It should be either 'jp2 ' or 'jpx '.")
msg = msg.format(brand=self.brand)
if writing:
raise IOError(msg)
raise InvalidJp2kError(msg)
else:
warnings.warn(msg, UserWarning)
for item in self.compatibility_list:
......@@ -1284,7 +1314,7 @@ class FileTypeBox(Jp2kBox):
msg = msg.format(items=self.compatibility_list,
valid_entries=self._valid_cls)
if writing:
raise IOError(msg)
raise InvalidJp2kError(msg)
else:
warnings.warn(msg, UserWarning)
......@@ -1374,14 +1404,23 @@ class FragmentListBox(Jp2kBox):
def _validate(self, writing=False):
"""Validate internal correctness."""
if (((len(self.fragment_offset) != len(self.fragment_length))
or (len(self.fragment_length) != len(self.data_reference)))):
msg = ("The lengths of the fragment offsets ({len_offsets}), "
"fragment lengths ({len_fragments}), and "
"data reference items ({len_drefs}) must be the same.")
msg = msg.format(len_offsets=len(self.fragment_offset),
len_fragments=len(self.fragment_length),
len_drefs=len(self.data_reference))
if (
len(self.fragment_offset) != len(self.fragment_length)
or len(self.fragment_length) != len(self.data_reference)
):
msg = (
"A FragmentListBox at byte offset {offset} has invalid "
"parameters. The number of fragment offsets, fragment "
"lengths, and reference items must be the same. Those items "
"number {num_offsets}, {num_lengths}, and {num_refitems} "
"respectively."
)
msg = msg.format(
offset=self.offset,
num_offsets=len(self.fragment_offset),
num_lengths=len(self.fragment_length),
num_refitems=len(self.data_reference)
)
self._dispatch_validation_error(msg, writing=writing)
if any([x <= 0 for x in self.fragment_offset]):
msg = "Fragment offsets must all be positive."
......@@ -2140,7 +2179,7 @@ class PaletteBox(Jp2kBox):
if any(signed) or len(set(bps)) != 1:
msg = ("Palettes with signed components or differently sized "
"components are not supported.")
raise IOError(msg)
raise InvalidJp2kError(msg)
# The palette is unsigned and all components have the same width.
# This should cover all but a vanishingly small share of palettes.
......@@ -2594,8 +2633,8 @@ class CaptureResolutionBox(Jp2kBox):
"""
read_buffer = fptr.read(10)
(rn1, rd1, rn2, rd2, re1, re2) = struct.unpack('>HHHHbb', read_buffer)
vres = rn1 / rd1 * math.pow(10, re1)
hres = rn2 / rd2 * math.pow(10, re2)
vres = rn1 / rd1 * float(10 ** re1)
hres = rn2 / rd2 * float(10 ** re2)
return cls(vres, hres, length=length, offset=offset)
......@@ -2670,8 +2709,8 @@ class DisplayResolutionBox(Jp2kBox):
read_buffer = fptr.read(10)
(rn1, rd1, rn2, rd2, re1, re2) = struct.unpack('>HHHHbb', read_buffer)
vres = rn1 / rd1 * math.pow(10, re1)
hres = rn2 / rd2 * math.pow(10, re2)
vres = rn1 / rd1 * float(10 ** re1)
hres = rn2 / rd2 * float(10 ** re2)
return cls(vres, hres, length=length, offset=offset)
......@@ -2872,7 +2911,7 @@ class XMLBox(Jp2kBox):
if filename is not None and xml is not None:
msg = ("Only one of either a filename or an ElementTree instance "
"should be provided.")
raise IOError(msg)
raise InvalidJp2kError(msg)
if filename is not None:
self.xml = ET.parse(filename)
else:
......@@ -2966,14 +3005,22 @@ class XMLBox(Jp2kBox):
# Strip out any trailing nulls, as they can foul up XML parsing.
text = text.rstrip(chr(0))
bfptr = io.BytesIO(text.encode('utf-8'))
f = io.BytesIO(text.encode('utf-8'))
try:
xml = ET.parse(bfptr)
xml = ET.parse(f)
except ET.ParseError as err:
msg = ('A problem was encountered while parsing an XML box:'
'\n\n\t"{reason}"\n\nNo XML was retrieved.')
msg = msg.format(reason=str(err))
exc_type, _, _ = sys.exc_info()
msg = (
'{error_name} was encountered while parsing an XML box at '
'byte offset {offset}:'
'\n\n\t'
'"{reason}"'
'\n\n'
'No XML was retrieved.'
)
msg = msg.format(error_name=exc_type.__name__, offset=offset,
reason=str(err))
warnings.warn(msg, UserWarning)
xml = None
......@@ -3314,7 +3361,15 @@ class UUIDBox(Jp2kBox):
try:
self._parse_raw_data()
except IOError as error:
except BadTiffTagDatatype as error:
orig_msg = str(error)
new_msg = (
"An issue was encountered while parsing a UUIDBox at byte "
"offset {offset}. {orig_msg}"
)
new_msg = new_msg.format(offset=self.offset, orig_msg=orig_msg)
warnings.warn(new_msg)
except RuntimeError as error:
# Such as when Exif byte order is unrecognized.
warnings.warn(str(error))
......@@ -3476,7 +3531,7 @@ class UUIDBox(Jp2kBox):
if hTransform is not None:
point = hTransform.TransformPoint(dfGeoX, dfGeoY, 0)
if point is not None:
line += '({},{}'.format(gdal.DecToDMS(point[0], 'Long', 2),
line += '({},{})'.format(gdal.DecToDMS(point[0], 'Long', 2),
gdal.DecToDMS(point[1], 'Lat', 2))
return line
......
This diff is collapsed.
......@@ -11,7 +11,7 @@ from ..config import glymur_config
OPENJP2, _ = glymur_config()
class OpenJPEGLibraryError(IOError):
class OpenJPEGLibraryError(RuntimeError):
"""
Issue when the OpenJPEG library signals an error.
"""
......
......@@ -20,7 +20,7 @@ from .lib import openjpeg as opj, openjp2 as opj2
# Do not change the format of this next line! Doing so risks breaking
# setup.py
version = "0.8.17"
version = "0.8.18"
_sv = LooseVersion(version)
version_tuple = _sv.version
......