Merge branch 'release-0.2.5'
This commit is contained in:
commit
729f42b5c9
9 changed files with 32 additions and 52 deletions
|
|
@ -1,3 +1,6 @@
|
||||||
|
Jul 23, 2013 - v0.2.5 Fixed inconsistency in XML handling, now all instances
|
||||||
|
are always ElementTree objects (issue82).
|
||||||
|
|
||||||
Jul 21, 2013 - v0.2.4 Fixed markdown bug for Fedora 17 information, fixed
|
Jul 21, 2013 - v0.2.4 Fixed markdown bug for Fedora 17 information, fixed
|
||||||
out-of-date windows information (issue79). Fixed incorrect
|
out-of-date windows information (issue79). Fixed incorrect
|
||||||
interpretation of Psot parameter (issue78).
|
interpretation of Psot parameter (issue78).
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ copyright = u'2013, John Evans'
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.1'
|
version = '0.1'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.2.4'
|
release = '0.2.5'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|
|
||||||
|
|
@ -185,9 +185,8 @@ Work with XMP UUIDs?
|
||||||
====================
|
====================
|
||||||
The example JP2 file shipped with glymur has an XMP UUID. ::
|
The example JP2 file shipped with glymur has an XMP UUID. ::
|
||||||
|
|
||||||
>>> from glymur import Jp2k
|
>>> import glymur
|
||||||
>>> file = glymur.data.nemo()
|
>>> j = glymur.Jp2k(glymur.data.nemo())
|
||||||
>>> j = Jp2k(file)
|
|
||||||
>>> print(j.box[4])
|
>>> print(j.box[4])
|
||||||
UUID Box (uuid) @ (715, 2412)
|
UUID Box (uuid) @ (715, 2412)
|
||||||
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
|
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
|
||||||
|
|
@ -198,7 +197,7 @@ The example JP2 file shipped with glymur has an XMP UUID. ::
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</ns0:xmpmeta>
|
</ns0:xmpmeta>
|
||||||
|
|
||||||
Since the UUID data in this case is returned as an ElementTree Element, one can
|
Since the UUID data in this case is returned as an ElementTree instance, one can
|
||||||
use ElementTree to access the data. For example, to extract the
|
use ElementTree to access the data. For example, to extract the
|
||||||
**CreatorTool** attribute value, the following would work::
|
**CreatorTool** attribute value, the following would work::
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ Here's an incomplete list of what I'd like to focus on in the near future.
|
||||||
|
|
||||||
* continue to monitor upstream changes in the openjp2 library
|
* continue to monitor upstream changes in the openjp2 library
|
||||||
* investigate using CFFI or cython instead of ctypes to wrap openjp2
|
* investigate using CFFI or cython instead of ctypes to wrap openjp2
|
||||||
* investigate swapping out ElementTree for LXML
|
|
||||||
* eventually expose the openjp2 API
|
* eventually expose the openjp2 API
|
||||||
* investigate JPIP
|
* investigate JPIP
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,16 +42,6 @@ for _marker in range(0xff90, 0xff94):
|
||||||
_VALID_MARKERS.append(_marker)
|
_VALID_MARKERS.append(_marker)
|
||||||
|
|
||||||
|
|
||||||
class InconsistentStartOfTileError(IOError):
|
|
||||||
"""To be raised if bad SOT segment encountered.
|
|
||||||
|
|
||||||
SOT segment offsets are recorded as encountered. The offsets should all be
|
|
||||||
different.
|
|
||||||
"""
|
|
||||||
def __init__(self, msg):
|
|
||||||
IOError.__init__(self, msg)
|
|
||||||
|
|
||||||
|
|
||||||
class Codestream(object):
|
class Codestream(object):
|
||||||
"""Container for codestream information.
|
"""Container for codestream information.
|
||||||
|
|
||||||
|
|
@ -115,8 +105,8 @@ class Codestream(object):
|
||||||
marker_id, = struct.unpack('>H', read_buffer)
|
marker_id, = struct.unpack('>H', read_buffer)
|
||||||
|
|
||||||
if marker_id == 0xff90 and header_only:
|
if marker_id == 0xff90 and header_only:
|
||||||
# start-of-tile (SOT) means we are out of the main header.
|
# Start-of-tile (SOT) means that we are out of the main header
|
||||||
# No need to go any further.
|
# and there is no need to go further.
|
||||||
break
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -135,7 +125,7 @@ class Codestream(object):
|
||||||
|
|
||||||
if marker_id == 0xff93:
|
if marker_id == 0xff93:
|
||||||
# If SOD, then we need to seek past the tile part bit stream.
|
# If SOD, then we need to seek past the tile part bit stream.
|
||||||
if self._parse_tpart_flag:
|
if self._parse_tpart_flag and not header_only:
|
||||||
# But first parse the tile part bit stream for SOP and
|
# But first parse the tile part bit stream for SOP and
|
||||||
# EPH segments.
|
# EPH segments.
|
||||||
self._parse_tile_part_bit_stream(fptr, segment,
|
self._parse_tile_part_bit_stream(fptr, segment,
|
||||||
|
|
@ -143,6 +133,7 @@ class Codestream(object):
|
||||||
|
|
||||||
fptr.seek(self._tile_offset[-1] + self._tile_length[-1])
|
fptr.seek(self._tile_offset[-1] + self._tile_length[-1])
|
||||||
|
|
||||||
|
|
||||||
def _process_marker_segment(self, fptr, marker_id):
|
def _process_marker_segment(self, fptr, marker_id):
|
||||||
"""Process and return a segment from the codestream.
|
"""Process and return a segment from the codestream.
|
||||||
"""
|
"""
|
||||||
|
|
@ -207,19 +198,12 @@ class Codestream(object):
|
||||||
# we encounter start-of-data marker segments.
|
# we encounter start-of-data marker segments.
|
||||||
|
|
||||||
segment = _parse_sot_segment(fptr)
|
segment = _parse_sot_segment(fptr)
|
||||||
if segment.offset not in self._tile_offset:
|
self._tile_offset.append(segment.offset)
|
||||||
self._tile_offset.append(segment.offset)
|
if segment.psot == 0:
|
||||||
if segment.psot == 0:
|
tile_part_length = self.offset + self.length - segment.offset - 2
|
||||||
tile_part_length = self.offset + self.length - segment.offset - 2
|
|
||||||
else:
|
|
||||||
tile_part_length = segment.psot
|
|
||||||
self._tile_length.append(tile_part_length)
|
|
||||||
else:
|
else:
|
||||||
msg = "Inconsistent start-of-tile (SOT) marker segment "
|
tile_part_length = segment.psot
|
||||||
msg += "encountered in tile with index {0}. "
|
self._tile_length.append(tile_part_length)
|
||||||
msg += "Codestream parsing terminated."
|
|
||||||
msg = msg.format(segment.isot)
|
|
||||||
raise InconsistentStartOfTileError(msg)
|
|
||||||
|
|
||||||
elif marker_id == 0xff93:
|
elif marker_id == 0xff93:
|
||||||
# start of data. Need to seek past the current tile part.
|
# start of data. Need to seek past the current tile part.
|
||||||
|
|
|
||||||
|
|
@ -1608,7 +1608,7 @@ class XMLBox(Jp2kBox):
|
||||||
offset of the box from the start of the file.
|
offset of the box from the start of the file.
|
||||||
longname : str
|
longname : str
|
||||||
more verbose description of the box.
|
more verbose description of the box.
|
||||||
xml : ElementTree.Element
|
xml : ElementTree object
|
||||||
XML section.
|
XML section.
|
||||||
"""
|
"""
|
||||||
def __init__(self, xml=None, filename=None, length=0, offset=-1):
|
def __init__(self, xml=None, filename=None, length=0, offset=-1):
|
||||||
|
|
@ -1636,10 +1636,7 @@ class XMLBox(Jp2kBox):
|
||||||
msg = Jp2kBox.__str__(self)
|
msg = Jp2kBox.__str__(self)
|
||||||
xml = self.xml
|
xml = self.xml
|
||||||
if self.xml is not None:
|
if self.xml is not None:
|
||||||
try:
|
msg += _pretty_print_xml(self.xml)
|
||||||
msg += _pretty_print_xml(self.xml)
|
|
||||||
except TypeError:
|
|
||||||
msg += _pretty_print_xml(self.xml.getroot())
|
|
||||||
else:
|
else:
|
||||||
msg += '\n {0}'.format(xml)
|
msg += '\n {0}'.format(xml)
|
||||||
return msg
|
return msg
|
||||||
|
|
@ -1682,7 +1679,8 @@ class XMLBox(Jp2kBox):
|
||||||
text = text.rstrip('\0')
|
text = text.rstrip('\0')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
xml = ET.fromstring(text)
|
elt = ET.fromstring(text)
|
||||||
|
xml = ET.ElementTree(elt)
|
||||||
except ParseError as parse_error:
|
except ParseError as parse_error:
|
||||||
msg = 'A problem was encountered while parsing an XML box: "{0}"'
|
msg = 'A problem was encountered while parsing an XML box: "{0}"'
|
||||||
msg = msg.format(str(parse_error))
|
msg = msg.format(str(parse_error))
|
||||||
|
|
@ -1926,13 +1924,11 @@ class UUIDBox(Jp2kBox):
|
||||||
# XMP data. Parse as XML. Seems to be a difference between
|
# XMP data. Parse as XML. Seems to be a difference between
|
||||||
# ElementTree in version 2.7 and 3.3.
|
# ElementTree in version 2.7 and 3.3.
|
||||||
if sys.hexversion < 0x03000000:
|
if sys.hexversion < 0x03000000:
|
||||||
#parser = ET.XMLParser(encoding='utf-8')
|
elt = ET.fromstring(raw_data)
|
||||||
#import pdb; pdb.set_trace()
|
|
||||||
#self.data = ET.fromstringlist(raw_data, parser=parser)
|
|
||||||
self.data = ET.fromstring(raw_data)
|
|
||||||
else:
|
else:
|
||||||
text = raw_data.decode('utf-8')
|
text = raw_data.decode('utf-8')
|
||||||
self.data = ET.fromstring(text)
|
elt = ET.fromstring(text)
|
||||||
|
self.data = ET.ElementTree(elt)
|
||||||
elif the_uuid.bytes == b'JpgTiffExif->JP2':
|
elif the_uuid.bytes == b'JpgTiffExif->JP2':
|
||||||
exif_obj = Exif(raw_data)
|
exif_obj = Exif(raw_data)
|
||||||
ifds = OrderedDict()
|
ifds = OrderedDict()
|
||||||
|
|
@ -2555,8 +2551,8 @@ def _pretty_print_xml(xml, level=0):
|
||||||
"""Pretty print XML data.
|
"""Pretty print XML data.
|
||||||
"""
|
"""
|
||||||
xml = copy.deepcopy(xml)
|
xml = copy.deepcopy(xml)
|
||||||
_indent(xml, level=level)
|
_indent(xml.getroot(), level=level)
|
||||||
xmltext = ET.tostring(xml).decode('utf-8')
|
xmltext = ET.tostring(xml.getroot()).decode('utf-8')
|
||||||
|
|
||||||
# Indent it a bit.
|
# Indent it a bit.
|
||||||
lst = [(' ' + x) for x in xmltext.split('\n')]
|
lst = [(' ' + x) for x in xmltext.split('\n')]
|
||||||
|
|
|
||||||
|
|
@ -365,7 +365,7 @@ class TestXML(unittest.TestCase):
|
||||||
j2k.wrap(tfile.name, boxes=boxes)
|
j2k.wrap(tfile.name, boxes=boxes)
|
||||||
jp2 = Jp2k(tfile.name)
|
jp2 = Jp2k(tfile.name)
|
||||||
self.assertEqual(jp2.box[3].box_id, 'xml ')
|
self.assertEqual(jp2.box[3].box_id, 'xml ')
|
||||||
self.assertEqual(ET.tostring(jp2.box[3].xml),
|
self.assertEqual(ET.tostring(jp2.box[3].xml.getroot()),
|
||||||
b'<data>0</data>')
|
b'<data>0</data>')
|
||||||
|
|
||||||
@unittest.skipIf(os.name == "nt",
|
@unittest.skipIf(os.name == "nt",
|
||||||
|
|
|
||||||
|
|
@ -4021,7 +4021,7 @@ class TestSuiteDump(unittest.TestCase):
|
||||||
self.assertEqual(jp2.box[1].compatibility_list[1], 'jp2 ')
|
self.assertEqual(jp2.box[1].compatibility_list[1], 'jp2 ')
|
||||||
|
|
||||||
# XML box
|
# XML box
|
||||||
tags = [x.tag for x in jp2.box[2].xml]
|
tags = [x.tag for x in jp2.box[2].xml.getroot()]
|
||||||
self.assertEqual(tags,
|
self.assertEqual(tags,
|
||||||
['{http://www.jpeg.org/jpx/1.0/xml}'
|
['{http://www.jpeg.org/jpx/1.0/xml}'
|
||||||
+ 'GENERAL_CREATION_INFO'])
|
+ 'GENERAL_CREATION_INFO'])
|
||||||
|
|
@ -4046,7 +4046,7 @@ class TestSuiteDump(unittest.TestCase):
|
||||||
self.assertEqual(jp2.box[3].box[1].colorspace, glymur.core.SRGB)
|
self.assertEqual(jp2.box[3].box[1].colorspace, glymur.core.SRGB)
|
||||||
|
|
||||||
# XML box
|
# XML box
|
||||||
tags = [x.tag for x in jp2.box[4].xml]
|
tags = [x.tag for x in jp2.box[4].xml.getroot()]
|
||||||
self.assertEqual(tags, ['{http://www.jpeg.org/jpx/1.0/xml}CAPTION',
|
self.assertEqual(tags, ['{http://www.jpeg.org/jpx/1.0/xml}CAPTION',
|
||||||
'{http://www.jpeg.org/jpx/1.0/xml}LOCATION',
|
'{http://www.jpeg.org/jpx/1.0/xml}LOCATION',
|
||||||
'{http://www.jpeg.org/jpx/1.0/xml}EVENT'])
|
'{http://www.jpeg.org/jpx/1.0/xml}EVENT'])
|
||||||
|
|
@ -4376,13 +4376,13 @@ class TestSuiteDump(unittest.TestCase):
|
||||||
self.assertIsNone(jp2.box[2].box[1].colorspace)
|
self.assertIsNone(jp2.box[2].box[1].colorspace)
|
||||||
|
|
||||||
# XML box
|
# XML box
|
||||||
tags = [x.tag for x in jp2.box[3].xml]
|
tags = [x.tag for x in jp2.box[3].xml.getroot()]
|
||||||
self.assertEqual(tags,
|
self.assertEqual(tags,
|
||||||
['{http://www.jpeg.org/jpx/1.0/xml}'
|
['{http://www.jpeg.org/jpx/1.0/xml}'
|
||||||
+ 'GENERAL_CREATION_INFO'])
|
+ 'GENERAL_CREATION_INFO'])
|
||||||
|
|
||||||
# XML box
|
# XML box
|
||||||
tags = [x.tag for x in jp2.box[5].xml]
|
tags = [x.tag for x in jp2.box[5].xml.getroot()]
|
||||||
self.assertEqual(tags,
|
self.assertEqual(tags,
|
||||||
['{http://www.jpeg.org/jpx/1.0/xml}CAPTION',
|
['{http://www.jpeg.org/jpx/1.0/xml}CAPTION',
|
||||||
'{http://www.jpeg.org/jpx/1.0/xml}LOCATION',
|
'{http://www.jpeg.org/jpx/1.0/xml}LOCATION',
|
||||||
|
|
@ -6954,8 +6954,7 @@ class TestSuiteDump(unittest.TestCase):
|
||||||
self.assertEqual(c.segment[3]._exponent, [4] + [5, 5, 6] * 5)
|
self.assertEqual(c.segment[3]._exponent, [4] + [5, 5, 6] * 5)
|
||||||
|
|
||||||
def test_NR_merged_dump(self):
|
def test_NR_merged_dump(self):
|
||||||
jfile = os.path.join(data_root,
|
jfile = os.path.join(data_root, 'input/nonregression/merged.jp2')
|
||||||
'input/nonregression/merged.jp2')
|
|
||||||
jp2 = Jp2k(jfile)
|
jp2 = Jp2k(jfile)
|
||||||
|
|
||||||
ids = [box.box_id for box in jp2.box]
|
ids = [box.box_id for box in jp2.box]
|
||||||
|
|
|
||||||
2
setup.py
2
setup.py
|
|
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
kwargs = {'name': 'Glymur',
|
kwargs = {'name': 'Glymur',
|
||||||
'version': '0.2.4',
|
'version': '0.2.5',
|
||||||
'description': 'Tools for accessing JPEG2000 files',
|
'description': 'Tools for accessing JPEG2000 files',
|
||||||
'long_description': open('README.md').read(),
|
'long_description': open('README.md').read(),
|
||||||
'author': 'John Evans',
|
'author': 'John Evans',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue