Merge branch 'master' into devel
Conflicts: CHANGES.txt Added FreeBox support.
This commit is contained in:
commit
9867901d84
9 changed files with 167 additions and 8 deletions
|
|
@ -1,6 +1,9 @@
|
|||
Nov 11, 2013 - Palette box now a 2D numpy array instead of a list of
|
||||
1D arrays. Super box constructors now take optional box list argument.
|
||||
|
||||
Jan 28, 2014 - v0.5.10 Fixed bad warning when reader requirements box mask
|
||||
length is unsupported.
|
||||
|
||||
Oct 29, 2013 - v0.5.9 Fixed bad library load on linux as a result of 0.5.8
|
||||
|
||||
Oct 29, 2013 - v0.5.8 Fixed unnecessary warnings when default locations for
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ copyright = u'2013, John Evans'
|
|||
# The short X.Y version.
|
||||
version = '0.5'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.5.9'
|
||||
release = '0.5.10'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
|
|||
|
|
@ -9,3 +9,4 @@ Here's an incomplete list of what I'd like to focus on in the future.
|
|||
* investigate adding write support for UUID/XMP boxes (potentially a big project)
|
||||
* investigate JPIP (likely to be an even bigger project)
|
||||
|
||||
Support for Python 2.6 will be dropped with the 0.6.0 release.
|
||||
|
|
|
|||
BIN
glymur/data/12-v6.4.jpx
Normal file
BIN
glymur/data/12-v6.4.jpx
Normal file
Binary file not shown.
|
|
@ -31,3 +31,16 @@ def goodstuff():
|
|||
"""
|
||||
filename = pkg_resources.resource_filename(__name__, "goodstuff.j2k")
|
||||
return filename
|
||||
|
||||
|
||||
def jpxfile():
|
||||
"""Shortcut for specifying path to 12-v6.4.jpx.
|
||||
|
||||
Returns
|
||||
-------
|
||||
file : str
|
||||
Platform-independent path to 12-v6.4.jpx
|
||||
"""
|
||||
filename = pkg_resources.resource_filename(__name__, "12-v6.4.jpx")
|
||||
return filename
|
||||
|
||||
|
|
|
|||
|
|
@ -915,6 +915,53 @@ class FileTypeBox(Jp2kBox):
|
|||
return box
|
||||
|
||||
|
||||
class FreeBox(Jp2kBox):
|
||||
"""Container for JPX free box information.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
box_id : str
|
||||
4-character identifier for the box.
|
||||
length : int
|
||||
length of the box in bytes.
|
||||
offset : int
|
||||
offset of the box from the start of the file.
|
||||
longname : str
|
||||
more verbose description of the box.
|
||||
"""
|
||||
def __init__(self, length=0, offset=-1):
|
||||
Jp2kBox.__init__(self, box_id='free', longname='Free')
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
|
||||
def __repr__(self):
|
||||
msg = "glymur.jp2box.FreeBox()"
|
||||
return msg
|
||||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
return msg
|
||||
|
||||
@staticmethod
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse JPX free box.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
f : file
|
||||
Open file object.
|
||||
offset : int
|
||||
Start position of box in bytes.
|
||||
length : int
|
||||
Length of the box in bytes.
|
||||
|
||||
Returns
|
||||
-------
|
||||
FreeBox instance
|
||||
"""
|
||||
return FreeBox(length=length, offset=offset)
|
||||
|
||||
|
||||
class ImageHeaderBox(Jp2kBox):
|
||||
"""Container for JPEG 2000 image header box information.
|
||||
|
||||
|
|
@ -1520,13 +1567,24 @@ class ReaderRequirementsBox(Jp2kBox):
|
|||
# Decodes Completely Mask
|
||||
read_buffer = fptr.read(2 * mask_length)
|
||||
|
||||
fuam = dcm = standard_flag = standard_mask = []
|
||||
vendor_feature = vendor_mask = []
|
||||
|
||||
# The mask length tells us the format string to use when unpacking
|
||||
# from the buffer read from file.
|
||||
mask_format = {1: 'B', 2: 'H', 4: 'I'}[mask_length]
|
||||
fuam, dcm = struct.unpack('>' + mask_format * 2, read_buffer)
|
||||
try:
|
||||
mask_format = {1: 'B', 2: 'H', 4: 'I', 8: 'Q'}[mask_length]
|
||||
fuam, dcm = struct.unpack('>' + mask_format * 2, read_buffer)
|
||||
standard_flag, standard_mask = _parse_standard_flag(fptr,
|
||||
mask_length)
|
||||
vendor_feature, vendor_mask = _parse_vendor_features(fptr,
|
||||
mask_length)
|
||||
|
||||
standard_flag, standard_mask = _parse_standard_flag(fptr, mask_length)
|
||||
vendor_feature, vendor_mask = _parse_vendor_features(fptr, mask_length)
|
||||
except KeyError:
|
||||
msg = 'The ReaderRequirements box (rreq) has a mask length of {0} '
|
||||
msg += 'bytes, but only values of 1, 2, 4, or 8 are supported. '
|
||||
msg += 'The box contents will not be interpreted.'
|
||||
warnings.warn(msg.format(mask_length), UserWarning)
|
||||
|
||||
box = ReaderRequirementsBox(fuam, dcm, standard_flag, standard_mask,
|
||||
vendor_feature, vendor_mask,
|
||||
|
|
@ -2804,6 +2862,7 @@ _BOX_WITH_ID = {
|
|||
'jpch': CodestreamHeaderBox,
|
||||
'jplh': CompositingLayerHeaderBox,
|
||||
'jp2c': ContiguousCodestreamBox,
|
||||
'free': FreeBox,
|
||||
'jp2h': JP2HeaderBox,
|
||||
'lbl ': LabelBox,
|
||||
'pclr': PaletteBox,
|
||||
|
|
|
|||
83
glymur/test/test_jp2box_jpx.py
Normal file
83
glymur/test/test_jp2box_jpx.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Test suite specifically targeting JPX box layout.
|
||||
"""
|
||||
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
import warnings
|
||||
import xml.etree.cElementTree as ET
|
||||
|
||||
if sys.hexversion < 0x02070000:
|
||||
import unittest2 as unittest
|
||||
else:
|
||||
import unittest
|
||||
|
||||
import glymur
|
||||
from glymur import Jp2k
|
||||
from glymur.jp2box import ReaderRequirementsBox
|
||||
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03000000, "Warning assert on 2.x.")
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
class TestReaderRequirements(unittest.TestCase):
|
||||
"""Test suite for XML boxes."""
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_mask_length_is_3(self):
|
||||
"""The standard says that the mask length should be 1, 2, 4, or 8."""
|
||||
# Rewrite nemo to include this kind of rreq box.
|
||||
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
|
||||
with open(self.jp2file, 'rb') as nemof:
|
||||
# Read the jP and ftyp boxes as-is.
|
||||
write_buffer = nemof.read(32)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Fake a rreq box with ML = 3.
|
||||
write_buffer = struct.pack('>I4sB', 74, b'rreq', 3)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# pad the rest with zeros
|
||||
write_buffer = struct.pack('>65s', b'\x00' * 65)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Write the rest of nemo.
|
||||
tfile.write(nemof.read())
|
||||
tfile.flush()
|
||||
|
||||
with self.assertWarns(UserWarning):
|
||||
j = Jp2k(tfile.name)
|
||||
self.assertEqual(j.box[2].box_id, 'rreq')
|
||||
self.assertEqual(type(j.box[2]),
|
||||
glymur.jp2box.ReaderRequirementsBox)
|
||||
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03000000, "Warning assert on 2.x.")
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
class TestJPXOther(unittest.TestCase):
|
||||
"""Test suite for other JPX boxes."""
|
||||
|
||||
def setUp(self):
|
||||
self.jpxfile = glymur.data.jpxfile()
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_free_box(self):
|
||||
"""Verify that we can handle a free box."""
|
||||
with warnings.catch_warnings():
|
||||
# This file has a rreq mask length that we do not recognize.
|
||||
warnings.simplefilter("ignore")
|
||||
j = Jp2k(self.jpxfile)
|
||||
self.assertEqual(j.box[16].box[0].box_id, 'free')
|
||||
self.assertEqual(type(j.box[16].box[0]), glymur.jp2box.FreeBox)
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ from .lib import openjp2 as opj2
|
|||
|
||||
# Do not change the format of this next line! Doing so risks breaking
|
||||
# setup.py
|
||||
version = "0.5.9"
|
||||
version = "0.5.10"
|
||||
_sv = LooseVersion(version)
|
||||
version_tuple = _sv.version
|
||||
|
||||
|
|
|
|||
4
setup.py
4
setup.py
|
|
@ -7,11 +7,11 @@ kwargs = {'name': 'Glymur',
|
|||
'description': 'Tools for accessing JPEG2000 files',
|
||||
'long_description': open('README.md').read(),
|
||||
'author': 'John Evans',
|
||||
'author_email': 'john.g.evans.ne at gmail dot com',
|
||||
'author_email': 'john.g.evans.ne@gmail.com',
|
||||
'url': 'https://github.com/quintusdias/glymur',
|
||||
'packages': ['glymur', 'glymur.data', 'glymur.test', 'glymur.lib',
|
||||
'glymur.lib.test'],
|
||||
'package_data': {'glymur': ['data/*.jp2', 'data/*.j2k']},
|
||||
'package_data': {'glymur': ['data/*.jp2', 'data/*.j2k', 'data/*.jpx']},
|
||||
'scripts': ['bin/jp2dump'],
|
||||
'license': 'MIT',
|
||||
'test_suite': 'glymur.test'}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue