Merge branch 'master' into devel

This commit is contained in:
jevans 2013-07-18 19:55:18 -04:00
commit f016bf69cb
13 changed files with 242 additions and 130 deletions

View file

@ -1,3 +1,6 @@
Jul 18, 2013 - v0.2.3 Support for Python 2.6, OpenJPEG 1.4. Incompatible
change to ChannelDefinitionBox constructor. Added RGBA example.
Jul 11, 2013 - v0.2.2 Fixed mistakes with trove classifier, pypi releases. Jul 11, 2013 - v0.2.2 Fixed mistakes with trove classifier, pypi releases.
Jul 11, 2013 - v0.2.0 Support for Python 2.7 on windows, OpenJPEG 1.5.1. Jul 11, 2013 - v0.2.0 Support for Python 2.7 on windows, OpenJPEG 1.5.1.

View file

@ -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.2' release = '0.2.3'
# 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.

View file

@ -7,7 +7,7 @@ Glymur Configuration
'''''''''''''''''''''' ''''''''''''''''''''''
The default glymur installation process relies upon OpenJPEG version The default glymur installation process relies upon OpenJPEG version
1.5.1 being properly installed on your system. This will, however, only 1.X being properly installed on your system. This will, however, only
give you you basic read capabilities, so if you wish to take advantage give you you basic read capabilities, so if you wish to take advantage
of more of glymur's features, you should compile OpenJPEG as a shared of more of glymur's features, you should compile OpenJPEG as a shared
library (named *openjp2* instead of *openjpeg*) from the developmental library (named *openjp2* instead of *openjpeg*) from the developmental
@ -23,21 +23,18 @@ environment variable for the purpose of running Glymur's test suite. ::
Glymur uses ctypes (for the moment) to access the openjp2 library, and Glymur uses ctypes (for the moment) to access the openjp2 library, and
because ctypes access libraries in a platform-dependent manner, it is because ctypes access libraries in a platform-dependent manner, it is
recommended that you create a configuration file to help Glymur properly find recommended that you create a configuration file to help Glymur properly find
the openjp2 library. You may create the configuration file as follows:: the openjp2 library. The configuration format is the same as used by Python's
configparser module, i.e. ::
$ mkdir -p ~/.config/glymur [library]
$ cd ~/.config/glymur openjp2: /opt/openjp2-svn/lib/libopenjp2.so
$ cat > glymurrc << EOF
> [library]
> openjp2: /opt/openjp2-svn/lib/libopenjp2.so
> EOF
This assumes, of course, that you've installed OpenJPEG into This assumes, of course, that you've installed OpenJPEG into
/opt/openjp2-svn on a linux system. You may also substitute /opt/openjp2-svn on a linux system. You may also substitute
**$XDG_CONFIG_HOME** for **$HOME/.config**. **$XDG_CONFIG_HOME** for **$HOME/.config**.
You may also include a line for the version 1.5.1 library if you have it installed You may also include a line for the version 1.x openjpeg library if you have it
in a non-standard place, i.e. :: installed in a non-standard place, i.e. ::
[library] [library]
openjp2: /opt/openjp2-svn/lib/libopenjp2.so openjp2: /opt/openjp2-svn/lib/libopenjp2.so
@ -91,11 +88,14 @@ meet the minimal set of requirements for running glymur.
* python3 * python3
* python3-numpy * python3-numpy
* python3-setuptools * python3-setuptools
* python3-matplotlib (for running tests)
For running the maximal number of tests, you also need
* python3-matplotlib
* python3-matplotlib-tk (or whichever matplotlib backend you prefer) * python3-matplotlib-tk (or whichever matplotlib backend you prefer)
Pillow is also needed in order to run the maximum number of tests, so Pillow is also needed in order to run the maximum number of tests, so
go ahead and install Pillow via pip since Pillow is not yet available go ahead and install Pillow via pip since Pillow is not available
in Fedora 18 default repositories:: in Fedora 18 default repositories::
$ yum install python3-devel # pip needs this in order to compile Pillow $ yum install python3-devel # pip needs this in order to compile Pillow
@ -105,29 +105,20 @@ in Fedora 18 default repositories::
Fedora 17 Fedora 17
''''''''' '''''''''
Fedora 17 ships with Python 2.7 and OpenJPEG 1.4. Fedora 17 ships with Python 2.7 and OpenJPEG 1.4. You should have the
following RPMs installed.
Required RPMs include::
* python * python
* python-mock * python-mock
* python-pip * python-pip
* python-setuptools * python-setuptools
* numpy * numpy
* matplotlib (optional)
In addition, you must install contextlib2 via pip. In addition, you must install contextlib2 and Pillow via pip.
A few tests still will not run, however, unless one of the following
combinations of RPMs / Python packages is installed.
* scikit-image and either Pillow or freeimage
* matplotlib and Pillow
scikit-image was not available in the Fedora 17 default repositories, but
it was installable via pip::
$ yum install python-devel # pip needs this in order to compile Pillow $ yum install python-devel # pip needs this in order to compile Pillow
$ pip-python3 install Pillow --user $ pip-python install Pillow --user
$ pip-python install contextlib2 --user $ pip-python install contextlib2 --user
$ export PYTHONPATH=$HOME/.local/lib/python2.7/site-packages:$PYTHONPATH $ export PYTHONPATH=$HOME/.local/lib/python2.7/site-packages:$PYTHONPATH

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 KiB

View file

@ -38,8 +38,8 @@ Add XML Metadata?
================= =================
An existing raw codestream (or JP2 file) can be wrapped (re-wrapped) in a An existing raw codestream (or JP2 file) can be wrapped (re-wrapped) in a
user-defined set of JP2 boxes. To get just a minimal JP2 jacket on the user-defined set of JP2 boxes. To get just a minimal JP2 jacket on the
codestream provided by `goodstuff.j2k`, you can use the **wrap** method with codestream provided by `goodstuff.j2k` (a file consisting of a raw codestream),
no box argument: :: you can use the **wrap** method with no box argument: ::
>>> import glymur >>> import glymur
>>> jfile = glymur.data.goodstuff() >>> jfile = glymur.data.goodstuff()
@ -119,6 +119,68 @@ and add it after the JP2 header box, but before the codestream box ::
. (truncated) . (truncated)
. .
Create an image with an alpha layer?
====================================
OpenJPEG can create JP2 files with more than 3 components, but by default, any
extra components are not described as such. In order to do so,
we need to rewrap 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 .
Instead of a circular mask, however, we'll make it an ellipse since the source
image isn't square.
>>> import numpy as np
>>> import glymur
>>> from glymur import Jp2k
>>> rgb = Jp2k(glymur.data.goodstuff()).read()
>>> lx, ly = rgb.shape[0:2]
>>> X, Y = np.ogrid[0:lx, 0:ly]
>>> mask = ly**2*(X - lx / 2) ** 2 + lx**2*(Y - ly / 2) ** 2 > (lx * ly / 2)**2
>>> alpha = 255 * np.ones((lx, ly, 1), dtype=np.uint8)
>>> alpha[mask] = 0
>>> rgba = np.concatenate((rgb, alpha), axis=2)
>>> jp2 = Jp2k('tmp.jp2', 'wb')
>>> jp2.write(rgba)
Next we need to specify what types of channels we have.
The first three channels are color channels, but we identify the fourth as
an alpha channel::
>>> from glymur.core import COLOR, OPACITY
>>> ctype = [COLOR, COLOR, COLOR, OPACITY]
And finally we have to specify just exactly how each channel is to be
interpreted. The color channels are straightforward, they correspond to R-G-B,
but the alpha (or opacity) channel in this case is to be applied against the
entire image (it is possible to apply an alpha channel to a single color
channel, but we aren't doing that). ::
>>> from glymur.core import RED, GREEN, BLUE, WHOLE_IMAGE
>>> asoc = [RED, GREEN, BLUE, WHOLE_IMAGE]
>>> cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=ctype, association=asoc)
>>> print(cdef)
Channel Definition Box (cdef) @ (0, 0)
Channel 0 (color) ==> (1)
Channel 1 (color) ==> (2)
Channel 2 (color) ==> (3)
Channel 3 (opacity) ==> (whole image)
It's easiest to take the existing jp2 jacket and just add the channel
definition box in the appropriate spot. The channel definition box **must**
go into the jp2 header box, and then we can rewrap the image. ::
>>> boxes = jp2.box # The box attribute is the list of JP2 boxes
>>> boxes[2].box.append(cdef)
>>> jp2_rgba = jp2.wrap("goodstuff_rgba.jp2", boxes=boxes)
Here's how the Preview application on the mac shows the RGBA image.
.. image:: goodstuff_alpha.png
Work with XMP UUIDs? 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. ::

View file

@ -18,17 +18,19 @@ Glymur works on Python 2.6, 2.7, and 3.3. Python 3.3 is strongly recommended.
OpenJPEG Installation OpenJPEG Installation
===================== =====================
The OpenJPEG library version should be 1.4, 1.5, or the trunk/development OpenJPEG should be version 1.4, 1.5, or the trunk/development
version of OpenJPEG. The official 2.0.0 release or versions earlier than 1.3.0 version of OpenJPEG. The official 2.0.0 release or versions earlier than 1.3.0
are not supported. Furthermore, the 1.4 and 1.5 versions of OpenJPEG are are not supported. Furthermore, the 1.X versions of OpenJPEG are
currently only utilized for read-only purposes. For more information currently only utilized for read-only purposes. In order to write JPEG 2000
images, you must compile the the trunk/development version. For more information
about OpenJPEG, please consult http://www.openjpeg.org. about OpenJPEG, please consult http://www.openjpeg.org.
If you use MacPorts on the mac or if you have a sufficiently recent version of If you use MacPorts on the mac or if you have a sufficiently recent
Linux, your package manager should already provide you with a version version of Linux, your package manager should already provide you
of OpenJPEG with which glymur can already use. If your platform is with a version of OpenJPEG 1.X with which glymur can already use
windows, I suggest using the 1.5.1 windows installer provided to you by for read-only purposes. If your platform is windows, I suggest
the OpenJPEG folks at https://code.google.com/p/openjpeg/downloads/list . using the 1.5.1 windows installer provided to you by the OpenJPEG
folks at https://code.google.com/p/openjpeg/downloads/list .
Glymur Installation Glymur Installation
=================== ===================

View file

@ -43,14 +43,14 @@ _COLORSPACE_MAP_DISPLAY = {
ROMM_RGB: 'ROMM-RGB'} ROMM_RGB: 'ROMM-RGB'}
# enumerated color channel types # enumerated color channel types
_COLOR = 0 COLOR = 0
_OPACITY = 1 OPACITY = 1
_PRE_MULTIPLIED_OPACITY = 2 PRE_MULTIPLIED_OPACITY = 2
_UNSPECIFIED = 65535 _UNSPECIFIED = 65535
_COLOR_TYPE_MAP_DISPLAY = { _COLOR_TYPE_MAP_DISPLAY = {
_COLOR: 'color', COLOR: 'color',
_OPACITY: 'opacity', OPACITY: 'opacity',
_PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity', PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity',
_UNSPECIFIED: 'unspecified'} _UNSPECIFIED: 'unspecified'}
# color channel definitions. # color channel definitions.
@ -58,6 +58,7 @@ RED = 1
GREEN = 2 GREEN = 2
BLUE = 3 BLUE = 3
GREY = 1 GREY = 1
WHOLE_IMAGE = 0
# enumerated color channel associations # enumerated color channel associations
_COLORSPACE = {SRGB: {"R": 1, "G": 2, "B": 3}, _COLORSPACE = {SRGB: {"R": 1, "G": 2, "B": 3},

View file

@ -16,6 +16,7 @@ References
import copy import copy
import datetime import datetime
import math import math
import os
import pprint import pprint
import struct import struct
import sys import sys
@ -73,9 +74,6 @@ class Jp2kBox(object):
self.offset = offset self.offset = offset
self.longname = longname self.longname = longname
# should never be used except maybe for last box in file.
self._file_size = -1
def __str__(self): def __str__(self):
msg = "{0} Box ({1})".format(self.longname, self.box_id) msg = "{0} Box ({1})".format(self.longname, self.box_id)
msg += " @ ({0}, {1})".format(self.offset, self.length) msg += " @ ({0}, {1})".format(self.offset, self.length)
@ -118,7 +116,7 @@ class Jp2kBox(object):
if box_length == 0: if box_length == 0:
# The length of the box is presumed to last until the end of # The length of the box is presumed to last until the end of
# the file. Compute the effective length of the box. # the file. Compute the effective length of the box.
num_bytes = self._file_size - fptr.tell() + 8 num_bytes = os.path.getsize(fptr.name) - fptr.tell() + 8
elif box_length == 1: elif box_length == 1:
# The length of the box is in the XL field, a 64-bit value. # The length of the box is in the XL field, a 64-bit value.
@ -428,14 +426,24 @@ class ChannelDefinitionBox(Jp2kBox):
longname : str longname : str
more verbose description of the box. more verbose description of the box.
index : int index : int
number of the channel number of the channel. Defaults to monotonically increasing sequence,
i.e. [0, 1, 2, ...]
channel_type : int channel_type : int
type of the channel type of the channel
association : int association : int
index of the associated color index of the associated color
""" """
def __init__(self, index, channel_type, association, **kwargs): def __init__(self, index=None, channel_type=None, association=None,
**kwargs):
Jp2kBox.__init__(self, box_id='cdef', longname='Channel Definition') Jp2kBox.__init__(self, box_id='cdef', longname='Channel Definition')
# channel type and association must be specified.
if channel_type is None or association is None:
raise IOError("channel_type and association must be specified.")
if index is None:
index = list(range(len(channel_type)))
if len(index) != len(channel_type) or len(index) != len(association): if len(index) != len(channel_type) or len(index) != len(association):
msg = "Length of channel definition box inputs must be the same." msg = "Length of channel definition box inputs must be the same."
raise IOError(msg) raise IOError(msg)
@ -506,8 +514,9 @@ class ChannelDefinitionBox(Jp2kBox):
channel_type = data[1:num_components * 6:3] channel_type = data[1:num_components * 6:3]
association = data[2:num_components * 6:3] association = data[2:num_components * 6:3]
box = ChannelDefinitionBox(index, channel_type, association, box = ChannelDefinitionBox(index=index, channel_type=channel_type,
length=length, offset=offset) association=association, length=length,
offset=offset)
return box return box

View file

@ -101,7 +101,6 @@ class Jp2k(Jp2kBox):
self.mode = mode self.mode = mode
self.box = [] self.box = []
self._codec_format = None self._codec_format = None
self._file_size = 0
# Parse the file for JP2/JPX contents only if we are reading it. # Parse the file for JP2/JPX contents only if we are reading it.
if mode == 'rb': if mode == 'rb':
@ -126,7 +125,6 @@ class Jp2k(Jp2kBox):
The file was not JPEG 2000. The file was not JPEG 2000.
""" """
self.length = os.path.getsize(self.filename) self.length = os.path.getsize(self.filename)
self._file_size = os.path.getsize(self.filename)
with open(self.filename, 'rb') as fptr: with open(self.filename, 'rb') as fptr:

View file

@ -23,7 +23,7 @@ def version():
# Need to get the minor version, make sure we are at least at 1.4.x # Need to get the minor version, make sure we are at least at 1.4.x
#import pdb; pdb.set_trace() #import pdb; pdb.set_trace()
_minor = version().split('.')[1] _MINOR = version().split('.')[1]
class EventMgrType(ctypes.Structure): class EventMgrType(ctypes.Structure):
@ -103,7 +103,7 @@ class DecompressionParametersType(ctypes.Structure):
# entire codestream or be limited to the main header # entire codestream or be limited to the main header
("cp_limit_decoding", ctypes.c_int)] ("cp_limit_decoding", ctypes.c_int)]
if _minor != '4': if _MINOR == '5':
_fields_.append(("flags", ctypes.c_uint)) _fields_.append(("flags", ctypes.c_uint))

View file

@ -16,6 +16,8 @@ import pkg_resources
import glymur import glymur
from glymur import Jp2k from glymur import Jp2k
from glymur.jp2box import * from glymur.jp2box import *
from glymur.core import COLOR, OPACITY
from glymur.core import RED, GREEN, BLUE, GREY, WHOLE_IMAGE
# Doc tests should be run as well. # Doc tests should be run as well.
@ -84,12 +86,19 @@ class TestChannelDefinition(unittest.TestCase):
def tearDown(self): def tearDown(self):
pass pass
def test_rgb(self): def test_cdef_no_inputs(self):
"""channel_type and association are required inputs."""
with self.assertRaises(IOError):
glymur.jp2box.ChannelDefinitionBox()
def test_rgb_with_index(self):
"""Just regular RGB.""" """Just regular RGB."""
j2k = Jp2k(self.j2kfile) j2k = Jp2k(self.j2kfile)
channel_type = [COLOR, COLOR, COLOR]
association = [RED, GREEN, BLUE]
cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2], cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2],
channel_type=[0, 0, 0], channel_type=channel_type,
association=[1, 2, 3]) association=association)
boxes = [self.ihdr, self.colr_rgb, cdef] boxes = [self.ihdr, self.colr_rgb, cdef]
self.jp2h.box = boxes self.jp2h.box = boxes
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c] boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
@ -101,15 +110,41 @@ class TestChannelDefinition(unittest.TestCase):
boxes = [box.box_id for box in jp2h.box] boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef']) self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0, 1, 2)) self.assertEqual(jp2h.box[2].index, (0, 1, 2))
self.assertEqual(jp2h.box[2].channel_type, (0, 0, 0)) self.assertEqual(jp2h.box[2].channel_type,
self.assertEqual(jp2h.box[2].association, (1, 2, 3)) (COLOR, COLOR, COLOR))
self.assertEqual(jp2h.box[2].association,
(RED, GREEN, BLUE))
def test_rgb(self):
"""Just regular RGB, but don't supply the optional index."""
j2k = Jp2k(self.j2kfile)
channel_type = [COLOR, COLOR, COLOR]
association = [RED, GREEN, BLUE]
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_rgb, cdef]
self.jp2h.box = boxes
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
j2k.wrap(tfile.name, boxes=boxes)
jp2 = Jp2k(tfile.name)
jp2h = jp2.box[2]
boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0, 1, 2))
self.assertEqual(jp2h.box[2].channel_type,
(COLOR, COLOR, COLOR))
self.assertEqual(jp2h.box[2].association,
(RED, GREEN, BLUE))
def test_rgba(self): def test_rgba(self):
"""Just regular RGBA.""" """Just regular RGBA."""
j2k = Jp2k(self.four_planes) j2k = Jp2k(self.four_planes)
cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2, 3], channel_type = (COLOR, COLOR, COLOR, OPACITY)
channel_type=[0, 0, 0, 1], association = (RED, GREEN, BLUE, WHOLE_IMAGE)
association=[1, 2, 3, 0]) cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_rgb, cdef] boxes = [self.ihdr, self.colr_rgb, cdef]
self.jp2h.box = boxes self.jp2h.box = boxes
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c] boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
@ -121,15 +156,16 @@ class TestChannelDefinition(unittest.TestCase):
boxes = [box.box_id for box in jp2h.box] boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef']) self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0, 1, 2, 3)) self.assertEqual(jp2h.box[2].index, (0, 1, 2, 3))
self.assertEqual(jp2h.box[2].channel_type, (0, 0, 0, 1)) self.assertEqual(jp2h.box[2].channel_type, channel_type)
self.assertEqual(jp2h.box[2].association, (1, 2, 3, 0)) self.assertEqual(jp2h.box[2].association, association)
def test_bad_rgba(self): def test_bad_rgba(self):
"""R, G, and B must be specified.""" """R, G, and B must be specified."""
j2k = Jp2k(self.four_planes) j2k = Jp2k(self.four_planes)
cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2, 3], channel_type = (COLOR, COLOR, OPACITY, OPACITY)
channel_type=[0, 0, 1, 1], association = (RED, GREEN, BLUE, WHOLE_IMAGE)
association=[1, 2, 3, 0]) cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_rgb, cdef] boxes = [self.ihdr, self.colr_rgb, cdef]
self.jp2h.box = boxes self.jp2h.box = boxes
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c] boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
@ -140,9 +176,10 @@ class TestChannelDefinition(unittest.TestCase):
def test_grey(self): def test_grey(self):
"""Just regular greyscale.""" """Just regular greyscale."""
j2k = Jp2k(self.one_plane) j2k = Jp2k(self.one_plane)
cdef = glymur.jp2box.ChannelDefinitionBox(index=[0], channel_type = (COLOR,)
channel_type=[0], association = (GREY,)
association=[1]) cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_gr, cdef] boxes = [self.ihdr, self.colr_gr, cdef]
self.jp2h.box = boxes self.jp2h.box = boxes
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c] boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
@ -154,15 +191,16 @@ class TestChannelDefinition(unittest.TestCase):
boxes = [box.box_id for box in jp2h.box] boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef']) self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0,)) self.assertEqual(jp2h.box[2].index, (0,))
self.assertEqual(jp2h.box[2].channel_type, (0,)) self.assertEqual(jp2h.box[2].channel_type, channel_type)
self.assertEqual(jp2h.box[2].association, (1,)) self.assertEqual(jp2h.box[2].association, association)
def test_grey_alpha(self): def test_grey_alpha(self):
"""Just regular greyscale plus alpha.""" """Just regular greyscale plus alpha."""
j2k = Jp2k(self.two_planes) j2k = Jp2k(self.two_planes)
cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1], channel_type = (COLOR, OPACITY)
channel_type=[0, 1], association = (GREY, WHOLE_IMAGE)
association=[1, 0]) cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_gr, cdef] boxes = [self.ihdr, self.colr_gr, cdef]
self.jp2h.box = boxes self.jp2h.box = boxes
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c] boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
@ -174,17 +212,19 @@ class TestChannelDefinition(unittest.TestCase):
boxes = [box.box_id for box in jp2h.box] boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef']) self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0, 1)) self.assertEqual(jp2h.box[2].index, (0, 1))
self.assertEqual(jp2h.box[2].channel_type, (0, 1)) self.assertEqual(jp2h.box[2].channel_type, channel_type)
self.assertEqual(jp2h.box[2].association, (1, 0)) self.assertEqual(jp2h.box[2].association, association)
def test_bad_grey_alpha(self): def test_bad_grey_alpha(self):
"""A greyscale image with alpha layer must specify Y""" """A greyscale image with alpha layer must specify a color channel"""
j2k = Jp2k(self.two_planes) j2k = Jp2k(self.two_planes)
channel_type = (OPACITY, OPACITY)
association = (GREY, WHOLE_IMAGE)
# This cdef box # This cdef box
cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1], cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
channel_type=[1, 1], association=association)
association=[0, 1])
boxes = [self.ihdr, self.colr_gr, cdef] boxes = [self.ihdr, self.colr_gr, cdef]
self.jp2h.box = boxes self.jp2h.box = boxes
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c] boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
@ -196,9 +236,10 @@ class TestChannelDefinition(unittest.TestCase):
"""There can only be one channel definition box in the jp2 header.""" """There can only be one channel definition box in the jp2 header."""
j2k = Jp2k(self.j2kfile) j2k = Jp2k(self.j2kfile)
cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2], channel_type = (COLOR, COLOR, COLOR)
channel_type=[0, 0, 0], association = (RED, GREEN, BLUE)
association=[1, 2, 3]) cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, cdef, self.colr_rgb, cdef] boxes = [self.ihdr, cdef, self.colr_rgb, cdef]
self.jp2h.box = boxes self.jp2h.box = boxes
@ -214,9 +255,10 @@ class TestChannelDefinition(unittest.TestCase):
boxes = [self.ihdr, self.colr_rgb] boxes = [self.ihdr, self.colr_rgb]
self.jp2h.box = boxes self.jp2h.box = boxes
cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2], channel_type = (COLOR, COLOR, COLOR)
channel_type=[0, 0, 0], association = (RED, GREEN, BLUE)
association=[1, 2, 3]) cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.jP, self.ftyp, self.jp2h, cdef, self.jp2c] boxes = [self.jP, self.ftyp, self.jp2h, cdef, self.jp2c]
@ -228,18 +270,20 @@ class TestChannelDefinition(unittest.TestCase):
# Channel types are limited to 0, 1, 2, 65535 # Channel types are limited to 0, 1, 2, 65535
# Should reject if not all of index, channel_type, association the # Should reject if not all of index, channel_type, association the
# same length. # same length.
channel_type = (COLOR, COLOR, 3)
association = (RED, GREEN, BLUE)
with self.assertRaises(IOError): with self.assertRaises(IOError):
box = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2], box = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
channel_type=[0, 0, 3], association=association)
association=[1, 2, 3])
def test_wrong_lengths(self): def test_wrong_lengths(self):
# Should reject if not all of index, channel_type, association the # Should reject if not all of index, channel_type, association the
# same length. # same length.
channel_type = (COLOR, COLOR)
association = (RED, GREEN, BLUE)
with self.assertRaises(IOError): with self.assertRaises(IOError):
box = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2], box = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
channel_type=[0, 0], association=association)
association=[1, 2, 3])
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@ -427,6 +471,7 @@ class TestJp2Boxes(unittest.TestCase):
def setUp(self): def setUp(self):
self.j2kfile = glymur.data.goodstuff() self.j2kfile = glymur.data.goodstuff()
self.jp2file = glymur.data.nemo()
def tearDown(self): def tearDown(self):
pass pass
@ -522,7 +567,7 @@ class TestJp2Boxes(unittest.TestCase):
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_wrap_jp2(self): def test_wrap_jp2(self):
j2k = Jp2k(self.j2kfile) j2k = Jp2k(self.jp2file)
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile: with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
jp2 = j2k.wrap(tfile.name) jp2 = j2k.wrap(tfile.name)
boxes = [box.box_id for box in jp2.box] boxes = [box.box_id for box in jp2.box]

View file

@ -1,37 +1,38 @@
| OS | Python | Python | Python | Notes | | OS | Python | Python | Python | Notes |
| | 2.6 | 2.7 | 3.3 | | | | 2.6 | 2.7 | 3.3 | |
+---------+--------+--------+--------+---------------------------------------+ +-----------+--------+--------+--------+--------------------------------------+
| Windows | | X | | Python(xy) with OpenJPEG 1.5.1. At | | Windows | | X | | Python(xy) with OpenJPEG 1.5.1 and |
| | | | | least 155 of 444 tests should pass. | | | | | | OpenJPEG svn. 285 of 448 tests |
+---------+--------+--------+--------+---------------------------------------+ | | | | | pass. |
| Windows | | X | | Python(xy) with OpenJPEG 1.5.1 and | +-----------+--------+--------+--------+--------------------------------------+
| | | | | OpenJPEG svn. At least 282 of 444 | | Mac | X | | | MacPorts with both OpenJPEG 1.5.1 |
| | | | | tests should pass. | | 10.6.8 | | | | and OpenJPEG svn. 353 of 449 tests |
+---------+--------+--------+--------+---------------------------------------+ | | | | | should pass. |
| Mac | X | | | MacPorts with both OpenJPEG 1.5.1 | +-----------+--------+--------+--------+--------------------------------------+
| | | | | and OpenJPEG svn. 342 of 451 tests | | Mac | | X | | MacPorts with both OpenJPEG 1.5.1 |
| | | | | should pass. | | 10.6.8 | | | | and OpenJPEG svn. 376 of 454 tests |
+---------+--------+--------+--------+---------------------------------------+ | | | | | should pass. |
| Mac | | X | | MacPorts with both OpenJPEG 1.5.1 | +-----------+--------+--------+--------+--------------------------------------+
| | | | | and OpenJPEG svn. 373 of 451 tests | | Mac | | | X | MacPorts with both OpenJPEG 1.5.1 |
| | | | | should pass. | | 10.6.8 | | | | and OpenJPEG svn. 401 of 454 |
+---------+--------+--------+--------+---------------------------------------+ | | | | | tests should pass. |
| Mac | | | X | MacPorts with both OpenJPEG 1.5.1 | +-----------+--------+--------+-----------------------------------------------+
| | | | | and OpenJPEG svn. 398 of 451 | | Fedora 19 | | | X | Ships with 1.5.1, openjp2 built too. |
| | | | | tests should pass. | | | | | | 401 of 454 tests should pass. |
+---------+--------+--------+------------------------------------------------+ +-----------+--------+--------+--------+--------------------------------------+
| Fedora | | | X | Ships with 1.5.1. 390 of 450 tests | | Fedora 18 | | | X | Ships with 1.5.1. 169 of 449 tests |
| 19 | | | | should pass. | | | | | | should pass. |
+---------+--------+--------+--------+---------------------------------------+ +-----------+--------+--------+--------+--------------------------------------+
| Fedora | | | X | Ships with 1.5.1. 167 of 445 tests | | Fedora 17 | | X | | Ships with 1.4.0. 169 of 449 tests |
| 18 | | | | should pass. | | | | | | should pass. |
+---------+--------+--------+--------+---------------------------------------+ +-----------+--------+--------+--------+--------------------------------------+
| Fedora | | X | | Ships with 1.4.0. 167 of 445 tests | | CentOS | X | | | Ships with 1.3.0. 167 of 449 tests |
| 17 | | | | should pass. | | 6.3 | | | | should pass. |
+---------+--------+--------+--------+---------------------------------------+ +-----------+--------+--------+--------+--------------------------------------+
| CentOS | X | | | Ships with 1.3.0. 165 of 445 tests | | Raspberry | | X | | Ships with 1.3.0. 169 of 449 tests |
| 6.3 | | | | should pass. | | Pi | | | | should pass. |
+---------+--------+--------+--------+---------------------------------------+ | Debian 7 | | | | |
+-----------+--------+--------+--------+--------------------------------------+
Pylint on entire package should exceed 0.95. Pylint on entire package should exceed 0.95.
pep8 should be pass cleanly. pep8 should be pass cleanly.

View file

@ -2,7 +2,7 @@ from setuptools import setup, find_packages
import sys import sys
kwargs = {'name': 'Glymur', kwargs = {'name': 'Glymur',
'version': '0.2.2', 'version': '0.2.3',
'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',