housecleaning for 0.7.0 release
Add testing mention of CentOS, windows. Skipping some tests on versions 1.3 and 1.4 Minor doc mods. For whatever stupid reason, np.log2(x) cannot be relied upon to be an integer when x is a power of 2 ON WIN32!!! All hail win32! Better error message if array-style slice other than [:]
This commit is contained in:
parent
64fa597b18
commit
0e2aa4492c
15 changed files with 92 additions and 35 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
Sep 25, 2014 - -v0.7.0 Added __getitem__, __setitem__ support.
|
||||||
|
|
||||||
Mar 06, 2014 - Added Cinema2K, Cinema4K write support.
|
Mar 06, 2014 - Added Cinema2K, Cinema4K write support.
|
||||||
Changed constructor for ChannelDefinition box. Removed support
|
Changed constructor for ChannelDefinition box. Removed support
|
||||||
for Python 2.6. Added write support for JP2 UUID, DataEntryURL,
|
for Python 2.6. Added write support for JP2 UUID, DataEntryURL,
|
||||||
|
|
|
||||||
|
|
@ -76,9 +76,9 @@ copyright = u'2013, John Evans'
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.6'
|
version = '0.7'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.6.0'
|
release = '0.7.0rc1'
|
||||||
|
|
||||||
# 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.
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,11 @@ configuration format is the same as used by Python’s configparser
|
||||||
module, i.e. ::
|
module, i.e. ::
|
||||||
|
|
||||||
[library]
|
[library]
|
||||||
openjp2: /opt/openjp2-svn/lib/libopenjp2.so
|
openjp2: /somewhere/lib/libopenjp2.so
|
||||||
|
|
||||||
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. The location of the configuration file
|
/opt/openjpeg on a linux system. The location of the configuration file
|
||||||
can vary as well (of course). If you use either linux or mac, the path
|
can vary as well. If you use either linux or mac, the path
|
||||||
to the configuration file would normally be ::
|
to the configuration file would normally be ::
|
||||||
|
|
||||||
$HOME/.config/glymur/glymurrc
|
$HOME/.config/glymur/glymurrc
|
||||||
|
|
@ -48,7 +48,7 @@ You may also include a line for the version 1.x openjpeg library if you have it
|
||||||
installed in a non-standard place, i.e. ::
|
installed in a non-standard place, i.e. ::
|
||||||
|
|
||||||
[library]
|
[library]
|
||||||
openjpeg: /not/the/usual/location/lib/libopenjpeg.so
|
openjpeg: /somewhere/lib/libopenjpeg.so
|
||||||
|
|
||||||
'''''''
|
'''''''
|
||||||
Testing
|
Testing
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,15 @@ How do I...?
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
||||||
... read the lower resolution images?
|
... read images?
|
||||||
=====================================
|
================
|
||||||
Jp2k implements slicing via the :py:meth:`__getitem__` method so
|
Jp2k implements slicing via the :py:meth:`__getitem__` method, meaning that
|
||||||
any lower resolution images in a JPEG 2000 file can easily be
|
multiple resolution imagery in a JPEG 2000 file can
|
||||||
accessed, for example here's how to retrieve the first sub-image ::
|
easily be accessed via array-style slicing. For example here's how to
|
||||||
|
retrieve a full resolution and first lower-resolution image ::
|
||||||
|
|
||||||
>>> import glymur
|
>>> import glymur
|
||||||
>>> jp2file = glymur.data.nemo()
|
>>> jp2file = glymur.data.nemo() # just a path to a JPEG2000 file
|
||||||
>>> jp2 = glymur.Jp2k(jp2file)
|
>>> jp2 = glymur.Jp2k(jp2file)
|
||||||
>>> fullres = jp2[:]
|
>>> fullres = jp2[:]
|
||||||
>>> print(fullres.shape)
|
>>> print(fullres.shape)
|
||||||
|
|
@ -19,20 +20,34 @@ accessed, for example here's how to retrieve the first sub-image ::
|
||||||
>>> print(thumbnail.shape)
|
>>> print(thumbnail.shape)
|
||||||
(728, 1296, 3)
|
(728, 1296, 3)
|
||||||
|
|
||||||
The :py:meth:`read` method gives many more options for other JPEG 2000 features
|
The :py:meth:`read` method exposes many more options for other JPEG 2000
|
||||||
such as quality layers.
|
features such as quality layers.
|
||||||
|
|
||||||
|
... write images?
|
||||||
|
=================
|
||||||
|
So long as the image data can fit entirely into memory, array-style slicing may
|
||||||
|
also be used to write JPEG 2000 files.
|
||||||
|
|
||||||
|
>>> import glymur, numpy as np
|
||||||
|
>>> jp2 = glymur.Jp2k('zeros.jp2', mode='wb')
|
||||||
|
>>> jp2[:] = np.zeros((640, 480), dtype=np.uint8)
|
||||||
|
|
||||||
|
The :py:meth:`write` method exposes many more options for other JPEG 2000
|
||||||
|
features. You should have OpenJPEG version 1.5 or more recent before writing
|
||||||
|
JPEG 2000 images.
|
||||||
|
|
||||||
... display metadata?
|
... display metadata?
|
||||||
=====================
|
=====================
|
||||||
There are two ways. From the command line, the script **jp2dump** is
|
There are two ways. From the command line, the console script **jp2dump** is
|
||||||
available. ::
|
available. ::
|
||||||
|
|
||||||
$ jp2dump /path/to/glymur/installation/data/nemo.jp2
|
$ jp2dump /path/to/glymur/installation/data/nemo.jp2
|
||||||
|
|
||||||
From within Python, it is as simple as printing the Jp2k object, i.e. ::
|
From within Python, the same result is obtained simply by printing the Jp2k
|
||||||
|
object, i.e. ::
|
||||||
|
|
||||||
>>> import glymur
|
>>> import glymur
|
||||||
>>> jp2file = glymur.data.nemo()
|
>>> jp2file = glymur.data.nemo() # just a path to a JP2 file
|
||||||
>>> jp2 = glymur.Jp2k(jp2file)
|
>>> jp2 = glymur.Jp2k(jp2file)
|
||||||
>>> print(jp2)
|
>>> print(jp2)
|
||||||
File: nemo.jp2
|
File: nemo.jp2
|
||||||
|
|
@ -326,10 +341,10 @@ is currently limited to XML and UUID boxes.
|
||||||
... create an image with an alpha layer?
|
... create an image with an alpha layer?
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
OpenJPEG can create JP2 files with more than 3 components (requires
|
OpenJPEG can create JP2 files with more than 3 components (use version 2.1.0+
|
||||||
the development version of OpenJPEG), but by default, any extra components are
|
for this), but by default, any extra components are not described
|
||||||
not described as such. In order to do so, we need to rewrap such
|
as such. In order to do so, we need to rewrap such an image in a
|
||||||
an image in a set of boxes that includes a channel definition box.
|
set of boxes that includes a channel definition box.
|
||||||
|
|
||||||
This example is based on SciPy example code found at
|
This example is based on SciPy example code found at
|
||||||
http://scipy-lectures.github.io/advanced/image_processing/#basic-manipulations .
|
http://scipy-lectures.github.io/advanced/image_processing/#basic-manipulations .
|
||||||
|
|
@ -387,7 +402,11 @@ Here's how the Preview application on the mac shows the RGBA image.
|
||||||
|
|
||||||
... work with XMP UUIDs?
|
... work with XMP UUIDs?
|
||||||
========================
|
========================
|
||||||
XMP is metadata on steroids.
|
`Wikipedia <http://en.wikipedia.org/wiki/Extensible_Metadata_Platform>`_ states
|
||||||
|
that "The Extensible Metadata Platform (XMP) is an ISO standard,
|
||||||
|
originally created by Adobe Systems Inc., for the creation, processing
|
||||||
|
and interchange of standardized and custom metadata for all kinds
|
||||||
|
of resources."
|
||||||
|
|
||||||
The example JP2 file shipped with glymur has an XMP UUID. ::
|
The example JP2 file shipped with glymur has an XMP UUID. ::
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ Contents:
|
||||||
introduction
|
introduction
|
||||||
detailed_installation
|
detailed_installation
|
||||||
how_do_i
|
how_do_i
|
||||||
api
|
|
||||||
whatsnew/index
|
whatsnew/index
|
||||||
roadmap
|
roadmap
|
||||||
|
api
|
||||||
|
|
||||||
------------------
|
------------------
|
||||||
Indices and tables
|
Indices and tables
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,16 @@ Glymur: a Python interface for JPEG 2000
|
||||||
**Glymur** is an interface to the OpenJPEG library
|
**Glymur** is an interface to the OpenJPEG library
|
||||||
which allows one to read and write JPEG 2000 files from Python.
|
which allows one to read and write JPEG 2000 files from Python.
|
||||||
Glymur supports both reading and writing of JPEG 2000 images, but writing
|
Glymur supports both reading and writing of JPEG 2000 images, but writing
|
||||||
JPEG 2000 images is currently limited to images that can fit in memory
|
JPEG 2000 images is currently limited to images that can fit in memory.
|
||||||
|
**Glymur** can read images using OpenJPEG library versions as far back as 1.3,
|
||||||
|
but it is strongly recommended to use version 2.1.0, which is the most recently
|
||||||
|
released version of OpenJPEG at this time.
|
||||||
|
|
||||||
In regards to metadata, most JP2 boxes are properly interpreted.
|
In regards to metadata, most JP2 boxes are properly interpreted.
|
||||||
Certain optional JP2 boxes can also be written, including XML boxes and
|
Certain optional JP2 boxes can also be written, including XML boxes and
|
||||||
XMP UUIDs. There is incomplete support for reading JPX metadata.
|
XMP UUIDs. There is incomplete support for reading JPX metadata.
|
||||||
|
|
||||||
Glymur 0.6 works on Python versions 2.7, 3.3 and 3.4. If you have Python 2.6,
|
Glymur works on Python versions 2.7, 3.3 and 3.4. If you have Python 2.6,
|
||||||
you should use the 0.5 series of Glymur.
|
you should use the 0.5 series of Glymur.
|
||||||
|
|
||||||
For more information about OpenJPEG, please consult http://www.openjpeg.org.
|
For more information about OpenJPEG, please consult http://www.openjpeg.org.
|
||||||
|
|
@ -27,5 +30,6 @@ but you should also be able to install Glymur via pip ::
|
||||||
|
|
||||||
$ pip install glymur
|
$ pip install glymur
|
||||||
|
|
||||||
In addition to the package, this also gives you a script **jp2dump** that can
|
In addition to the package, this also gives you a command line script
|
||||||
be used from the command line line to print JPEG 2000 metadata.
|
**jp2dump** that can be used from the command line line to print JPEG 2000
|
||||||
|
metadata.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,12 @@
|
||||||
|
-------------------------------------
|
||||||
|
Platforms Tested (0.7.0 release only)
|
||||||
|
-------------------------------------
|
||||||
|
* Linux Mint 17 / Python 3.4.0 and 2.7.6 / OpenJPEG 2.1.0 and 1.3.0
|
||||||
|
* MacOS 10.6.8 / MacPorts Python 3.4.1, 3.3.5,and 2.7.8 / OpenJPEG 2.1.0
|
||||||
|
* CentOS 6.5 / Anaconda Python 3.4.1 / OpenJPEG 1.3.0
|
||||||
|
* Fedora 20 i386 / Python 2.7.5 and 3.3.2 / OpenJPEG 1.5.1
|
||||||
|
* Windows 7 32bit / Anaconda Python 2.7.6 and 3.4.1 / OpenJPEG 2.1.0
|
||||||
|
|
||||||
------------
|
------------
|
||||||
Known Issues
|
Known Issues
|
||||||
------------
|
------------
|
||||||
|
|
|
||||||
11
docs/source/whatsnew/0.7.rst
Normal file
11
docs/source/whatsnew/0.7.rst
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
=====================
|
||||||
|
Changes in glymur 0.7
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Changes in 0.7.0
|
||||||
|
=================
|
||||||
|
|
||||||
|
* implemented :py:meth:`__getitem__`, :py:meth:`__setitem__` support
|
||||||
|
* added back windows support
|
||||||
|
* box_id and longname are class attributes now instead of instance
|
||||||
|
attributes (see issue 248)
|
||||||
|
|
@ -10,3 +10,4 @@ These document the changes between minor (or major) versions of glymur.
|
||||||
|
|
||||||
0.5
|
0.5
|
||||||
0.6
|
0.6
|
||||||
|
0.7
|
||||||
|
|
|
||||||
|
|
@ -772,7 +772,7 @@ class Jp2k(Jp2kBox):
|
||||||
# Should have a slice object where start = stop = step = None
|
# Should have a slice object where start = stop = step = None
|
||||||
self.write(data)
|
self.write(data)
|
||||||
else:
|
else:
|
||||||
msg = "Images currently must be written entirely at once."
|
msg = "Partial write operations are currently not allowed."
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
|
|
||||||
def __getitem__(self, pargs):
|
def __getitem__(self, pargs):
|
||||||
|
|
@ -832,9 +832,11 @@ class Jp2k(Jp2kBox):
|
||||||
# one of them.
|
# one of them.
|
||||||
step = rows_step
|
step = rows_step
|
||||||
|
|
||||||
if np.log2(step) != np.floor(np.log2(step)):
|
# Check if the step size is a power of 2.
|
||||||
|
if np.abs(np.log2(step) - np.round(np.log2(step))) > 1e-6:
|
||||||
msg = "Row and column strides must be powers of 2."
|
msg = "Row and column strides must be powers of 2."
|
||||||
raise IndexError(msg)
|
raise IndexError(msg)
|
||||||
|
rlevel = np.int(np.round(np.log2(step)))
|
||||||
|
|
||||||
if rows.start is None:
|
if rows.start is None:
|
||||||
rows_start = 0
|
rows_start = 0
|
||||||
|
|
@ -857,7 +859,7 @@ class Jp2k(Jp2kBox):
|
||||||
cols_stop = cols.stop
|
cols_stop = cols.stop
|
||||||
|
|
||||||
area = (rows_start, cols_start, rows_stop, cols_stop)
|
area = (rows_start, cols_start, rows_stop, cols_stop)
|
||||||
data = self.read(area=area, rlevel=np.int(np.log2(step)))
|
data = self.read(area=area, rlevel=rlevel)
|
||||||
if len(pargs) == 2:
|
if len(pargs) == 2:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
@ -873,7 +875,7 @@ class Jp2k(Jp2kBox):
|
||||||
rlevel : int, optional
|
rlevel : int, optional
|
||||||
Factor by which to rlevel output resolution. Use -1 to get the
|
Factor by which to rlevel output resolution. Use -1 to get the
|
||||||
lowest resolution thumbnail. This is the only keyword option
|
lowest resolution thumbnail. This is the only keyword option
|
||||||
available to use when only the OpenJPEG version 1.5.1 is present.
|
available to use when the OpenJPEG version is 1.5 or earlier.
|
||||||
layer : int, optional
|
layer : int, optional
|
||||||
Number of quality layer to decode.
|
Number of quality layer to decode.
|
||||||
area : tuple, optional
|
area : tuple, optional
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ if sys.hexversion < 0x03000000:
|
||||||
WARNING_INFRASTRUCTURE_MSG = "3.x warning infrastructure only"
|
WARNING_INFRASTRUCTURE_MSG = "3.x warning infrastructure only"
|
||||||
elif re.match('1.[0-6]', six.__version__) is not None:
|
elif re.match('1.[0-6]', six.__version__) is not None:
|
||||||
WARNING_INFRASTRUCTURE_ISSUE = True
|
WARNING_INFRASTRUCTURE_ISSUE = True
|
||||||
WARNING_INFRASTRUCTURE_MSG = "Cannot use with this version of six"
|
msg = "Cannot run test with version {0} of python-six"
|
||||||
|
WARNING_INFRASTRUCTURE_MSG = msg.format(six.__version__)
|
||||||
|
|
||||||
class MetadataBase(unittest.TestCase):
|
class MetadataBase(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ class TestSuite(unittest.TestCase):
|
||||||
Jp2k(self.jp2file)
|
Jp2k(self.jp2file)
|
||||||
|
|
||||||
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
|
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
|
||||||
|
@unittest.skipIf(os.name == "nt", 'named temporary file issue on windows')
|
||||||
def test_xdg_env_config_file_is_bad(self):
|
def test_xdg_env_config_file_is_bad(self):
|
||||||
"""A non-existant library location should be rejected."""
|
"""A non-existant library location should be rejected."""
|
||||||
with tempfile.TemporaryDirectory() as tdir:
|
with tempfile.TemporaryDirectory() as tdir:
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import pkg_resources
|
||||||
|
|
||||||
import glymur
|
import glymur
|
||||||
from glymur import Jp2k
|
from glymur import Jp2k
|
||||||
|
from glymur.version import openjpeg_version
|
||||||
|
|
||||||
from .fixtures import HAS_PYTHON_XMP_TOOLKIT
|
from .fixtures import HAS_PYTHON_XMP_TOOLKIT
|
||||||
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
|
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
|
||||||
|
|
@ -441,8 +442,9 @@ class TestJp2k(unittest.TestCase):
|
||||||
actdata = j2.read()
|
actdata = j2.read()
|
||||||
self.assertTrue(fixtures.mse(actdata[0], expdata[0]) < 0.38)
|
self.assertTrue(fixtures.mse(actdata[0], expdata[0]) < 0.38)
|
||||||
|
|
||||||
@unittest.skipIf(re.match('1.5.(1|2)',
|
@unittest.skipIf(re.match('1.[0-4]', openjpeg_version) is not None,
|
||||||
glymur.version.openjpeg_version) is not None,
|
"Not supported with OpenJPEG {0}".format(openjpeg_version))
|
||||||
|
@unittest.skipIf(re.match('1.5.(1|2)', openjpeg_version) is not None,
|
||||||
"Mysteriously fails in 1.5.1 and 1.5.2")
|
"Mysteriously fails in 1.5.1 and 1.5.2")
|
||||||
def test_no_cxform_pclr_jpx(self):
|
def test_no_cxform_pclr_jpx(self):
|
||||||
"""Indices for pclr jpxfile if no color transform"""
|
"""Indices for pclr jpxfile if no color transform"""
|
||||||
|
|
@ -772,6 +774,8 @@ class TestJp2k(unittest.TestCase):
|
||||||
self.assertEqual(data.shape, (1024, 1024, 3))
|
self.assertEqual(data.shape, (1024, 1024, 3))
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(re.match('1.[0-4]', openjpeg_version) is not None,
|
||||||
|
"Not supported with OpenJPEG {0}".format(openjpeg_version))
|
||||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||||
class TestJp2k_write(unittest.TestCase):
|
class TestJp2k_write(unittest.TestCase):
|
||||||
"""Write tests, can be run by versions 1.5+"""
|
"""Write tests, can be run by versions 1.5+"""
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ from . import fixtures
|
||||||
import glymur
|
import glymur
|
||||||
from glymur import Jp2k
|
from glymur import Jp2k
|
||||||
from glymur.codestream import SIZsegment
|
from glymur.codestream import SIZsegment
|
||||||
|
from glymur.version import openjpeg_version
|
||||||
|
|
||||||
class CinemaBase(fixtures.MetadataBase):
|
class CinemaBase(fixtures.MetadataBase):
|
||||||
|
|
||||||
|
|
@ -218,6 +219,8 @@ class TestSuiteNegative2pointzero(unittest.TestCase):
|
||||||
j.write(data, cinema2k=48)
|
j.write(data, cinema2k=48)
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(re.match(r'''1.[0-4]''', openjpeg_version) is not None,
|
||||||
|
"Writing not supported until OpenJPEG 1.5")
|
||||||
@unittest.skipIf(os.name == "nt", "no write support on windows, period")
|
@unittest.skipIf(os.name == "nt", "no write support on windows, period")
|
||||||
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
|
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
|
||||||
@unittest.skipIf(OPJ_DATA_ROOT is None,
|
@unittest.skipIf(OPJ_DATA_ROOT is None,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ from .lib import openjp2 as opj2
|
||||||
|
|
||||||
# Do not change the format of this next line! Doing so risks breaking
|
# Do not change the format of this next line! Doing so risks breaking
|
||||||
# setup.py
|
# setup.py
|
||||||
version = "0.6.0"
|
version = "0.7.0rc1"
|
||||||
_sv = LooseVersion(version)
|
_sv = LooseVersion(version)
|
||||||
version_tuple = _sv.version
|
version_tuple = _sv.version
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue