Compare commits

..

553 commits

Author SHA1 Message Date
jevans
f3db36017c merge branch 'release-0.8.0rc2' 2015-01-10 19:58:27 -05:00
jevans
3c7205038f releasing 0.8.0 2015-01-10 19:58:00 -05:00
John Evans
2ffdf716c0 remove test requirement for six, doc modifications, doctest fix
The test requirement for six was problematic, as some versions cause
problems with assertWarns and some do not.  We are already filtering
out versions that we know cause problems and it can unintentionally
cause an upgrade superceding the system version if it remains as a
"test_requires" option, so best to get rid of it.  Additionally, the
"test_requires" option was entirely removed as pip doesn't recognize it
upon install, so "mock" would not be installed on Python2.7 via pip.

The doctest fix was the real fix for #316, not sure why this did
not show up when testing on linux mint
2015-01-10 19:48:09 -05:00
John Evans
7b1522bb0e merge branch 'issue314' into devel 2015-01-08 13:25:04 -05:00
John Evans
8cc1155252 removed check for six version 1.8.0, closes #314
Not sure how this issue came about as it no longer seems to exist.  The
version of six installed on Linux Mint 17 is 1.5.2, not 1.8.0 as thought
when the issue was filed.  All seems ok.
2015-01-08 13:23:55 -05:00
John Evans
1bfb2f5fc8 merge branch 'issue316' into devel 2015-01-08 12:08:16 -05:00
John Evans
4686c40c57 fix test failure, not a real bug, closes #316
Had assumed that the error was due to parse_options not being properly
reset, but that was not the case.  Seems to have just been bad expected
data.
2015-01-08 12:07:10 -05:00
jevans
05e343b2e4 merge branch 'issue315' into devel 2015-01-07 20:18:51 -05:00
John Evans
4d680cf90b refactor shape property to be less dependent on property, closes #315 2015-01-07 20:14:45 -05:00
John Evans
bd3f491e20 merge branch 'issue311' into devel 2015-01-07 08:20:51 -05:00
John Evans
059bee50e2 all tests passing on opensuse 2015-01-06 19:55:59 -05:00
John Evans
4ceb4dce61 pep8 work 2015-01-06 16:37:55 -05:00
John Evans
a24bff0af1 replaced main_header codestream attribute with codestream
changed "codestream" parameter of set_parseoptions to "full_codestream"
2015-01-06 16:35:38 -05:00
John Evans
fe5e784b58 get all tests passing 2015-01-06 11:00:08 -05:00
John Evans
a131d83d48 merge branch 'issue311' of github.com:quintusdias/glymur into issue311
Conflicts:
	glymur/test/test_printing.py
2015-01-06 09:24:04 -05:00
John Evans
aeec03c829 blah 2015-01-06 09:23:23 -05:00
jevans
7dfcc0fd7c documented rename of ContiguousCodestream attribute codesream. 2015-01-05 21:10:02 -05:00
jevans
2755e8edd4 Jp2dump tests passing, more need to be written 2015-01-05 20:23:52 -05:00
jevans
e2465c5c73 merge branch 'devel' of https://github.com/quintusdias/glymur into devel
Conflicts:
	glymur/test/test_config.py
	glymur/test/test_glymur_warnings.py
	glymur/test/test_opj_suite_dump.py
	glymur/test/test_printing.py
2015-01-05 19:24:13 -05:00
John Evans
e93392a10e print the main header by default 2015-01-05 08:13:31 -05:00
John Evans
dc2b2bda15 the main header will be printed by default 2015-01-04 21:39:14 -05:00
John Evans
c23fe48815 merge branch 'issue312' into devel 2015-01-04 20:22:49 -05:00
John Evans
43da1824b6 don't error out on bad ftyp entry or colr method, closes #312 2015-01-04 20:21:33 -05:00
John Evans
48fdceda52 merge branch 'issue310' into devel 2015-01-01 22:18:45 -05:00
John Evans
a921b1101d refactor install_requires list, closes #310
split into install_requires and test_requires
2015-01-01 22:17:55 -05:00
John Evans
0ce15e93c4 merge branch 'issue309' into devel 2015-01-01 15:17:28 -05:00
John Evans
80f696c600 fixed irreversible test to match upstream, closes #309 2015-01-01 15:14:54 -05:00
John Evans
3eae87543c merge branch 'issue308' into devel
Conflicts:
	glymur/test/test_opj_suite.py
2015-01-01 09:53:02 -05:00
John Evans
3e723605b9 fix broken test due to upstream openjpeg test suite changes, closes #308
removed test_NR_broken3_jp2_dump, it is mostly just an extreme duplicate
case of test_NR_broken_jp2_dump.  It must be skipped on 32bit platforms
anyway.

refactored some NR_broken tests, consolidating them
2015-01-01 09:48:39 -05:00
John Evans
398125b1aa merge branch 'issue308' into devel 2015-01-01 09:09:37 -05:00
John Evans
acf6b28bc9 fix broken test due to upstream openjpeg test suite changes, closes #308
removed test_NR_broken3_jp2_dump, it is mostly just an extreme duplicate
case of test_NR_broken_jp2_dump.  It must be skipped on 32bit platforms
anyway.
2015-01-01 09:07:19 -05:00
John Evans
6572fd8772 merge branch 'issue275' into devel 2014-12-31 23:32:20 -05:00
John Evans
8440d69222 codestream now a property of Jp2k object, closes #275
repeated calls to get_codestream removed
2014-12-31 23:29:39 -05:00
John Evans
c16ecd7ae9 merge branch 'issue298' into devel 2014-12-31 22:46:28 -05:00
John Evans
20f2c0c291 remove coverall changes, closes #298
no further action planned
2014-12-31 22:45:34 -05:00
John Evans
671bd88910 merge branch 'issue307' into devel 2014-12-31 22:41:20 -05:00
John Evans
6f697526f2 pep8 work, closes #307 2014-12-31 22:41:02 -05:00
jevans
13cc6aa7e5 pep8 work 2014-12-23 08:59:17 -05:00
jevans
02ff730784 pep8 work 2014-12-23 07:43:05 -05:00
John Evans
39cc8a845a merge branch 'devel' of github.com:quintusdias/glymur into devel 2014-11-23 22:22:18 -05:00
John Evans
4a4f1f5738 merge branch 'issue306' into devel 2014-11-23 22:21:12 -05:00
John Evans
4527c774fa Failures on windows are due to named temp file issue, closes #306 2014-11-23 22:20:15 -05:00
jevans
c39661b586 pep8 cleanup 2014-11-21 21:53:39 -05:00
John Evans
5541fb6465 merge branch 'issue304' into devel 2014-11-21 19:34:44 -05:00
John Evans
6a59e38aed reading metadata still works if library not installed, closes #304 2014-11-21 19:32:40 -05:00
John Evans
0889d8999b merge branch 'issue299' into devel 2014-11-21 10:39:06 -05:00
John Evans
03cb19d22b deprecated read method, removed write method, closes #299
use array-style slicing instead.  Many former read methods are now
properties.  Many former write method parameters are now moved into the
constructor.
2014-11-21 10:37:23 -05:00
jevans
7cdc5c6828 merge branch 'issue298' into devel 2014-11-05 20:57:25 -05:00
jevans
eeee8ae9dc modified travis config for coveralls support 2014-11-05 20:47:53 -05:00
jevans
7633572b49 merge branch 'devel' of https://github.com/quintusdias/glymur into devel 2014-11-05 20:35:51 -05:00
jevans
6ffd229512 merge branch 'issue286' into devel 2014-11-05 20:34:41 -05:00
jevans
1f0d0c3786 deleted TccpInfo, TileInfoV2, CodestreamInvoV2 classes
They are used in tests, but not in top-level glymur classes.
2014-11-05 20:33:10 -05:00
John Evans
24ba8c1df8 merge branch 'issue297' into devel 2014-10-30 11:48:55 -04:00
John Evans
1782cb957f removed img_array from private _determine_colorspace method, closes #297 2014-10-30 11:48:20 -04:00
jevans
73f2257d92 merge branch 'issue295' into devel 2014-10-25 11:22:42 -04:00
jevans
a713d44238 added shape attribute, closes #295 2014-10-25 11:22:19 -04:00
jevans
3e411ab5e1 merge branch 'issue294' into devel 2014-10-24 21:58:45 -04:00
jevans
aef47ed318 skip test on 2.7, closes #294
assertRegex not available
2014-10-24 21:58:08 -04:00
jevans
4aad8cd306 merge branch 'issue294' into devel 2014-10-24 21:23:12 -04:00
jevans
4ffb46833f fixed printing of j2k files with "-c 0", closes #294
It's kind of meaningless to supply that option with a raw codestream,
but if it's what the user wanted to do, then it's what the user wanted
to do.
2014-10-24 21:21:54 -04:00
jevans
41eaec6464 merge branch 'issue292' into devel 2014-10-24 20:33:41 -04:00
jevans
351ae294d6 add test for config file in current directory, closes #292 2014-10-24 20:33:01 -04:00
jevans
fa23fddfd8 merge branch 'issue290' into devel 2014-10-24 19:33:55 -04:00
jevans
5c262025b3 fix test to pick up library on macports, closes #290
The environment DYLD_FALLBACK_LIBRARY_PATH helps to find macports
libraries in /opt/local/lib
2014-10-24 19:32:21 -04:00
John Evans
34092dff5b merge branch 'issue290' into devel 2014-10-24 09:49:16 -04:00
John Evans
d36f521b61 added test for case when config dir is empty, closes #290 2014-10-24 09:48:47 -04:00
John Evans
87c9aeedd9 merge branch 'issue293' into devel 2014-10-23 12:22:12 -04:00
John Evans
5aac625981 added test for None usage in config file, closes #293 2014-10-23 12:21:37 -04:00
jevans
9a6a5affb7 merge branch 'issue291' into devel 2014-10-22 20:24:52 -04:00
jevans
954e86a2ab added negative test for int32 imagery, closes #291 2014-10-22 20:23:45 -04:00
jevans
cad26a2d88 merge branch 'issue289' into devel 2014-10-22 20:04:09 -04:00
jevans
61cafc00b8 remove FORMAT_CORPUS tests, closes #289
We don't lose any code coverage, so it's just one less thing to worry
about.
2014-10-22 20:02:55 -04:00
John Evans
22725b94b3 merge branch 'issue288' into devel 2014-10-22 19:02:31 -04:00
John Evans
b9e44a4f8a re-enabled test_glymur_warning tests on linux/python3.3, closes #288
The origin issue was probably fixed during the whole #253, #255, #260,
2014-10-22 18:58:11 -04:00
John Evans
529dc50465 merge branch 'issue280' into devel 2014-10-22 15:34:46 -04:00
John Evans
fc4f5cec80 add negative tests for bad precinct sizes, closes #280 2014-10-22 15:34:13 -04:00
John Evans
08ef7846bb merge branch 'issue281' into devel 2014-10-22 09:45:55 -04:00
John Evans
1c87d982f8 add negative test for writing non-uint8-uint16 images, closes #281
Improved the error message.
2014-10-22 09:44:51 -04:00
jevans
689cedfa78 merge branch 'issue287' into devel 2014-10-21 19:44:08 -04:00
jevans
da25953de3 updated tests to run on fully loaded platform, closes #287 2014-10-21 19:43:26 -04:00
jevans
c1bb57f086 merge branch 'issue284' into devel 2014-10-21 18:14:09 -04:00
jevans
ad42363586 fix error message when no OpenJPEG library can be found, closes #284 2014-10-21 18:02:16 -04:00
jevans
1211c83df2 merge branch 'issue285' into devel 2014-10-21 17:51:50 -04:00
jevans
3636939c12 use end_decompress when decoding a tile, closes #285
had mistakenly only been using end_decompress when decoding by area
2014-10-21 17:49:32 -04:00
John Evans
84b0d4360e merge branch 'issue279' into devel 2014-10-21 12:59:58 -04:00
jevans
ff849df520 add __str__ methods for openjp2 ctypes structures, refactored their use
The openjp2 structures are now largely maintained as weak internal-use-only
attributes where possible.  This allows us to inspect (print) them from
the command line after the fact.
2014-10-21 12:57:19 -04:00
jevans
185f4da073 fix library path issue when no configuration file exists, #265 2014-10-21 12:57:19 -04:00
jevans
25d19226d2 merge branch 'issue278' into devel 2014-10-19 11:32:46 -04:00
jevans
5de1b8b240 remove LibraryNotFoundError, use RuntimeError instead, closes #274, #278
LibraryNotFoundError isn't needed because we already error out during
the import of glymur if neither openjpeg nor openjp2 can be found.

When read_bands is used and the library version is not at least 2.0.0,
use RuntimeError instead of LibraryNotFoundError.
2014-10-19 11:24:23 -04:00
jevans
dba289677d Merge branch 'issue265' into devel 2014-10-19 00:00:33 -04:00
jevans
60dcdfe9c5 refactored configuration file handling, closes #265 2014-10-18 23:59:32 -04:00
jevans
19b0533764 Merge branch 'issue277' into devel 2014-10-18 23:10:42 -04:00
jevans
41252f54de tidied up top-level imports, closes #277 2014-10-18 23:09:15 -04:00
jevans
ac019b32f7 Merge branch 'issue276' into devel 2014-10-18 21:43:10 -04:00
jevans
378cab4350 replaced windows temp file skip messages with a constant, closes #276 2014-10-18 21:41:44 -04:00
jevans
6b7a3be5de Merge branch 'issue273' into devel 2014-10-18 19:55:48 -04:00
jevans
f36c169f52 raise RuntimeError if writing with library version is too early, closes #273
We still raise a LibraryNotFoundError if there's no library at all
2014-10-18 19:52:22 -04:00
jevans
55acd9260c Merge branch 'issue270' into devel 2014-10-18 10:46:40 -04:00
jevans
b500287700 improved LibraryNotFoundError messages, docstring information, closes #270, #272 2014-10-18 10:45:07 -04:00
jevans
944bf95d45 Merge branch 'issue269' into devel 2014-10-18 08:39:05 -04:00
jevans
edde7d36b1 refactored private methods used by Jp2k write method, closes #269 2014-10-18 08:37:09 -04:00
jevans
2cbc0f3d1b Merge branch 'master' into devel 2014-10-17 20:31:16 -04:00
jevans
76014f9402 Merge branch 'devel' 2014-10-06 21:16:28 -04:00
jevans
617b9c4f00 bumping to 0.7.2 2014-10-06 21:16:11 -04:00
jevans
09f35d0db1 Merge branch 'issue267' into devel 2014-10-06 21:11:58 -04:00
jevans
4d652895bd added ellipsis support, fixed an array slicing corner case
Implemented most common ellipsis use cases.  Some refactoring.
Corner case where a single non-degenerate slice object is passed.
2014-10-06 21:09:07 -04:00
jevans
26fc4e7dfe Merge branch 'master' into devel 2014-10-04 17:33:35 -04:00
John Evans
e17c5d6092 Merge branch 'release-0.7.1' 2014-10-02 08:26:43 -04:00
John Evans
454afec67b bumping to 0.7.1 2014-10-02 08:21:04 -04:00
John Evans
af699fedfe updated README to mention Python 3.4 2014-10-02 08:18:40 -04:00
jevans
9ae8e8bd2f Merge branch 'master' into devel
Conflicts:
	CHANGES.txt
	docs/source/conf.py
	docs/source/roadmap.rst
	glymur/version.py
2014-10-01 19:02:18 -04:00
jevans
6af4b7f0a7 fix merge conflict 2014-10-01 18:55:19 -04:00
jevans
074bc588a8 Merge branch 'release-0.7.0rc1'
Conflicts:
	docs/source/conf.py
	glymur/version.py
2014-10-01 18:54:53 -04:00
jevans
fc56012dce release 0.7.0 2014-10-01 18:53:46 -04:00
John Evans
0e2aa4492c 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 [:]
2014-09-30 18:41:02 -04:00
jevans
83df953389 more doc updates 2014-09-25 18:52:19 -04:00
John Evans
a2a6b62316 minor doc mods 2014-09-25 15:26:34 -04:00
John Evans
653db644b5 skipping some tests on versions 1.3 and 1.4 2014-09-25 15:26:19 -04:00
John Evans
4284adb387 add testing mention of CentOS 2014-09-25 14:51:39 -04:00
John Evans
55ef875275 clarification of wording 2014-09-25 14:51:23 -04:00
John Evans
7feb71e55b skip one test for openjpeg versions < 1.5 2014-09-25 14:50:53 -04:00
John Evans
873bb0c900 housecleaning for 0.7.0 release 2014-09-25 09:12:46 -04:00
jevans
64fa597b18 Merge branch 'issue266' into devel 2014-09-24 21:48:21 -04:00
jevans
f22a653110 TestParsing tearDown was not being done correctly
By just passing, the correct test state was not being restored.
2014-09-24 21:47:09 -04:00
jevans
2e55a0a8a8 pinpointed test_main_header as culprit for 3 unexplained failures 2014-09-24 20:59:39 -04:00
jevans
f6c1f57177 Merge branch 'issue248' into devel 2014-09-23 20:06:03 -04:00
jevans
9bebd6438c box_id and longname are class attributes now instead of instance attributes
Some simplification of the individual box constructors, and a palette box
error message became a bit more clear because of this.
2014-09-23 20:00:47 -04:00
jevans
a45e653a0a Merge branch 'devel' into issue248 2014-09-23 18:53:12 -04:00
jevans
6035517831 Merge branch 'issue265' into devel 2014-09-22 21:17:47 -04:00
jevans
d2dc37bd5e fixed two bugs unknowingly introduced into cinema2k/4k testing 2014-09-22 21:15:49 -04:00
jevans
4ac5b575d2 config module refactor 2014-09-22 21:15:12 -04:00
jevans
cf6d40904f Merge branch 'issue263' into devel 2014-09-20 12:59:41 -04:00
John Evans
82466f2b80 refactor of test suite 2014-09-20 12:56:14 -04:00
John Evans
3366812936 refactor of CME testing 2014-09-19 09:17:40 -04:00
John Evans
b1cd14c6a5 __setitem__ working for writing an entire image at once 2014-09-19 08:17:15 -04:00
John Evans
a580fe5097 UTs written for __setitem__ support 2014-09-18 20:14:13 -04:00
John Evans
91b7ccbbe0 Merge branch 'issue258' into devel 2014-09-18 19:08:46 -04:00
John Evans
a6a9b5215b folded jp2dump module into command_line module 2014-09-18 19:08:14 -04:00
John Evans
262089f6f7 Merge branch 'issue260' into devel 2014-09-18 18:38:09 -04:00
John Evans
2afb7590dc reorganized test infrastructure, only runs on 3.x
Three tests skipped due to unexplained failures.  Several tests had
to be skipped where the python3-six version was earlier than 1.7.0.
Tested on 32-bit Fedora, Mac 10.6, Linux Mint 32 and 64-bit, Anaconda3.
2014-09-18 18:33:34 -04:00
John Evans
ebc05648eb Merge branch 'issue261' into devel 2014-09-16 10:45:21 -04:00
John Evans
6114b0f474 Merge branch 'devel' into issue261 2014-09-16 08:54:40 -04:00
John Evans
72a65943a1 Progress... 1000 lines fewer code. 2014-09-16 08:11:56 -04:00
jevans
14b19dd1e2 Merge branch 'issue246' into devel 2014-09-15 20:09:03 -04:00
John Evans
b5c4b98913 Added slice protocol support.
This includes 1.5.x, which means adding read area support.
2014-09-15 20:08:07 -04:00
jevans
4f5e6968bf Merge branch 'devel' of https://github.com/quintusdias/glymur into issue246 2014-09-11 20:01:35 -04:00
John Evans
e02217e214 Merge branch 'issue259' into devel 2014-09-11 11:58:07 -04:00
John Evans
cde16a062e Add six to travis harness requirements. 2014-09-11 11:47:01 -04:00
John Evans
5c7dd5ebb6 Restored set_parseoptions, get_parseoptions to glymur/__init__
Was mistakenly removed.
2014-09-11 11:37:36 -04:00
John Evans
5c083a7f53 Merge branch 'issue254' into devel 2014-09-11 11:29:56 -04:00
John Evans
7d9a4efdbd Rewrote jp2dump as an entry point console script.
Some printing UT refactoring was done.
2014-09-11 11:29:17 -04:00
John Evans
385f4f32a2 Merge branch 'issue256' into devel 2014-09-10 14:44:58 -04:00
John Evans
72093f05f8 Finesses the check of skimage.io
If on Anaconda and python3 and the scikit image version < 0.11, then
don't bother.  Otherwise, go back to prior try/except code for existance
of skimage.io and availability of freeimage backend, which fixes the
issue on Linux Mint.
2014-09-10 14:43:11 -04:00
John Evans
2252519b2d Merge branch 'issue255' into devel 2014-09-10 11:22:19 -04:00
John Evans
81c804e74c Must skip warning tests if version of six is < 1.7. 2014-09-10 11:21:48 -04:00
jevans
2c8e30e320 Documentation for slicing. 2014-09-09 19:10:31 -04:00
jevans
30219d01bf Basic functionality and UTs are in. 2014-09-08 20:10:21 -04:00
John Evans
1ce3113f95 Merge branch 'issue253' into devel 2014-09-03 20:26:54 -04:00
John Evans
69d3c1a846 Need to use extra care on skimage.io.plugin('freeimage'...) 2014-09-03 20:26:11 -04:00
jevans
4c4fecabd2 Merge branch 'issue251' into devel 2014-08-28 19:48:54 -04:00
jevans
5304734dfa Removed test_ETS_C1P0_p0_07_j2k. Closes #251
Test has always failed, so just remove it.
2014-08-28 19:45:39 -04:00
jevans
b29aaf3f19 Removed duplicated warning tests. Closes #250. 2014-08-27 20:49:59 -04:00
jevans
b80c0d7c6a Merge branch 'issue249' into devel 2014-08-26 20:30:47 -04:00
jevans
20d2f33cfa Skipping failing test. Closes #249
Test was failing already in openjpeg's own test suite on 1.5.2 and
2.0.0.  Best to just skip the test for those configurations.
2014-08-26 20:29:26 -04:00
John Evans
363786724c Merge branch 'issue245' into devel 2014-08-25 21:06:27 -04:00
John Evans
af80a9e81a Reworked warning tests, closes #245.
Using 3.x warning infrastructure to verify warnings.  Using old 2.x
infrastructure to suppress warnings when the point of the test is not
the warning itself but something else.

All tests for warnings moved into glymur.test.test_glymur_warnings.
2014-08-25 21:02:18 -04:00
jevans
c0929d8e15 Merge branch 'release-0.6.1' 2014-08-17 20:10:59 -04:00
jevans
925610ae3c Releasing 0.6.1.
Reverting b24ae781a6

That commit removed the capitalization, preventing it from being
uploaded to pypi.
2014-08-17 20:09:47 -04:00
John Evans
a854123bca Merge branch 'master' into devel 2014-08-17 18:17:11 -04:00
jevans
f88218d482 Releasing 0.6.0
Skipping a test that segfaults only on 1.5.0 and 2.0.0.  The test was
test_NR_DEC_issue188_beach_64bitsbox_jp2_41_decode.  It was not introduced
until the 2.1.x series and the fix was backported to 2.0.1.

glymur.test.test_jp2k.TestJp2k.test_no_cxform_pclr_jpx was failing on
1.5.2 only.  It's a pretty obscure test, so just skipping it on that
release.

Some tests for warnings are being skipped.
2014-08-17 17:42:57 -04:00
jevans
5311eb731b Merge branch 'devel' of https://github.com/quintusdias/glymur into devel 2014-05-25 21:45:29 -04:00
jevans
8a023c63b5 Merge branch 'issue238' into devel 2014-05-25 21:45:05 -04:00
jevans
83755cef0a Added another irreversible test to not use OPJ_TEST_SUITE. #238 2014-05-25 21:44:08 -04:00
John Evans
6e5cb5d6db Merge branch 'issue238' into devel 2014-05-23 06:36:47 -04:00
John Evans
6adbae067b Irreversible test needed OPJ_DATA_ROOT decorator. #238 2014-05-23 06:35:53 -04:00
jevans
81057fc03b Merge branch 'issue237' into devel 2014-05-22 21:35:54 -04:00
jevans
298c493029 New "whatsnew" documents, sort of look like h5py. #237 2014-05-22 21:35:20 -04:00
jevans
5975842d2c Merge branch 'issue238' into devel 2014-05-22 21:32:09 -04:00
jevans
a719bb4ac9 Added irreversible 9-7 transform support. #238 2014-05-22 21:30:30 -04:00
jevans
e202895ced Merge branch 'issue236' into devel 2014-05-21 21:05:45 -04:00
jevans
5d072604f7 Refactored test_codestream into test_codestream and test_codestream_warnings #236 2014-05-21 21:04:43 -04:00
jevans
334103d86d Merge branch 'issue237' into devel 2014-05-20 20:56:08 -04:00
jevans
133205d66b Changed look and feel of changelog to match 0.5.12. #237 2014-05-20 20:52:27 -04:00
jevans
4cf9f7841e Refactored test_opj_suite.py 2014-05-18 22:01:28 -04:00
John Evans
9bcea6c090 Merge branch 'issue234' into devel 2014-05-12 06:35:16 -04:00
John Evans
6a7be5363b Cinema parameters were incorrectly specified for 2.0.1 #234 2014-05-12 06:34:32 -04:00
jevans
c709215713 Merge branch 'issue229' into devel 2014-05-10 20:02:39 -04:00
jevans
c230a9b0b2 Fixed expected warning message on 2.7. #229 2014-05-10 20:02:12 -04:00
jevans
ecc1669490 Merge branch 'issue229' into devel 2014-05-10 18:36:51 -04:00
jevans
61192b73d3 Fixed warnings. #229 2014-05-10 18:35:19 -04:00
jevans
b7e2770a5a Merge branch 'issue230' into devel 2014-05-10 17:40:20 -04:00
jevans
c01774c036 Improved warning message when the tiff exif byte order is bad. #230 2014-05-10 17:39:40 -04:00
John Evans
14f495b0cf Merge branch 'issue233' into devel 2014-05-10 16:20:05 -04:00
John Evans
c31751685b Added Python 3.4 for travis-ci runs. #233 2014-05-10 16:19:28 -04:00
John Evans
de28b3b1a1 Merge branch 'issue232' into devel 2014-05-10 16:12:18 -04:00
John Evans
2750aced14 Updated versioning for pending 0.6.0 release. Removed documentation cruft. 2014-05-10 16:10:58 -04:00
John Evans
0a4bb217e3 Removed two tests that we chose not to run because of stderr issues.
They produce too much output on stderr, it would make interpreting test
results difficult.
2014-05-10 16:02:35 -04:00
John Evans
bf65a00f28 Improved warning message when brand is not proper. #232 2014-05-10 15:58:57 -04:00
John Evans
a79e234f8a Removed apparently unreachable XML code for 2.6. 2014-05-10 15:54:28 -04:00
John Evans
756ade30fa Merge branch 'devel' of https://github.com/quintusdias/glymur into devel
Conflicts:
	glymur/test/test_jp2box_jpx.py
	glymur/test/test_jp2k.py
	glymur/test/test_opj_suite.py
2014-05-10 15:36:33 -04:00
John Evans
d48b0bde50 Merge branch 'issue228' into devel 2014-05-10 15:30:53 -04:00
John Evans
937d8c971c Warnings tested with warnings.catch_warnings infrastructure.
Until there's some explanation as to why assertWarns method is failing,
this seems to be the only way forward.
2014-05-10 15:29:36 -04:00
jevans
564a9d2410 Removed tests that still cannot be run as of 2.1.0 2014-05-08 20:16:02 -04:00
John Evans
9fc3395693 Merge branch 'issue227' into devel 2014-04-27 14:16:08 -04:00
John Evans
4d15054b0c Fixed cinema profile writing on 2.1. #227
Was not forcing CINEMA_2K, 4K images to be written out as 12bps in 2.1.0.  Was
ok in 2.0.1.

Removed "OPJ_" prefix from CINEMA_{24,48}_COMP and CINEMA_{24,48}_CS fields in
core.
2014-04-27 14:15:06 -04:00
John Evans
3fbeacc581 Merge branch 'issue221' into devel 2014-04-26 12:15:33 -04:00
jevans
1e754f0e85 Updated openjp2 API for upstream openjpeg r2837 and r2847. #221
Removed "_v3" suffixes from glymur.lib.openjp2 functions.
Changed JP2k object to use both 2.0 and 2.1 means of setting cinema
compression parameter values.
2014-04-26 12:11:26 -04:00
quintusdias
772f6fbaef Merge pull request #225 from bogdanni/patch-1
Lower case for 'glymur' package name in setup.py
2014-04-24 15:35:41 -04:00
quintusdias
835673d2c5 Merge pull request #226 from bogdanni/patch-2
Python 2.6 is not supported anymore
2014-04-24 15:34:54 -04:00
Bogdan Nicula
e6723b18dd Python 2.6 is not supported anymore 2014-04-24 21:06:44 +02:00
Bogdan Nicula
b24ae781a6 Lower case for 'glymur' package name in setup.py
Is there a reason for different capitalization?
2014-04-24 21:04:08 +02:00
John Evans
62b0464f39 Merge branch 'issue224' into devel 2014-04-24 12:03:36 -04:00
John Evans
e4578db535 Removed OPENJP2_IS_V2_OFFICIAL token. #224
This can be done by a regular expression against the library version.
It had not been done because much of the original development was
against the svn 2.0+ version of openjpeg before the library version got
bumped to 2.1
2014-04-24 12:01:53 -04:00
jevans
346ae47b10 Merge branch 'devel' of https://github.com/quintusdias/glymur into devel 2014-04-23 20:13:15 -04:00
jevans
275324fce8 Merge branch 'issue217' into devel 2014-04-23 20:06:53 -04:00
jevans
506e4fff92 Improved code coverage to over 95% 2014-04-23 20:05:49 -04:00
quintusdias
f971d5bbcb Merge pull request #220 from bogdanni/patch-1
DataEntryURLBox.write(): one too many url.encode()
2014-04-19 20:10:32 -04:00
Bogdan Nicula
a7e160133f DataEntryURLBox.write(): one too many url.encode() 2014-04-20 02:22:59 +03:00
John Evans
afb61d28e6 Merge branch 'issue218' into devel 2014-04-09 17:03:06 -04:00
John Evans
0c19deb182 Added main_header_offset to ContiguousCodestreamBox. #218 2014-04-09 17:02:36 -04:00
quintusdias
7d3fbb2883 Merge pull request #215 from bogdanni/patch-1
jp2box.py: _parse_rreq3 - small fixup
2014-04-09 09:12:17 -04:00
bogdanni
e5dd222905 jp2box.py: _parse_rreq3 - small fixup 2014-04-09 14:41:23 +02:00
quintusdias
446a9be1ce Merge pull request #214 from bogdanni/patch-1
Small cleanups in jp2box.py
2014-04-08 21:06:58 -04:00
John Evans
718eb9dd6e Merge branch 'issue212' into devel 2014-04-08 21:04:05 -04:00
John Evans
f71aeaee73 Fixed test on python2.7 2014-04-08 21:03:34 -04:00
John Evans
807a0e5d3c Merge branch 'issue200' into issue212 2014-04-08 20:57:04 -04:00
John Evans
487cc9c967 Added set and get_parseoptions to control codestream parsing. #212 2014-04-08 20:54:52 -04:00
bogdanni
d89be23af2 Small cleanups in jp2box.py 2014-04-08 23:27:59 +02:00
jevans
b719313554 main_header of Codestream object is now a property. #212
This improves loading time of glymur.data.jpxfile() by 33%.
2014-04-06 18:31:23 -04:00
jevans
96db5e1a6a Removed box_is_XL parameter. #212
We only get around a 1% performance increase, which is not worth the
increased complexitiy.
2014-04-06 10:51:50 -04:00
jevans
f15913cee6 Refactored reader requireents box to use just a single file read. #212 2014-04-05 22:24:11 -04:00
jevans
578470e149 Refactored PCLR box parsing to use a single file read operation. #212 2014-04-05 17:16:49 -04:00
jevans
bb4e5cfe16 Refactored dtbl box to use just a single file read. #212 2014-04-05 15:41:49 -04:00
John Evans
02f02ce154 Merge branch 'issue213' into devel 2014-04-04 13:55:26 -04:00
John Evans
2e1af15cb1 Adjusted some comments in XML box parsing. #213 2014-04-04 13:54:58 -04:00
John Evans
1485bda7ff Passing down XL flag into each box parser. #212
This should prevent having to call the tell method on the file pointer.
2014-04-04 13:24:16 -04:00
John Evans
c12180ccb0 Merge branch 'issue204' into devel 2014-04-04 12:27:52 -04:00
John Evans
196255d780 No superbox needs to encode its box ID anymore. #204 2014-04-04 12:27:11 -04:00
John Evans
0c8b11b722 Merge branch 'issue130' into devel 2014-04-04 12:20:09 -04:00
John Evans
2dc4e8400e Refactored the TLM segment. #130 2014-04-04 12:17:58 -04:00
John Evans
3dbaf9f458 Refactored QCC segment parsing. #130 2014-04-04 07:11:43 -04:00
jevans
828abe942a Removed one read statement, using struct.unpack_from. #130 2014-04-03 22:53:52 -04:00
jevans
4e19e688a0 Variable renaming. #130 2014-04-03 22:52:11 -04:00
jevans
6ee48e3f91 Merge branch 'issue130' of https://github.com/quintusdias/glymur into issue130
Conflicts:
	glymur/jp2box.py
2014-04-03 21:38:08 -04:00
John Evans
576571fa85 Streamlined SIZ parsing. #130 2014-04-03 07:09:34 -04:00
John Evans
28a131797e Merge branch 'devel' into issue130
Conflicts:
	glymur/jp2box.py
2014-04-03 06:51:34 -04:00
jevans
7ebe4ff59e Fixed rlevel assignment issue causing segfault in 1.5.
Segfault introduced in 0e370f5882
2014-04-02 21:30:01 -04:00
jevans
0e370f5882 Refactoring, lint cleanup. 2014-04-02 20:49:17 -04:00
John Evans
eb6f5c87a9 Merge branch 'issue210' into devel 2014-04-02 12:22:31 -04:00
John Evans
63d203796b Use memoryview instead of np.getbuffer. #210
np.getbuffer is not available in python3.
2014-04-02 12:21:56 -04:00
John Evans
d2ba8a14b6 Merge branch 'issue210' into devel 2014-04-02 11:29:03 -04:00
John Evans
eb1df90fb9 Speed up of about 33%, maybe? #210
Added a real fix for #209, seeing about a 22% speed up there.
2014-04-02 11:28:00 -04:00
John Evans
8e6dc486da If palette columns are the same width, read it in one step. #210
Should be more efficient, hopefully.
2014-04-02 10:35:24 -04:00
John Evans
9b533b72e3 Merge branch 'devel' into issue210 2014-04-02 09:50:20 -04:00
John Evans
fd41614b51 Merge branch 'issue136' into devel 2014-04-02 09:40:52 -04:00
John Evans
900a44f00b Changed static methods into class methods. #136
Since the static methods were being used as constructors, they really
did deserve to be class methods.
2014-04-02 09:35:53 -04:00
John Evans
9840b66cae Merge branch 'issue209' into devel 2014-04-02 09:01:21 -04:00
John Evans
9ef39ddecb Updated test for unknown superbox printing. #209
Can no longer detect known interior boxes.  That's ok for now.
2014-04-02 09:00:23 -04:00
jevans
aacee3ddcf Merge branch 'devel' of https://github.com/quintusdias/glymur into devel 2014-04-02 07:07:29 -04:00
jevans
f6b1bd4d29 Merge branch 'issue208' into devel 2014-04-02 07:07:04 -04:00
jevans
7418dd9cac Refactored try/except fragment of box parsing. 2014-04-02 07:06:13 -04:00
John Evans
c2cae15723 Merge branch 'issue208' into devel 2014-04-01 20:56:08 -04:00
John Evans
6314458bc7 Simplified pclr writing in most cases. #208 2014-04-01 20:53:59 -04:00
jevans
738c338246 Merge branch 'issue202' into devel 2014-03-31 21:23:50 -04:00
jevans
96cb70e5a5 Added negative test for writing with bad approximation. #202 2014-03-31 21:23:11 -04:00
jevans
d96d1ff150 Merge branch 'issue206' into devel 2014-03-26 21:05:45 -04:00
jevans
6815a46902 Refactoring. #206 2014-03-26 21:04:28 -04:00
jevans
9b4e0a10fb More testing for jpx wrapping. Needs some refactoring, though. #206 2014-03-25 21:17:29 -04:00
jevans
9ecbc81e7a Strengthened the test by reordering the boxes. #206 2014-03-24 21:26:04 -04:00
jevans
faf49b11c3 Added ability to wrap more than one codestream. #206 2014-03-24 20:54:49 -04:00
jevans
9be8bed66a Updated for upstream openjpeg changes. #206 2014-03-24 18:36:17 -04:00
John Evans
69cb3d5401 Merge branch 'issue205' into devel 2014-03-23 11:33:30 -04:00
John Evans
9399ef8496 Adjusted tests for newer JPX file. #205 2014-03-23 11:33:03 -04:00
jevans
02651a420d Merge branch 'issue204' into devel 2014-03-22 20:50:32 -04:00
jevans
992cd5b205 not explicitly encoding non-superbox IDs upon write anymore. #204 2014-03-22 20:49:04 -04:00
John Evans
2642e1ab55 Merge branch 'issue188' into devel 2014-03-20 09:10:58 -04:00
John Evans
6060ccd37d Readded jpch, jplh write support. #188 2014-03-20 09:10:24 -04:00
jevans
49f7c0e1f6 Merge branch 'issue188' into devel 2014-03-19 20:15:13 -04:00
jevans
cf4317df57 Added Colour group box support. #188 2014-03-19 20:14:46 -04:00
John Evans
8a448600d2 Merge branch 'issue204' into devel 2014-03-19 16:53:54 -04:00
John Evans
0a826ad882 Most parsing and writing warning/exceptions now regularized. #203
Only exception was ftbl and flst, because ftbl is the one box consisting
of boxes that is not a superbox.
2014-03-19 16:53:31 -04:00
John Evans
4e3d58ed20 Merge branch 'issue197' into devel 2014-03-19 15:17:11 -04:00
John Evans
55a01cbc39 Not decoding box ID anymore. #197
We don't actually use the box ID as parsed from the file, so there was
no need to decode it.  This means that unrecognized box IDs are actually
kept as bytes, but no big deal.  The code is simplified a bit because of
this.
2014-03-19 15:15:55 -04:00
John Evans
2a75fcfff2 Merge branch 'issue194' into devel 2014-03-19 11:24:06 -04:00
John Evans
2ab8691898 Added warning about incorrect ftyp brand. #194
While at it, added new infrastructure for either erroring or just
warning when an conformance issue is encountered.  If parsing a file, we
warn.  If about to write a file, we error out.
2014-03-19 11:22:44 -04:00
John Evans
235e53ce87 Merge branch 'issue198' into devel 2014-03-19 10:01:34 -04:00
John Evans
f5741697d9 Test shouldn't run on 2.7 #198 2014-03-19 10:01:13 -04:00
John Evans
baba6c9bc5 Merge branch 'issue198' into devel 2014-03-19 09:21:45 -04:00
John Evans
1808d563b9 Warn instead of error out when reading invalid approximation. #198 2014-03-19 09:21:10 -04:00
jevans
f9e27fe551 Merge branch 'issue201' into devel 2014-03-18 20:05:20 -04:00
jevans
661f5bfadb Cinema 2K and Cinema 4K profiles are printed as such. #201 2014-03-18 20:04:50 -04:00
jevans
869f8e9e3e Merge branch 'issue199' into devel 2014-03-18 18:48:47 -04:00
jevans
f42c892287 Another case for a modified defaultdict. #199 2014-03-18 18:48:09 -04:00
John Evans
34cc6783df Merge branch 'issue196' into devel 2014-03-18 15:03:33 -04:00
John Evans
01524dcb99 Hardened the handling of RSIZ and profiles. #196
Did not have an entry for RSIZ=4 ==> Profile 4 for cinema 4K.
2014-03-18 15:02:41 -04:00
John Evans
b7807fa445 Merge branch 'issue193' into devel 2014-03-18 13:09:59 -04:00
John Evans
181dab1650 Fixed incorrect tests on account of #193
Probably should not have used this file as it is highly corrupt.
2014-03-18 13:04:22 -04:00
quintusdias
847d121972 Merge pull request #193 from bogdanni/patch-1
'cmap' - correct stride interpreting CMP,MTYP,PCOL
2014-03-18 12:17:46 -04:00
John Evans
80f135c7bd Merge branch 'issue195' into devel 2014-03-18 12:09:32 -04:00
John Evans
161833ee5c Checking for bad wavelet transform while parsing. #195
Being more intelligent about printing in such cases.
2014-03-18 12:08:16 -04:00
John Evans
d6cd57896f One doubled up test, failing one in wrong section. #179 2014-03-18 11:33:49 -04:00
John Evans
ec8c5906e8 Merge branch 'issue179' into devel
Conflicts:
	glymur/test/test_jp2k.py
	glymur/test/test_opj_suite_write.py
2014-03-18 11:16:59 -04:00
John Evans
1be7c4ec50 Changing name to "ignore_pclr_cmap_cdef". #179 2014-03-18 11:00:35 -04:00
John Evans
d483e2cd4b Merge branch 'issue179' of github.com:quintusdias/glymur into issue179 2014-03-18 10:39:26 -04:00
bogdanni
844540df92 'cmap' - correct stride interpreting CMP,MTYP,PCOL
Fix for number of components different from 3
2014-03-18 15:22:40 +01:00
John Evans
0c32b403b0 Merge branch 'issue192' into devel 2014-03-17 19:57:49 -04:00
John Evans
74a960ed84 Added printing of lxml version. #192 2014-03-17 19:57:15 -04:00
quintusdias
eaa9f33b25 Merge pull request #191 from bogdanni/patch-1
'nlst' - compositing layer association display fix
2014-03-17 15:01:14 -04:00
bogdanni
dec37eec49 'nlst' - compositing layer association display fix 2014-03-17 14:42:33 +01:00
jevans
4a1bba217e Merge branch 'issue139' into devel 2014-03-15 22:11:19 -04:00
jevans
093f9c49fb Got 2.0.0 working again. #139 2014-03-15 22:09:49 -04:00
jevans
569476c688 Merge branch 'devel' into issue139 2014-03-15 20:36:54 -04:00
jevans
b46eb9bb29 Merge branch 'issue139' of https://github.com/quintusdias/glymur into issue139 2014-03-15 20:36:19 -04:00
John Evans
993e669cc4 Fixed test now that openjpeg version has rolled to 2.1.0 2014-03-15 11:24:15 -04:00
John Evans
24687124d3 Merge branch 'issue190' into devel 2014-03-14 10:40:29 -04:00
John Evans
b614f4818f Added proper unittest.skipIf when skimage.io plugin freeimage not found. #190 2014-03-14 10:39:51 -04:00
John Evans
ffbf0bdbf8 Merge branch 'issue185' into devel 2014-03-13 21:40:02 -04:00
John Evans
86ac1c4ae5 Fixed test skipping when no OPJ_DATA_ROOT present. #185 2014-03-13 21:39:24 -04:00
John Evans
9ff572f9fd Merge branch 'issue185' into devel 2014-03-13 21:18:36 -04:00
John Evans
58d3d9dc04 Remove any BOM and encoding declaration from xml text. #185 2014-03-13 21:17:53 -04:00
John Evans
6b7176bf67 Merge branch 'issue187' into devel 2014-03-13 19:43:04 -04:00
John Evans
d82c9b465e Less than 8 bytes at end of file indicates corruption. #187 2014-03-13 19:41:05 -04:00
John Evans
d76305683f Added jp2 and jpx cxform tests. jpx fails on i386 linux. 2014-03-13 18:46:29 -04:00
John Evans
35dd743ba8 Merge branch 'issue179' of github.com:quintusdias/glymur into devel 2014-03-13 18:24:56 -04:00
John Evans
7afd2f6956 Merge branch 'devel' of github.com:quintusdias/glymur into devel 2014-03-13 18:01:17 -04:00
John Evans
ada829406c Merge branch 'issue179' into devel 2014-03-13 18:01:02 -04:00
John Evans
48d2c97a39 Merge branch 'issue186' into devel 2014-03-13 14:36:55 -04:00
John Evans
e15a8a6dba Don't error out when progression order is invalid. #186
Instead of a regular dictionary for the display of progression order,
use a subclass of defaultdict instead.  The defaultdict's __missing__
method is overridden to supply a custom error message that used the
offending key.  Everybody wins!!!
2014-03-13 14:34:16 -04:00
John Evans
2708e85be1 Merge branch 'issue182' into devel 2014-03-13 12:26:41 -04:00
John Evans
8f95a67013 Updated test to skip since it needs OPJ_DATA_ROOT. #182
Updated tests for #183 and #184 as well.  Refactored tests in
test_printing, split into those needing OPJ_DATA_ROOT and those
who don't.
2014-03-13 12:24:31 -04:00
John Evans
baecdad9b2 Merge branch 'devel' into issue182 2014-03-13 12:04:09 -04:00
John Evans
061e93a06e Merge branch 'devel' into issue179 2014-03-13 12:01:57 -04:00
John Evans
78351219e9 Added test for reversed components and cdef box. #179 2014-03-13 07:15:07 -04:00
John Evans
0ad00be004 Merge branch 'devel' into issue179 2014-03-13 07:02:31 -04:00
John Evans
03d1553363 Merge branch 'issue184' into devel 2014-03-12 20:52:45 -04:00
John Evans
42e1b21356 Should not raise an exception during parsing of XML box. #184 2014-03-12 20:50:42 -04:00
John Evans
d35422250c Merge branch 'issue181' into devel 2014-03-12 20:03:43 -04:00
John Evans
2ae848b6f0 Checking for division by zero with bad tile dimensions. #181 2014-03-12 20:03:04 -04:00
John Evans
9e98f044c7 Merge branch 'issue183' into devel 2014-03-12 19:22:34 -04:00
John Evans
77d2ab194a Checking for ICC profile that is None. #183 2014-03-12 19:21:35 -04:00
John Evans
df651a66d8 Merge branch 'issue182' into devel 2014-03-12 12:28:24 -04:00
John Evans
c56b919c36 Fixed printing of cmap boxes when not pclr. #182 2014-03-12 12:27:52 -04:00
John Evans
eab71d2ec0 Merge branch 'devel' into issue179 2014-03-12 10:33:15 -04:00
John Evans
4d4ecac166 Merge branch 'issue159' into devel 2014-03-12 10:11:19 -04:00
John Evans
b479ece7b4 Bring back check for bad rlevel. #159
OpenJPEG 1.5 needs the protection, it would seem.
2014-03-12 10:10:38 -04:00
John Evans
539ee438f6 Removed repeated/mangled testpoint. 2014-03-12 09:16:15 -04:00
John Evans
07398a33d5 Merge branch 'issue139' into devel 2014-03-12 08:57:35 -04:00
John Evans
ac3aa4d664 alpha is a uint16, not a uint16 pointer. #139 2014-03-12 08:57:11 -04:00
John Evans
f761e6815c Merge branch 'devel' into issue139 2014-03-12 08:45:41 -04:00
John Evans
0ebb506800 Merge branch 'devel' of github.com:quintusdias/glymur into devel 2014-03-12 08:34:04 -04:00
jevans
868d275c97 Merge branch 'issue159' into devel 2014-03-11 21:40:55 -04:00
jevans
d098dd5d5e Removed consideration of openjpeg versions 1.3 and 1.4. #159 2014-03-11 21:40:19 -04:00
jevans
735d3afff6 Merge branch 'issue180' into devel 2014-03-11 21:03:16 -04:00
jevans
1cefd80a76 Just remove the conformance tests, they aren't really needed. #180 2014-03-11 21:02:15 -04:00
John Evans
e75364e372 Merge branch 'issue139' into devel 2014-03-11 15:47:36 -04:00
John Evans
96f32395eb Merge branch 'devel' of github.com:quintusdias/glymur into devel 2014-03-11 15:47:23 -04:00
John Evans
417503764e Updated through r2691. #139 2014-03-11 15:46:17 -04:00
John Evans
f75a8a32a6 Merge branch 'devel' into issue179 2014-03-10 20:45:19 -04:00
John Evans
3e490d0c28 Rewrote the test for a file truncated by 5000 bytes. #180 2014-03-10 20:44:24 -04:00
John Evans
c8fdf399f1 Merge branch 'issue139' into devel
Conflicts:
	glymur/test/test_jp2k.py
	glymur/test/test_opj_suite.py
	glymur/test/test_printing.py
2014-03-10 20:13:07 -04:00
John Evans
de6984e204 Validated through 2686. #139 2014-03-10 19:54:38 -04:00
John Evans
95cae59841 Removing --use-mirros flag. 2014-03-09 11:57:42 -04:00
John Evans
6f1d15eda9 Adding no_cxform parameter to read. Added pclr no_cxform test. #179 2014-03-09 11:56:37 -04:00
John Evans
4a3c768a4b Updated tests for r2651 in opj_data_root. 2014-03-08 20:36:05 -05:00
John Evans
8827908b28 Updated through r2651. #139 2014-03-08 15:23:35 -05:00
John Evans
554f066d0b Added alpha member. Updated through r2451. #139 2014-03-08 14:13:36 -05:00
John Evans
ed5c6a37b4 Added .gitignore 2014-03-08 13:57:33 -05:00
John Evans
82f60b328b Validated through r2436. #139
Most cinema code was moved into the library between 2386 and 2436,
so most of glymur's was removed period.
2014-03-08 13:19:17 -05:00
John Evans
47b8dad003 Check for supplying cinema2k/4k with other options. #139 2014-03-08 07:46:12 -05:00
John Evans
4ecc23b6bf Verified through r2386. #139 2014-03-07 12:08:46 -05:00
John Evans
d74c514302 Merge branch 'issue139' into devel 2014-03-07 11:01:01 -05:00
John Evans
d68b1aacb1 Cinema4K seems to be working. #139 2014-03-07 11:00:20 -05:00
John Evans
af4b6e64bf Refactoring. #139 2014-03-07 08:40:14 -05:00
John Evans
9a74109501 Added cinema2k/48 support. #139 2014-03-07 07:00:02 -05:00
jevans
80326718a5 Finished Cinema2K upstream tests. #139 2014-03-06 21:13:40 -05:00
John Evans
3bad8a4b2e Added negative test for cinema2k frame rate not 24 or 48. #139
Some refactoring of cinema2k code.
2014-03-06 09:20:21 -05:00
John Evans
afa611ae54 Can write and parse Cinema2K image. #139
Using scikit-image to read the test data.  Testing still not complete.
2014-03-06 07:10:29 -05:00
John Evans
b6a17d60f1 Starting to implement cinema2k support. #139
Need to add scikit-image with freeimage backend in order to read
16-bit TIFFs.
2014-03-05 21:17:35 -05:00
John Evans
2fbdf146b4 Verified through r2366. #139
423 of 457 glymur tests passing, 34 skips
21 of 214 openjpeg tests failed
2014-03-05 07:04:10 -05:00
jevans
bf0d94e65b colr, flst, and pclr box. #130
The pclr box is the problematic one.  If the box length is wrong, then
it's hard to reliably parse when reading just one raw buffer.
2014-03-03 20:49:00 -05:00
jevans
55be4b2cf1 Merge branch 'devel' into issue130 2014-03-03 19:38:04 -05:00
John Evans
a224e7dff8 Merge branch 'issue177' into devel 2014-03-02 11:18:32 -05:00
John Evans
53f46fa0d9 Wrapping indentation for sake of 2.7. #177
Textwrap's indent method is not available on 2.7, so we have to fake it
ourselves.
2014-03-02 11:17:44 -05:00
John Evans
c01079d677 Refactored filetype box to use struct.unpack_from. #130 2014-03-02 07:58:48 -05:00
John Evans
692cee0345 Merge branch 'issue176' into devel 2014-03-01 12:31:44 -05:00
John Evans
5bfe7d7b95 Merge branch 'issue176' of https://github.com/quintusdias/glymur into issue176
Conflicts:
	glymur/test/fixtures.py
2014-03-01 12:31:02 -05:00
John Evans
3f37494803 Fixing indentation issues with textwrap. #176
XML had been flush left since introducing lxml, but the textwrap module
fixes that easily.
2014-03-01 12:16:42 -05:00
jevans
7be9e72638 refactored nemo xml #176 2014-02-27 20:43:57 -05:00
jevans
892715e21d Updated docs for lxml requirement. #176 2014-02-27 20:19:18 -05:00
jevans
6a635a61c7 Merge branch 'issue176' of https://github.com/quintusdias/glymur into issue176
Conflicts:
	setup.py
2014-02-27 19:46:20 -05:00
jevans
7828dc75e6 Updated lxml requirements, checked on Raspbian. #176 2014-02-27 19:44:05 -05:00
John Evans
5943aa6c7a Removed orphaned pretty print code for old element tree interface. #176 2014-02-27 18:48:48 -05:00
John Evans
e8a0681a99 Confirmed to work with lxml 3.2.3, down from 3.3. #176 2014-02-27 11:07:02 -05:00
John Evans
f176204b2c Updated requirements for lxml. #176 2014-02-27 06:55:30 -05:00
jevans
63fdde230d Migrated from ElementTree to lxml. #176 2014-02-26 20:56:25 -05:00
jevans
15358326da Merge branch 'issue175' into devel 2014-02-25 21:42:09 -05:00
jevans
04b143e1ff Added proof of concept test for linking exterior codestreams. Closes #175 2014-02-25 21:41:02 -05:00
John Evans
99d1a584d8 Verifying that data entry url box URLs are null terminated. #175 2014-02-25 07:15:12 -05:00
jevans
992c036da7 Added ftbl/data reference test. Removed bad asoc check. #175 2014-02-24 21:12:24 -05:00
jevans
16ce2ef883 More negative tests, pylint work. #175 2014-02-23 12:37:47 -05:00
jevans
f8ced317db More negative tests. Incompatible change to ChannelDefinitionBox. #175 2014-02-22 21:30:52 -05:00
jevans
4caa13a955 More negative tests. #175 2014-02-20 22:34:52 -05:00
John Evans
4276a978ea Allowing DataReferenceBoxes to be empty. #175 2014-02-20 09:19:41 -05:00
jevans
c82d525dd2 FileType box sanity checks. #175 2014-02-19 20:25:08 -05:00
jevans
cd606e1f9d Starting write support for ftbl and flst boxes. #175 2014-02-18 20:01:28 -05:00
jevans
5e76d1cf39 Added print support for unknown boxes. #175 2014-02-17 17:38:26 -05:00
jevans
df89b5523a Some pylint work. 2014-02-16 22:16:46 -05:00
jevans
331f901dae Refactored superbox parsing. #175 2014-02-16 22:03:33 -05:00
jevans
9999a60656 Improved the warning when an exif tag is bad. #175 2014-02-16 21:43:05 -05:00
jevans
3c333e999d Parsing unknown superboxes with known 1st sub box. #175 2014-02-16 20:05:39 -05:00
jevans
75785e4ab0 Refactored __str__ for superboxes. #175 2014-02-15 16:37:08 -05:00
jevans
7533dcf971 Merge branch 'issue168' into devel 2014-02-14 21:46:10 -05:00
jevans
5ba6fd5d53 Added write support for Label box. #168 2014-02-14 21:45:40 -05:00
John Evans
f264bb00f3 Default value for codestream argument should be [0], not 0. 2014-02-13 11:30:04 -05:00
jevans
17112b9f0b Merge branch 'issue169' into devel 2014-02-12 19:36:07 -05:00
jevans
d016fc504a Added another XMP example. #169 2014-02-12 19:35:45 -05:00
John Evans
c0774d2f1e Merge branch 'issue172' into devel 2014-02-12 10:01:06 -05:00
John Evans
1906bb6004 Added 'jpxb' to accepted items in the ftyp compatibility list. #172 2014-02-12 10:00:35 -05:00
John Evans
5ae5ce209b Merge branch 'issue174' into devel 2014-02-12 09:18:05 -05:00
John Evans
db92f3fea7 rreq masks and standard features now printed together. #174
Masks are printed in hex.
2014-02-12 09:17:17 -05:00
jevans
5c971a6981 Merge branch 'issue173' into devel 2014-02-11 20:00:23 -05:00
jevans
e2539b04e1 Added deprecated rreq descriptions. #173 2014-02-11 19:59:35 -05:00
John Evans
1a4d6a54c6 Merge branch 'issue165' into devel 2014-02-11 16:16:48 -05:00
John Evans
b0719450b5 Added support for rreq boxes with mask length of 3. #165 2014-02-11 16:16:22 -05:00
John Evans
a2df4d6c79 Merge branch 'issue170' into devel 2014-02-11 13:57:55 -05:00
John Evans
0205a3cbba More refactoring, think it's in good shape now. #170 2014-02-11 13:57:30 -05:00
John Evans
df5bf539ef Some refactoring to reduce complexity for box validity. #170 2014-02-11 13:39:56 -05:00
John Evans
ffc7379e68 Merge branch 'issue171' into devel 2014-02-11 08:23:28 -05:00
John Evans
0feca73399 Added changelog section to docs. #171 2014-02-11 08:23:03 -05:00
jevans
1d00015a6f Merge branch 'issue167' into devel 2014-02-10 19:39:03 -05:00
jevans
09651c27b6 No longer claiming any windows support. #167 2014-02-10 19:38:37 -05:00
John Evans
beb8877e3e Merge branch 'issue157' into devel 2014-02-10 16:48:10 -05:00
John Evans
87cbf87ed7 Checking for proper location of jp2h children. #157
Certain boxes can only reside in jp2h or jpch (which is not currently
supported for writing purposed).
2014-02-10 16:47:09 -05:00
John Evans
4543a64f5d Merge branch 'issue160' into devel 2014-02-10 15:43:43 -05:00
John Evans
1484fd974f Removed trailing newline from XML string output. #160 2014-02-10 15:43:18 -05:00
John Evans
6e501710b9 Merge branch 'issue161' into devel 2014-02-10 15:14:11 -05:00
John Evans
3f56a08d2c Added usage of set_printoptions method. #161 2014-02-10 15:13:42 -05:00
John Evans
a7e4a5b593 Merge branch 'issue164' into devel 2014-02-10 14:53:14 -05:00
John Evans
f2f05652e4 Added printoption support to jp2dump. #164 2014-02-10 14:52:53 -05:00
John Evans
fc91455e46 Merge branch 'devel' into issue164 2014-02-10 11:53:02 -05:00
John Evans
4706b667ff Merge branch 'issue166' into devel 2014-02-10 11:49:01 -05:00
John Evans
116ef6e664 _uuid_io no longer a sub package but rather a module of glymur proper. #166 2014-02-10 11:48:16 -05:00
John Evans
23e5f4db3f Adding hooks into set_printoptions. 2014-02-10 11:38:54 -05:00
John Evans
6432fc7ddf Merge branch 'issue163' into devel 2014-02-10 09:39:01 -05:00
John Evans
29dbf594a5 Now printing fuam, dcm, standard masks. #163
Improves visual decoding of the reader requirements box.
2014-02-10 09:38:15 -05:00
John Evans
de5a8fe6e2 Merge branch 'issue162' into devel 2014-02-10 06:58:47 -05:00
John Evans
47d8e8470b Print options remaining persistent across invocations. #162 2014-02-10 06:58:11 -05:00
jevans
012eef71e1 Merge branch 'issue158' into devel 2014-02-09 12:52:07 -05:00
jevans
4fafaa8661 Added set_printoptions, get_printoptions functions. Closes #158 2014-02-09 12:51:28 -05:00
jevans
79d2969acc Merge branch 'issue104' into devel
Conflicts:
	CHANGES.txt
	docs/source/how_do_i.rst
	glymur/codestream.py
	glymur/jp2box.py
	glymur/test/test_jp2box.py
	glymur/test/test_jp2k.py
2014-02-08 20:29:52 -05:00
jevans
321a254464 Completed XMP description. 2014-02-08 19:52:39 -05:00
jevans
6bfb98d550 Merge branch 'issue156' into devel 2014-02-08 14:57:26 -05:00
jevans
14743d6633 Added write support for dtbl boxes. 2014-02-08 14:56:50 -05:00
John Evans
ddfbd20e78 Merge branch 'issue155' into devel 2014-02-07 16:52:52 -05:00
John Evans
fcbc8c52b4 Added new error message for case when wrapping jp2h box is empty. Closes #155 2014-02-07 16:52:28 -05:00
jevans
fc36a0bd25 Merge branch 'issue154' into devel 2014-02-06 21:12:47 -05:00
jevans
03ea0f4b54 Removed test artifact. Closes #154 2014-02-06 21:11:42 -05:00
jevans
2c1490d173 Merge branch 'issue154' into devel 2014-02-06 20:46:27 -05:00
jevans
1e3556e901 Added write support for DataEntryURL box. Closes #154 2014-02-06 20:45:26 -05:00
John Evans
e5d5e5b7ff Merge branch 'issue153' into devel 2014-02-06 10:16:08 -05:00
John Evans
3fc782b6fd Refactored superbox writing. Closes #153.
At the moment this only affects jp2s and asoc superboxes for now.
2014-02-06 10:14:10 -05:00
jevans
a54ce4bad4 Merge branch 'issue152' into devel 2014-02-05 20:59:07 -05:00
jevans
8ce1c72d6d Added write support for Association and NumberList boxes. Closes #152. 2014-02-05 20:58:32 -05:00
John Evans
f2245e0e05 Removal of 2.6 2014-02-05 15:59:39 -05:00
John Evans
7d94508549 Merge branch 'issue150' into devel 2014-02-05 15:57:57 -05:00
John Evans
4edaa7b9e6 Remove dangling 2.6 reference, simplify test script clause. Closes #150
Had left a dangling reference to 2.6 that showed up on travis-ci web
page report.

The test script section was only different for 2.6.  Versions 2.7 and 3.3 are
the same (and 3.4 should be the same when it arrives).  That section can
now be simplified.
2014-02-05 15:55:28 -05:00
John Evans
cf57fce069 Merge branch 'issue150' into devel 2014-02-05 15:21:24 -05:00
John Evans
423daf1dfe Removed support for 2.6. Closes #150 2014-02-05 15:20:33 -05:00
John Evans
4fca25baad Merge branch 'issue151' into devel 2014-02-05 11:36:03 -05:00
John Evans
4487bb1f42 Fixed repr on palette box. Closes #151
Had thought that numpy arrays could not be reconstituted through repr,
but that is not the case.
2014-02-05 11:35:05 -05:00
jevans
c9a25e47c6 Merge branch 'issue149' into devel 2014-02-04 20:52:10 -05:00
jevans
a3fb3ec037 Write support for Palette, Component Mapping box. Closes #149 2014-02-04 20:51:27 -05:00
jevans
60656be667 closes #148 2014-02-03 19:51:34 -05:00
John Evans
9fcdbb0ef8 Merge branch 'issue147' into devel 2014-02-03 08:37:00 -05:00
John Evans
a9d62da2c8 openjpeg 1.3 does not apply the palette. Closes #147 2014-02-03 08:36:18 -05:00
John Evans
ebf62f416b Merge branch 'issue146' into devel 2014-02-03 08:07:13 -05:00
John Evans
92c77a1dff Can now read image from JPX/JP2 file with > 1 codestream. Closes #146.
Now that we have a good JPX file with more than one image, that section
of code could be worked thru a bit more intelligently.
2014-02-03 08:04:53 -05:00
jevans
f08b89fc64 Merge branch 'issue145' into devel 2014-02-01 18:00:07 -05:00
jevans
11fa080910 Added test for flst, ftbl boxes. Closes #145 2014-02-01 17:58:11 -05:00
jevans
6740be931b Added fragment list and fragment table boxes. #145 2014-02-01 17:31:07 -05:00
jevans
8877060bb6 Merge branch 'issue144' into devel 2014-02-01 15:43:03 -05:00
jevans
1e43cb32cb Added support for Data Reference box. 2014-02-01 15:42:13 -05:00
jevans
5efa90491e Merge branch 'issue104' of https://github.com/quintusdias/glymur into issue104
Conflicts:
	docs/source/how_do_i.rst
2014-02-01 13:29:11 -05:00
jevans
f3fca7d7d3 More xmp blurbs. 2014-02-01 13:21:51 -05:00
jevans
dfa1fce072 NumberListBox 2014-01-30 20:05:09 -05:00
jevans
ff668a4967 Merge branch 'issue143' into devel 2014-01-30 20:00:57 -05:00
jevans
ef629e041c Added support for NumberListBox. closes #143 2014-01-30 20:00:18 -05:00
jevans
6e9846ca91 Fixed repr for XMP uuids. 2014-01-30 18:49:48 -05:00
jevans
f214459ef7 Starting to fill out python xmp toolkit advocacy. #104 2014-01-30 18:48:56 -05:00
jevans
e843d887e1 Added freebox blurb. 2014-01-29 20:19:08 -05:00
jevans
9867901d84 Merge branch 'master' into devel
Conflicts:
	CHANGES.txt

Added FreeBox support.
2014-01-29 20:17:29 -05:00
John Evans
052cadbf8e No longer presenting ElementTree as viable for XMP in docs. #104 2014-01-27 16:48:40 -05:00
jevans
8617ce0442 Using fixtures for expected values. Removed one duplicated test. #104 2014-01-25 18:16:54 -05:00
jevans
3efd4169d9 Added fixtures for ICC profiles for 27, 33, and 34. 2014-01-25 18:14:31 -05:00
jevans
2bca4ffdf2 Removed python-xmp-toolkit requirement 2014-01-25 17:08:53 -05:00
jevans
d6a8736aea Removed shutil debugging statement. 2014-01-25 17:07:33 -05:00
jevans
6cbcfb64a2 Removed restriction on only writing XMP UUIDs. #104 2014-01-25 16:04:57 -05:00
jevans
505c972170 Fixing tests broken by bad merge. 2014-01-25 15:55:36 -05:00
jevans
84c50c8499 Merge branch 'issue104' of https://github.com/quintusdias/glymur into issue104
Conflicts:
	glymur/_uuid_io/Exif.py
	glymur/_uuid_io/__init__.py
	glymur/jp2box.py
	glymur/test/test_jp2box_uuid.py
	glymur/test/test_jp2k.py
2014-01-25 15:43:03 -05:00
jevans
77b58c1c5f No explicit dependence on libxmp anymore. Back to ElementTree. 2014-01-25 15:36:55 -05:00
John Evans
c8f6aff4d8 pylint work. #104 2014-01-24 15:56:50 -05:00
John Evans
6d340a5a8a Tests passing on bare 2.6.6 python. #104 2014-01-24 15:35:23 -05:00
John Evans
553b36d40e Passing on Anaconda platform with python-xmp-toolkit 2.0. #104 2014-01-24 11:08:23 -05:00
jevans
ffe17f12cb Introducing python-xmp-toolkit requirement. #104
Down to 3 failures and 1 error.
2014-01-23 21:50:48 -05:00
jevans
ce36d7a5ee Merge branch 'devel' of https://github.com/quintusdias/glymur into devel 2014-01-21 20:09:50 -05:00
jevans
b43a79cb5d Merge branch 'issue140' into devel 2014-01-20 20:07:43 -05:00
John Evans
3ea7e7d936 Merge branch 'issue140' into devel 2013-11-15 09:35:13 -05:00
jevans
09d96c1769 Handling the case of signed data as well. #140. 2013-11-14 20:53:29 -05:00
jevans
9e87780ed3 Restored ssiz attribute to SIZsegment. #140 2013-11-14 20:07:15 -05:00
jevans
3534d8c9a4 Merge branch 'devel' of https://github.com/quintusdias/glymur into devel 2013-11-14 18:36:57 -05:00
jevans
f0f1c853df Merge branch 'master' into devel 2013-11-14 18:33:33 -05:00
John Evans
52914d1411 Merge branch 'devel' of github.com:quintusdias/glymur into devel 2013-11-13 17:44:13 -05:00
jevans
7da7bc35e4 Merge branch 'issue139' into devel 2013-11-06 20:34:38 -05:00
jevans
e471f25a6e Updated for upstream openjpeg r2354. #139 2013-11-06 20:34:03 -05:00
jevans
2465a212a1 Fixed too-short underlines. 2013-11-06 20:33:44 -05:00
jevans
606bd12f00 Merge branch 'devel' into issue139 2013-11-06 20:31:38 -05:00
jevans
5a20b59cab Merge branch 'devel' of github.com:quintusdias/glymur into devel
Conflicts:
	CHANGES.txt
2013-10-29 19:54:19 -04:00
jevans
fb63b8956e Changelog update 2013-10-29 19:52:00 -04:00
jevans
fb60140fe4 Merge branch 'issue139' into devel 2013-10-29 19:46:00 -04:00
jevans
d41f019c59 Removed class-0 conformance tests. Closes #139
Keeps us in sync with upstream openjpeg.  See r2350.
2013-10-29 19:43:14 -04:00
jevans
5845372585 Merge branch 'master' into devel 2013-10-29 19:39:30 -04:00
John Evans
b3d20fb4ef Merge branch 'master' into devel 2013-10-29 08:26:14 -04:00
jevans
32760a6ecc Doc updates for writing XMP UUIDs. #104 2013-10-27 22:09:15 -04:00
jevans
727c4dd2ea Verifying that we can write XMP UUIDs. 2013-10-27 18:13:42 -04:00
John Evans
119dc0dfcd minor documentation tweaks. #104 2013-10-27 14:28:22 -04:00
John Evans
f3d43cef7f Merge branch 'issue104' of github.com:quintusdias/glymur into issue104
Conflicts:
	CHANGES.txt
2013-10-27 14:10:53 -04:00
John Evans
6948f40f27 Merge branch 'devel' into issue104 2013-10-27 14:07:03 -04:00
John Evans
632481b31d Merge branch 'devel' of github.com:quintusdias/glymur into devel 2013-10-27 14:01:25 -04:00
John Evans
5845a9a6bb Merge branch 'issue133' into devel 2013-10-27 14:01:12 -04:00
John Evans
5e5bff39c3 Added UUIDBox and ContiguousCodeStreamBox repr support. Closes #133 2013-10-27 14:00:40 -04:00
John Evans
9caf5c9f08 Added rreg repr support. #133 2013-10-27 06:09:39 -04:00
jevans
0b16ca16cb Regexp tests can only run on 2.7 and 3.3. #133 2013-10-26 22:16:01 -04:00
jevans
dc994377e1 Added palette and xml box repr support. #133 2013-10-26 21:43:32 -04:00
jevans
c4060f23c8 Added big endian Exif support. #104 2013-10-26 19:23:33 -04:00
jevans
60a77477c9 Pylint issues, #104 2013-10-26 18:21:24 -04:00
jevans
7e717b5037 Made Exif handling more resilient. #104 2013-10-26 18:05:44 -04:00
jevans
3474e49fce Refactored UUID handling. #104
New classes for each type in _uuid_io sub package.
2013-10-26 16:51:07 -04:00
jevans
dc31ff7d91 Refactored Exif uuid code to separate subpackage. #104 2013-10-24 20:38:29 -04:00
jevans
1b09fd8eaa Merge branch 'devel' into issue104 2013-10-24 19:06:24 -04:00
jevans
08aaa25fdd Changed nemo.jp2 to have a single XMP UUID. #104 2013-10-24 19:05:11 -04:00
John Evans
638c2451b8 Merge branch 'issue135' into devel 2013-10-24 16:55:49 -04:00
John Evans
6ffe1a08a4 The palette box now returns a regular numpy array. Closes #135
Simplifies the code quite a bit.  Palette boxes seem to be quite rare.
2013-10-24 16:54:39 -04:00
John Evans
c8fe9ed776 Added proper repr support for association box. #133 2013-10-24 09:29:45 -04:00
John Evans
9799762fb5 Added repr support for Jp2k class. #133 2013-10-24 08:48:14 -04:00
John Evans
d3dd654c17 Proper repr support for SIZ segment. SIZ segment constructor change.
The SIZ segment was taking raw buffer arguments, which are difficult
for eval(repr()) to deal with, so the constructor was changed to make
the arguments more explicit. #133
2013-10-24 08:21:14 -04:00
John Evans
7ac1134872 Added ulst and uinf repr support. #133 2013-10-23 18:58:09 -04:00
John Evans
74420e587c Added 'url ', 'lbl ' box support. #133 2013-10-23 08:17:17 -04:00
John Evans
3ad31c91b8 Added support for jplh, jpch, cmap, res , resd, resc #133 2013-10-23 08:07:15 -04:00
John Evans
18818495d2 Added jp2h __repr__ method. #133 2013-10-23 06:41:31 -04:00
John Evans
cdd00d2c2d added __repr__ for colr, cdef, ihdr boxes. #133 2013-10-23 06:01:48 -04:00
John Evans
0e302a5710 Adding XMP UUID write support. Still needs tests. #104 2013-10-20 11:57:51 -04:00
John Evans
368c355560 Added __repr__ for JPEG2000SignatureBox, FileTypeBox. 2013-10-20 07:52:28 -04:00
John Evans
016443faef Merge branch 'master' into devel 2013-10-20 06:56:27 -04:00
56 changed files with 13370 additions and 5493 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*.pyc
*.swp

View file

@ -1,6 +1,5 @@
language: python
python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
@ -13,17 +12,13 @@ before_install:
# command to install dependencies
install:
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --use-mirrors contextlib2 mock ordereddict unittest2; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --use-mirrors contextlib2 mock; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then pip install --use-mirrors numpy; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then pip install --use-mirrors numpy; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install lxml contextlib2 mock six; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then pip install lxml numpy six; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then pip install lxml numpy six; fi
# command to run tests
script:
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then unit2 discover; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then python -m unittest discover; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then python -m unittest discover; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then python -m unittest discover; fi
- python -m unittest discover
notifications:
email: "john.g.evans.ne@gmail.com"

View file

@ -1,5 +1,26 @@
May 09, 2014 - v0.5.11 Added support for Python 3.4, OpenJPEG 2.0.1, and
OpenJPEG 2.1.0.
Jan 10, 2015 - v0.8.0 Reduced number of steps required for writing
images. Deprecated old read and write methods in favor of
array-style slicing. Added ignore_pclr_cmap_cdef, verbose,
shape, codestream, layer properties.
Oct 06, 2014 - v0.7.2 Added ellipsis support in array-style slicing.
Oct 02, 2014 - v0.7.1 Fixed README to mention Python 3.4
Oct 01, 2014 - v0.7.0 Added array-style slicing.
August 03, 2014 - v0.6.0 Added Cinema2K, Cinema4K write support.
Changed constructor for ChannelDefinition box. Removed support
for Python 2.6. Added write support for JP2 UUID, DataEntryURL,
Palette and Component Mapping boxes, JPX Association, NumberList
and DataReference boxes. Added read support for JPX free,
number list, data reference, fragment table, and fragment list
boxes. Improved JPX Reader Requirements box support. Added
get_printoptions, set_printoptions functions. Palette box now
a 2D numpy array instead of a list of 1D arrays. JP2 super box
constructors now take optional box list argument. Fixed bug
where JPX files with more than one codestream but advertising
jp2 compatibility were not being read.
Jan 28, 2014 - v0.5.10 Fixed bad warning when reader requirements box mask
length is unsupported.

View file

@ -3,6 +3,6 @@ glymur: a Python interface for JPEG 2000
**glymur** contains a Python interface to the OpenJPEG library which
allows one to read and write JPEG 2000 files. **glymur** works on
Python 2.6, 2.7, 3.3, and 3.4.
Python 2.7, 3.3, and 3.4.
Please read the docs, https://glymur.readthedocs.org/en/latest/

View file

@ -1,15 +0,0 @@
#!/usr/bin/env python
import argparse
import sys
import glymur
description='Print JPEG2000 metadata.'
parser = argparse.ArgumentParser(description=description)
parser.add_argument('-c', '--codestream', help='dump codestream',
action='store_true')
parser.add_argument('filename')
args = parser.parse_args()
filename = args.filename
glymur.jp2dump(args.filename, codestream=args.codestream)

View file

@ -1,116 +0,0 @@
---
API
---
Jp2k
----
.. autoclass:: glymur.Jp2k
:members: read, write, wrap, read_bands, get_codestream
Individual Boxes
----------------
Jp2kbox
'''''''
.. autoclass:: glymur.jp2box.Jp2kBox
:members:
AssociationBox
''''''''''''''
.. autoclass:: glymur.jp2box.AssociationBox
:members:
ColourSpecificationBox
''''''''''''''''''''''
.. autoclass:: glymur.jp2box.ColourSpecificationBox
:members:
ChannelDefinitionBox
''''''''''''''''''''''
.. autoclass:: glymur.jp2box.ChannelDefinitionBox
:members:
ComponentMappingBox
'''''''''''''''''''
.. autoclass:: glymur.jp2box.ComponentMappingBox
:members:
ContiguousCodestreamBox
'''''''''''''''''''''''
.. autoclass:: glymur.jp2box.ContiguousCodestreamBox
:members:
DataEntryURLBox
'''''''''''''''
.. autoclass:: glymur.jp2box.DataEntryURLBox
:members:
FileTypeBox
'''''''''''
.. autoclass:: glymur.jp2box.FileTypeBox
:members:
ImageHeaderBox
''''''''''''''
.. autoclass:: glymur.jp2box.ImageHeaderBox
:members:
JP2HeaderBox
''''''''''''
.. autoclass:: glymur.jp2box.JP2HeaderBox
:members:
JPEG2000SignatureBox
''''''''''''''''''''
.. autoclass:: glymur.jp2box.JPEG2000SignatureBox
:members:
LabelBox
''''''''
.. autoclass:: glymur.jp2box.LabelBox
:members:
PaletteBox
''''''''''
.. autoclass:: glymur.jp2box.PaletteBox
:members:
ReaderRequirementsBox
'''''''''''''''''''''
.. autoclass:: glymur.jp2box.ReaderRequirementsBox
:members:
ResolutionBox
'''''''''''''
.. autoclass:: glymur.jp2box.ResolutionBox
:members:
CaptureResolutionBox
''''''''''''''''''''
.. autoclass:: glymur.jp2box.CaptureResolutionBox
:members:
DisplayResolutionBox
''''''''''''''''''''
.. autoclass:: glymur.jp2box.DisplayResolutionBox
:members:
UUIDBox
'''''''
.. autoclass:: glymur.jp2box.UUIDBox
:members:
UUIDInfoBox
'''''''''''
.. autoclass:: glymur.jp2box.UUIDInfoBox
:members:
UUIDListBox
'''''''''''
.. autoclass:: glymur.jp2box.UUIDListBox
:members:
XMLBox
''''''
.. autoclass:: glymur.jp2box.XMLBox
:members:

View file

@ -13,7 +13,6 @@
# serve to show the default.
import sys
import os
class Mock(object):
@ -42,12 +41,12 @@ for mod_name in MOCK_MODULES:
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
@ -62,7 +61,7 @@ templates_path = ['_templates']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
@ -76,19 +75,19 @@ copyright = u'2013, John Evans'
# built documents.
#
# The short X.Y version.
version = '0.5'
version = '0.8'
# The full version, including alpha/beta/rc tags.
release = '0.5.11'
release = '0.8.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@ -96,24 +95,24 @@ exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# modindex_common_prefix = []
# -- Options for HTML output --------------------------------------------------
@ -125,26 +124,26 @@ html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@ -153,44 +152,44 @@ html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'glymurdoc'
@ -199,13 +198,13 @@ htmlhelp_basename = 'glymurdoc'
# -- Options for LaTeX output -------------------------------------------------
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# 'preamble': '',
latex_elements = {}
# Grouping the document tree into LaTeX files. List of tuples
@ -216,23 +215,23 @@ latex_documents = [('index', 'glymur.tex', u'glymur Documentation',
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# latex_domain_indices = True
# -- Options for manual page output -------------------------------------------
@ -245,7 +244,7 @@ man_pages = [
]
# If true, show URL addresses after external links.
#man_show_urls = False
# man_show_urls = False
# -- Options for Texinfo output -----------------------------------------------
@ -258,13 +257,13 @@ texinfo_documents = [('index', 'glymur', u'glymur Documentation',
'One line description of project.', 'Miscellaneous'), ]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# texinfo_show_urls = 'footnote'
# Example configuration for intersphinx: refer to the Python standard library.

View file

@ -1,31 +1,33 @@
----------------------------------
Advanced Installation Instructions
----------------------------------
Most users won't need to read this! You've been warned...
''''''''''''''''''''''
Glymur Configuration
''''''''''''''''''''''
The default glymur installation process relies upon OpenJPEG being
properly installed on your system as a shared library. You need
at least version 1.5 in order to read and write JPEG 2000 files.
properly installed on your system as a shared library. If you have
OpenJPEG installed through your systems package manager on linux
or if you use MacPorts on the mac, you are probably already set to
go. But if you have OpenJPEG installed into a non-standard place
or if you use windows, then read on.
Glymur uses ctypes to access the openjp2/openjpeg libraries, and
because ctypes accesses libraries in a platform-dependent manner,
it is recommended that if you compile and install OpenJPEG into a
non-standard location, you should create a configuration file to
help Glymur properly find the openjpeg or openjp2 libraries (linux
users or macports users don't need to bother with this if you are
using OpenJPEG as provided by your package manager). The configuration
format is the same as used by Python's configparser module,
i.e. ::
it is recommended that **if** you compile and install OpenJPEG into a
non-standard location, you should then create a configuration file
to help Glymur properly find the openjpeg or openjp2 libraries
(linux users or macports users dont need to bother with this if
you are using OpenJPEG as provided by your package manager). The
configuration format is the same as used by Pythons configparser
module, i.e. ::
[library]
openjp2: /opt/openjp2-svn/lib/libopenjp2.so
openjp2: /somewhere/lib/libopenjp2.so
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. If you use either linux or mac, the path
to the configuration file would normally be ::
@ -36,22 +38,25 @@ the path will be ::
$XDG_CONFIG_HOME/glymur/glymurrc
On windows, the path to the configuration file can be determined
by starting up Python and typing ::
On windows, the path to the configuration file can be determined by starting
up Python and typing ::
import os
os.path.join(os.path.expanduser('~'), 'glymur', 'glymurrc')
os.path.join(os.path.expanduser('~', 'glymur', 'glymurrc')
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. ::
[library]
openjpeg: /not/the/usual/location/lib/libopenjpeg.so
openjpeg: /somewhere/lib/libopenjpeg.so
Once again, you should not have to bother with a configuration file if you use
mac or linux and OpenJPEG is provided by your package manager.
'''''''
Testing
'''''''
It is not necessary, but you may wish to download OpenJPEG's test
data for the purpose of configuring and running OpenJPEG's test
suite. Check their instructions on how to do that. You can then

View file

@ -3,36 +3,220 @@ How do I...?
------------
... read the lowest resolution thumbnail?
=========================================
Printing the Jp2k object should reveal the number of resolutions (look in the
COD segment section), but you can take a shortcut by supplying -1 as the
resolution level. ::
... 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 ::
>>> import glymur
>>> file = glymur.data.nemo()
>>> j = glymur.Jp2k(file)
>>> thumbnail = j.read(rlevel=-1)
>>> jp2file = glymur.data.nemo() # just a path to a JPEG2000 file
>>> jp2 = glymur.Jp2k(jp2file)
>>> fullres = jp2[:]
>>> fullres.shape
(1456, 2592, 3)
>>> thumbnail = jp2[::2, ::2]
>>> thumbnail.shape
(728, 1296, 3)
... write images?
=================
It's pretty simple, just supply the image data as the 2nd argument to the Jp2k
constructor.
>>> import glymur, numpy as np
>>> jp2 = glymur.Jp2k('zeros.jp2', data=np.zeros((640, 480), dtype=np.uint8)
You must have OpenJPEG version 1.5 or more recent in order to write JPEG 2000
images with glymur.
... display metadata?
=====================
There are two ways. From the unix command line, the script *jp2dump* is
There are two ways. From the command line, the console script **jp2dump** is
available. ::
$ 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. ::
>>> from glymur import Jp2k
>>> file = glymur.data.nemo()
>>> j = Jp2k(file)
>>> print(j)
>>> import glymur
>>> jp2file = glymur.data.nemo() # just a path to a JP2 file
>>> jp2 = glymur.Jp2k(jp2file)
>>> print(jp2)
File: nemo.jp2
JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Size: [1456 2592 3]
Bitdepth: 8
Signed: False
Compression: wavelet
Colorspace Unknown: False
Colour Specification Box (colr) @ (62, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
<ns0:xmpmeta xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:ns3="http://ns.adobe.com/tiff/1.0/" xmlns:ns4="http://ns.adobe.com/exif/1.0/" xmlns:ns5="http://ns.adobe.com/photoshop/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="Exempi + XMP Core 5.1.2">
<rdf:RDF>
<rdf:Description rdf:about="">
<ns2:CreatorTool>Google</ns2:CreatorTool>
<ns2:CreateDate>2013-02-09T14:47:53</ns2:CreateDate>
</rdf:Description>
<rdf:Description rdf:about="">
<ns3:YCbCrPositioning>1</ns3:YCbCrPositioning>
<ns3:XResolution>72/1</ns3:XResolution>
<ns3:YResolution>72/1</ns3:YResolution>
<ns3:ResolutionUnit>2</ns3:ResolutionUnit>
<ns3:Make>HTC</ns3:Make>
<ns3:Model>HTC Glacier</ns3:Model>
<ns3:ImageWidth>2592</ns3:ImageWidth>
<ns3:ImageLength>1456</ns3:ImageLength>
<ns3:BitsPerSample>
<rdf:Seq>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
</rdf:Seq>
</ns3:BitsPerSample>
<ns3:PhotometricInterpretation>2</ns3:PhotometricInterpretation>
<ns3:SamplesPerPixel>3</ns3:SamplesPerPixel>
<ns3:WhitePoint>
<rdf:Seq>
<rdf:li>1343036288/4294967295</rdf:li>
<rdf:li>1413044224/4294967295</rdf:li>
</rdf:Seq>
</ns3:WhitePoint>
<ns3:PrimaryChromaticities>
<rdf:Seq>
<rdf:li>2748779008/4294967295</rdf:li>
<rdf:li>1417339264/4294967295</rdf:li>
<rdf:li>1288490240/4294967295</rdf:li>
<rdf:li>2576980480/4294967295</rdf:li>
<rdf:li>644245120/4294967295</rdf:li>
<rdf:li>257698032/4294967295</rdf:li>
</rdf:Seq>
</ns3:PrimaryChromaticities>
</rdf:Description>
<rdf:Description rdf:about="">
<ns4:ColorSpace>1</ns4:ColorSpace>
<ns4:PixelXDimension>2528</ns4:PixelXDimension>
<ns4:PixelYDimension>1424</ns4:PixelYDimension>
<ns4:FocalLength>353/100</ns4:FocalLength>
<ns4:GPSAltitudeRef>0</ns4:GPSAltitudeRef>
<ns4:GPSAltitude>0/1</ns4:GPSAltitude>
<ns4:GPSMapDatum>WGS-84</ns4:GPSMapDatum>
<ns4:DateTimeOriginal>2013-02-09T14:47:53</ns4:DateTimeOriginal>
<ns4:ISOSpeedRatings>
<rdf:Seq>
<rdf:li>76</rdf:li>
</rdf:Seq>
</ns4:ISOSpeedRatings>
<ns4:ExifVersion>0220</ns4:ExifVersion>
<ns4:FlashpixVersion>0100</ns4:FlashpixVersion>
<ns4:ComponentsConfiguration>
<rdf:Seq>
<rdf:li>1</rdf:li>
<rdf:li>2</rdf:li>
<rdf:li>3</rdf:li>
<rdf:li>0</rdf:li>
</rdf:Seq>
</ns4:ComponentsConfiguration>
<ns4:GPSLatitude>42,20.56N</ns4:GPSLatitude>
<ns4:GPSLongitude>71,5.29W</ns4:GPSLongitude>
<ns4:GPSTimeStamp>2013-02-09T19:47:53Z</ns4:GPSTimeStamp>
<ns4:GPSProcessingMethod>NETWORK</ns4:GPSProcessingMethod>
</rdf:Description>
<rdf:Description rdf:about="">
<ns5:DateCreated>2013-02-09T14:47:53</ns5:DateCreated>
</rdf:Description>
<rdf:Description rdf:about="">
<dc:Creator>
<rdf:Seq>
<rdf:li>Glymur</rdf:li>
<rdf:li>Python XMP Toolkit</rdf:li>
</rdf:Seq>
</dc:Creator>
</rdf:Description>
</rdf:RDF>
</ns0:xmpmeta>
Contiguous Codestream Box (jp2c) @ (3223, 1132296)
Main header:
SOC marker segment @ (3231, 0)
SIZ marker segment @ (3233, 47)
Profile: 2
Reference Grid Height, Width: (1456 x 2592)
Vertical, Horizontal Reference Grid Offset: (0 x 0)
Reference Tile Height, Width: (1456 x 2592)
Vertical, Horizontal Reference Tile Offset: (0 x 0)
Bitdepth: (8, 8, 8)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
COD marker segment @ (3282, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
EPH marker segments: False
Coding style parameters:
Progression order: LRCP
Number of layers: 2
Multiple component transformation usage: reversible
Number of resolutions: 2
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Precinct size: default, 2^15 x 2^15
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCD marker segment @ (3296, 7)
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
CME marker segment @ (3305, 37)
"Created by OpenJPEG version 2.0.0"
That's fairly overwhelming, and perhaps lost in the flood of information
is the fact that the codestream metadata is limited to just what's in the
main codestream header. You can suppress the codestream and XML details by
making use of the :py:meth:`set_printoptions` function::
This prints the metadata found in the JP2 boxes, but in the case of the
codestream box, only the main header is printed. It is possible to print
**only** the codestream information as well, i.e. ::
>>> glymur.set_printoptions(codestream=False, xml=False)
>>> print(jp2)
File: nemo.jp2
JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Size: [1456 2592 3]
Bitdepth: 8
Signed: False
Compression: wavelet
Colorspace Unknown: False
Colour Specification Box (colr) @ (62, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
Contiguous Codestream Box (jp2c) @ (3223, 1132296)
>>> print(j.get_codestream())
It is possible to easily print the codestream header details as well, i.e. ::
>>> print(j.codestream) # details not show
... add XML metadata?
=====================
@ -55,12 +239,11 @@ Consider the following XML file `data.xml` : ::
</locality>
</info>
The **append** method can add an XML box as shown below::
The :py:meth:`append` method can add an XML box as shown below::
>>> import shutil
>>> import glymur
>>> shutil.copyfile(glymur.data.nemo(), 'myfile.jp2')
>>> from xml.etree import cElementTree as ET
>>> jp2 = glymur.Jp2k('myfile.jp2')
>>> xmlbox = glymur.jp2box.XMLBox(filename='data.xml')
>>> jp2.append(xmlbox)
@ -71,11 +254,12 @@ The **append** method can add an XML box as shown below::
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
codestream provided by `goodstuff.j2k` (a file consisting of a raw codestream),
you can use the **wrap** method with no box argument: ::
you can use the :py:meth:`wrap` method with no box argument: ::
>>> import glymur
>>> jfile = glymur.data.goodstuff()
>>> j2k = glymur.Jp2k(jfile)
>>> glymur.set_printoptions(codestream=False)
>>> jp2file = glymur.data.goodstuff()
>>> j2k = glymur.Jp2k(jp2file)
>>> jp2 = j2k.wrap("newfile.jp2")
>>> print(jp2)
File: newfile.jp2
@ -96,10 +280,6 @@ you can use the **wrap** method with no box argument: ::
Precedence: 0
Colorspace: sRGB
Contiguous Codestream Box (jp2c) @ (77, 115228)
Main header:
.
. (truncated)
.
The raw codestream was wrapped in a JP2 jacket with four boxes in the outer
layer (the signature, file type, JP2 header, and contiguous codestream), with
@ -108,8 +288,9 @@ JP2 header superbox.
XML boxes are not in the minimal set of box requirements for the JP2 format, so
in order to add an XML box into the mix before the codestream box, we'll need to
re-specify all of the boxes. If you already have a JP2 jacket in place, you can just reuse that,
though. Take the following example content in an XML file `favorites.xml` : ::
re-specify all of the boxes. If you already have a JP2 jacket in place,
you can just reuse that, though. Take the following example content in
an XML file `favorites.xml` : ::
<?xml version="1.0"?>
<favorite_things>
@ -145,25 +326,20 @@ the following will work. ::
<favorite_things>
<category>Light Ale</category>
</favorite_things>
Contiguous Codestream Box (jp2c) @ (153, 115236)
Main header:
.
. (truncated)
.
As to the question of which method you should use, **append** or **wrap**,
to add metadata, you should keep in mind that **wrap** produces a new JP2 file,
while **append** modifies an existing file and is currently limited to XML
boxes.
As to the question of which method you should use, :py:meth:`append` or
:py:meth:`wrap`, to add metadata, you should keep in mind that :py:meth:`wrap`
produces a new JP2 file, while :py:meth:`append` modifies an existing file and
is currently limited to XML and UUID boxes.
... create an image with an alpha layer?
========================================
OpenJPEG can create JP2 files with more than 3 components (requires version
2.1), but by default any extra components are not described as such by the JP2
boxes created by OpenJPEG. In order to do so, we need to rewrap such
an image in a set of boxes that includes a channel definition box.
OpenJPEG can create JP2 files with more than 3 components (use version 2.1.0+
for this), 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 .
@ -173,15 +349,14 @@ image isn't square. ::
>>> import numpy as np
>>> import glymur
>>> from glymur import Jp2k
>>> rgb = Jp2k(glymur.data.goodstuff()).read()
>>> rgb = Jp2k(glymur.data.goodstuff())[:]
>>> 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)
>>> jp2 = Jp2k('tmp.jp2', data=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
@ -198,7 +373,7 @@ 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)
>>> cdef = glymur.jp2box.ChannelDefinitionBox(ctype, asoc)
>>> print(cdef)
Channel Definition Box (cdef) @ (0, 0)
Channel 0 (color) ==> (1)
@ -219,32 +394,213 @@ 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?
========================
`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. ::
>>> import glymur
>>> j = glymur.Jp2k(glymur.data.nemo())
>>> print(j.box[4])
UUID Box (uuid) @ (715, 2412)
>>> print(j.box[3]) # formatting added to the XML below
<ns0:xmpmeta xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ns0="adobe:ns:meta/"
xmlns:ns2="http://ns.adobe.com/xap/1.0/"
xmlns:ns3="http://ns.adobe.com/tiff/1.0/"
xmlns:ns4="http://ns.adobe.com/exif/1.0/"
xmlns:ns5="http://ns.adobe.com/photoshop/1.0/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
ns0:xmptk="Exempi + XMP Core 5.1.2">
<rdf:RDF>
<rdf:Description rdf:about="">
<ns2:CreatorTool>Google</ns2:CreatorTool>
<ns2:CreateDate>2013-02-09T14:47:53</ns2:CreateDate>
</rdf:Description>
.
.
.
</ns0:xmpmeta>
Since the UUID data in this case is returned as an lxml ElementTree
instance, one can use lxml to access the data. For example, to
extract the **CreatorTool** attribute value, one could do the
following
>>> xmp = j.box[3].data
>>> rdf = '{http://www.w3.org/1999/02/22-rdf-syntax-ns#}'
>>> ns2 = '{http://ns.adobe.com/xap/1.0/}'
>>> name = '{0}RDF/{0}Description/{1}CreatorTool'.format(rdf, ns2)
>>> elt = xmp.find(name)
>>> elt
<Element '{http://ns.adobe.com/xap/1.0/#}CreatorTool' at 0xb50684a4>
>>> elt.text
'Google'
But that would be painful. A better solution is to install the Python XMP
Toolkit (make sure it is at least version 2.0)::
>>> from libxmp import XMPMeta
>>> from libxmp.consts import XMP_NS_XMP as NS_XAP
>>> meta = XMPMeta()
>>> meta.parse_from_str(j.box[3].raw_data.decode('utf-8'))
>>> meta.get_property(NS_XAP, 'CreatorTool')
'Google'
Where the Python XMP Toolkit can really shine, though, is when you are
converting an image from another format such as TIFF or JPEG into JPEG 2000.
For example, if you were to be converting the TIFF image found at
http://photojournal.jpl.nasa.gov/tiff/PIA17145.tif info JPEG 2000::
>>> import skimage.io
>>> image = skimage.io.imread('PIA17145.tif')
>>> from glymur import Jp2k
>>> jp2 = Jp2k('PIA17145.jp2', data=image)
Next you can extract the XMP metadata.
>>> from libxmp import XMPFiles
>>> xf = XMPFiles()
>>> xf.open_file('PIA17145.tif')
>>> xmp = xf.get_xmp()
>>> print(xmp)
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Exempi + XMP Core 5.1.2">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:tiff="http://ns.adobe.com/tiff/1.0/">
<tiff:ImageWidth>1016</tiff:ImageWidth>
<tiff:ImageLength>1016</tiff:ImageLength>
<tiff:BitsPerSample>
<rdf:Seq>
<rdf:li>8</rdf:li>
</rdf:Seq>
</tiff:BitsPerSample>
<tiff:Compression>1</tiff:Compression>
<tiff:PhotometricInterpretation>1</tiff:PhotometricInterpretation>
<tiff:SamplesPerPixel>1</tiff:SamplesPerPixel>
<tiff:PlanarConfiguration>1</tiff:PlanarConfiguration>
<tiff:ResolutionUnit>2</tiff:ResolutionUnit>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:description>
<rdf:Alt>
<rdf:li xml:lang="x-default">converted PNM file</rdf:li>
</rdf:Alt>
</dc:description>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
If you are familiar with TIFF, you can verify that there's no XMP tag in the
TIFF file, but the Python XMP Toolkit takes advantage of the TIFF header
structure to populate an XMP packet for you. If you were working with a JPEG
file with Exif metadata, that information would be included in the XMP packet
as well. Now you can append the XMP packet in a UUIDBox. In order to do this,
though, you have to know the UUID that signifies XMP data.::
>>> import uuid
>>> xmp_uuid = uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')
>>> box = glymur.jp2box.UUIDBox(xmp_uuid, str(xmp).encode())
>>> jp2.append(box)
>>> print(jp2.box[-1])
UUID Box (uuid) @ (592316, 1053)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
<ns0:xmpmeta xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="XMP Core 4.4.0-Exiv2">
<ns0:xmpmeta xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/tiff/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="Exempi + XMP Core 5.1.2">
<rdf:RDF>
<rdf:Description ns2:CreatorTool="glymur" rdf:about="" />
<rdf:Description rdf:about="">
<ns2:ImageWidth>1016</ns2:ImageWidth>
<ns2:ImageLength>1016</ns2:ImageLength>
<ns2:BitsPerSample>
<rdf:Seq>
<rdf:li>8</rdf:li>
</rdf:Seq>
</ns2:BitsPerSample>
<ns2:Compression>1</ns2:Compression>
<ns2:PhotometricInterpretation>1</ns2:PhotometricInterpretation>
<ns2:SamplesPerPixel>1</ns2:SamplesPerPixel>
<ns2:PlanarConfiguration>1</ns2:PlanarConfiguration>
<ns2:ResolutionUnit>2</ns2:ResolutionUnit>
</rdf:Description>
<rdf:Description rdf:about="">
<dc:description>
<rdf:Alt>
<rdf:li xml:lang="x-default">converted PNM file</rdf:li>
</rdf:Alt>
</dc:description>
</rdf:Description>
</rdf:RDF>
</ns0:xmpmeta>
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
**CreatorTool** attribute value, the following would work::
You can also build up XMP metadata from scratch. For instance, if we try to
wrap `goodstuff.j2k` again::
>>> import glymur
>>> j2kfile = glymur.data.goodstuff()
>>> j2k = glymur.Jp2k(j2kfile)
>>> jp2 = j2k.wrap("goodstuff.jp2")
Now build up the metadata piece-by-piece. It would help to have the XMP
standard close at hand::
>>> from libxmp import XMPMeta
>>> from libxmp.consts import XMP_NS_TIFF as NS_TIFF
>>> from libxmp.consts import XMP_NS_DC as NS_DC
>>> xmp = XMPMeta()
>>> ihdr = jp2.box[2].box[0]
>>> xmp.set_property(NS_TIFF, "ImageWidth", str(ihdr.width))
>>> xmp.set_property(NS_TIFF, "ImageHeight", str(ihdr.height))
>>> xmp.set_property(NS_TIFF, "BitsPerSample", '3')
>>> xmp.set_property(NS_DC, "Title", u'Stürm und Drang')
>>> xmp.set_property(NS_DC, "Creator", 'Glymur')
We can then append the XMP in a UUID box just as before::
>>> import uuid
>>> xmp_uuid = uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')
>>> box = glymur.jp2box.UUIDBox(xmp_uuid, str(xmp).encode())
>>> jp2.append(box)
>>> glymur.set_printoptions(codestream=False)
>>> print(jp2)
File: goodstuff.jp2
JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Size: [800 480 3]
Bitdepth: 8
Signed: False
Compression: wavelet
Colorspace Unknown: False
Colour Specification Box (colr) @ (62, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
Contiguous Codestream Box (jp2c) @ (77, 115228)
UUID Box (uuid) @ (115305, 671)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
<ns0:xmpmeta xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/tiff/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="Exempi + XMP Core 5.1.2">
<rdf:RDF>
<rdf:Description rdf:about="">
<ns2:ImageWidth>480</ns2:ImageWidth>
<ns2:ImageHeight>800</ns2:ImageHeight>
<ns2:BitsPerSample>3</ns2:BitsPerSample>
</rdf:Description>
<rdf:Description rdf:about="">
<dc:Title>Stürm und Drang</dc:Title>
<dc:Creator>Glymur</dc:Creator>
</rdf:Description>
</rdf:RDF>
</ns0:xmpmeta>
>>> xmp = j.box[4].data
>>> ns0 = '{http://www.w3.org/1999/02/22-rdf-syntax-ns#}'
>>> ns1 = '{http://ns.adobe.com/xap/1.0/}'
>>> name = '{0}RDF/{0}Description'.format(ns0)
>>> elt = xmp.find(name)
>>> elt
<Element '{http://www.w3.org/1999/02/22-rdf-syntax-ns#}Description' at 0xb4baa93c>
>>> elt.attrib['{0}CreatorTool'.format(ns1)]
'glymur'

View file

@ -15,8 +15,8 @@ Contents:
introduction
detailed_installation
how_do_i
whatsnew/index
roadmap
api
------------------
Indices and tables

View file

@ -3,46 +3,33 @@ Glymur: a Python interface for JPEG 2000
----------------------------------------
**Glymur** is an interface to the OpenJPEG library
which allows one to read and write JPEG 2000 files from within 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
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.
Of particular focus is retrieval of metadata. Reading Exif UUIDs is supported,
as is reading XMP UUIDs as the XMP data packet is just XML. There is
some very limited support for reading JPX metadata. For instance,
**asoc** and **labl** boxes are recognized, so GMLJP2 metadata can
be retrieved from such JPX files.
In regards to metadata, most JP2 boxes are properly interpreted.
Certain optional JP2 boxes can also be written, including XML boxes and
XMP UUIDs. There is incomplete support for reading JPX metadata.
Glymur works on Python 2.6, 2.7, 3.3, and 3.4.
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.
OpenJPEG Installation
=====================
Glymur will read JPEG 2000 images with versions 1.3, 1.4, 1.5, 2.0, and 2.1 of
OpenJPEG. Writing images is only supported with the 1.5 or better, however,
and version 2.1 is strongly recommended. For more information about OpenJPEG,
please consult http://www.openjpeg.org.
If you use MacPorts or if you have a sufficiently recent version of
Linux, your package manager should already provide you with a version of
OpenJPEG 1.X which glymur can already use. If your platform is windows,
I suggest using the windows installers provided to you by the OpenJPEG
folks at https://code.google.com/p/openjpeg/downloads/list .
For more information about OpenJPEG, please consult http://www.openjpeg.org.
Glymur Installation
===================
You can retrieve the source for Glymur from either of
* https://pypi.python.org/pypi/Glymur/ (stable releases)
* http://github.com/quintusdias/glymur (bleeding edge)
* http://github.com/quintusdias/glymur (bleeding edge, use the devel branch)
but you should also be able to install Glymur via pip ::
$ pip install glymur
This will install the **jp2dump** script that can be used from the unix command
line, so you should adjust your **$PATH**
to take advantage of it. For example, if you install with pip's
`--user` option on linux ::
$ export PATH=$HOME/.local/bin:$PATH
In addition to the package, this also gives you a command line script
**jp2dump** that can be used from the command line line to print JPEG 2000
metadata.

View file

@ -1,3 +1,11 @@
------------
Known Issues
------------
* Creating a Jp2 file with the irreversible option does not work
on windows.
* Eval-ing a :py:meth:`repr` string does not work on windows.
-------
Roadmap
-------
@ -5,8 +13,4 @@ Roadmap
Here's an incomplete list of what I'd like to focus on in the future.
* continue to monitor upstream changes in the openjp2 library
* investigate using CFFI or cython instead of ctypes to wrap openjp2
* 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.
* investigate JPIP (likely to be a big project)

View file

@ -0,0 +1,50 @@
=====================
Changes in glymur 0.5
=====================
Changes in 0.5.12
=================
* Minor documentation fixes for grammar and style.
* The functions removed in 0.5.11 due to API changes in OpenJPEG 2.1.0 were
restored for backwards compatibility. They are deprecated, though, and will
be removed in 0.6.0.
* ``glymur.lib.openjp2.stream_create_default_file_stream_v3``
* ``glymur.lib.openjp2.opj.stream_destroy_v3``
Changes in 0.5.11
=================
* Added support for Python 3.4.
* OpenJPEG 1.5.2 and 2.0.1 are officially supported.
* OpenJPEG 2.1.0 is officially supported, but the ABI changes introduced by
OpenJPEG 2.1.0 required corresponding changes to glymur's ctypes interface.
The functions
* ``glymur.lib.openjp2.stream_create_default_file_stream_v3``
* ``glymur.lib.openjp2.opj.stream_destroy_v3``
functions were renamed to
* ``glymur.lib.openjp2.stream_create_default_file_stream``
* ``glymur.lib.openjp2.opj.stream_destroy``
in order to follow OpenJPEG's upstream changes. Unless you were using the
svn version of OpenJPEG, you should not be affected by this.
Changes in 0.5.10
=================
* Fixed bad warning issued when an unsupported reader requirement box mask
length was encountered.
Changes in 0.5.9
================
* Fixed bad library load on linux as a result of botched 0.5.8 release.
This release was primarily aimed at supporting SunPy.

View file

@ -0,0 +1,23 @@
=====================
Changes in glymur 0.6
=====================
Changes in 0.6.0
=================
* Added Cinema2K, Cinema4K write support.
* Added irreversible 9-7 transform write support.
* Added set_printoptions, get_printoptions functions.
* Added write support for JP2 UUID, data entry URL, palette, and component
mapping boxes.
* Added read/write support for JPX free, number list, and data reference boxes
* Added read support for JPX fragment list and fragment table boxes
* Incompatible change to channel definition box constructor, channel_type and
association are no longer keyword arguments
* Incompatible change to palette box constructor, it now takes a 2D numpy array
instead of a list of 1D arrays
* Dropped support for 1.3 and 1.4.
* Dropped support for Python 2.6.
* Dropped windows support. It might still work, I don't have access to a windows
box with which to test it.
* Added lxml as a package dependency, replacing ElementTree.

View file

@ -0,0 +1,27 @@
=====================
Changes in glymur 0.7
=====================
Changes in 0.7.3
=================
* added read support back for metadata only when the OpenJPEG library is
not installed
Changes in 0.7.2
=================
* added ellipsis support in array-style slicing
Changes in 0.7.1
=================
* fixed release notes regarding Python 3.4
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

View file

@ -0,0 +1,24 @@
=====================
Changes in glymur 0.8
=====================
Changes in 0.8.0
=================
* Simplified writing images by moving data and options into the
constructor.
* Deprecated :py:meth:`read` method in favor of array-style slicing.
In order to retain certain functionality, the following parameters
to the :py:meth:`read` method have become top-level properties
* verbose
* layer
* ignore_pclr_cmap_cdef
* Two additional properties were introduced.
* codestream
* shape

View file

@ -0,0 +1,14 @@
.. _whatsnew:
**********************
"What's new" documents
**********************
These document the changes between minor (or major) versions of glymur.
.. toctree::
0.8
0.7
0.6
0.5

View file

@ -1,24 +1,25 @@
"""glymur - read, write, and interrogate JPEG 2000 files
"""
import sys
import unittest
from glymur import version
__version__ = version.version
from .jp2k import Jp2k
from .jp2dump import jp2dump
from .jp2box import (get_printoptions,
set_printoptions,
get_parseoptions,
set_parseoptions)
from . import data
# unittest2 only in python-2.6 (pylint/python2.7 issue)
# pylint: disable=F0401
def runtests():
"""Discover and run all tests for the glymur package.
"""
if sys.hexversion <= 0x02070000:
import unittest2 as unittest
else:
import unittest
suite = unittest.defaultTestLoader.discover(__path__[0])
unittest.TextTestRunner(verbosity=2).run(suite)
__all__ = [__version__, Jp2k, get_printoptions, set_printoptions,
get_parseoptions, set_parseoptions, data, runtests]

505
glymur/_uuid_io.py Normal file
View file

@ -0,0 +1,505 @@
# -*- coding: utf-8 -*-
"""
Part of glymur.
"""
from collections import OrderedDict
import struct
import sys
import warnings
import lxml.etree as ET
def xml(raw_data):
"""
XMP data to be parsed as XML.
"""
if sys.hexversion < 0x03000000:
elt = ET.fromstring(raw_data)
else:
text = raw_data.decode('utf-8')
elt = ET.fromstring(text)
return ET.ElementTree(elt)
def tiff_header(read_buffer):
"""
Interpret the uuid raw data as a tiff header.
"""
# Ignore the first six bytes.
# Next 8 should be (73, 73, 42, 8) or (77, 77, 42, 8)
data = struct.unpack('<BB', read_buffer[6:8])
if data[0] == 73 and data[1] == 73:
# little endian
endian = '<'
elif data[0] == 77 and data[1] == 77:
# big endian
endian = '>'
else:
msg = "The byte order indication in the TIFF header ({0}) is "
msg += "invalid. It should be either {1} or {2}."
msg = msg.format(read_buffer[6:8], bytes([73, 73]), bytes([77, 77]))
raise IOError(msg)
_, offset = struct.unpack(endian + 'HI', read_buffer[8:14])
# This is the 'Exif Image' portion.
exif = _ExifImageIfd(endian, read_buffer[6:], offset)
return exif.processed_ifd
class _Ifd(object):
"""
Attributes
----------
read_buffer : bytes
Raw byte stream consisting of the UUID data.
datatype2fmt : dictionary
Class attribute, maps the TIFF enumerated datatype to the python
datatype and data width.
endian : str
Either '<' for big-endian, or '>' for little-endian.
num_tags : int
Number of tags in the IFD.
raw_ifd : dictionary
Maps tag number to "mildly-interpreted" tag value.
processed_ifd : dictionary
Maps tag name to "mildly-interpreted" tag value.
"""
datatype2fmt = {1: ('B', 1),
2: ('B', 1),
3: ('H', 2),
4: ('I', 4),
5: ('II', 8),
7: ('B', 1),
9: ('i', 4),
10: ('ii', 8)}
def __init__(self, endian, read_buffer, offset):
self.endian = endian
self.read_buffer = read_buffer
self.processed_ifd = OrderedDict()
self.num_tags, = struct.unpack(endian + 'H',
read_buffer[offset:offset + 2])
fmt = self.endian + 'HHII' * self.num_tags
ifd_buffer = read_buffer[offset + 2:offset + 2 + self.num_tags * 12]
data = struct.unpack(fmt, ifd_buffer)
self.raw_ifd = OrderedDict()
for j, tag in enumerate(data[0::4]):
# The offset to the tag offset/payload is the offset to the IFD
# plus 2 bytes for the number of tags plus 12 bytes for each
# tag entry plus 8 bytes to the offset/payload itself.
toffp = read_buffer[offset + 10 + j * 12:offset + 10 + j * 12 + 4]
tag_data = self.parse_tag(data[j * 4 + 1],
data[j * 4 + 2],
toffp)
self.raw_ifd[tag] = tag_data
def parse_tag(self, dtype, count, offset_buf):
"""Interpret an Exif image tag data payload.
"""
try:
fmt = self.datatype2fmt[dtype][0] * count
payload_size = self.datatype2fmt[dtype][1] * count
except KeyError:
msg = 'Invalid TIFF tag datatype ({0}).'.format(dtype)
raise IOError(msg)
if payload_size <= 4:
# Interpret the payload from the 4 bytes in the tag entry.
target_buffer = offset_buf[:payload_size]
else:
# Interpret the payload at the offset specified by the 4 bytes in
# the tag entry.
offset, = struct.unpack(self.endian + 'I', offset_buf)
target_buffer = self.read_buffer[offset:offset + payload_size]
if dtype == 2:
# ASCII
if sys.hexversion < 0x03000000:
payload = target_buffer.rstrip('\x00')
else:
payload = target_buffer.decode('utf-8').rstrip('\x00')
else:
payload = struct.unpack(self.endian + fmt, target_buffer)
if dtype == 5 or dtype == 10:
# Rational or Signed Rational. Construct the list of values.
rational_payload = []
for j in range(count):
value = float(payload[j * 2]) / float(payload[j * 2 + 1])
rational_payload.append(value)
payload = rational_payload
if count == 1:
# If just a single value, then return a scalar instead of a
# tuple.
payload = payload[0]
return payload
def post_process(self, tagnum2name):
"""Map the tag name instead of tag number to the tag value.
"""
for tag, value in self.raw_ifd.items():
try:
tag_name = tagnum2name[tag]
except KeyError:
# Ok, we don't recognize this tag. Just use the numeric id.
msg = 'Unrecognized Exif tag: {0}'.format(tag)
warnings.warn(msg, UserWarning)
tag_name = tag
self.processed_ifd[tag_name] = value
class _ExifImageIfd(_Ifd):
"""
Attributes
----------
tagnum2name : dict
Maps Exif image tag numbers to the tag names.
ifd : dict
Maps tag names to tag values.
"""
tagnum2name = {11: 'ProcessingSoftware',
254: 'NewSubfileType',
255: 'SubfileType',
256: 'ImageWidth',
257: 'ImageLength',
258: 'BitsPerSample',
259: 'Compression',
262: 'PhotometricInterpretation',
263: 'Threshholding',
264: 'CellWidth',
265: 'CellLength',
266: 'FillOrder',
269: 'DocumentName',
270: 'ImageDescription',
271: 'Make',
272: 'Model',
273: 'StripOffsets',
274: 'Orientation',
277: 'SamplesPerPixel',
278: 'RowsPerStrip',
279: 'StripByteCounts',
282: 'XResolution',
283: 'YResolution',
284: 'PlanarConfiguration',
290: 'GrayResponseUnit',
291: 'GrayResponseCurve',
292: 'T4Options',
293: 'T6Options',
296: 'ResolutionUnit',
301: 'TransferFunction',
305: 'Software',
306: 'DateTime',
315: 'Artist',
316: 'HostComputer',
317: 'Predictor',
318: 'WhitePoint',
319: 'PrimaryChromaticities',
320: 'ColorMap',
321: 'HalftoneHints',
322: 'TileWidth',
323: 'TileLength',
324: 'TileOffsets',
325: 'TileByteCounts',
330: 'SubIFDs',
332: 'InkSet',
333: 'InkNames',
334: 'NumberOfInks',
336: 'DotRange',
337: 'TargetPrinter',
338: 'ExtraSamples',
339: 'SampleFormat',
340: 'SMinSampleValue',
341: 'SMaxSampleValue',
342: 'TransferRange',
343: 'ClipPath',
344: 'XClipPathUnits',
345: 'YClipPathUnits',
346: 'Indexed',
347: 'JPEGTables',
351: 'OPIProxy',
512: 'JPEGProc',
513: 'JPEGInterchangeFormat',
514: 'JPEGInterchangeFormatLength',
515: 'JPEGRestartInterval',
517: 'JPEGLosslessPredictors',
518: 'JPEGPointTransforms',
519: 'JPEGQTables',
520: 'JPEGDCTables',
521: 'JPEGACTables',
529: 'YCbCrCoefficients',
530: 'YCbCrSubSampling',
531: 'YCbCrPositioning',
532: 'ReferenceBlackWhite',
700: 'XMLPacket',
18246: 'Rating',
18249: 'RatingPercent',
32781: 'ImageID',
33421: 'CFARepeatPatternDim',
33422: 'CFAPattern',
33423: 'BatteryLevel',
33432: 'Copyright',
33434: 'ExposureTime',
33437: 'FNumber',
33723: 'IPTCNAA',
34377: 'ImageResources',
34665: 'ExifTag',
34675: 'InterColorProfile',
34850: 'ExposureProgram',
34852: 'SpectralSensitivity',
34853: 'GPSTag',
34855: 'ISOSpeedRatings',
34856: 'OECF',
34857: 'Interlace',
34858: 'TimeZoneOffset',
34859: 'SelfTimerMode',
36867: 'DateTimeOriginal',
37122: 'CompressedBitsPerPixel',
37377: 'ShutterSpeedValue',
37378: 'ApertureValue',
37379: 'BrightnessValue',
37380: 'ExposureBiasValue',
37381: 'MaxApertureValue',
37382: 'SubjectDistance',
37383: 'MeteringMode',
37384: 'LightSource',
37385: 'Flash',
37386: 'FocalLength',
37387: 'FlashEnergy',
37388: 'SpatialFrequencyResponse',
37389: 'Noise',
37390: 'FocalPlaneXResolution',
37391: 'FocalPlaneYResolution',
37392: 'FocalPlaneResolutionUnit',
37393: 'ImageNumber',
37394: 'SecurityClassification',
37395: 'ImageHistory',
37396: 'SubjectLocation',
37397: 'ExposureIndex',
37398: 'TIFFEPStandardID',
37399: 'SensingMethod',
40091: 'XPTitle',
40092: 'XPComment',
40093: 'XPAuthor',
40094: 'XPKeywords',
40095: 'XPSubject',
50341: 'PrintImageMatching',
50706: 'DNGVersion',
50707: 'DNGBackwardVersion',
50708: 'UniqueCameraModel',
50709: 'LocalizedCameraModel',
50710: 'CFAPlaneColor',
50711: 'CFALayout',
50712: 'LinearizationTable',
50713: 'BlackLevelRepeatDim',
50714: 'BlackLevel',
50715: 'BlackLevelDeltaH',
50716: 'BlackLevelDeltaV',
50717: 'WhiteLevel',
50718: 'DefaultScale',
50719: 'DefaultCropOrigin',
50720: 'DefaultCropSize',
50721: 'ColorMatrix1',
50722: 'ColorMatrix2',
50723: 'CameraCalibration1',
50724: 'CameraCalibration2',
50725: 'ReductionMatrix1',
50726: 'ReductionMatrix2',
50727: 'AnalogBalance',
50728: 'AsShotNeutral',
50729: 'AsShotWhiteXY',
50730: 'BaselineExposure',
50731: 'BaselineNoise',
50732: 'BaselineSharpness',
50733: 'BayerGreenSplit',
50734: 'LinearResponseLimit',
50735: 'CameraSerialNumber',
50736: 'LensInfo',
50737: 'ChromaBlurRadius',
50738: 'AntiAliasStrength',
50739: 'ShadowScale',
50740: 'DNGPrivateData',
50741: 'MakerNoteSafety',
50778: 'CalibrationIlluminant1',
50779: 'CalibrationIlluminant2',
50780: 'BestQualityScale',
50781: 'RawDataUniqueID',
50827: 'OriginalRawFileName',
50828: 'OriginalRawFileData',
50829: 'ActiveArea',
50830: 'MaskedAreas',
50831: 'AsShotICCProfile',
50832: 'AsShotPreProfileMatrix',
50833: 'CurrentICCProfile',
50834: 'CurrentPreProfileMatrix',
50879: 'ColorimetricReference',
50931: 'CameraCalibrationSignature',
50932: 'ProfileCalibrationSignature',
50934: 'AsShotProfileName',
50935: 'NoiseReductionApplied',
50936: 'ProfileName',
50937: 'ProfileHueSatMapDims',
50938: 'ProfileHueSatMapData1',
50939: 'ProfileHueSatMapData2',
50940: 'ProfileToneCurve',
50941: 'ProfileEmbedPolicy',
50942: 'ProfileCopyright',
50964: 'ForwardMatrix1',
50965: 'ForwardMatrix2',
50966: 'PreviewApplicationName',
50967: 'PreviewApplicationVersion',
50968: 'PreviewSettingsName',
50969: 'PreviewSettingsDigest',
50970: 'PreviewColorSpace',
50971: 'PreviewDateTime',
50972: 'RawImageDigest',
50973: 'OriginalRawFileDigest',
50974: 'SubTileBlockSize',
50975: 'RowInterleaveFactor',
50981: 'ProfileLookTableDims',
50982: 'ProfileLookTableData',
51008: 'OpcodeList1',
51009: 'OpcodeList2',
51022: 'OpcodeList3',
51041: 'NoiseProfile'}
def __init__(self, endian, read_buffer, offset):
_Ifd.__init__(self, endian, read_buffer, offset)
self.post_process(self.tagnum2name)
class _ExifPhotoIfd(_Ifd):
"""Represents tags found in the Exif sub ifd.
"""
tagnum2name = {33434: 'ExposureTime',
33437: 'FNumber',
34850: 'ExposureProgram',
34852: 'SpectralSensitivity',
34855: 'ISOSpeedRatings',
34856: 'OECF',
34864: 'SensitivityType',
34865: 'StandardOutputSensitivity',
34866: 'RecommendedExposureIndex',
34867: 'ISOSpeed',
34868: 'ISOSpeedLatitudeyyy',
34869: 'ISOSpeedLatitudezzz',
36864: 'ExifVersion',
36867: 'DateTimeOriginal',
36868: 'DateTimeDigitized',
37121: 'ComponentsConfiguration',
37122: 'CompressedBitsPerPixel',
37377: 'ShutterSpeedValue',
37378: 'ApertureValue',
37379: 'BrightnessValue',
37380: 'ExposureBiasValue',
37381: 'MaxApertureValue',
37382: 'SubjectDistance',
37383: 'MeteringMode',
37384: 'LightSource',
37385: 'Flash',
37386: 'FocalLength',
37396: 'SubjectArea',
37500: 'MakerNote',
37510: 'UserComment',
37520: 'SubSecTime',
37521: 'SubSecTimeOriginal',
37522: 'SubSecTimeDigitized',
40960: 'FlashpixVersion',
40961: 'ColorSpace',
40962: 'PixelXDimension',
40963: 'PixelYDimension',
40964: 'RelatedSoundFile',
40965: 'InteroperabilityTag',
41483: 'FlashEnergy',
41484: 'SpatialFrequencyResponse',
41486: 'FocalPlaneXResolution',
41487: 'FocalPlaneYResolution',
41488: 'FocalPlaneResolutionUnit',
41492: 'SubjectLocation',
41493: 'ExposureIndex',
41495: 'SensingMethod',
41728: 'FileSource',
41729: 'SceneType',
41730: 'CFAPattern',
41985: 'CustomRendered',
41986: 'ExposureMode',
41987: 'WhiteBalance',
41988: 'DigitalZoomRatio',
41989: 'FocalLengthIn35mmFilm',
41990: 'SceneCaptureType',
41991: 'GainControl',
41992: 'Contrast',
41993: 'Saturation',
41994: 'Sharpness',
41995: 'DeviceSettingDescription',
41996: 'SubjectDistanceRange',
42016: 'ImageUniqueID',
42032: 'CameraOwnerName',
42033: 'BodySerialNumber',
42034: 'LensSpecification',
42035: 'LensMake',
42036: 'LensModel',
42037: 'LensSerialNumber'}
def __init__(self, endian, read_buffer, offset):
_Ifd.__init__(self, endian, read_buffer, offset)
self.post_process(self.tagnum2name)
class _ExifGPSInfoIfd(_Ifd):
"""Represents information found in the GPSInfo sub IFD.
"""
tagnum2name = {0: 'GPSVersionID',
1: 'GPSLatitudeRef',
2: 'GPSLatitude',
3: 'GPSLongitudeRef',
4: 'GPSLongitude',
5: 'GPSAltitudeRef',
6: 'GPSAltitude',
7: 'GPSTimeStamp',
8: 'GPSSatellites',
9: 'GPSStatus',
10: 'GPSMeasureMode',
11: 'GPSDOP',
12: 'GPSSpeedRef',
13: 'GPSSpeed',
14: 'GPSTrackRef',
15: 'GPSTrack',
16: 'GPSImgDirectionRef',
17: 'GPSImgDirection',
18: 'GPSMapDatum',
19: 'GPSDestLatitudeRef',
20: 'GPSDestLatitude',
21: 'GPSDestLongitudeRef',
22: 'GPSDestLongitude',
23: 'GPSDestBearingRef',
24: 'GPSDestBearing',
25: 'GPSDestDistanceRef',
26: 'GPSDestDistance',
27: 'GPSProcessingMethod',
28: 'GPSAreaInformation',
29: 'GPSDateStamp',
30: 'GPSDifferential'}
def __init__(self, endian, read_buffer, offset):
_Ifd.__init__(self, endian, read_buffer, offset)
self.post_process(self.tagnum2name)
class _ExifInteroperabilityIfd(_Ifd):
"""Represents tags found in the Interoperability sub IFD.
"""
tagnum2name = {1: 'InteroperabilityIndex',
2: 'InteroperabilityVersion',
4096: 'RelatedImageFileFormat',
4097: 'RelatedImageWidth',
4098: 'RelatedImageLength'}
def __init__(self, endian, read_buffer, offset):
_Ifd.__init__(self, endian, read_buffer, offset)
self.post_process(self.tagnum2name)

View file

@ -6,16 +6,13 @@ codestreams.
# The number of lines in the module is long and that's ok. It would not help
# matters to move anything out to another file.
# pylint: disable=C0302
# "Too many instance attributes", "Too many arguments"
# Some segments just have a lot of information.
# It doesn't make sense to subclass just for that.
# pylint: disable=R0902,R0913
# "Too few public methods" Some segments don't define any new methods from
# the base Segment class.
# pylint: disable=R0903
import math
import struct
@ -24,22 +21,37 @@ import warnings
import numpy as np
from .core import LRCP, RLCP, RPCL, PCRL, CPRL
from .core import WAVELET_XFORM_9X7_IRREVERSIBLE
from .core import WAVELET_XFORM_5X3_REVERSIBLE
from .core import _CAPABILITIES_DISPLAY
from .core import (LRCP, RLCP, RPCL, PCRL, CPRL,
WAVELET_XFORM_9X7_IRREVERSIBLE,
WAVELET_XFORM_5X3_REVERSIBLE,
_Keydefaultdict)
from .lib import openjp2 as opj2
_PROGRESSION_ORDER_DISPLAY = {
LRCP: 'LRCP',
RLCP: 'RLCP',
RPCL: 'RPCL',
PCRL: 'PCRL',
CPRL: 'CPRL'}
_factory = lambda x: '{0} (invalid)'.format(x)
_PROGRESSION_ORDER_DISPLAY = _Keydefaultdict(_factory, {LRCP: 'LRCP',
RLCP: 'RLCP',
RPCL: 'RPCL',
PCRL: 'PCRL',
CPRL: 'CPRL'})
_WAVELET_TRANSFORM_DISPLAY = {
WAVELET_XFORM_9X7_IRREVERSIBLE: '9-7 irreversible',
WAVELET_XFORM_5X3_REVERSIBLE: '5-3 reversible'}
_keysvalues = {WAVELET_XFORM_9X7_IRREVERSIBLE: '9-7 irreversible',
WAVELET_XFORM_5X3_REVERSIBLE: '5-3 reversible'}
_WAVELET_TRANSFORM_DISPLAY = _Keydefaultdict(_factory, _keysvalues)
_NO_PROFILE = 0
_PROFILE_0 = 1
_PROFILE_1 = 2
_PROFILE_3 = 3
_PROFILE_4 = 4
_KNOWN_PROFILES = [_NO_PROFILE, _PROFILE_0, _PROFILE_1, _PROFILE_3, _PROFILE_4]
# How to display the codestream profile.
_CAPABILITIES_DISPLAY = _Keydefaultdict(_factory, {_NO_PROFILE: 'no profile',
_PROFILE_0: '0',
_PROFILE_1: '1',
_PROFILE_3: 'Cinema 2K',
_PROFILE_4: 'Cinema 4K'})
# Need a catch-all list of valid markers.
# See table A-1 in ISO/IEC FCD15444-1.
@ -171,15 +183,7 @@ class Codestream(object):
while True:
read_buffer = fptr.read(2)
try:
self._marker_id, = struct.unpack('>H', read_buffer)
except struct.error:
# Treat this as a warning.
msg = "Marker had length {0} instead of expected length of 2 "
msg += "bytes. Codestream parsing terminated."
warnings.warn(msg.format(len(read_buffer)))
break
self._marker_id, = struct.unpack('>H', read_buffer)
self._offset = fptr.tell() - 2
if self._marker_id == 0xff90 and header_only:
@ -193,7 +197,7 @@ class Codestream(object):
msg = 'Invalid marker id encountered at byte {0:d} '
msg += 'in codestream: "0x{1:x}"'
msg = msg.format(self._offset, self._marker_id)
warnings.warn(msg)
warnings.warn(msg, UserWarning)
break
self.segment.append(segment)
@ -289,7 +293,6 @@ class Codestream(object):
msg += ''.join(strs)
return msg
# pylint: disable=R0201
def _parse_cme_segment(self, fptr):
"""Parse the CME marker segment.
@ -363,14 +366,22 @@ class Codestream(object):
COD segment instance.
"""
offset = fptr.tell() - 2
offset = fptr.tell() - 2
read_buffer = fptr.read(3)
length, scod = struct.unpack('>HB', read_buffer)
read_buffer = fptr.read(2)
length, = struct.unpack('>H', read_buffer)
numbytes = offset + 2 + length - fptr.tell()
spcod = fptr.read(numbytes)
read_buffer = fptr.read(length - 2)
scod, = struct.unpack_from('>B', read_buffer, offset=0)
spcod = read_buffer[1:]
spcod = np.frombuffer(spcod, dtype=np.uint8)
if spcod[0] not in [LRCP, RLCP, RPCL, PCRL, CPRL]:
msg = "Invalid progression order in COD segment: {0}."
warnings.warn(msg.format(spcod[0]))
if spcod[8] not in [WAVELET_XFORM_9X7_IRREVERSIBLE,
WAVELET_XFORM_5X3_REVERSIBLE]:
msg = "Invalid wavelet transform in COD segment: {0}."
warnings.warn(msg.format(spcod[8]))
sop = (scod & 2) > 0
eph = (scod & 4) > 0
@ -558,22 +569,21 @@ class Codestream(object):
read_buffer = fptr.read(2)
length, = struct.unpack('>H', read_buffer)
read_buffer = fptr.read(length - 2)
if self._csiz > 256:
read_buffer = fptr.read(3)
fmt = '>HB'
mantissa_exponent_buffer_length = length - 5
mantissa_exponent_offset = 3
else:
read_buffer = fptr.read(2)
fmt = '>BB'
mantissa_exponent_buffer_length = length - 4
cqcc, sqcc = struct.unpack(fmt, read_buffer)
mantissa_exponent_offset = 2
cqcc, sqcc = struct.unpack_from(fmt, read_buffer)
if cqcc >= self._csiz:
msg = "Invalid component number ({0}), "
msg += "number of components is only {1}."
msg = msg.format(cqcc, self._csiz)
warnings.warn(msg)
spqcc = fptr.read(mantissa_exponent_buffer_length)
spqcc = read_buffer[mantissa_exponent_offset:]
return QCCsegment(cqcc, sqcc, spqcc, length, offset)
@ -626,7 +636,7 @@ class Codestream(object):
srgn = data[1]
sprgn = data[2]
return RGNsegment(length, offset, crgn, srgn, sprgn)
return RGNsegment(crgn, srgn, sprgn, length, offset)
def _parse_siz_segment(self, fptr):
"""Parse the SIZ segment.
@ -645,17 +655,63 @@ class Codestream(object):
read_buffer = fptr.read(2)
length, = struct.unpack('>H', read_buffer)
xy_buffer = fptr.read(36)
read_buffer = fptr.read(length - 2)
data = struct.unpack_from('>HIIIIIIIIH', read_buffer)
num_components, = struct.unpack('>H', xy_buffer[-2:])
rsiz = data[0]
if rsiz not in _KNOWN_PROFILES:
warnings.warn("Invalid profile: (Rsiz={0}).".format(rsiz))
component_buffer = fptr.read(num_components * 3)
xysiz = (data[1], data[2])
xyosiz = (data[3], data[4])
xytsiz = (data[5], data[6])
xytosiz = (data[7], data[8])
segment = SIZsegment(xy_buffer, component_buffer, length, offset)
# Csiz is the number of components
Csiz = data[9]
data = struct.unpack_from('>' + 'B' * (length - 36 - 2),
read_buffer, offset=36)
bitdepth = tuple(((x & 0x7f) + 1) for x in data[0::3])
signed = tuple(((x & 0x80) > 0) for x in data[0::3])
xrsiz = data[1::3]
yrsiz = data[2::3]
for j, subsampling in enumerate(zip(xrsiz, yrsiz)):
if 0 in subsampling:
msg = "Invalid subsampling value for component {0}: "
msg += "dx={1}, dy={2}."
msg = msg.format(j, subsampling[0], subsampling[1])
warnings.warn(msg)
try:
num_tiles_x = (xysiz[0] - xyosiz[0]) / (xytsiz[0] - xytosiz[0])
num_tiles_y = (xysiz[1] - xyosiz[1]) / (xytsiz[1] - xytosiz[1])
except ZeroDivisionError:
warnings.warn("Invalid tile dimensions.")
else:
numtiles = math.ceil(num_tiles_x) * math.ceil(num_tiles_y)
if numtiles > 65535:
msg = "Invalid number of tiles ({0}).".format(numtiles)
warnings.warn(msg)
kwargs = {'rsiz': rsiz,
'xysiz': xysiz,
'xyosiz': xyosiz,
'xytsiz': xytsiz,
'xytosiz': xytosiz,
'Csiz': Csiz,
'bitdepth': bitdepth,
'signed': signed,
'xyrsiz': (xrsiz, yrsiz),
'length': length,
'offset': offset}
segment = SIZsegment(**kwargs)
# Need to keep track of the number of components from SIZ for
# other markers
self._csiz = len(segment.ssiz)
# other markers.
self._csiz = Csiz
return segment
@ -731,8 +787,8 @@ class Codestream(object):
read_buffer = fptr.read(2)
length, = struct.unpack('>H', read_buffer)
read_buffer = fptr.read(2)
ztlm, stlm = struct.unpack('>BB', read_buffer)
read_buffer = fptr.read(length - 2)
ztlm, stlm = struct.unpack_from('>BB', read_buffer)
ttlm_st = (stlm >> 4) & 0x3
ptlm_sp = (stlm >> 6) & 0x1
@ -742,7 +798,6 @@ class Codestream(object):
else:
ntiles = nbytes / (ttlm_st + (ptlm_sp + 1) * 2)
read_buffer = fptr.read(nbytes)
if ttlm_st == 0:
ttlm = None
fmt = ''
@ -756,7 +811,8 @@ class Codestream(object):
else:
fmt += 'I'
data = struct.unpack('>' + fmt * int(ntiles), read_buffer)
data = struct.unpack_from('>' + fmt * int(ntiles), read_buffer,
offset=2)
if ttlm_st == 0:
ttlm = None
ptlm = data
@ -766,7 +822,6 @@ class Codestream(object):
return TLMsegment(length, offset, ztlm, ttlm, ptlm)
# pylint: disable=W0613
def _parse_reserved_marker(self, fptr):
"""Marker range between 0xff30 and 0xff39.
"""
@ -1011,7 +1066,7 @@ class CMEsegment(Segment):
15444-1:2004 - Information technology -- JPEG 2000 image coding system:
Core coding system
"""
def __init__(self, rcme, ccme, length, offset):
def __init__(self, rcme, ccme, length=-1, offset=-1):
Segment.__init__(self, marker_id='CME')
self.rcme = rcme
self.ccme = ccme
@ -1400,7 +1455,7 @@ class RGNsegment(Segment):
15444-1:2004 - Information technology -- JPEG 2000 image coding system:
Core coding system
"""
def __init__(self, length, offset, crgn, srgn, sprgn):
def __init__(self, crgn, srgn, sprgn, length=-1, offset=-1):
Segment.__init__(self, marker_id='RGN')
self.length = length
self.offset = offset
@ -1441,8 +1496,8 @@ class SIZsegment(Segment):
Width and height of reference tile with respect to the reference grid.
xtosiz, ytosiz : int
Horizontal and vertical offsets of tile from origin of reference grid.
ssiz : iterable bytes
Encoded precision (depth) in bits and sign of each component.
Csiz : int
Number of components in image.
bitdepth : iterable bytes
Precision (depth) in bits of each component.
signed : iterable bool
@ -1457,48 +1512,45 @@ class SIZsegment(Segment):
15444-1:2004 - Information technology -- JPEG 2000 image coding system:
Core coding system
"""
def __init__(self, xy_buffer, component_buffer, length, offset):
Segment.__init__(self, marker_id='SIZ')
def __init__(self, rsiz=-1, xysiz=None, xyosiz=-1, xytsiz=-1, xytosiz=-1,
Csiz=-1, bitdepth=None, signed=None, xyrsiz=-1, length=-1,
offset=-1):
Segment.__init__(self, marker_id='SIZ', length=length, offset=offset)
data = struct.unpack('>HIIIIIIIIH', xy_buffer)
self.rsiz = rsiz
self.xsiz, self.ysiz = xysiz
self.xosiz, self.yosiz = xyosiz
self.xtsiz, self.ytsiz = xytsiz
self.xtosiz, self.ytosiz = xytosiz
self.Csiz = Csiz
self.bitdepth = bitdepth
self.signed = signed
self.xrsiz, self.yrsiz = xyrsiz
self.rsiz = data[0]
self.xsiz = data[1]
self.ysiz = data[2]
self.xosiz = data[3]
self.yosiz = data[4]
self.xtsiz = data[5]
self.ytsiz = data[6]
self.xtosiz = data[7]
self.ytosiz = data[8]
# disregarding the last element in data
# ssiz attribute to be removed in 1.0.0
lst = []
for bitdepth, signed in zip(self.bitdepth, self.signed):
if signed:
lst.append((bitdepth - 1) | 0x80)
else:
lst.append(bitdepth - 1)
self.ssiz = tuple(lst)
num_tiles_x = (self.xsiz - self.xosiz) / (self.xtsiz - self.xtosiz)
num_tiles_y = (self.ysiz - self.yosiz) / (self.ytsiz - self.ytosiz)
numtiles = math.ceil(num_tiles_x) * math.ceil(num_tiles_y)
if numtiles > 65535:
msg = "Invalid number of tiles ({0}).".format(numtiles)
warnings.warn(msg)
data = struct.unpack('>' + 'B' * len(component_buffer),
component_buffer)
self.ssiz = data[0::3]
for j, subsampling in enumerate(list(zip(data[1::3], data[2::3]))):
if 0 in subsampling:
msg = "Invalid subsampling value for component {0}: "
msg += "dx={1}, dy={2}."
msg = msg.format(j, subsampling[0], subsampling[1])
warnings.warn(msg)
self.xrsiz = data[1::3]
self.yrsiz = data[2::3]
self.bitdepth = tuple(((x & 0x7f) + 1) for x in self.ssiz)
self.signed = tuple(((x & 0xb0) > 0) for x in self.ssiz)
self.length = length
self.offset = offset
def __repr__(self):
msg = "glymur.codestream.SIZsegment(rsiz={rsiz}, xysiz={xysiz}, "
msg += "xyosiz={xyosiz}, xytsiz={xytsiz}, xytosiz={xytosiz}, "
msg += "Csiz={Csiz}, bitdepth={bitdepth}, signed={signed}, "
msg += "xyrsiz={xyrsiz})"
msg = msg.format(rsiz=self.rsiz,
xysiz=(self.xsiz, self.ysiz),
xyosiz=(self.xosiz, self.yosiz),
xytsiz=(self.xtsiz, self.ytsiz),
xytosiz=(self.xtosiz, self.ytosiz),
Csiz=self.Csiz,
bitdepth=self.bitdepth,
signed=self.signed,
xyrsiz=(self.xrsiz, self.yrsiz))
return msg
def __str__(self):
msg = Segment.__str__(self)
@ -1549,6 +1601,10 @@ class SOCsegment(Segment):
Segment.__init__(self, marker_id='SOC')
self.__dict__.update(**kwargs)
def __repr__(self):
msg = "glymur.codestream.SOCsegment()"
return msg
class SODsegment(Segment):
"""Container for Start of Data (SOD) segment information.
@ -1663,7 +1719,7 @@ class SOTsegment(Segment):
15444-1:2004 - Information technology -- JPEG 2000 image coding system:
Core coding system
"""
def __init__(self, isot, psot, tpsot, tnsot, length, offset):
def __init__(self, isot, psot, tpsot, tnsot, length=-1, offset=-1):
Segment.__init__(self, marker_id='SOT')
self.isot = isot
self.psot = psot

78
glymur/command_line.py Normal file
View file

@ -0,0 +1,78 @@
"""
Entry point for console script jp2dump.
"""
import argparse
import os
import warnings
from . import Jp2k, set_printoptions, set_parseoptions, lib
def main():
"""
Entry point for console script jp2dump.
"""
kwargs = {'description': 'Print JPEG2000 metadata.',
'formatter_class': argparse.ArgumentDefaultsHelpFormatter}
parser = argparse.ArgumentParser(**kwargs)
parser.add_argument('-x', '--noxml',
help='suppress XML',
action='store_true')
parser.add_argument('-s', '--short',
help='only print box id, offset, and length',
action='store_true')
chelp = 'Level of codestream information. 0 suppresses all details, '
chelp += '1 prints the main header, 2 prints the full codestream.'
parser.add_argument('-c', '--codestream',
help=chelp,
metavar='LEVEL',
nargs=1,
type=int,
default=[1])
parser.add_argument('filename')
args = parser.parse_args()
if args.noxml:
set_printoptions(xml=False)
if args.short:
set_printoptions(short=True)
codestream_level = args.codestream[0]
if codestream_level not in [0, 1, 2]:
raise ValueError("Invalid level of codestream information specified.")
if codestream_level == 0:
set_printoptions(codestream=False)
elif codestream_level == 2:
set_parseoptions(full_codestream=True)
filename = args.filename
with warnings.catch_warnings(record=True) as wctx:
# JP2 metadata can be extensive, so don't print any warnings until we
# are done with the metadata.
jp2 = Jp2k(filename)
if jp2._codec_format == lib.openjp2.CODEC_J2K:
if codestream_level == 0:
print('File: {0}'.format(os.path.basename(filename)))
elif codestream_level == 1:
print(jp2)
elif codestream_level == 2:
print('File: {0}'.format(os.path.basename(filename)))
print(jp2.get_codestream(header_only=False))
else:
print(jp2)
# Re-emit any warnings that may have been suppressed.
if len(wctx) > 0:
print("\n")
for warning in wctx:
print("{0}:{1}: {2}: {3}".format(warning.filename,
warning.lineno,
warning.category.__name__,
warning.message))

View file

@ -1,5 +1,21 @@
"""Core definitions to be shared amongst the modules.
"""
import collections
class _Keydefaultdict(collections.defaultdict):
"""Unlisted keys help form their own error message.
Normally defaultdict uses a factory function with no input arguments, but
that's not quite the behavior we want.
"""
def __missing__(self, key):
if self.default_factory is None:
raise KeyError(key)
else:
ret = self[key] = self.default_factory(key)
return ret
# Progression order
LRCP = 0
RLCP = 1
@ -7,6 +23,74 @@ RPCL = 2
PCRL = 3
CPRL = 4
STD = 0
CINEMA2K = 3
CINEMA4K = 4
RSIZ = {
'STD': STD,
'CINEMA2K': CINEMA2K,
'CINEMA4K': CINEMA4K}
OFF = 0
CINEMA2K_24 = 1
CINEMA2K_48 = 2
CINEMA4K_24 = 3
OPJ_OFF = 0 # Not Digital Cinema
OPJ_CINEMA2K_24 = 1 # 2K Digital Cinema at 24 fps
OPJ_CINEMA2K_48 = 2 # 2K Digital Cinema at 48 fps
OPJ_CINEMA4K_24 = 3 # 4K Digital Cinema at 24 fps
# no profile, conform to 15444-1
OPJ_PROFILE_NONE = 0x0000
# Profile 0 as described in 15444-1,Table A.45
OPJ_PROFILE_0 = 0x0001
# Profile 1 as described in 15444-1,Table A.45
OPJ_PROFILE_1 = 0x0002
# At least 1 extension defined in 15444-2 (Part-2)
OPJ_PROFILE_PART2 = 0x8000
# 2K cinema profile defined in 15444-1 AMD1
OPJ_PROFILE_CINEMA_2K = 0x0003
# 4K cinema profile defined in 15444-1 AMD1
OPJ_PROFILE_CINEMA_4K = 0x0004
# Scalable 2K cinema profile defined in 15444-1 AMD2
OPJ_PROFILE_CINEMA_S2K = 0x0005
# Scalable 4K cinema profile defined in 15444-1 AMD2
OPJ_PROFILE_CINEMA_S4K = 0x0006
# Long term storage cinema profile defined in 15444-1 AMD2
OPJ_PROFILE_CINEMA_LTS = 0x0007
# Single Tile Broadcast profile defined in 15444-1 AMD3
OPJ_PROFILE_BC_SINGLE = 0x0100
# Multi Tile Broadcast profile defined in 15444-1 AMD3
OPJ_PROFILE_BC_MULTI = 0x0200
# Multi Tile Reversible Broadcast profile defined in 15444-1 AMD3
OPJ_PROFILE_BC_MULTI_R = 0x0300
# 2K Single Tile Lossy IMF profile defined in 15444-1 AMD 8
OPJ_PROFILE_IMF_2K = 0x0400
# 4K Single Tile Lossy IMF profile defined in 15444-1 AMD 8
OPJ_PROFILE_IMF_4K = 0x0401
# 8K Single Tile Lossy IMF profile defined in 15444-1 AMD 8
OPJ_PROFILE_IMF_8K = 0x0402
# 2K Single/Multi Tile Reversible IMF profile defined in 15444-1 AMD 8
OPJ_PROFILE_IMF_2K_R = 0x0403
# 4K Single/Multi Tile Reversible IMF profile defined in 15444-1 AMD 8
OPJ_PROFILE_IMF_4K_R = 0x0800
# 8K Single/Multi Tile Reversible IMF profile defined in 15444-1 AMD 8
OPJ_PROFILE_IMF_8K_R = 0x0801
# JPEG 2000 codestream and component size limits in cinema profiles
#
# Maximum codestream length for 24fps
OPJ_CINEMA_24_CS = 1302083
# Maximum codestream length for 48fps
OPJ_CINEMA_48_CS = 651041
# Maximum size per color component for 2K & 4K @ 24fps
OPJ_CINEMA_24_COMP = 1041666
# Maximum size per color component for 2K @ 48fps
OPJ_CINEMA_48_COMP = 520833
PROGRESSION_ORDER = {
'LRCP': LRCP,
'RLCP': RLCP,
@ -34,24 +118,26 @@ YCC = 18
E_SRGB = 20
ROMM_RGB = 21
_COLORSPACE_MAP_DISPLAY = {
CMYK: 'CMYK',
SRGB: 'sRGB',
GREYSCALE: 'greyscale',
YCC: 'YCC',
E_SRGB: 'e-sRGB',
ROMM_RGB: 'ROMM-RGB'}
_factory = lambda x: '{0} (unrecognized)'.format(x)
_COLORSPACE_MAP_DISPLAY = _Keydefaultdict(_factory,
{CMYK: 'CMYK',
SRGB: 'sRGB',
GREYSCALE: 'greyscale',
YCC: 'YCC',
E_SRGB: 'e-sRGB',
ROMM_RGB: 'ROMM-RGB'})
# enumerated color channel types
COLOR = 0
OPACITY = 1
PRE_MULTIPLIED_OPACITY = 2
_UNSPECIFIED = 65535
_COLOR_TYPE_MAP_DISPLAY = {
COLOR: 'color',
OPACITY: 'opacity',
PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity',
_UNSPECIFIED: 'unspecified'}
_factory = lambda x: '{0} (invalid)'.format(x)
_dict = {COLOR: 'color',
OPACITY: 'opacity',
PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity',
_UNSPECIFIED: 'unspecified'}
_COLOR_TYPE_MAP_DISPLAY = _Keydefaultdict(_factory, _dict)
# color channel definitions.
RED = 1
@ -66,10 +152,3 @@ _COLORSPACE = {SRGB: {"R": 1, "G": 2, "B": 3},
YCC: {"Y": 1, "Cb": 2, "Cr": 3},
E_SRGB: {"R": 1, "G": 2, "B": 3},
ROMM_RGB: {"R": 1, "G": 2, "B": 3}}
# How to display the codestream profile.
_CAPABILITIES_DISPLAY = {
0: '2',
1: '0',
2: '1',
3: '3'}

View file

@ -31,3 +31,15 @@ def goodstuff():
"""
filename = pkg_resources.resource_filename(__name__, "goodstuff.j2k")
return filename
def jpxfile():
"""Shortcut for specifying path to heliov.jpx.
Returns
-------
file : str
Platform-independent path to 12-v6.4.jpx
"""
filename = pkg_resources.resource_filename(__name__, "heliov.jpx")
return filename

BIN
glymur/data/heliov.jpx Normal file

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -1,36 +0,0 @@
"""
Entry point for jp2dump script.
"""
import warnings
from .jp2k import Jp2k
def jp2dump(filename, codestream=False):
"""Prints JPEG2000 metadata.
Parameters
----------
filename : string
The input JPEG2000 file.
codestream : optional, logical scalar
Whether or not to dump codestream contents.
"""
with warnings.catch_warnings(record=True) as wctx:
# JP2 metadata can be extensive, so don't print any warnings until we
# are done with the metadata.
j = Jp2k(filename)
if codestream:
print(j.get_codestream(header_only=False))
else:
print(j)
# Re-emit any warnings that may have been suppressed.
if len(wctx) > 0:
print("\n")
for warning in wctx:
print("{0}:{1}: {2}: {3}".format(warning.filename,
warning.lineno,
warning.category.__name__,
warning.message))

File diff suppressed because it is too large Load diff

View file

@ -2,3 +2,5 @@
from . import openjp2 as openjp2
from . import openjpeg as openjpeg
from . import c
__all__ = [openjp2, openjpeg, c]

View file

@ -1,9 +1,6 @@
"""
Configure glymur to use installed libraries if possible.
"""
# configparser is new in python3 (pylint/python-2.7)
# pylint: disable=F0401
import ctypes
from ctypes.util import find_library
import os
@ -18,6 +15,22 @@ else:
from configparser import ConfigParser
from configparser import NoOptionError
# default library locations for MacPorts
_macports_default_location = {'openjp2': '/opt/local/lib/libopenjp2.dylib',
'openjpeg': '/opt/local/lib/libopenjpeg.dylib'}
# default library locations on Windows
_windows_default_location = {'openjp2': os.path.join('C:\\',
'Program files',
'OpenJPEG 2.0',
'bin',
'openjp2.dll'),
'openjpeg': os.path.join('C:\\',
'Program files',
'OpenJPEG 1.5',
'bin',
'openjpeg.dll')}
def glymurrc_fname():
"""Return the path to the configuration file.
@ -43,52 +56,23 @@ def glymurrc_fname():
return None
def load_openjpeg(path):
"""Load the openjpeg library, falling back on defaults if necessary.
def load_openjpeg_library(libname):
Parameters
----------
path : str
Path to openjpeg 1.5 library as specified by configuration file. Will
be None if no configuration file specified.
"""
if path is None:
# Let ctypes try to find it.
path = find_library('openjpeg')
path = read_config_file(libname)
if path is not None:
return load_library_handle(path)
# If we could not find it, then look in some likely locations on mac
# and win.
if path is None:
# Could not find a library via ctypes
if platform.system() == 'Darwin':
# MacPorts
path = '/opt/local/lib/libopenjpeg.dylib'
elif os.name == 'nt':
path = os.path.join('C:\\', 'Program files', 'OpenJPEG 1.5',
'bin', 'openjpeg.dll')
if path is not None and not os.path.exists(path):
# the mac/win default location does not exist.
return None
return load_library_handle(path)
def load_openjp2(path):
"""Load the openjp2 library, falling back on defaults if necessary.
"""
if path is None:
# No help from the config file, try to find it via ctypes.
path = find_library('openjp2')
# No location specified by the configuration file, must look for it
# elsewhere.
path = find_library(libname)
if path is None:
# Could not find a library via ctypes
if platform.system() == 'Darwin':
# MacPorts
path = '/opt/local/lib/libopenjp2.dylib'
path = _macports_default_location[libname]
elif os.name == 'nt':
path = os.path.join('C:\\', 'Program files', 'OpenJPEG 2.0',
'bin', 'openjp2.dll')
path = _windows_default_location[libname]
if path is not None and not os.path.exists(path):
# the mac/win default location does not exist.
@ -100,10 +84,11 @@ def load_openjp2(path):
def load_library_handle(path):
"""Load the library, return the ctypes handle."""
if path is None:
# Either could not find a library via ctypes or user-configuration-file,
# or we could not find it in any of the default locations.
# This is probably a very old linux.
if path is None or path in ['None', 'none']:
# Either could not find a library via ctypes or
# user-configuration-file, or we could not find it in any of the
# default locations, or possibly the user intentionally does not want
# one of the libraries to load.
return None
try:
@ -112,47 +97,59 @@ def load_library_handle(path):
else:
opj_lib = ctypes.CDLL(path)
except (TypeError, OSError):
msg = '"Library {0}" could not be loaded. Operating in degraded mode.'
msg = msg.format(path)
warnings.warn(msg, UserWarning)
opj_lib = None
msg = 'The library specified by configuration file at {0} could not '
msg += 'be loaded.'
warnings.warn(msg.format(path), UserWarning)
opj_lib = None
return opj_lib
def read_config_file():
def read_config_file(libname):
"""
We must use a configuration file that the user must write.
"""
lib = {'openjp2': None, 'openjpeg': None}
filename = glymurrc_fname()
if filename is not None:
# Read the configuration file for the library location.
parser = ConfigParser()
parser.read(filename)
try:
lib['openjp2'] = parser.get('library', 'openjp2')
except NoOptionError:
pass
try:
lib['openjpeg'] = parser.get('library', 'openjpeg')
except NoOptionError:
pass
Extract library locations from a configuration file.
return lib
Parameters
----------
libname : str
One of either 'openjp2' or 'openjpeg'
Returns
-------
path : None or str
None if no location is specified, otherwise a path to the library
"""
filename = glymurrc_fname()
if filename is None:
# There's no library file path to return in this case.
return None
# Read the configuration file for the library location.
parser = ConfigParser()
parser.read(filename)
try:
path = parser.get('library', libname)
except NoOptionError:
path = None
return path
def glymur_config():
"""Try to ascertain locations of openjp2, openjpeg libraries.
"""
libs = read_config_file()
libopenjp2_handle = load_openjp2(libs['openjp2'])
libopenjpeg_handle = load_openjpeg(libs['openjpeg'])
if libopenjp2_handle is None and libopenjpeg_handle is None:
Try to ascertain locations of openjp2, openjpeg libraries.
Returns
-------
tpl : tuple
tuple of library handles
"""
lst = []
for libname in ['openjp2', 'openjpeg']:
lst.append(load_openjpeg_library(libname))
if all(handle is None for handle in lst):
msg = "Neither the openjp2 nor the openjpeg library could be loaded. "
msg += "Operating in severely degraded mode."
warnings.warn(msg, UserWarning)
return libopenjp2_handle, libopenjpeg_handle
warnings.warn(msg)
return tuple(lst)
def get_configdir():

View file

@ -2,22 +2,23 @@
Wraps individual functions in openjp2 library.
"""
# pylint: disable=C0302,R0903,W0201
import ctypes
import re
import sys
import textwrap
from .config import glymur_config
OPENJP2, OPENJPEG = glymur_config()
def version():
"""Wrapper for opj_version library routine."""
try:
OPENJP2.opj_version.restype = ctypes.c_char_p
except AttributeError:
# No library, so the version is zero.
except:
return "0.0.0"
library_version = OPENJP2.opj_version()
if sys.hexversion >= 0x03000000:
return library_version.decode('utf-8')
@ -25,9 +26,10 @@ def version():
return library_version
if OPENJP2 is not None:
_MAJOR, _MINOR, _PATH = version().split('.')
_MAJOR, _MINOR, _PATCH = version().split('.')
else:
_MINOR = 0
ERROR_MSG_LST = []
# Map certain atomic OpenJPEG datatypes to the ctypes equivalents.
@ -53,6 +55,7 @@ CLRSPC_UNSPECIFIED = 0
CLRSPC_SRGB = 1
CLRSPC_GRAY = 2
CLRSPC_YCC = 3
CLRSPC_EYCC = 4
COLOR_SPACE_TYPE = ctypes.c_int
# supported codec
@ -128,6 +131,13 @@ class PocType(ctypes.Structure):
("tx0_t", ctypes.c_uint32),
("ty0_t", ctypes.c_uint32)]
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
class DecompressionParametersType(ctypes.Structure):
"""Decompression parameters.
@ -191,6 +201,13 @@ class DecompressionParametersType(ctypes.Structure):
# maximum number of tiles
("flags", ctypes.c_uint32)]
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
class CompressionParametersType(ctypes.Structure):
"""Compression parameters.
@ -382,6 +399,46 @@ class CompressionParametersType(ctypes.Structure):
# values.
_fields_.append(("rsiz", ctypes.c_uint16))
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
if field_name == 'poc':
msg += " numpocs: {0}\n".format(self.numpocs)
for j in range(self.numpocs):
msg += " [#{0}]:".format(j)
msg += " {0}".format(str(self.poc[j]))
elif field_name in ['tcp_rates', 'tcp_distoratio']:
lst = []
arr = getattr(self, field_name)
lst = [arr[j] for j in range(self.tcp_numlayers)]
msg += " {0}: {1}\n".format(field_name, lst)
elif field_name in ['prcw_init', 'prch_init']:
pass
elif field_name == 'res_spec':
prcw_init = [self.prcw_init[j] for j in range(self.res_spec)]
prch_init = [self.prch_init[j] for j in range(self.res_spec)]
msg += " res_spec: {0}\n".format(self.res_spec)
msg += " prch_init: {0}\n".format(prch_init)
msg += " prcw_init: {0}\n".format(prcw_init)
elif field_name in [
'jpwl_hprot_tph_tileno', 'jpwl_hprot_tph',
'jpwl_pprot_tileno', 'jpwl_pprot_packno', 'jpwl_pprot',
'jpwl_sens_tph_tileno', 'jpwl_sens_tph']:
arr = getattr(self, field_name)
lst = [arr[j] for j in range(JPWL_MAX_NO_TILESPECS)]
msg += " {0}: {1}\n".format(field_name, lst)
else:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
class ImageCompType(ctypes.Structure):
"""Defines a single image component.
@ -421,7 +478,14 @@ class ImageCompType(ctypes.Structure):
("data", ctypes.POINTER(ctypes.c_int32))]
if _MINOR == '1':
_fields_.append(("alpha", ctypes.c_uint16))
_fields_.append(("alpha", ctypes.c_uint16))
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
class ImageType(ctypes.Structure):
@ -454,6 +518,26 @@ class ImageType(ctypes.Structure):
# restricted ICC profile buffer length
("icc_profile_len", ctypes.c_uint32)]
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
if field_name == "numcomps":
msg += " numcomps: {0}\n".format(self.numcomps)
for j in range(self.numcomps):
msg += " comps[#{0}]:\n".format(j)
msg += textwrap.indent(str(self.comps[j]), ' ' * 12)
elif field_name == "comps":
# handled above
pass
else:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
class ImageComptParmType(ctypes.Structure):
"""Component parameters structure used by image_create function.
@ -483,106 +567,12 @@ class ImageComptParmType(ctypes.Structure):
# signed (1) / unsigned (0)
("sgnd", ctypes.c_uint32)]
class TccpInfo(ctypes.Structure):
"""Tile-component coding parameters information.
Corresponds to tccp_info_t type in openjp2 header file.
"""
_fields_ = [
# component index
("compno", ctypes.c_uint32),
# coding style
("csty", ctypes.c_uint32),
# number of resolutions
("numresolutions", ctypes.c_uint32),
# code-blocks width
("cblkw", ctypes.c_uint32),
# code-blocks height
("cblkh", ctypes.c_uint32),
# code-block coding style
("cblksty", ctypes.c_uint32),
# discrete wavelet transform identifier
("qmfbid", ctypes.c_uint32),
# quantization style
("qntsty", ctypes.c_uint32),
# stepsizes used for quantization
("stepsizes_mant", ctypes.c_uint32 * J2K_MAXBANDS),
("stepsizes_expn", ctypes.c_uint32 * J2K_MAXBANDS),
# stepsizes used for quantization
("numgbits", ctypes.c_uint32),
# region of interest shift
("roishift", ctypes.c_int32),
# precinct width
("prcw", ctypes.c_uint32 * J2K_MAXRLVLS),
# precinct width
("prch", ctypes.c_uint32 * J2K_MAXRLVLS)]
class TileInfoV2(ctypes.Structure):
"""Tile coding parameters information
Corresponds to tile_info_v2_t type in openjp2 headers.
"""
_fields_ = [
# number (index) of tile
("tileno", ctypes.c_int32),
# coding style
("csty", ctypes.c_uint32),
# progression order
("prg", PROG_ORDER_TYPE),
# number of layers
("numlayers", ctypes.c_uint32),
# multi-component transform identifier
("mct", ctypes.c_uint32),
# information concerning tile component parameters
("tccp_info", ctypes.POINTER(TccpInfo))]
class CodestreamInfoV2(ctypes.Structure):
"""information about the codestream.
Corresponds to codestream_info_v2_t type in openjp2 header files.
"""
_fields_ = [
# tile info
# tile origin in x, y (XTOsiz, YTOsiz)
("tx0", ctypes.c_uint32),
("ty0", ctypes.c_uint32),
# tile size in x, y = XTsiz, YTsiz
("tdx", ctypes.c_uint32),
("tdy", ctypes.c_uint32),
# number of tiles in X, Y
("tw", ctypes.c_uint32),
("th", ctypes.c_uint32),
# number of components
("nbcomps", ctypes.c_uint32),
# default information regarding tiles inside of image
("m_default_tile_info", TileInfoV2),
# information regarding tiles inside of image
("tile_info", ctypes.POINTER(TileInfoV2))]
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
def check_error(status):
@ -747,28 +737,6 @@ def encode(codec, stream):
OPENJP2.opj_encode(codec, stream)
def get_cstr_info(codec):
"""get the codestream information from the codec
Wraps the openjp2 library function opj_get_cstr_info.
Parameters
----------
codec : CODEC_TYPE
The jpeg2000 codec.
Returns
-------
cstr_info_p : CodestreamInfoV2
Reference to codestream information.
"""
OPENJP2.opj_get_cstr_info.argtypes = [CODEC_TYPE]
OPENJP2.opj_get_cstr_info.restype = ctypes.POINTER(CodestreamInfoV2)
cstr_info_p = OPENJP2.opj_get_cstr_info(codec)
return cstr_info_p
def get_decoded_tile(codec, stream, imagep, tile_index):
"""get the decoded tile from the codec
@ -799,23 +767,6 @@ def get_decoded_tile(codec, stream, imagep, tile_index):
OPENJP2.opj_get_decoded_tile(codec, stream, imagep, tile_index)
def destroy_cstr_info(cstr_info_p):
"""destroy codestream information after compression or decompression
Wraps the openjp2 library function opj_destroy_cstr_info.
Parameters
----------
cstr_info_p : CodestreamInfoV2 pointer
Pointer to codestream info structure.
"""
ARGTYPES = [ctypes.POINTER(ctypes.POINTER(CodestreamInfoV2))]
OPENJP2.opj_destroy_cstr_info.argtypes = ARGTYPES
OPENJP2.opj_destroy_cstr_info.restype = ctypes.c_void_p
OPENJP2.opj_destroy_cstr_info(ctypes.byref(cstr_info_p))
def end_compress(codec, stream):
"""End of compressing the current image.
@ -958,7 +909,7 @@ def read_header(stream, codec):
ARGTYPES = [STREAM_TYPE_P, CODEC_TYPE,
ctypes.POINTER(ctypes.POINTER(ImageType))]
OPENJP2.opj_read_header.argtypes = ARGTYPES
OPENJP2.opj_read_header.restype = check_error
OPENJP2.opj_read_header.restype = check_error
imagep = ctypes.POINTER(ImageType)()
OPENJP2.opj_read_header(stream, codec, ctypes.byref(imagep))
@ -1295,7 +1246,8 @@ def start_compress(codec, image, stream):
def _stream_create_default_file_stream_2p0(fptr, isa_read_stream):
"""Wraps openjp2 library function opj_stream_create_default_vile_stream.
Sets the stream to be a file stream.
Sets the stream to be a file stream. This is valid only for version 2.0.0
of OpenJPEG.
Parameters
----------
@ -1320,7 +1272,8 @@ def _stream_create_default_file_stream_2p0(fptr, isa_read_stream):
def _stream_create_default_file_stream_2p1(fname, isa_read_stream):
"""Wraps openjp2 library function opj_stream_create_default_vile_stream.
Sets the stream to be a file stream.
Sets the stream to be a file stream. This function is only valid for the
2.1 version of the openjp2 library.
Parameters
----------
@ -1348,6 +1301,7 @@ if re.match(r'''2.0''', version()):
else:
stream_create_default_file_stream = _stream_create_default_file_stream_2p1
def stream_destroy(stream):
"""Wraps openjp2 library function opj_stream_destroy.
@ -1404,5 +1358,3 @@ def write_tile(codec, tile_index, data, data_size, stream):
def set_error_message(msg):
"""The openjpeg error handler has recorded an error message."""
ERROR_MSG_LST.append(msg)

View file

@ -1,18 +1,15 @@
"""Wraps library calls to openjpeg.
"""
# pylint: disable=R0903
import ctypes
import sys
import numpy as np
from .config import glymur_config
_, OPENJPEG = glymur_config()
# Maximum number of tile parts expected by JPWL: increase at your will
JPWL_MAX_NO_TILESPECS = 16
# Maximum number of tile parts expected by JPWL: increase at your will
JPWL_MAX_NO_TILESPECS = 16
J2K_MAXRLVLS = 33 # Number of maximum resolution level authorized
PATH_LEN = 4096 # maximum allowed size for filenames
@ -58,8 +55,10 @@ class CommonStructType(ctypes.Structure):
("mj2_handle", ctypes.c_void_p)]
STREAM_READ = 0x0001 # The stream was opened for reading.
STREAM_WRITE = 0x0002 # The stream was opened for writing.
STREAM_READ = 0x0001 # The stream was opened for reading.
STREAM_WRITE = 0x0002 # The stream was opened for writing.
class CioType(ctypes.Structure):
"""Byte input-output stream (CIO)
@ -81,7 +80,7 @@ class CioType(ctypes.Structure):
class CompressionInfoType(CommonStructType):
"""Common fields between JPEG-2000 compression and decompression contexts.
"""Common fields between JPEG-2000 compression and decompression contexts.
This is for compression contexts. Corresponds to common_struct_t.
"""
pass
@ -90,70 +89,57 @@ class CompressionInfoType(CommonStructType):
class PocType(ctypes.Structure):
"""Progression order changes."""
_fields_ = [("resno", ctypes.c_int),
# Resolution num start, Component num start, given by POC
("compno0", ctypes.c_int),
# Resolution num start, Component num start, given by POC
("compno0", ctypes.c_int),
# Layer num end,Resolution num end, Component num end, given by POC
("layno1", ctypes.c_int),
("resno1", ctypes.c_int),
("compno1", ctypes.c_int),
# Layer num end,Resolution num end, Component num end, given
# by POC
("layno1", ctypes.c_int),
("resno1", ctypes.c_int),
("compno1", ctypes.c_int),
# Layer num start,Precinct num start, Precinct num end
("layno0", ctypes.c_int),
("precno0", ctypes.c_int),
("precno1", ctypes.c_int),
# Layer num start,Precinct num start, Precinct num end
("layno0", ctypes.c_int),
("precno0", ctypes.c_int),
("precno1", ctypes.c_int),
# Progression order enum
# OPJ_PROG_ORDER prg1,prg;
("prg1", ctypes.c_int),
("prg", ctypes.c_int),
# Progression order enum
# OPJ_PROG_ORDER prg1,prg;
("prg1", ctypes.c_int),
("prg", ctypes.c_int),
# Progression order string
# char progorder[5];
("progorder", ctypes.c_char * 5),
# Progression order string
# char progorder[5];
("progorder", ctypes.c_char * 5),
# Tile number
# int tile;
("tile", ctypes.c_int),
# Tile number
# int tile;
("tile", ctypes.c_int),
# /** Start and end values for Tile width and height*/
# int tx0,tx1,ty0,ty1;
("tx0", ctypes.c_int),
("tx1", ctypes.c_int),
("ty0", ctypes.c_int),
("ty1", ctypes.c_int),
# /** Start value, initialised in pi_initialise_encode*/
# int layS, resS, compS, prcS;
("layS", ctypes.c_int),
("resS", ctypes.c_int),
("compS", ctypes.c_int),
("prcS", ctypes.c_int),
# /** End value, initialised in pi_initialise_encode */
# int layE, resE, compE, prcE;
("layE", ctypes.c_int),
("resE", ctypes.c_int),
("compE", ctypes.c_int),
("prcE", ctypes.c_int),
# Start and end values of Tile width and height, initialised in
# pi_initialise_encode int txS,txE,tyS,tyE,dx,dy;
("txS", ctypes.c_int),
("txE", ctypes.c_int),
("tyS", ctypes.c_int),
("tyE", ctypes.c_int),
("dx", ctypes.c_int),
("dy", ctypes.c_int),
# Temporary values for Tile parts, initialised in pi_create_encode
# int lay_t, res_t, comp_t, prc_t,tx0_t,ty0_t;
("lay_t", ctypes.c_int),
("res_t", ctypes.c_int),
("comp_t", ctypes.c_int),
("prc_t", ctypes.c_int),
("tx0_t", ctypes.c_int),
("ty0_t", ctypes.c_int)]
("tx0", ctypes.c_int),
("tx1", ctypes.c_int),
("ty0", ctypes.c_int),
("ty1", ctypes.c_int),
("layS", ctypes.c_int),
("resS", ctypes.c_int),
("compS", ctypes.c_int),
("prcS", ctypes.c_int),
("layE", ctypes.c_int),
("resE", ctypes.c_int),
("compE", ctypes.c_int),
("prcE", ctypes.c_int),
("txS", ctypes.c_int),
("txE", ctypes.c_int),
("tyS", ctypes.c_int),
("tyE", ctypes.c_int),
("dx", ctypes.c_int),
("dy", ctypes.c_int),
("lay_t", ctypes.c_int),
("res_t", ctypes.c_int),
("comp_t", ctypes.c_int),
("prc_t", ctypes.c_int),
("tx0_t", ctypes.c_int),
("ty0_t", ctypes.c_int)]
class CompressionParametersType(ctypes.Structure):
@ -374,48 +360,47 @@ class DecompressionParametersType(ctypes.Structure):
class ImageComptParmType(ctypes.Structure):
"""Component parameters structure used by the opj_image_create function.
"""
_fields_ = [
# XRsiz: horizontal separation of a sample of ith component with
# respect to the reference grid
("dx", ctypes.c_int),
_fields_ = [("dx", ctypes.c_int),
# XRsiz: horizontal separation of a sample of ith component
# with respect to the reference grid
# YRsiz: vertical separation of a sample of ith component with
# respect to the reference grid */
("dy", ctypes.c_int),
# data width, height
("w", ctypes.c_int),
("h", ctypes.c_int),
# YRsiz: vertical separation of a sample of ith component with
# respect to the reference grid */
("dy", ctypes.c_int),
# x component offset compared to the whole image
# y component offset compared to the whole image
("x0", ctypes.c_int),
("y0", ctypes.c_int),
# data width, height
("w", ctypes.c_int),
("h", ctypes.c_int),
# precision
('prec', ctypes.c_int),
# x component offset compared to the whole image
# y component offset compared to the whole image
("x0", ctypes.c_int),
("y0", ctypes.c_int),
# image depth in bits
('bpp', ctypes.c_int),
# precision
('prec', ctypes.c_int),
# signed (1) / unsigned (0)
('sgnd', ctypes.c_int)]
# image depth in bits
('bpp', ctypes.c_int),
# signed (1) / unsigned (0)
('sgnd', ctypes.c_int)]
class ImageCompType(ctypes.Structure):
"""Defines a single image component. """
_fields_ = [("dx", ctypes.c_int),
("dy", ctypes.c_int),
("w", ctypes.c_int),
("h", ctypes.c_int),
("x0", ctypes.c_int),
("y0", ctypes.c_int),
("prec", ctypes.c_int),
("bpp", ctypes.c_int),
("sgnd", ctypes.c_int),
("resno_decoded", ctypes.c_int),
("factor", ctypes.c_int),
("data", ctypes.POINTER(ctypes.c_int))]
("dy", ctypes.c_int),
("w", ctypes.c_int),
("h", ctypes.c_int),
("x0", ctypes.c_int),
("y0", ctypes.c_int),
("prec", ctypes.c_int),
("bpp", ctypes.c_int),
("sgnd", ctypes.c_int),
("resno_decoded", ctypes.c_int),
("factor", ctypes.c_int),
("data", ctypes.POINTER(ctypes.c_int))]
class ImageType(ctypes.Structure):
@ -467,6 +452,7 @@ def cio_tell(cio):
pos = OPENJPEG.cio_tell(cio)
return pos
def create_compress(fmt):
"""Wrapper for openjpeg library function opj_create_compress.
@ -511,7 +497,7 @@ def destroy_compress(cinfo):
def encode(cinfo, cio, image):
"""Wrapper for openjpeg library function opj_encode.
Encodes an image into a JPEG-2000 codestream.
Encodes an image into a JPEG-2000 codestream.
Parameters
----------
@ -537,56 +523,11 @@ def destroy_decompress(dinfo):
OPENJPEG.opj_destroy_decompress(dinfo)
def image_cmptparm_t_from_np(np_image):
"""Return appropriate image_cmptparm_t based on given numpy array.
"""
try:
num_comps = np_image.shape[2]
except IndexError:
num_comps = 1
cmpt_parm_array_t = ImageCmptparmType * num_comps
tarr = cmpt_parm_array_t()
if np_image.dtype == np.uint8:
prec = 8
bpp = 8
sgnd = 0
elif np_image.dtype == np.int8:
prec = 8
bpp = 8
sgnd = 1
elif np_image.dtype == np.uint16:
prec = 16
bpp = 16
sgnd = 0
elif np_image.dtype == np.int16:
prec = 16
bpp = 16
sgnd = 1
else:
raise(TypeError("unhandled"))
for j in range(0, num_comps):
tarr[j].dx = 1
tarr[j].dy = 1
tarr[j].w = np_image.shape[1]
tarr[j].h = np_image.shape[0]
tarr[j].x0 = 0
tarr[j].y0 = 0
tarr[j].prec = prec
tarr[j].bpp = bpp
tarr[j].sgnd = sgnd
return(tarr)
def image_create(cmptparms, cspace):
"""Wrapper for openjpeg library function opj_image_create.
"""
OPENJPEG.opj_image_create.argtypes = [ctypes.c_int,
ctypes.POINTER(ImageComptParmType),
ctypes.c_int]
lst = [ctypes.c_int, ctypes.POINTER(ImageComptParmType), ctypes.c_int]
OPENJPEG.opj_image_create.argtypes = lst
OPENJPEG.opj_image_create.restype = ctypes.POINTER(ImageType)
image = OPENJPEG.opj_image_create(len(cmptparms), cmptparms, cspace)

144
glymur/lib/test/fixtures.py Normal file
View file

@ -0,0 +1,144 @@
decompression_parameters_type = """<class 'glymur.lib.openjp2.DecompressionParametersType'>:
cp_reduce: 0
cp_layer: 0
infile: b''
outfile: b''
decod_format: -1
cod_format: -1
DA_x0: 0
DA_x1: 0
DA_y0: 0
DA_y1: 0
m_verbose: 0
tile_index: 0
nb_tile_to_decode: 0
jpwl_correct: 0
jpwl_exp_comps: 0
jpwl_max_tiles: 0
flags: 0"""
default_progression_order_changes_type = """<class 'glymur.lib.openjp2.PocType'>:
resno0: 0
compno0: 0
layno1: 0
resno1: 0
compno1: 0
layno0: 0
precno0: 0
precno1: 0
prg1: 0
prg: 0
progorder: b''
tile: 0
tx0: 0
tx1: 0
ty0: 0
ty1: 0
layS: 0
resS: 0
compS: 0
prcS: 0
layE: 0
resE: 0
compE: 0
prcE: 0
txS: 0
txE: 0
tyS: 0
tyE: 0
dx: 0
dy: 0
lay_t: 0
res_t: 0
comp_t: 0
prec_t: 0
tx0_t: 0
ty0_t: 0"""
default_compression_parameters_type = """<class 'glymur.lib.openjp2.CompressionParametersType'>:
tile_size_on: 0
cp_tx0: 0
cp_ty0: 0
cp_tdx: 0
cp_tdy: 0
cp_disto_alloc: 0
cp_fixed_alloc: 0
cp_fixed_quality: 0
cp_matrice: None
cp_comment: None
csty: 0
prog_order: 0
numpocs: 0
numpocs: 0
tcp_numlayers: 0
tcp_rates: []
tcp_distoratio: []
numresolution: 6
cblockw_init: 64
cblockh_init: 64
mode: 0
irreversible: 0
roi_compno: -1
roi_shift: 0
res_spec: 0
prch_init: []
prcw_init: []
infile: b''
outfile: b''
index_on: 0
index: b''
image_offset_x0: 0
image_offset_y0: 0
subsampling_dx: 1
subsampling_dy: 1
decod_format: -1
cod_format: -1
jpwl_epc_on: 0
jpwl_hprot_mh: 0
jpwl_hprot_tph_tileno: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_hprot_tph: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_pprot_tileno: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_pprot_packno: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_pprot: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_sens_size: 0
jpwl_sens_addr: 0
jpwl_sens_range: 0
jpwl_sens_mh: 0
jpwl_sens_tph_tileno: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_sens_tph: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
cp_cinema: 0
max_comp_size: 0
cp_rsiz: 0
tp_on: 0
tp_flag: 0
tcp_mct: 0
jpip_on: 0
mct_data: None
max_cs_size: 0
rsiz: 0"""
default_image_component_parameters = """<class 'glymur.lib.openjp2.ImageComptParmType'>:
dx: 0
dy: 0
w: 0
h: 0
x0: 0
y0: 0
prec: 0
bpp: 0
sgnd: 0"""
# The "icc_profile_buf" field is problematic as it is a pointer value, i.e.
#
# icc_profile_buf: <glymur.lib.openjp2.LP_c_ubyte object at 0x7f28cd5d5d90>
#
# Have to treat it as a regular expression.
default_image_type = """<class 'glymur.lib.openjp2.ImageType'>:
x0: 0
y0: 0
x1: 0
y1: 0
numcomps: 0
color_space: 0
icc_profile_buf: <glymur.lib.openjp2.LP_c_ubyte object at 0x[0-9A-Fa-f]*>
icc_profile_len: 0"""

View file

@ -1,37 +1,23 @@
"""
Tests for libopenjp2 wrapping functions.
Tests for libopenjp2 wrapping functions.
"""
# R0904: Seems like pylint is fooled in this situation
# W0142: using kwargs is ok in this context
# pylint: disable=R0904,W0142
# unittest2 is python-2.6 only (pylint/python-2.7)
# pylint: disable=F0401
import os
import re
import sys
import tempfile
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import unittest
import numpy as np
import glymur
from glymur.lib import openjp2
if re.match("2.0", glymur.version.openjpeg_version):
OPENJP2_IS_V2_OFFICIAL = True
else:
OPENJP2_IS_V2_OFFICIAL = False
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@unittest.skipIf(openjp2.OPENJP2 is None,
"Missing openjp2 library.")
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL, "API followed here specific to V2.1")
@unittest.skipIf(re.match(r'''(1|2.0)''',
glymur.version.openjpeg_version) is not None,
"Not to be run until 2.1.0")
class TestOpenJP2(unittest.TestCase):
"""Test openjp2 library functionality.
@ -65,53 +51,6 @@ class TestOpenJP2(unittest.TestCase):
self.assertEqual(dparams.DA_x1, 0)
self.assertEqual(dparams.DA_y1, 0)
def tile_macro(self, codec, stream, imagep, tidx):
"""called only by j2k_random_tile_access"""
openjp2.get_decoded_tile(codec, stream, imagep, tidx)
for j in range(imagep.contents.numcomps):
self.assertIsNotNone(imagep.contents.comps[j].data)
def j2k_random_tile_access(self, filename, codec_format=None):
"""fixture called by the test_rtaX methods"""
dparam = openjp2.set_default_decoder_parameters()
infile = filename.encode()
nelts = openjp2.PATH_LEN - len(infile)
infile += b'0' * nelts
dparam.infile = infile
dparam.decod_format = codec_format
codec = openjp2.create_decompress(codec_format)
openjp2.set_info_handler(codec, None)
openjp2.set_warning_handler(codec, None)
openjp2.set_error_handler(codec, None)
stream = openjp2.stream_create_default_file_stream(filename, True)
openjp2.setup_decoder(codec, dparam)
image = openjp2.read_header(stream, codec)
cstr_info = openjp2.get_cstr_info(codec)
tile_ul = 0
tile_ur = cstr_info.contents.tw - 1
tile_lr = cstr_info.contents.tw * cstr_info.contents.th - 1
tile_ll = tile_lr - cstr_info.contents.tw
self.tile_macro(codec, stream, image, tile_ul)
self.tile_macro(codec, stream, image, tile_ur)
self.tile_macro(codec, stream, image, tile_lr)
self.tile_macro(codec, stream, image, tile_ll)
openjp2.destroy_cstr_info(cstr_info)
openjp2.end_decompress(codec, stream)
openjp2.destroy_codec(codec)
openjp2.stream_destroy(stream)
openjp2.image_destroy(image)
def test_tte0(self):
"""Runs test designated tte0 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
@ -169,15 +108,6 @@ class TestOpenJP2(unittest.TestCase):
tile_decoder(**kwargs)
self.assertTrue(True)
def test_rta1(self):
"""Runs test designated rta1 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
self.xtx1_setup(tfile.name)
codec_format = openjp2.CODEC_J2K
self.j2k_random_tile_access(tfile.name, codec_format)
self.assertTrue(True)
def test_tte2(self):
"""Runs test designated tte2 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
@ -199,62 +129,25 @@ class TestOpenJP2(unittest.TestCase):
tile_decoder(**kwargs)
self.assertTrue(True)
def test_rta2(self):
"""Runs test designated rta2 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
xtx2_setup(tfile.name)
codec_format = openjp2.CODEC_JP2
self.j2k_random_tile_access(tfile.name, codec_format)
def test_tte3(self):
"""Runs test designated tte3 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx3_setup(tfile.name)
self.assertTrue(True)
def test_rta3(self):
"""Runs test designated rta3 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx3_setup(tfile.name)
codec_format = openjp2.CODEC_J2K
self.j2k_random_tile_access(tfile.name, codec_format)
self.assertTrue(True)
self.assertTrue(True)
def test_tte4(self):
"""Runs test designated tte4 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx4_setup(tfile.name)
self.assertTrue(True)
def test_rta4(self):
"""Runs test designated rta4 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx4_setup(tfile.name)
codec_format = openjp2.CODEC_J2K
self.j2k_random_tile_access(tfile.name, codec_format)
self.assertTrue(True)
def test_tte5(self):
"""Runs test designated tte5 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx5_setup(tfile.name)
self.assertTrue(True)
def test_rta5(self):
"""Runs test designated rta5 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx5_setup(tfile.name)
codec_format = openjp2.CODEC_J2K
self.j2k_random_tile_access(tfile.name, codec_format)
self.assertTrue(True)
#def tile_encoder(num_comps=None, tile_width=None, tile_height=None,
# filename=None, codec=None, comp_prec=None,
# image_width=None, image_height=None,
# irreversible=None):
def tile_encoder(**kwargs):
"""Fixture used by many tests."""
num_tiles = ((kwargs['image_width'] / kwargs['tile_width']) *
@ -329,10 +222,11 @@ def tile_encoder(**kwargs):
openjp2.destroy_codec(codec)
openjp2.image_destroy(l_image)
def tile_decoder(**kwargs):
"""Fixture called with various configurations by many tests.
Reads a tile. That's all it does.
Reads a tile. That's all it does.
"""
stream = openjp2.stream_create_default_file_stream(kwargs['filename'],
True)
@ -354,7 +248,7 @@ def tile_decoder(**kwargs):
openjp2.setup_decoder(codec, dparam)
image = openjp2.read_header(stream, codec)
openjp2.set_decode_area(codec, image,
openjp2.set_decode_area(codec, image,
kwargs['x0'], kwargs['y0'],
kwargs['x1'], kwargs['y1'])
@ -373,6 +267,7 @@ def tile_decoder(**kwargs):
openjp2.stream_destroy(stream)
openjp2.image_destroy(image)
def ttx0_setup(filename):
"""Runs tests tte0, tte0."""
kwargs = {'filename': filename,
@ -386,6 +281,7 @@ def ttx0_setup(filename):
'tile_width': 100}
tile_encoder(**kwargs)
def xtx2_setup(filename):
"""Runs tests rta2, tte2, ttd2."""
kwargs = {'filename': filename,
@ -399,6 +295,7 @@ def xtx2_setup(filename):
'tile_width': 128}
tile_encoder(**kwargs)
def xtx3_setup(filename):
"""Runs tests tte3, rta3."""
kwargs = {'filename': filename,
@ -412,6 +309,7 @@ def xtx3_setup(filename):
'tile_width': 128}
tile_encoder(**kwargs)
def xtx4_setup(filename):
"""Runs tests rta4, tte4."""
kwargs = {'filename': filename,
@ -425,6 +323,7 @@ def xtx4_setup(filename):
'tile_width': 128}
tile_encoder(**kwargs)
def xtx5_setup(filename):
"""Runs tests rta5, tte5."""
kwargs = {'filename': filename,
@ -437,6 +336,3 @@ def xtx5_setup(filename):
'tile_height': 256,
'tile_width': 256}
tile_encoder(**kwargs)
if __name__ == "__main__":
unittest.main()

View file

@ -1,22 +1,14 @@
"""
Tests for OpenJPEG module.
"""
# unittest2 is python2.6 only (pylint/python-2.7)
# pylint: disable=F0401
# pylint: disable=E1101,R0904
import ctypes
import re
import sys
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import unittest
import glymur
@unittest.skipIf(glymur.lib.openjpeg.OPENJPEG is None,
"Missing openjpeg library.")
class TestOpenJPEG(unittest.TestCase):

View file

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
"""Test suite for printing.
"""
import re
import sys
import unittest
if sys.hexversion < 0x03000000:
from mock import patch
from StringIO import StringIO
else:
from unittest.mock import patch
from io import StringIO
import glymur
from . import fixtures
@unittest.skipIf(sys.hexversion < 0x03000000, "do not care about 2.7 here")
@unittest.skipIf(re.match('0|1|2.0', glymur.version.openjpeg_version),
"Requires openjpeg 2.1.0 or higher")
class TestPrintingOpenjp2(unittest.TestCase):
"""Tests for verifying how printing works on openjp2 library structures."""
def setUp(self):
self.jp2file = glymur.data.nemo()
def tearDown(self):
pass
def test_decompression_parameters(self):
"""printing DecompressionParametersType"""
dparams = glymur.lib.openjp2.set_default_decoder_parameters()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(dparams)
actual = fake_out.getvalue().strip()
expected = fixtures.decompression_parameters_type
self.assertEqual(actual, expected)
def test_progression_order_changes(self):
"""printing PocType"""
ptype = glymur.lib.openjp2.PocType()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(ptype)
actual = fake_out.getvalue().strip()
expected = fixtures.default_progression_order_changes_type
self.assertEqual(actual, expected)
def test_default_compression_parameters(self):
"""printing default compression parameters"""
cparams = glymur.lib.openjp2.set_default_encoder_parameters()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(cparams)
actual = fake_out.getvalue().strip()
expected = fixtures.default_compression_parameters_type
self.assertEqual(actual, expected)
def test_default_component_parameters(self):
"""printing default image component parameters"""
icpt = glymur.lib.openjp2.ImageComptParmType()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(icpt)
actual = fake_out.getvalue().strip()
expected = fixtures.default_image_component_parameters
self.assertEqual(actual, expected)
def test_default_image_type(self):
"""printing default image type"""
it = glymur.lib.openjp2.ImageType()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(it)
actual = fake_out.getvalue().strip()
expected = fixtures.default_image_type
self.assertRegex(actual, expected)

View file

@ -4,20 +4,171 @@ Test fixtures common to more than one test point.
import os
import re
import sys
import textwrap
import unittest
import warnings
import numpy as np
import six
import glymur
# If openjpeg is not installed, many tests cannot be run.
if glymur.version.openjpeg_version == '0.0.0':
OPENJPEG_NOT_AVAILABLE = True
OPENJPEG_NOT_AVAILABLE_MSG = 'OpenJPEG library not installed'
else:
OPENJPEG_NOT_AVAILABLE = False
OPENJPEG_NOT_AVAILABLE_MSG = None
# Need to know of the libopenjp2 version is the official 2.0.0 release and NOT
# the 2.0+ development version.
OPENJP2_IS_V2_OFFICIAL = False
if glymur.lib.openjp2.OPENJP2 is not None:
if not hasattr(glymur.lib.openjp2.OPENJP2,
'opj_stream_create_default_file_stream_v3'):
OPENJP2_IS_V2_OFFICIAL = True
# Some versions of "six" on python3 cause problems when verifying warnings.
# Only use when the version is 1.7 or higher.
# And moreover, we only test using the 3.x infrastructure, never on 2.x.
WARNING_INFRASTRUCTURE_ISSUE = False
WARNING_INFRASTRUCTURE_MSG = ""
if sys.hexversion < 0x03000000:
WARNING_INFRASTRUCTURE_ISSUE = True
WARNING_INFRASTRUCTURE_MSG = "3.x warning infrastructure only"
elif re.match('1.[0-6]', six.__version__) is not None:
WARNING_INFRASTRUCTURE_ISSUE = True
msg = "Cannot run test with version {0} of python-six"
WARNING_INFRASTRUCTURE_MSG = msg.format(six.__version__)
# Cannot reopen a named temporary file in windows.
WINDOWS_TMP_FILE_MSG = "cannot use NamedTemporaryFile like this in windows"
class MetadataBase(unittest.TestCase):
"""
Base class for testing metadata.
This class has helper routines defined for testing metadata so that it can
be subclassed and used easily.
"""
def setUp(self):
pass
def tearDown(self):
pass
def verify_codeblock_style(self, actual, style):
"""
Verify the code-block style for SPcod and SPcoc parameters.
This information is stored in a single byte. Please reference
Table A-17 in FCD15444-1
"""
expected = 0
if style[0]:
# Selective arithmetic coding bypass
expected |= 0x01
if style[1]:
# Reset context probabilities
expected |= 0x02
if style[2]:
# Termination on each coding pass
expected |= 0x04
if style[3]:
# Vertically causal context
expected |= 0x08
if style[4]:
# Predictable termination
expected |= 0x10
if style[5]:
# Segmentation symbols
expected |= 0x20
self.assertEqual(actual, expected)
def verifySignatureBox(self, box):
"""
The signature box is a constant.
"""
self.assertEqual(box.signature, (13, 10, 135, 10))
def verify_filetype_box(self, actual, expected):
"""
All JP2 files should have a brand reading 'jp2 ' and just a single
entry in the compatibility list, also 'jp2 '. JPX files can have more
compatibility items.
"""
self.assertEqual(actual.brand, expected.brand)
self.assertEqual(actual.minor_version, expected.minor_version)
self.assertEqual(actual.minor_version, 0)
for cl in expected.compatibility_list:
self.assertIn(cl, actual.compatibility_list)
def verifyRGNsegment(self, actual, expected):
"""
verify the fields of a RGN segment
"""
self.assertEqual(actual.crgn, expected.crgn) # 0 = component
self.assertEqual(actual.srgn, expected.srgn) # 0 = implicit
self.assertEqual(actual.sprgn, expected.sprgn)
def verifySOTsegment(self, actual, expected):
"""
verify the fields of a SOT (start of tile) segment
"""
self.assertEqual(actual.isot, expected.isot)
self.assertEqual(actual.psot, expected.psot)
self.assertEqual(actual.tpsot, expected.tpsot)
self.assertEqual(actual.tnsot, expected.tnsot)
def verifyCMEsegment(self, actual, expected):
"""
verify the fields of a CME (comment) segment
"""
self.assertEqual(actual.rcme, expected.rcme)
self.assertEqual(actual.ccme, expected.ccme)
def verifySizSegment(self, actual, expected):
"""
Verify the fields of the SIZ segment.
"""
for field in ['rsiz', 'xsiz', 'ysiz', 'xosiz', 'yosiz', 'xtsiz',
'ytsiz', 'xtosiz', 'ytosiz', 'bitdepth',
'xrsiz', 'yrsiz']:
self.assertEqual(getattr(actual, field), getattr(expected, field))
def verifyImageHeaderBox(self, box1, box2):
self.assertEqual(box1.height, box2.height)
self.assertEqual(box1.width, box2.width)
self.assertEqual(box1.num_components, box2.num_components)
self.assertEqual(box1.bits_per_component, box2.bits_per_component)
self.assertEqual(box1.signed, box2.signed)
self.assertEqual(box1.compression, box2.compression)
self.assertEqual(box1.colorspace_unknown, box2.colorspace_unknown)
self.assertEqual(box1.ip_provided, box2.ip_provided)
def verifyColourSpecificationBox(self, actual, expected):
"""
Does not currently check icc profiles.
"""
self.assertEqual(actual.method, expected.method)
self.assertEqual(actual.precedence, expected.precedence)
self.assertEqual(actual.approximation, expected.approximation)
if expected.colorspace is None:
self.assertIsNone(actual.colorspace)
self.assertIsNotNone(actual.icc_profile)
else:
self.assertEqual(actual.colorspace, expected.colorspace)
self.assertIsNone(actual.icc_profile)
# The Python XMP Toolkit may be used for XMP UUIDs, but only if available and
# if the version is at least 2.0.0.
try:
import libxmp
if hasattr(libxmp, 'version') and re.match(r'''[2-9].\d*.\d*''',
libxmp.version.VERSION):
from libxmp import XMPMeta
HAS_PYTHON_XMP_TOOLKIT = True
else:
HAS_PYTHON_XMP_TOOLKIT = False
except:
HAS_PYTHON_XMP_TOOLKIT = False
NO_READ_BACKEND_MSG = "Matplotlib with the PIL backend must be available in "
@ -31,6 +182,50 @@ except:
raise
# The Cinema2K/4K tests seem to need the freeimage backend to skimage.io
# in order to work. Unfortunately, scikit-image/freeimage is about as wonky as
# it gets. Anaconda can get totally weirded out on versions up through 3.6.4
# on Python3 with scikit-image up through version 0.10.0.
NO_SKIMAGE_FREEIMAGE_SUPPORT = False
try:
import skimage
import skimage.io
if (((sys.hexversion >= 0x03000000) and
('Anaconda' in sys.version) and
(re.match('0.10', skimage.__version__)))):
NO_SKIMAGE_FREEIMAGE_SUPPORT = True
else:
skimage.io.use_plugin('freeimage', 'imread')
except ((ImportError, RuntimeError)):
NO_SKIMAGE_FREEIMAGE_SUPPORT = True
def _indent(textstr):
"""
Indent a string.
Textwrap's indent method only exists for 3.3 or above. In 2.7 we have
to fake it.
Parameters
----------
textstring : str
String to be indented.
indent_level : str
Number of spaces of indentation to add.
Returns
-------
indented_string : str
Possibly multi-line string indented a certain bit.
"""
if sys.hexversion >= 0x03030000:
return textwrap.indent(textstr, ' ')
else:
lst = [(' ' + x) for x in textstr.split('\n')]
return '\n'.join(lst)
def opj_data_file(relative_file_name):
"""Compact way of forming a full filename from OpenJPEG's test suite."""
jfile = os.path.join(OPJ_DATA_ROOT, relative_file_name)
@ -41,7 +236,6 @@ try:
# The whole point of trying to import PIL is to determine if it's there
# or not. We won't use it directly.
# pylint: disable=F0401,W0611
import PIL
NO_READ_BACKEND = False
@ -168,6 +362,117 @@ def read_pgx_header(pgx_file):
header = header.rstrip()
return header, pos
nemo_xmp = """<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<ns0:xmpmeta xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:ns3="http://ns.adobe.com/tiff/1.0/" xmlns:ns4="http://ns.adobe.com/exif/1.0/" xmlns:ns5="http://ns.adobe.com/photoshop/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="Exempi + XMP Core 5.1.2">
<rdf:RDF>
<rdf:Description rdf:about="">
<ns2:CreatorTool>Google</ns2:CreatorTool>
<ns2:CreateDate>2013-02-09T14:47:53</ns2:CreateDate>
</rdf:Description>
<rdf:Description rdf:about="">
<ns3:YCbCrPositioning>1</ns3:YCbCrPositioning>
<ns3:XResolution>72/1</ns3:XResolution>
<ns3:YResolution>72/1</ns3:YResolution>
<ns3:ResolutionUnit>2</ns3:ResolutionUnit>
<ns3:Make>HTC</ns3:Make>
<ns3:Model>HTC Glacier</ns3:Model>
<ns3:ImageWidth>2592</ns3:ImageWidth>
<ns3:ImageLength>1456</ns3:ImageLength>
<ns3:BitsPerSample>
<rdf:Seq>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
</rdf:Seq>
</ns3:BitsPerSample>
<ns3:PhotometricInterpretation>2</ns3:PhotometricInterpretation>
<ns3:SamplesPerPixel>3</ns3:SamplesPerPixel>
<ns3:WhitePoint>
<rdf:Seq>
<rdf:li>1343036288/4294967295</rdf:li>
<rdf:li>1413044224/4294967295</rdf:li>
</rdf:Seq>
</ns3:WhitePoint>
<ns3:PrimaryChromaticities>
<rdf:Seq>
<rdf:li>2748779008/4294967295</rdf:li>
<rdf:li>1417339264/4294967295</rdf:li>
<rdf:li>1288490240/4294967295</rdf:li>
<rdf:li>2576980480/4294967295</rdf:li>
<rdf:li>644245120/4294967295</rdf:li>
<rdf:li>257698032/4294967295</rdf:li>
</rdf:Seq>
</ns3:PrimaryChromaticities>
</rdf:Description>
<rdf:Description rdf:about="">
<ns4:ColorSpace>1</ns4:ColorSpace>
<ns4:PixelXDimension>2528</ns4:PixelXDimension>
<ns4:PixelYDimension>1424</ns4:PixelYDimension>
<ns4:FocalLength>353/100</ns4:FocalLength>
<ns4:GPSAltitudeRef>0</ns4:GPSAltitudeRef>
<ns4:GPSAltitude>0/1</ns4:GPSAltitude>
<ns4:GPSMapDatum>WGS-84</ns4:GPSMapDatum>
<ns4:DateTimeOriginal>2013-02-09T14:47:53</ns4:DateTimeOriginal>
<ns4:ISOSpeedRatings>
<rdf:Seq>
<rdf:li>76</rdf:li>
</rdf:Seq>
</ns4:ISOSpeedRatings>
<ns4:ExifVersion>0220</ns4:ExifVersion>
<ns4:FlashpixVersion>0100</ns4:FlashpixVersion>
<ns4:ComponentsConfiguration>
<rdf:Seq>
<rdf:li>1</rdf:li>
<rdf:li>2</rdf:li>
<rdf:li>3</rdf:li>
<rdf:li>0</rdf:li>
</rdf:Seq>
</ns4:ComponentsConfiguration>
<ns4:GPSLatitude>42,20.56N</ns4:GPSLatitude>
<ns4:GPSLongitude>71,5.29W</ns4:GPSLongitude>
<ns4:GPSTimeStamp>2013-02-09T19:47:53Z</ns4:GPSTimeStamp>
<ns4:GPSProcessingMethod>NETWORK</ns4:GPSProcessingMethod>
</rdf:Description>
<rdf:Description rdf:about="">
<ns5:DateCreated>2013-02-09T14:47:53</ns5:DateCreated>
</rdf:Description>
<rdf:Description rdf:about="">
<dc:Creator>
<rdf:Seq>
<rdf:li>Glymur</rdf:li>
<rdf:li>Python XMP Toolkit</rdf:li>
</rdf:Seq>
</dc:Creator>
</rdf:Description>
</rdf:RDF>
</ns0:xmpmeta>
<?xpacket end="w"?>"""
nemo_xmp_box = """UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
{0}""".format(_indent(nemo_xmp))
nemo_xmp_box = """UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
{0}""".format(_indent(nemo_xmp))
SimpleRDF = """<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<rdf:Description rdf:about='Test:XMPCoreCoverage/kSimpleRDF'
xmlns:ns1='ns:test1/' xmlns:ns2='ns:test2/'>
<ns1:SimpleProp>Simple value</ns1:SimpleProp>
<ns1:Distros>
<rdf:Bag>
<rdf:li>Suse</rdf:li>
<rdf:li>Fedora</rdf:li>
</rdf:Bag>
</ns1:Distros>
</rdf:Description>
</rdf:RDF>"""
text_gbr_27 = """Colour Specification Box (colr) @ (179, 1339)
Method: any ICC profile
Precedence: 2
@ -237,10 +542,10 @@ text_gbr_34 = """Colour Specification Box (colr) @ (179, 1339)
# Metadata dump of nemo.
nemo_dump_full_opj2 = r'''JPEG 2000 Signature Box (jP ) @ (0, 12)
dump = r'''JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
@ -253,68 +558,15 @@ JP2 Header Box (jp2h) @ (32, 45)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 638)
UUID: 4a706754-6966-6645-7869-662d3e4a5032 (Exif)
UUID Data:
{'Image': {'Make': 'HTC',
'Model': 'HTC Glacier',
'XResolution': 72.0,
'YResolution': 72.0,
'ResolutionUnit': 2,
'YCbCrPositioning': 1,
'ExifTag': 138,
'GPSTag': 354},
'Photo': {'ISOSpeedRatings': 76,
'ExifVersion': (48, 50, 50, 48),
'DateTimeOriginal': '2013:02:09 14:47:53',
'DateTimeDigitized': '2013:02:09 14:47:53',
'ComponentsConfiguration': (1, 2, 3, 0),
'FocalLength': 3.53,
'FlashpixVersion': (48, 49, 48, 48),
'ColorSpace': 1,
'PixelXDimension': 2528,
'PixelYDimension': 1424,
'InteroperabilityTag': 324},
'GPSInfo': {'GPSVersionID': (2, 2, 0),
'GPSLatitudeRef': 'N',
'GPSLatitude': [42.0, 20.0, 33.61],
'GPSLongitudeRef': 'W',
'GPSLongitude': [71.0, 5.0, 17.32],
'GPSAltitudeRef': 0,
'GPSAltitude': 0.0,
'GPSTimeStamp': [19.0, 47.0, 53.0],
'GPSMapDatum': 'WGS-84',
'GPSProcessingMethod': (65,
83,
67,
73,
73,
0,
0,
0,
78,
69,
84,
87,
79,
82,
75),
'GPSDateStamp': '2013:02:09'},
'Iop': None}
UUID Box (uuid) @ (715, 2412)
UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
<ns0:xmpmeta xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="XMP Core 4.4.0-Exiv2">
<rdf:RDF>
<rdf:Description ns2:CreatorTool="glymur" rdf:about="" />
</rdf:RDF>
</ns0:xmpmeta>
Contiguous Codestream Box (jp2c) @ (3127, 1132296)
UUID Data:
{0}
Contiguous Codestream Box (jp2c) @ (3223, 1132296)
Main header:
SOC marker segment @ (3135, 0)
SIZ marker segment @ (3137, 47)
Profile: 2
SOC marker segment @ (3231, 0)
SIZ marker segment @ (3233, 47)
Profile: no profile
Reference Grid Height, Width: (1456 x 2592)
Vertical, Horizontal Reference Grid Offset: (0 x 0)
Reference Tile Height, Width: (1456 x 2592)
@ -322,7 +574,7 @@ Contiguous Codestream Box (jp2c) @ (3127, 1132296)
Bitdepth: (8, 8, 8)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
COD marker segment @ (3186, 12)
COD marker segment @ (3282, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
@ -342,15 +594,26 @@ Contiguous Codestream Box (jp2c) @ (3127, 1132296)
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCD marker segment @ (3200, 7)
QCD marker segment @ (3296, 7)
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
CME marker segment @ (3209, 37)
CME marker segment @ (3305, 37)
"Created by OpenJPEG version 2.0.0"'''
nemo_dump_full_p27 = r'''JPEG 2000 Signature Box (jP ) @ (0, 12)
nemo_with_codestream_header = dump.format(_indent(nemo_xmp))
nemo_dump_short = r"""JPEG 2000 Signature Box (jP ) @ (0, 12)
File Type Box (ftyp) @ (12, 20)
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Colour Specification Box (colr) @ (62, 15)
UUID Box (uuid) @ (77, 3146)
Contiguous Codestream Box (jp2c) @ (3223, 1132296)"""
nemo_dump_no_xml = '''JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
@ -363,27 +626,13 @@ JP2 Header Box (jp2h) @ (32, 45)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 638)
UUID: 4a706754-6966-6645-7869-662d3e4a5032 (Exif)
UUID Data:
{'GPSInfo': OrderedDict([('GPSVersionID', (2, 2, 0)), ('GPSLatitudeRef', 'N'), ('GPSLatitude', [42.0, 20.0, 33.61]), ('GPSLongitudeRef', 'W'), ('GPSLongitude', [71.0, 5.0, 17.32]), ('GPSAltitudeRef', 0), ('GPSAltitude', 0.0), ('GPSTimeStamp', [19.0, 47.0, 53.0]), ('GPSMapDatum', 'WGS-84'), ('GPSProcessingMethod', (65, 83, 67, 73, 73, 0, 0, 0, 78, 69, 84, 87, 79, 82, 75)), ('GPSDateStamp', '2013:02:09')]),
'Image': OrderedDict([('Make', 'HTC'), ('Model', 'HTC Glacier'), ('XResolution', 72.0), ('YResolution', 72.0), ('ResolutionUnit', 2), ('YCbCrPositioning', 1), ('ExifTag', 138), ('GPSTag', 354)]),
'Iop': None,
'Photo': OrderedDict([('ISOSpeedRatings', 76), ('ExifVersion', (48, 50, 50, 48)), ('DateTimeOriginal', '2013:02:09 14:47:53'), ('DateTimeDigitized', '2013:02:09 14:47:53'), ('ComponentsConfiguration', (1, 2, 3, 0)), ('FocalLength', 3.53), ('FlashpixVersion', (48, 49, 48, 48)), ('ColorSpace', 1), ('PixelXDimension', 2528), ('PixelYDimension', 1424), ('InteroperabilityTag', 324)])}
UUID Box (uuid) @ (715, 2412)
UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
<ns0:xmpmeta xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="XMP Core 4.4.0-Exiv2">
<rdf:RDF>
<rdf:Description ns2:CreatorTool="glymur" rdf:about="" />
</rdf:RDF>
</ns0:xmpmeta>
Contiguous Codestream Box (jp2c) @ (3127, 1132296)
Contiguous Codestream Box (jp2c) @ (3223, 1132296)
Main header:
SOC marker segment @ (3135, 0)
SIZ marker segment @ (3137, 47)
Profile: 2
SOC marker segment @ (3231, 0)
SIZ marker segment @ (3233, 47)
Profile: no profile
Reference Grid Height, Width: (1456 x 2592)
Vertical, Horizontal Reference Grid Offset: (0 x 0)
Reference Tile Height, Width: (1456 x 2592)
@ -391,7 +640,7 @@ Contiguous Codestream Box (jp2c) @ (3127, 1132296)
Bitdepth: (8, 8, 8)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
COD marker segment @ (3186, 12)
COD marker segment @ (3282, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
@ -411,8 +660,435 @@ Contiguous Codestream Box (jp2c) @ (3127, 1132296)
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCD marker segment @ (3200, 7)
QCD marker segment @ (3296, 7)
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
CME marker segment @ (3209, 37)
CME marker segment @ (3305, 37)
"Created by OpenJPEG version 2.0.0"'''
dump = r"""JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Size: [1456 2592 3]
Bitdepth: 8
Signed: False
Compression: wavelet
Colorspace Unknown: False
Colour Specification Box (colr) @ (62, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
{0}
Contiguous Codestream Box (jp2c) @ (3223, 1132296)"""
nemo_dump_no_codestream = dump.format(_indent(nemo_xmp))
nemo_dump_no_codestream_no_xml = r"""JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Size: [1456 2592 3]
Bitdepth: 8
Signed: False
Compression: wavelet
Colorspace Unknown: False
Colour Specification Box (colr) @ (62, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
Contiguous Codestream Box (jp2c) @ (3223, 1132296)"""
nemo = """JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Size: [1456 2592 3]
Bitdepth: 8
Signed: False
Compression: wavelet
Colorspace Unknown: False
Colour Specification Box (colr) @ (62, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<ns0:xmpmeta xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:ns3="http://ns.adobe.com/tiff/1.0/" xmlns:ns4="http://ns.adobe.com/exif/1.0/" xmlns:ns5="http://ns.adobe.com/photoshop/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="Exempi + XMP Core 5.1.2">
<rdf:RDF>
<rdf:Description rdf:about="">
<ns2:CreatorTool>Google</ns2:CreatorTool>
<ns2:CreateDate>2013-02-09T14:47:53</ns2:CreateDate>
</rdf:Description>
<rdf:Description rdf:about="">
<ns3:YCbCrPositioning>1</ns3:YCbCrPositioning>
<ns3:XResolution>72/1</ns3:XResolution>
<ns3:YResolution>72/1</ns3:YResolution>
<ns3:ResolutionUnit>2</ns3:ResolutionUnit>
<ns3:Make>HTC</ns3:Make>
<ns3:Model>HTC Glacier</ns3:Model>
<ns3:ImageWidth>2592</ns3:ImageWidth>
<ns3:ImageLength>1456</ns3:ImageLength>
<ns3:BitsPerSample>
<rdf:Seq>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
</rdf:Seq>
</ns3:BitsPerSample>
<ns3:PhotometricInterpretation>2</ns3:PhotometricInterpretation>
<ns3:SamplesPerPixel>3</ns3:SamplesPerPixel>
<ns3:WhitePoint>
<rdf:Seq>
<rdf:li>1343036288/4294967295</rdf:li>
<rdf:li>1413044224/4294967295</rdf:li>
</rdf:Seq>
</ns3:WhitePoint>
<ns3:PrimaryChromaticities>
<rdf:Seq>
<rdf:li>2748779008/4294967295</rdf:li>
<rdf:li>1417339264/4294967295</rdf:li>
<rdf:li>1288490240/4294967295</rdf:li>
<rdf:li>2576980480/4294967295</rdf:li>
<rdf:li>644245120/4294967295</rdf:li>
<rdf:li>257698032/4294967295</rdf:li>
</rdf:Seq>
</ns3:PrimaryChromaticities>
</rdf:Description>
<rdf:Description rdf:about="">
<ns4:ColorSpace>1</ns4:ColorSpace>
<ns4:PixelXDimension>2528</ns4:PixelXDimension>
<ns4:PixelYDimension>1424</ns4:PixelYDimension>
<ns4:FocalLength>353/100</ns4:FocalLength>
<ns4:GPSAltitudeRef>0</ns4:GPSAltitudeRef>
<ns4:GPSAltitude>0/1</ns4:GPSAltitude>
<ns4:GPSMapDatum>WGS-84</ns4:GPSMapDatum>
<ns4:DateTimeOriginal>2013-02-09T14:47:53</ns4:DateTimeOriginal>
<ns4:ISOSpeedRatings>
<rdf:Seq>
<rdf:li>76</rdf:li>
</rdf:Seq>
</ns4:ISOSpeedRatings>
<ns4:ExifVersion>0220</ns4:ExifVersion>
<ns4:FlashpixVersion>0100</ns4:FlashpixVersion>
<ns4:ComponentsConfiguration>
<rdf:Seq>
<rdf:li>1</rdf:li>
<rdf:li>2</rdf:li>
<rdf:li>3</rdf:li>
<rdf:li>0</rdf:li>
</rdf:Seq>
</ns4:ComponentsConfiguration>
<ns4:GPSLatitude>42,20.56N</ns4:GPSLatitude>
<ns4:GPSLongitude>71,5.29W</ns4:GPSLongitude>
<ns4:GPSTimeStamp>2013-02-09T19:47:53Z</ns4:GPSTimeStamp>
<ns4:GPSProcessingMethod>NETWORK</ns4:GPSProcessingMethod>
</rdf:Description>
<rdf:Description rdf:about="">
<ns5:DateCreated>2013-02-09T14:47:53</ns5:DateCreated>
</rdf:Description>
<rdf:Description rdf:about="">
<dc:Creator>
<rdf:Seq>
<rdf:li>Glymur</rdf:li>
<rdf:li>Python XMP Toolkit</rdf:li>
</rdf:Seq>
</dc:Creator>
</rdf:Description>
</rdf:RDF>
</ns0:xmpmeta>
<?xpacket end="w"?>
Contiguous Codestream Box (jp2c) @ (3223, 1132296)
SOC marker segment @ (3231, 0)
SIZ marker segment @ (3233, 47)
Profile: no profile
Reference Grid Height, Width: (1456 x 2592)
Vertical, Horizontal Reference Grid Offset: (0 x 0)
Reference Tile Height, Width: (1456 x 2592)
Vertical, Horizontal Reference Tile Offset: (0 x 0)
Bitdepth: (8, 8, 8)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
COD marker segment @ (3282, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
EPH marker segments: False
Coding style parameters:
Progression order: LRCP
Number of layers: 2
Multiple component transformation usage: reversible
Number of resolutions: 2
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Precinct size: default, 2^15 x 2^15
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCD marker segment @ (3296, 7)
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
CME marker segment @ (3305, 37)
"Created by OpenJPEG version 2.0.0"
SOT marker segment @ (3344, 10)
Tile part index: 0
Tile part length: 1132173
Tile part instance: 0
Number of tile parts: 1
COC marker segment @ (3356, 9)
Associated component: 1
Coding style for this component: Entropy coder, PARTITION = 0
Coding style parameters:
Number of resolutions: 2
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCC marker segment @ (3367, 8)
Associated Component: 1
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
COC marker segment @ (3377, 9)
Associated component: 2
Coding style for this component: Entropy coder, PARTITION = 0
Coding style parameters:
Number of resolutions: 2
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCC marker segment @ (3388, 8)
Associated Component: 2
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
SOD marker segment @ (3398, 0)
EOC marker segment @ (1135517, 0)"""
# Output of reader requirements printing for text_GBR.jp2
text_GBR_rreq = r"""Reader Requirements Box (rreq) @ (40, 109)
Fully Understands Aspect Mask: 0xffff
Display Completely Mask: 0xf8f0
Standard Features and Masks:
Feature 001: 0x8000 Deprecated - contains no extensions
Feature 005: 0x4080 Unrestricted JPEG 2000 Part 1 codestream, ITU-T Rec. T.800 | ISO/IEC 15444-1
Feature 012: 0x2040 Deprecated - codestream is contiguous
Feature 018: 0x1020 Deprecated - support for compositing is not required
Feature 044: 0x810 Compositing layer uses Any ICC profile
Vendor Features:
UUID 3a0d0218-0ae9-4115-b376-4bca41ce0e71
UUID 47c92ccc-d1a1-4581-b904-38bb5467713b
UUID bc45a774-dd50-4ec6-a9f6-f3a137f47e90
UUID d7c8c5ef-951f-43b2-8757-042500f538e8"""
file1_xml = """XML Box (xml ) @ (36, 439)
<IMAGE_CREATION xmlns="http://www.jpeg.org/jpx/1.0/xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jpeg.org/jpx/1.0/xml http://www.jpeg.org/metadata/15444-2.xsd">
\t<GENERAL_CREATION_INFO>
\t\t<CREATION_TIME>2001-11-01T13:45:00.000-06:00</CREATION_TIME>
\t\t<IMAGE_SOURCE>Professional 120 Image</IMAGE_SOURCE>
\t</GENERAL_CREATION_INFO>
</IMAGE_CREATION>"""
issue_182_cmap = """Component Mapping Box (cmap) @ (130, 24)
Component 0 ==> palette column 0
Component 0 ==> palette column 1
Component 0 ==> palette column 2
Component 0 ==> palette column 3"""
issue_183_colr = """Colour Specification Box (colr) @ (62, 12)
Method: restricted ICC profile
Precedence: 0
ICC Profile: None"""
# Progression order is invalid.
issue_186_progression_order = """COD marker segment @ (174, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
EPH marker segments: False
Coding style parameters:
Progression order: 33 (invalid)
Number of layers: 1
Multiple component transformation usage: reversible
Number of resolutions: 6
Code block height, width: (32 x 32)
Wavelet transform: 9-7 irreversible
Precinct size: default, 2^15 x 2^15
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False"""
# Cinema 2K profile
cinema2k_profile = """SIZ marker segment @ (2, 47)
Profile: Cinema 2K
Reference Grid Height, Width: (1080 x 1920)
Vertical, Horizontal Reference Grid Offset: (0 x 0)
Reference Tile Height, Width: (1080 x 1920)
Vertical, Horizontal Reference Tile Offset: (0 x 0)
Bitdepth: (12, 12, 12)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))"""
jplh_color_group_box = r"""Compositing Layer Header Box (jplh) @ (314227, 31)
Colour Group Box (cgrp) @ (314235, 23)
Colour Specification Box (colr) @ (314243, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB"""
fragment_list_box = r"""Fragment List Box (flst) @ (-1, 0)
Offset 0: 89
Fragment Length 0: 1132288
Data Reference 0: 0"""
number_list_box = r"""Number List Box (nlst) @ (-1, 0)
Association[0]: the rendered result
Association[1]: codestream 0
Association[2]: compositing layer 0"""
goodstuff_codestream_header = r"""Codestream:
SOC marker segment @ (0, 0)
SIZ marker segment @ (2, 47)
Profile: no profile
Reference Grid Height, Width: (800 x 480)
Vertical, Horizontal Reference Grid Offset: (0 x 0)
Reference Tile Height, Width: (800 x 480)
Vertical, Horizontal Reference Tile Offset: (0 x 0)
Bitdepth: (8, 8, 8)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
COD marker segment @ (51, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
EPH marker segments: False
Coding style parameters:
Progression order: LRCP
Number of layers: 1
Multiple component transformation usage: reversible
Number of resolutions: 6
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Precinct size: default, 2^15 x 2^15
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCD marker segment @ (65, 19)
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10)]"""
goodstuff_with_full_header = r"""Codestream:
SOC marker segment @ (0, 0)
SIZ marker segment @ (2, 47)
Profile: no profile
Reference Grid Height, Width: (800 x 480)
Vertical, Horizontal Reference Grid Offset: (0 x 0)
Reference Tile Height, Width: (800 x 480)
Vertical, Horizontal Reference Tile Offset: (0 x 0)
Bitdepth: (8, 8, 8)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
COD marker segment @ (51, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
EPH marker segments: False
Coding style parameters:
Progression order: LRCP
Number of layers: 1
Multiple component transformation usage: reversible
Number of resolutions: 6
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Precinct size: default, 2^15 x 2^15
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCD marker segment @ (65, 19)
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10)]
SOT marker segment @ (86, 10)
Tile part index: 0
Tile part length: 115132
Tile part instance: 0
Number of tile parts: 1
COC marker segment @ (98, 9)
Associated component: 1
Coding style for this component: Entropy coder, PARTITION = 0
Coding style parameters:
Number of resolutions: 6
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCC marker segment @ (109, 20)
Associated Component: 1
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10)]
COC marker segment @ (131, 9)
Associated component: 2
Coding style for this component: Entropy coder, PARTITION = 0
Coding style parameters:
Number of resolutions: 6
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCC marker segment @ (142, 20)
Associated Component: 2
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10)]
SOD marker segment @ (164, 0)
EOC marker segment @ (115218, 0)"""

View file

@ -1,22 +1,12 @@
"""
Test suite for openjpeg's callback functions.
"""
# R0904: Seems like pylint is fooled in this situation
# pylint: disable=R0904
# 'mock' most certainly is in unittest (Python 3.3)
# pylint: disable=E0611,F0401
import os
import re
import sys
import tempfile
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import unittest
if sys.hexversion <= 0x03030000:
from mock import patch
@ -27,9 +17,9 @@ else:
import glymur
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
"Missing openjp2 library.")
class TestCallbacks(unittest.TestCase):
"""Test suite for callbacks."""
@ -40,68 +30,60 @@ class TestCallbacks(unittest.TestCase):
def tearDown(self):
pass
@unittest.skipIf(glymur.version.openjpeg_version[0] != '2',
"Missing openjp2 library.")
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_info_callback_on_write_backwards_compatibility(self):
"""Verify messages printed when writing an image in verbose mode."""
j = glymur.Jp2k(self.jp2file)
with self.assertWarns(UserWarning):
tiledata = j.read(tile=0)
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
with patch('sys.stdout', new=StringIO()) as fake_out:
glymur.Jp2k(tfile.name, data=tiledata, verbose=True)
actual = fake_out.getvalue().strip()
expected = '[INFO] tile number 1 / 1'
self.assertEqual(actual, expected)
@unittest.skipIf(glymur.version.openjpeg_version[0] != '2',
"Missing openjp2 library.")
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_info_callback_on_write(self):
"""Verify messages printed when writing an image in verbose mode."""
j = glymur.Jp2k(self.jp2file)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
tiledata = j.read(tile=0)
tiledata = j[:]
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
j = glymur.Jp2k(tfile.name, 'wb')
with patch('sys.stdout', new=StringIO()) as fake_out:
j.write(tiledata, verbose=True)
glymur.Jp2k(tfile.name, data=tiledata, verbose=True)
actual = fake_out.getvalue().strip()
expected = '[INFO] tile number 1 / 1'
self.assertEqual(actual, expected)
@unittest.skipIf(glymur.version.openjpeg_version[0] == '0',
"Missing openjpeg/openjp2 library.")
def test_info_callbacks_on_read(self):
"""stdio output when info callback handler is enabled"""
# Verify that we get the expected stdio output when our internal info
# callback handler is enabled.
j = glymur.Jp2k(self.j2kfile)
jp2 = glymur.Jp2k(self.j2kfile)
with patch('sys.stdout', new=StringIO()) as fake_out:
j.read(rlevel=1, verbose=True, area=(0, 0, 200, 150))
jp2.verbose = True
jp2[::2, ::2]
actual = fake_out.getvalue().strip()
lines = ['[INFO] Start to read j2k main header (0).',
'[INFO] Main header has been correctly decoded.',
'[INFO] Setting decoding area to 0,0,150,200',
'[INFO] Header of tile 0 / 0 has been read.',
'[INFO] Tile 1/1 has been decoded.',
'[INFO] Image data has been updated with tile 1.']
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
@unittest.skipIf(glymur.lib.openjpeg.OPENJPEG is None,
"Missing openjpeg library.")
class TestCallbacks15(unittest.TestCase):
"""This test suite is for OpenJPEG 1.5.1 properties.
"""
def setUp(self):
self.jp2file = glymur.data.nemo()
self.j2kfile = glymur.data.goodstuff()
def tearDown(self):
pass
def test_info_callbacks_on_read(self):
"""Verify stdout when reading.
Verify that we get the expected stdio output when our internal info
callback handler is enabled.
"""
with patch('glymur.lib.openjp2.OPENJP2', new=None):
# Force to use OPENJPEG instead of OPENJP2.
j = glymur.Jp2k(self.j2kfile)
with patch('sys.stdout', new=StringIO()) as fake_out:
j.read(rlevel=1, verbose=True)
actual = fake_out.getvalue().strip()
if glymur.version.openjpeg_version[0] == '2':
lines = ['[INFO] Start to read j2k main header (0).',
'[INFO] Main header has been correctly decoded.',
'[INFO] Setting decoding area to 0,0,480,800',
'[INFO] Header of tile 0 / 0 has been read.',
'[INFO] Tile 1/1 has been decoded.',
'[INFO] Image data has been updated with tile 1.']
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
else:
regex = re.compile(r"""\[INFO\]\stile\s1\sof\s1\s+
\[INFO\]\s-\stiers-1\stook\s
[0-9]+\.[0-9]+\ss\s+
@ -111,13 +93,7 @@ class TestCallbacks15(unittest.TestCase):
[0-9]+\.[0-9]+\ss""",
re.VERBOSE)
# assertRegex in Python 3.3 (python2.7/pylint issue)
# pylint: disable=E1101
if sys.hexversion <= 0x03020000:
self.assertRegexpMatches(actual, regex)
else:
self.assertRegex(actual, regex)
if __name__ == "__main__":
unittest.main()

View file

@ -1,123 +0,0 @@
"""
Test suite for codestream parsing.
"""
# unittest doesn't work well with R0904.
# pylint: disable=R0904
# tempfile.TemporaryDirectory, unittest.assertWarns introduced in 3.2
# pylint: disable=E1101
# unittest2 is python2.6 only (pylint/python-2.7)
# pylint: disable=F0401
import os
import struct
import sys
import tempfile
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
from glymur import Jp2k
import glymur
try:
DATA_ROOT = os.environ['OPJ_DATA_ROOT']
except KeyError:
DATA_ROOT = None
except:
raise
@unittest.skipIf(DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
class TestCodestream(unittest.TestCase):
"""Test suite for unusual codestream cases."""
def setUp(self):
self.jp2file = glymur.data.nemo()
def tearDown(self):
pass
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_reserved_marker_segment(self):
"""Reserved marker segments are ok."""
# Some marker segments were reserved in FCD15444-1. Since that
# standard is old, some of them may have come into use.
#
# Let's inject a reserved marker segment into a file that
# we know something about to make sure we can still parse it.
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_01.j2k')
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
with open(filename, 'rb') as ifile:
# Everything up until the first QCD marker.
read_buffer = ifile.read(45)
tfile.write(read_buffer)
# Write the new marker segment, 0xff6f = 65391
read_buffer = struct.pack('>HHB', int(65391), int(3), int(0))
tfile.write(read_buffer)
# Get the rest of the input file.
read_buffer = ifile.read()
tfile.write(read_buffer)
tfile.flush()
codestream = Jp2k(tfile.name).get_codestream()
self.assertEqual(codestream.segment[2].marker_id, '0xff6f')
self.assertEqual(codestream.segment[2].length, 3)
self.assertEqual(codestream.segment[2].data, b'\x00')
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_unknown_marker_segment(self):
"""Should warn for an unknown marker."""
# Let's inject a marker segment whose marker does not appear to
# be valid. We still parse the file, but warn about the offending
# marker.
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_01.j2k')
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
with open(filename, 'rb') as ifile:
# Everything up until the first QCD marker.
read_buffer = ifile.read(45)
tfile.write(read_buffer)
# Write the new marker segment, 0xff79 = 65401
read_buffer = struct.pack('>HHB', int(65401), int(3), int(0))
tfile.write(read_buffer)
# Get the rest of the input file.
read_buffer = ifile.read()
tfile.write(read_buffer)
tfile.flush()
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
codestream = Jp2k(tfile.name).get_codestream()
self.assertEqual(len(w), 1)
self.assertEqual(codestream.segment[2].marker_id, '0xff79')
self.assertEqual(codestream.segment[2].length, 3)
self.assertEqual(codestream.segment[2].data, b'\x00')
def test_psot_is_zero(self):
"""Psot=0 in SOT is perfectly legal. Issue #78."""
filename = os.path.join(DATA_ROOT,
'input/nonregression/123.j2c')
j = Jp2k(filename)
codestream = j.get_codestream(header_only=False)
# The codestream is valid, so we should be able to get the entire
# codestream, so the last one is EOC.
self.assertEqual(codestream.segment[-1].marker_id, 'EOC')
if __name__ == "__main__":
unittest.main()

View file

@ -1,26 +1,13 @@
"""These tests are for edge cases where OPENJPEG does not exist, but
OPENJP2 may be present in some form or other.
"""
# unittest doesn't work well with R0904.
# pylint: disable=R0904
# tempfile.TemporaryDirectory, unittest.assertWarns introduced in 3.2
# pylint: disable=E1101
# unittest.mock only in Python 3.3 (python2.7/pylint import issue)
# pylint: disable=E0611,F0401
import contextlib
import ctypes
import imp
import os
import sys
import tempfile
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import unittest
if sys.hexversion <= 0x03030000:
from mock import patch
@ -30,6 +17,43 @@ else:
import glymur
from glymur import Jp2k
from .fixtures import (WARNING_INFRASTRUCTURE_ISSUE,
WARNING_INFRASTRUCTURE_MSG,
WINDOWS_TMP_FILE_MSG)
def openjpeg_not_found_by_ctypes():
"""
Need to know if openjpeg library can be picked right up by ctypes for one
of the tests.
"""
with patch.dict('os.environ',
{'DYLD_FALLBACK_LIBRARY_PATH': '/opt/local/lib'}):
if ctypes.util.find_library('openjpeg') is None:
return True
else:
return False
@contextlib.contextmanager
def chdir(dirname=None):
"""
This context manager restores the value of the current working directory
(cwd) after the enclosed code block completes or raises an exception. If a
directory name is supplied to the context manager then the cwd is changed
prior to running the code block.
Shamelessly lifted from
http://www.astropython.org/snippet/2009/10/chdir-context-manager
"""
curdir = os.getcwd()
try:
if dirname is not None:
os.chdir(dirname)
yield
finally:
os.chdir(curdir)
@unittest.skipIf(sys.hexversion < 0x03020000,
"TemporaryDirectory introduced in 3.2.")
@ -65,7 +89,6 @@ class TestSuite(unittest.TestCase):
# Need to reliably recover the location of the openjp2 library,
# so using '_name' appears to be the only way to do it.
# pylint: disable=W0212
libloc = glymur.lib.openjp2.OPENJP2._name
line = 'openjp2: {0}\n'.format(libloc)
tfile.write(line)
@ -74,6 +97,8 @@ class TestSuite(unittest.TestCase):
imp.reload(glymur.lib.openjp2)
Jp2k(self.jp2file)
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG)
def test_xdg_env_config_file_is_bad(self):
"""A non-existant library location should be rejected."""
with tempfile.TemporaryDirectory() as tdir:
@ -88,55 +113,60 @@ class TestSuite(unittest.TestCase):
with patch.dict('os.environ', {'XDG_CONFIG_HOME': tdir}):
# Misconfigured new configuration file should
# be rejected.
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
regex = 'could not be loaded'
with self.assertWarnsRegex(UserWarning, regex):
imp.reload(glymur.lib.openjp2)
self.assertEqual(len(w), 1)
@unittest.skipIf(glymur.lib.openjp2.OPENJPEG is None,
"Needs openjp2 and openjpeg before this test make sense.")
@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG)
def test_library_specified_as_None(self):
"""Verify that we can stop library from being loaded by using None."""
with tempfile.TemporaryDirectory() as tdir:
configdir = os.path.join(tdir, 'glymur')
os.mkdir(configdir)
fname = os.path.join(configdir, 'glymurrc')
with open(fname, 'w') as fptr:
# Essentially comment out openjp2 and preferentially load
# openjpeg instead.
fptr.write('[library]\n')
fptr.write('openjp2: None\n')
msg = 'openjpeg: {0}\n'
msg = msg.format(glymur.lib.openjp2.OPENJPEG._name)
fptr.write(msg)
fptr.flush()
with patch.dict('os.environ', {'XDG_CONFIG_HOME': tdir}):
imp.reload(glymur.lib.openjp2)
self.assertIsNone(glymur.lib.openjp2.OPENJP2)
self.assertIsNotNone(glymur.lib.openjp2.OPENJPEG)
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None and
glymur.lib.openjpeg.OPENJPEG is None,
"Missing openjp2 library.")
class TestConfig(unittest.TestCase):
"""Test suite for reading without proper library in place."""
@unittest.skipIf(glymur.lib.openjp2.OPENJPEG is None,
"Needs openjpeg before this test make sense.")
@unittest.skipIf(openjpeg_not_found_by_ctypes(),
"OpenJPEG must be found before this test can work.")
@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG)
def test_config_dir_but_no_config_file(self):
def setUp(self):
self.jp2file = glymur.data.nemo()
self.j2kfile = glymur.data.goodstuff()
with tempfile.TemporaryDirectory() as tdir:
configdir = os.path.join(tdir, 'glymur')
os.mkdir(configdir)
with patch.dict('os.environ', {'XDG_CONFIG_HOME': tdir}):
# Should still be able to load openjpeg, despite the
# configuration file not being there
imp.reload(glymur.lib.openjpeg)
self.assertIsNotNone(glymur.lib.openjp2.OPENJPEG)
def tearDown(self):
pass
def test_read_without_library(self):
"""Don't have either openjp2 or openjpeg libraries? Must error out.
"""
with patch('glymur.lib.openjp2.OPENJP2', new=None):
with patch('glymur.lib.openjpeg.OPENJPEG', new=None):
with self.assertRaises(glymur.jp2k.LibraryNotFoundError):
glymur.Jp2k(self.jp2file).read()
def test_read_bands_without_library(self):
"""Don't have openjp2 library? Must error out.
"""
with patch('glymur.lib.openjp2.OPENJP2', new=None):
with patch('glymur.lib.openjpeg.OPENJPEG', new=None):
with patch('glymur.version.openjpeg_version_tuple',
new=(0, 0, 0)):
with self.assertRaises(glymur.jp2k.LibraryNotFoundError):
glymur.Jp2k(self.jp2file).read_bands()
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
def test_write_without_library(self):
"""Don't have openjpeg libraries? Must error out.
"""
data = glymur.Jp2k(self.j2kfile).read()
with patch('glymur.lib.openjp2.OPENJP2', new=None):
with patch('glymur.lib.openjpeg.OPENJPEG', new=None):
with self.assertRaises(glymur.jp2k.LibraryNotFoundError):
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
ofile = Jp2k(tfile.name, 'wb')
ofile.write(data)
if __name__ == "__main__":
unittest.main()
@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG)
def test_config_file_in_current_directory(self):
"""A configuration file in the current directory should be honored."""
libloc = glymur.lib.openjp2.OPENJP2._name
with tempfile.TemporaryDirectory() as tdir1:
fname = os.path.join(tdir1, 'glymurrc')
with open(fname, 'w') as fptr:
fptr.write('[library]\n')
fptr.write('openjp2: {0}\n'.format(libloc))
fptr.flush()
with chdir(tdir1):
# Should be able to load openjp2 as before.
imp.reload(glymur.lib.openjp2)
self.assertEqual(glymur.lib.openjp2.OPENJP2._name, libloc)

View file

@ -1,126 +0,0 @@
"""
These tests deal with JPX/JP2/J2K images in the format-corpus repository.
"""
# R0904: Not too many methods in unittest.
# pylint: disable=R0904
# E1101: assertWarns introduced in python 3.2
# pylint: disable=E1101
# unittest2 is python2.6 only (pylint/python-2.7)
# pylint: disable=F0401
import os
from os.path import join
import re
import sys
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import glymur
from glymur import Jp2k
try:
FORMAT_CORPUS_DATA_ROOT = os.environ['FORMAT_CORPUS_DATA_ROOT']
except KeyError:
FORMAT_CORPUS_DATA_ROOT = None
try:
OPJ_DATA_ROOT = os.environ['OPJ_DATA_ROOT']
except KeyError:
OPJ_DATA_ROOT = None
@unittest.skipIf(FORMAT_CORPUS_DATA_ROOT is None,
"FORMAT_CORPUS_DATA_ROOT environment variable not set")
class TestSuiteFormatCorpus(unittest.TestCase):
"""Test suite for files in format corpus repository."""
@unittest.skipIf(re.match(r"""1\.[0123]""",
glymur.version.openjpeg_version) is not None,
"Needs 1.3+ to catch this.")
def test_balloon_trunc1(self):
"""Has one byte shaved off of EOC marker."""
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
'jp2k-test/byteCorruption/balloon_trunc1.jp2')
j2k = Jp2k(jfile)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
codestream = j2k.get_codestream(header_only=False)
self.assertEqual(len(w), 1)
# The last segment is truncated, so there should not be an EOC marker.
self.assertNotEqual(codestream.segment[-1].marker_id, 'EOC')
# The codestream is not as long as claimed.
with self.assertRaises((OSError, IOError)):
j2k.read(rlevel=-1)
def test_balloon_trunc3(self):
"""Most of last tile is missing."""
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
'jp2k-test/byteCorruption/balloon_trunc3.jp2')
j2k = Jp2k(jfile)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
codestream = j2k.get_codestream(header_only=False)
self.assertEqual(len(w), 1)
# The last segment is truncated, so there should not be an EOC marker.
self.assertNotEqual(codestream.segment[-1].marker_id, 'EOC')
# Should error out, it does not.
#with self.assertRaises(OSError):
# j2k.read(rlevel=-1)
def test_jp2_brand_any_icc_profile(self):
"""If 'jp2 ', then the method cannot be any icc profile."""
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
'jp2k-test', 'icc',
'balloon_eciRGBv2_ps_adobeplugin.jpf')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(jfile)
self.assertEqual(len(w), 1)
def test_jp2_brand_iccpr_mult_colr(self):
"""Has colr box, one that conforms, one that does not."""
# Wrong 'brand' field; contains two versions of ICC profile: one
# embedded using "Any ICC" method; other embedded using "Restricted
# ICC" method, with description ("Modified eciRGB v2") and profileClass
# ("Input Device") changed relative to original profile.
jfile = join(FORMAT_CORPUS_DATA_ROOT, 'jp2k-test', 'icc',
'balloon_eciRGBv2_ps_adobeplugin_jp2compatible.jpf')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(jfile)
self.assertEqual(len(w), 1)
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
class TestSuiteOpj(unittest.TestCase):
"""Test suite for files in openjpeg repository."""
def setUp(self):
pass
def tearDown(self):
pass
def test_jp2_brand_any_icc_profile(self):
"""If 'jp2 ', then the method cannot be any icc profile."""
filename = os.path.join(OPJ_DATA_ROOT,
'input/nonregression/text_GBR.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(filename)
self.assertEqual(len(w), 1)
if __name__ == "__main__":
unittest.main()

View file

@ -0,0 +1,164 @@
"""
Test suite for warnings issued by glymur.
"""
import os
import re
import struct
import tempfile
import unittest
from glymur import Jp2k
import glymur
from .fixtures import opj_data_file, OPJ_DATA_ROOT
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
class TestWarnings(unittest.TestCase):
"""Test suite for warnings issued by glymur."""
def test_invalid_compatibility_list_entry(self):
"""should not error out with invalid compatibility list entry"""
filename = opj_data_file('input/nonregression/issue397.jp2')
with self.assertWarns(UserWarning):
Jp2k(filename)
self.assertTrue(True)
def test_exceeded_box_length(self):
"""
should warn if reading past end of a box
Verify that a warning is issued if we read past the end of a box
This file has a palette (pclr) box whose length is impossibly
short.
"""
infile = os.path.join(OPJ_DATA_ROOT,
'input/nonregression/mem-b2ace68c-1381.jp2')
regex = re.compile(r'''Encountered\san\sunrecoverable\sValueError\s
while\sparsing\sa\sPalette\sbox\sat\sbyte\s
offset\s\d+\.\s+The\soriginal\serror\smessage\s
was\s"total\ssize\sof\snew\sarray\smust\sbe\s
unchanged"''',
re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(infile)
def test_NR_DEC_issue188_beach_64bitsbox_jp2_41_decode(self):
"""
Has an 'XML ' box instead of 'xml '. Yes that is pedantic, but it
really does deserve a warning.
"""
relpath = 'input/nonregression/issue188_beach_64bitsbox.jp2'
jfile = opj_data_file(relpath)
pattern = r"""Unrecognized\sbox\s\(b'XML\s'\)\sencountered."""
regex = re.compile(pattern, re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile)
def test_NR_gdal_fuzzer_unchecked_numresolutions_dump(self):
"""
Has an invalid number of resolutions.
"""
lst = ['input', 'nonregression',
'gdal_fuzzer_unchecked_numresolutions.jp2']
jfile = opj_data_file('/'.join(lst))
regex = re.compile(r"""Invalid\snumber\sof\sresolutions\s
\(\d+\)\.""",
re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile).get_codestream()
@unittest.skipIf(re.match("1.5|2.0.0", glymur.version.openjpeg_version),
"Test not passing on 1.5.x, not introduced until 2.x")
def test_NR_gdal_fuzzer_check_number_of_tiles(self):
"""
Has an impossible tiling setup.
"""
lst = ['input', 'nonregression',
'gdal_fuzzer_check_number_of_tiles.jp2']
jfile = opj_data_file('/'.join(lst))
regex = re.compile(r"""Invalid\snumber\sof\stiles\s
\(\d+\)\.""",
re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile).get_codestream()
def test_NR_gdal_fuzzer_check_comp_dx_dy_jp2_dump(self):
"""
Invalid subsampling value.
"""
lst = ['input', 'nonregression', 'gdal_fuzzer_check_comp_dx_dy.jp2']
jfile = opj_data_file('/'.join(lst))
regex = re.compile(r"""Invalid\ssubsampling\svalue\sfor\scomponent\s
\d+:\s+
dx=\d+,\s*dy=\d+""",
re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile).get_codestream()
def test_NR_gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc_patch_jp2(self):
lst = ['input', 'nonregression',
'gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc.patch.jp2']
jfile = opj_data_file('/'.join(lst))
regex = re.compile(r"""Invalid\scomponent\snumber\s\(\d+\),\s
number\sof\scomponents\sis\sonly\s\d+""",
re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile).get_codestream()
def test_bad_rsiz(self):
"""Should warn if RSIZ is bad. Issue196"""
filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2')
with self.assertWarnsRegex(UserWarning, 'Invalid profile'):
Jp2k(filename).get_codestream()
def test_bad_wavelet_transform(self):
"""Should warn if wavelet transform is bad. Issue195"""
filename = opj_data_file('input/nonregression/edf_c2_10025.jp2')
with self.assertWarnsRegex(UserWarning, 'Invalid wavelet transform'):
Jp2k(filename).get_codestream()
def test_invalid_progression_order(self):
"""Should still be able to parse even if prog order is invalid."""
jfile = opj_data_file('input/nonregression/2977.pdf.asan.67.2198.jp2')
with self.assertWarnsRegex(UserWarning, 'Invalid progression order'):
Jp2k(jfile).get_codestream()
def test_tile_height_is_zero(self):
"""Zero tile height should not cause an exception."""
filename = 'input/nonregression/2539.pdf.SIGFPE.706.1712.jp2'
filename = opj_data_file(filename)
with self.assertWarnsRegex(UserWarning, 'Invalid tile dimensions'):
Jp2k(filename).get_codestream()
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_unknown_marker_segment(self):
"""Should warn for an unknown marker."""
# Let's inject a marker segment whose marker does not appear to
# be valid. We still parse the file, but warn about the offending
# marker.
filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_01.j2k')
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
with open(filename, 'rb') as ifile:
# Everything up until the first QCD marker.
read_buffer = ifile.read(45)
tfile.write(read_buffer)
# Write the new marker segment, 0xff79 = 65401
read_buffer = struct.pack('>HHB', int(65401), int(3), int(0))
tfile.write(read_buffer)
# Get the rest of the input file.
read_buffer = ifile.read()
tfile.write(read_buffer)
tfile.flush()
with self.assertWarnsRegex(UserWarning, 'Unrecognized marker'):
Jp2k(tfile.name).get_codestream()
if __name__ == "__main__":
unittest.main()

View file

@ -1,29 +1,17 @@
"""
ICC profile tests.
"""
# unittest doesn't work well with R0904.
# pylint: disable=R0904
# unittest2 is python2.6 only (pylint/python-2.7)
# pylint: disable=F0401
import datetime
import os
import sys
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import unittest
import numpy as np
from glymur import Jp2k
from .fixtures import OPJ_DATA_ROOT, opj_data_file
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
class TestICC(unittest.TestCase):
@ -38,7 +26,9 @@ class TestICC(unittest.TestCase):
def test_file5(self):
"""basic ICC profile"""
filename = opj_data_file('input/conformance/file5.jp2')
j = Jp2k(filename)
with self.assertWarns(UserWarning):
# The file has a bad compatibility list entry. Not important here.
j = Jp2k(filename)
profile = j.box[3].box[1].icc_profile
self.assertEqual(profile['Size'], 546)
self.assertEqual(profile['Preferred CMM Type'], 0)
@ -70,12 +60,6 @@ class TestICC(unittest.TestCase):
"""invalid ICC header data should cause UserWarning"""
jfile = opj_data_file('input/nonregression/orb-blue10-lin-jp2.jp2')
# assertWarns in Python 3.3 (python2.7/pylint issue)
# pylint: disable=E1101
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
regex = 'ICC profile header is corrupt'
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile)
self.assertEqual(len(w), 1)
if __name__ == "__main__":
unittest.main()

File diff suppressed because it is too large Load diff

View file

@ -3,61 +3,614 @@
Test suite specifically targeting JPX box layout.
"""
import ctypes
import os
import struct
import sys
import tempfile
import warnings
import xml.etree.cElementTree as ET
import unittest
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import lxml.etree as ET
import glymur
from glymur import Jp2k
from glymur.jp2box import ReaderRequirementsBox
from glymur.jp2box import DataEntryURLBox, FileTypeBox, JPEG2000SignatureBox
from glymur.jp2box import DataReferenceBox, FragmentListBox, FragmentTableBox
from glymur.jp2box import ColourSpecificationBox
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
@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."""
class TestJPXWrap(unittest.TestCase):
"""Test suite for wrapping JPX files."""
def setUp(self):
self.jpxfile = glymur.data.jpxfile()
self.jp2file = glymur.data.nemo()
self.j2kfile = glymur.data.goodstuff()
raw_xml = b"""<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank>1</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
</data>"""
with tempfile.NamedTemporaryFile(suffix=".xml", delete=False) as tfile:
tfile.write(raw_xml)
tfile.flush()
self.xmlfile = tfile.name
def tearDown(self):
os.unlink(self.xmlfile)
def test_jpx_ftbl_no_codestream(self):
"""Can have a jpx with no codestream."""
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile1:
with open(self.jp2file, 'rb') as fptr:
tfile1.write(fptr.read())
tfile1.flush()
jp2_1 = Jp2k(tfile1.name)
jp2h = jp2_1.box[2]
jp2c = [box for box in jp2_1.box if box.box_id == 'jp2c'][0]
# coff and clen will be the offset and length input arguments
# to the fragment list box. dr_idx is the data reference index.
coff = []
clen = []
dr_idx = []
coff.append(jp2c.main_header_offset)
clen.append(jp2c.length - (coff[0] - jp2c.offset))
dr_idx.append(1)
# Make the url box for this codestream.
url1 = DataEntryURLBox(0, [0, 0, 0], 'file://' + tfile1.name)
url1_name_len = len(url1.url) + 1
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile2:
j2k = Jp2k(self.j2kfile)
jp2_2 = j2k.wrap(tfile2.name)
jp2c = [box for box in jp2_2.box if box.box_id == 'jp2c'][0]
coff.append(jp2c.main_header_offset)
clen.append(jp2c.length - (coff[0] - jp2c.offset))
dr_idx.append(2)
# Make the url box for this codestream.
url2 = DataEntryURLBox(0, [0, 0, 0], 'file://' + tfile2.name)
boxes = [JPEG2000SignatureBox(),
FileTypeBox(brand='jpx ',
compatibility_list=['jpx ',
'jp2 ', 'jpxb']),
jp2h]
with tempfile.NamedTemporaryFile(suffix='.jpx') as tjpx:
for box in boxes:
box.write(tjpx)
flst = FragmentListBox(coff, clen, dr_idx)
ftbl = FragmentTableBox([flst])
ftbl.write(tjpx)
boxes = [url1, url2]
dtbl = DataReferenceBox(data_entry_url_boxes=boxes)
dtbl.write(tjpx)
tjpx.flush()
jpx_no_jp2c = Jp2k(tjpx.name)
jpx_boxes = [box.box_id for box in jpx_no_jp2c.box]
self.assertEqual(jpx_boxes, ['jP ', 'ftyp', 'jp2h',
'ftbl', 'dtbl'])
self.assertEqual(jpx_no_jp2c.box[4].DR[0].offset, 141)
offset = 141 + 8 + 4 + url1_name_len
self.assertEqual(jpx_no_jp2c.box[4].DR[1].offset, offset)
def test_jp2_with_jpx_box(self):
"""If the brand is jp2, then no jpx boxes are allowed."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
boxes = jp2.box
boxes.append(glymur.jp2box.AssociationBox())
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
def test_jpch_jplh(self):
"""Write a codestream header, compositing layer header box."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# The ftyp box must be modified to jpx.
boxes[1].brand = 'jpx '
boxes[1].compatibility_list = ['jp2 ', 'jpxb']
jpch = glymur.jp2box.CodestreamHeaderBox()
boxes.append(jpch)
jplh = glymur.jp2box.CompositingLayerHeaderBox()
boxes.append(jplh)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
jpx = jp2.wrap(tfile.name, boxes=boxes)
self.assertEqual(jpx.box[-2].box_id, 'jpch')
self.assertEqual(jpx.box[-1].box_id, 'jplh')
def test_cgrp(self):
"""Write a color group box."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# The ftyp box must be modified to jpx.
boxes[1].brand = 'jpx '
boxes[1].compatibility_list = ['jp2 ', 'jpxb']
colr_rgb = ColourSpecificationBox(colorspace=glymur.core.SRGB)
colr_gr = ColourSpecificationBox(colorspace=glymur.core.GREYSCALE)
box = [colr_rgb, colr_gr]
cgrp = glymur.jp2box.ColourGroupBox(box=box)
boxes.append(cgrp)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
jpx = jp2.wrap(tfile.name, boxes=boxes)
self.assertEqual(jpx.box[-1].box_id, 'cgrp')
self.assertEqual(jpx.box[-1].box[0].box_id, 'colr')
self.assertEqual(jpx.box[-1].box[1].box_id, 'colr')
def test_label_neg(self):
"""Can't write a label box embedded in any old box."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# The ftyp box must be modified to jpx.
boxes[1].brand = 'jpx '
boxes[1].compatibility_list = ['jp2 ', 'jpxb']
lblb = glymur.jp2box.LabelBox("Just a test")
box = [lblb]
cgrp = glymur.jp2box.ColourGroupBox(box=box)
boxes.append(cgrp)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
def test_cgrp_neg(self):
"""Can't write a cgrp with anything but colr sub boxes"""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# The ftyp box must be modified to jpx.
boxes[1].brand = 'jpx '
boxes[1].compatibility_list = ['jp2 ', 'jpxb']
the_xml = ET.fromstring('<?xml version="1.0"?><data>0</data>')
xmlb = glymur.jp2box.XMLBox(xml=the_xml)
box = [xmlb]
cgrp = glymur.jp2box.ColourGroupBox(box=box)
boxes.append(cgrp)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
def test_ftbl(self):
"""Write a fragment table box."""
# Add a negative test where offset < 0
# Add a negative test where length < 0
# Add a negative test where ref > 0 but no data reference box.
# Add a negative test where more than one flst
# Add negative test where ftbl contained in a superbox.
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# The ftyp box must be modified to jpx.
boxes[1].brand = 'jpx '
boxes[1].compatibility_list = ['jp2 ', 'jpxb']
offset = [89]
length = [1132288]
reference = [0]
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
ftbl = glymur.jp2box.FragmentTableBox(box=[flst])
boxes.append(ftbl)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
jpx = jp2.wrap(tfile.name, boxes=boxes)
self.assertEqual(jpx.box[1].compatibility_list, ['jp2 ', 'jpxb'])
self.assertEqual(jpx.box[-1].box_id, 'ftbl')
self.assertEqual(jpx.box[-1].box[0].box_id, 'flst')
def test_jpxb_compatibility(self):
"""Wrap JP2 to JPX, state jpxb compatibility"""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# The ftyp box must be modified to jpx with jp2 compatibility.
boxes[1].brand = 'jpx '
boxes[1].compatibility_list = ['jp2 ', 'jpxb']
numbers = (0, 1)
nlst = glymur.jp2box.NumberListBox(numbers)
the_xml = ET.fromstring('<?xml version="1.0"?><data>0</data>')
xmlb = glymur.jp2box.XMLBox(xml=the_xml)
asoc = glymur.jp2box.AssociationBox([nlst, xmlb])
boxes.append(asoc)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
jpx = jp2.wrap(tfile.name, boxes=boxes)
self.assertEqual(jpx.box[1].compatibility_list, ['jp2 ', 'jpxb'])
self.assertEqual(jpx.box[-1].box_id, 'asoc')
self.assertEqual(jpx.box[-1].box[0].box_id, 'nlst')
self.assertEqual(jpx.box[-1].box[1].box_id, 'xml ')
self.assertEqual(jpx.box[-1].box[0].associations, numbers)
self.assertEqual(ET.tostring(jpx.box[-1].box[1].xml.getroot()),
b'<data>0</data>')
def test_association_label_box(self):
"""Wrap JP2 to JPX with asoc, label, and nlst boxes"""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# The ftyp box must be modified to jpx with jp2 compatibility.
boxes[1].brand = 'jpx '
boxes[1].compatibility_list = ['jp2 ', 'jpx ']
label = 'this is a test'
lblb = glymur.jp2box.LabelBox(label)
numbers = (0, 1)
nlst = glymur.jp2box.NumberListBox(numbers)
the_xml = ET.fromstring('<?xml version="1.0"?><data>0</data>')
xmlb = glymur.jp2box.XMLBox(xml=the_xml)
asoc = glymur.jp2box.AssociationBox([nlst, xmlb, lblb])
boxes.append(asoc)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
jpx = jp2.wrap(tfile.name, boxes=boxes)
self.assertEqual(jpx.box[1].compatibility_list, ['jp2 ', 'jpx '])
self.assertEqual(jpx.box[-1].box_id, 'asoc')
self.assertEqual(jpx.box[-1].box[0].box_id, 'nlst')
self.assertEqual(jpx.box[-1].box[0].associations, numbers)
self.assertEqual(jpx.box[-1].box[1].box_id, 'xml ')
self.assertEqual(ET.tostring(jpx.box[-1].box[1].xml.getroot()),
b'<data>0</data>')
self.assertEqual(jpx.box[-1].box[2].box_id, 'lbl ')
self.assertEqual(jpx.box[-1].box[2].label, label)
def test_empty_data_reference(self):
"""Empty data reference boxes can be created, but not written."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
boxes[1].brand = 'jpx '
dref = glymur.jp2box.DataReferenceBox()
boxes.append(dref)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
def test_deurl_child_of_dtbl(self):
"""Data reference boxes can only contain data entry url boxes."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
ftyp = glymur.jp2box.FileTypeBox()
with self.assertWarns(UserWarning):
dref = glymur.jp2box.DataReferenceBox([ftyp])
# Try to get around it by appending the ftyp box after creation.
dref = glymur.jp2box.DataReferenceBox()
dref.DR.append(ftyp)
boxes.append(dref)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
def test_only_one_data_reference(self):
"""Data reference boxes cannot be inside a superbox ."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# Have to make the ftyp brand jpx.
boxes[1].brand = 'jpx '
flag = 0
version = (0, 0, 0)
url = 'file:////usr/local/bin'
deurl = glymur.jp2box.DataEntryURLBox(flag, version, url)
dref = glymur.jp2box.DataReferenceBox([deurl])
boxes.append(dref)
boxes.append(dref)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
def test_lbl_at_top_level(self):
"""Label boxes can only be inside a asoc box ."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# Have to make the ftyp brand jpx.
boxes[1].brand = 'jpx '
lblb = glymur.jp2box.LabelBox('hi there')
# Put it inside the jp2 header box.
boxes[2].box.append(lblb)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
def test_data_reference_in_subbox(self):
"""Data reference boxes cannot be inside a superbox ."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# Have to make the ftyp brand jpx.
boxes[1].brand = 'jpx '
flag = 0
version = (0, 0, 0)
url = 'file:////usr/local/bin'
deurl = glymur.jp2box.DataEntryURLBox(flag, version, url)
dref = glymur.jp2box.DataReferenceBox([deurl])
# Put it inside the jp2 header box.
boxes[2].box.append(dref)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
def test_jp2_to_jpx_sans_jp2_compatibility(self):
"""jp2 wrapped to jpx not including jp2 compatibility is wrong."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# Have to make the ftyp brand jpx.
boxes[1].brand = 'jpx '
boxes[1].compatibility_list.append('jp2 ')
numbers = [0, 1]
nlst = glymur.jp2box.NumberListBox(numbers)
the_xml = ET.fromstring('<?xml version="1.0"?><data>0</data>')
xmlb = glymur.jp2box.XMLBox(xml=the_xml)
asoc = glymur.jp2box.AssociationBox([nlst, xmlb])
boxes.append(asoc)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(RuntimeError):
jp2.wrap(tfile.name, boxes=boxes)
def test_jp2_to_jpx_sans_jpx_brand(self):
"""Verify error when jp2 wrapped to jpx does not include jpx brand."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
boxes[1].brand = 'jpx '
numbers = [0, 1]
nlst = glymur.jp2box.NumberListBox(numbers)
the_xml = ET.fromstring('<?xml version="1.0"?><data>0</data>')
xmlb = glymur.jp2box.XMLBox(xml=the_xml)
asoc = glymur.jp2box.AssociationBox([nlst, xmlb])
boxes.append(asoc)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(RuntimeError):
jp2.wrap(tfile.name, boxes=boxes)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
class TestJPX(unittest.TestCase):
"""Test suite for other JPX boxes."""
def setUp(self):
self.jp2file = glymur.data.nemo()
pass
self.jpxfile = glymur.data.jpxfile()
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)
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
def test_flst_lens_not_the_same(self):
"""A fragment list box items must be the same length."""
offset = [89]
length = [1132288]
reference = [0, 0]
with self.assertWarns(UserWarning):
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
with self.assertRaises(IOError):
with tempfile.TemporaryFile() as tfile:
flst.write(tfile)
# Fake a rreq box with ML = 3.
write_buffer = struct.pack('>I4sB', 74, b'rreq', 3)
tfile.write(write_buffer)
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
def test_flst_offsets_not_positive(self):
"""A fragment list box offsets must be positive."""
offset = [0]
length = [1132288]
reference = [0]
with self.assertWarns(UserWarning):
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
with self.assertRaises((IOError, OSError)):
with tempfile.TemporaryFile() as tfile:
flst.write(tfile)
# pad the rest with zeros
write_buffer = struct.pack('>65s', b'\x00' * 65)
tfile.write(write_buffer)
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
def test_flst_lengths_not_positive(self):
"""A fragment list box lengths must be positive."""
offset = [89]
length = [0]
reference = [0]
with self.assertWarns(UserWarning):
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
with self.assertRaises(IOError):
with tempfile.TemporaryFile() as tfile:
flst.write(tfile)
# Write the rest of nemo.
tfile.write(nemof.read())
tfile.flush()
def test_ftbl_boxes_empty(self):
"""A fragment table box must have at least one child box."""
ftbl = glymur.jp2box.FragmentTableBox()
with self.assertRaises(IOError):
with tempfile.TemporaryFile() as tfile:
ftbl.write(tfile)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
j = Jp2k(tfile.name)
self.assertEqual(len(w), 1)
self.assertEqual(j.box[2].box_id, 'rreq')
self.assertEqual(type(j.box[2]),
glymur.jp2box.ReaderRequirementsBox)
def test_ftbl_child_not_flst(self):
"""A fragment table box can only contain a fragment list."""
free = glymur.jp2box.FreeBox()
ftbl = glymur.jp2box.FragmentTableBox(box=[free])
with self.assertRaises(IOError):
with tempfile.TemporaryFile() as tfile:
ftbl.write(tfile)
def test_data_reference_requires_dtbl(self):
"""The existance of data reference box requires a ftbl box as well."""
flag = 0
version = (0, 0, 0)
url1 = 'file:////usr/local/bin'
url2 = 'http://glymur.readthedocs.org'
jpx1 = glymur.Jp2k(self.jp2file)
boxes = jpx1.box
boxes[1].brand = 'jpx '
deurl1 = glymur.jp2box.DataEntryURLBox(flag, version, url1)
deurl2 = glymur.jp2box.DataEntryURLBox(flag, version, url2)
dref = glymur.jp2box.DataReferenceBox([deurl1, deurl2])
boxes.append(dref)
with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile:
with self.assertRaises(IOError):
jpx1.wrap(tfile.name, boxes=boxes)
def test_dtbl(self):
"""Verify that we can interpret Data Reference boxes."""
# Copy the existing JPX file, add a data reference box onto the end.
flag = 0
version = (0, 0, 0)
url1 = 'file:////usr/local/bin'
url2 = 'http://glymur.readthedocs.org' + chr(0) * 3
with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile:
with open(self.jpxfile, 'rb') as ifile:
tfile.write(ifile.read())
deurl1 = glymur.jp2box.DataEntryURLBox(flag, version, url1)
deurl2 = glymur.jp2box.DataEntryURLBox(flag, version, url2)
dref = glymur.jp2box.DataReferenceBox([deurl1, deurl2])
dref.write(tfile)
tfile.flush()
jpx = Jp2k(tfile.name)
self.assertEqual(jpx.box[-1].box_id, 'dtbl')
self.assertEqual(len(jpx.box[-1].DR), 2)
self.assertEqual(jpx.box[-1].DR[0].url, url1)
self.assertEqual(jpx.box[-1].DR[1].url, url2.rstrip('\0'))
def test_ftbl(self):
"""Verify that we can interpret Fragment Table boxes."""
# Copy the existing JPX file, add a fragment table box onto the end.
with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile:
with open(self.jpxfile, 'rb') as ifile:
tfile.write(ifile.read())
write_buffer = struct.pack('>I4s', 32, b'ftbl')
tfile.write(write_buffer)
# Just one fragment list box
write_buffer = struct.pack('>I4s', 24, b'flst')
tfile.write(write_buffer)
# Simple offset, length, reference
write_buffer = struct.pack('>HQIH', 1, 4237, 170246, 3)
tfile.write(write_buffer)
tfile.flush()
jpx = Jp2k(tfile.name)
self.assertEqual(jpx.box[-1].box_id, 'ftbl')
self.assertEqual(jpx.box[-1].box[0].box_id, 'flst')
self.assertEqual(jpx.box[-1].box[0].fragment_offset, (4237,))
self.assertEqual(jpx.box[-1].box[0].fragment_length, (170246,))
self.assertEqual(jpx.box[-1].box[0].data_reference, (3,))
def test_rreq3(self):
"""Verify that we can read a rreq box with mask length 3 bytes"""
rreq_buffer = ctypes.create_string_buffer(74)
struct.pack_into('>I4s', rreq_buffer, 0, 74, b'rreq')
# mask length
struct.pack_into('>B', rreq_buffer, 8, 3)
# fuam, dcm. 6 bytes, two sets of 3.
lst = (255, 224, 0, 0, 31, 252)
struct.pack_into('>BBBBBB', rreq_buffer, 9, *lst)
# number of standard features: 11
struct.pack_into('>H', rreq_buffer, 15, 11)
standard_flags = [5, 42, 45, 2, 18, 19, 1, 8, 12, 31, 20]
standard_masks = [8388608, 4194304, 2097152, 1048576, 524288, 262144,
131072, 65536, 32768, 16384, 8192]
for j in range(len(standard_flags)):
mask = (standard_masks[j] >> 16,
standard_masks[j] & 0x0000ffff >> 8,
standard_masks[j] & 0x000000ff)
struct.pack_into('>HBBB', rreq_buffer, 17 + j * 5,
standard_flags[j], *mask)
# num vendor features: 0
struct.pack_into('>H', rreq_buffer, 72, 0)
# Ok, done with the box, we can now insert it into the jpx file after
# the ftyp box.
with tempfile.NamedTemporaryFile(suffix=".jpx") as ofile:
with open(self.jpxfile, 'rb') as ifile:
ofile.write(ifile.read(40))
ofile.write(rreq_buffer)
ofile.write(ifile.read())
ofile.flush()
jpx = Jp2k(ofile.name)
self.assertEqual(jpx.box[2].box_id, 'rreq')
self.assertEqual(type(jpx.box[2]),
glymur.jp2box.ReaderRequirementsBox)
self.assertEqual(jpx.box[2].standard_flag,
(5, 42, 45, 2, 18, 19, 1, 8, 12, 31, 20))
def test_nlst(self):
"""Verify that we can handle a number list box."""
j = Jp2k(self.jpxfile)
nlst = j.box[12].box[0].box[0]
self.assertEqual(nlst.box_id, 'nlst')
self.assertEqual(type(nlst), glymur.jp2box.NumberListBox)
# Two associations.
self.assertEqual(len(nlst.associations), 2)
# Codestream 0
self.assertEqual(nlst.associations[0], 1 << 24)
# Compositing Layer 0
self.assertEqual(nlst.associations[1], 2 << 24)

View file

@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
"""Test suite for printing.
"""
import os
import shutil
import struct
import sys
import tempfile
import uuid
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import lxml.etree
from .fixtures import (WARNING_INFRASTRUCTURE_ISSUE,
WARNING_INFRASTRUCTURE_MSG,
WINDOWS_TMP_FILE_MSG)
import glymur
from glymur import Jp2k
from .fixtures import SimpleRDF
@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG)
class TestSuite(unittest.TestCase):
"""Tests for XMP, Exif UUIDs."""
def setUp(self):
self.jp2file = glymur.data.nemo()
def tearDown(self):
pass
def test_append_xmp_uuid(self):
"""Should be able to append an XMP UUID box."""
the_uuid = uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')
raw_data = SimpleRDF.encode('utf-8')
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
shutil.copyfile(self.jp2file, tfile.name)
jp2 = Jp2k(tfile.name)
ubox = glymur.jp2box.UUIDBox(the_uuid=the_uuid, raw_data=raw_data)
jp2.append(ubox)
# Should be two UUID boxes now.
expected_ids = ['jP ', 'ftyp', 'jp2h', 'uuid', 'jp2c', 'uuid']
actual_ids = [b.box_id for b in jp2.box]
self.assertEqual(actual_ids, expected_ids)
# The data should be an XMP packet, which gets interpreted as
# an ElementTree.
self.assertTrue(isinstance(jp2.box[-1].data,
lxml.etree._ElementTree))
def test_big_endian_exif(self):
"""Verify read of Exif big-endian IFD."""
with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile:
with open(self.jp2file, 'rb') as ifptr:
tfile.write(ifptr.read())
# Write L, T, UUID identifier.
tfile.write(struct.pack('>I4s', 52, b'uuid'))
tfile.write(b'JpgTiffExif->JP2')
tfile.write(b'Exif\x00\x00')
xbuffer = struct.pack('>BBHI', 77, 77, 42, 8)
tfile.write(xbuffer)
# We will write just a single tag.
tfile.write(struct.pack('>H', 1))
# The "Make" tag is tag no. 271.
tfile.write(struct.pack('>HHI4s', 271, 2, 3, b'HTC\x00'))
tfile.flush()
jp2 = glymur.Jp2k(tfile.name)
self.assertEqual(jp2.box[-1].data['Make'], "HTC")
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG)
class TestSuiteWarns(unittest.TestCase):
"""Tests for XMP, Exif UUIDs, issues warnings."""
def setUp(self):
self.jp2file = glymur.data.nemo()
def tearDown(self):
pass
def test_unrecognized_exif_tag(self):
"""Verify warning in case of unrecognized tag."""
with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile:
with open(self.jp2file, 'rb') as ifptr:
tfile.write(ifptr.read())
# Write L, T, UUID identifier.
tfile.write(struct.pack('>I4s', 52, b'uuid'))
tfile.write(b'JpgTiffExif->JP2')
tfile.write(b'Exif\x00\x00')
xbuffer = struct.pack('<BBHI', 73, 73, 42, 8)
tfile.write(xbuffer)
# We will write just a single tag.
tfile.write(struct.pack('<H', 1))
# The "Make" tag is tag no. 271. Corrupt it to 171.
tfile.write(struct.pack('<HHI4s', 171, 2, 3, b'HTC\x00'))
tfile.flush()
with self.assertWarnsRegex(UserWarning, 'Unrecognized Exif tag'):
glymur.Jp2k(tfile.name)
def test_bad_tag_datatype(self):
"""Only certain datatypes are allowable"""
with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile:
with open(self.jp2file, 'rb') as ifptr:
tfile.write(ifptr.read())
# Write L, T, UUID identifier.
tfile.write(struct.pack('>I4s', 52, b'uuid'))
tfile.write(b'JpgTiffExif->JP2')
tfile.write(b'Exif\x00\x00')
xbuffer = struct.pack('<BBHI', 73, 73, 42, 8)
tfile.write(xbuffer)
# We will write just a single tag.
tfile.write(struct.pack('<H', 1))
# 2000 is not an allowable TIFF datatype.
tfile.write(struct.pack('<HHI4s', 271, 2000, 3, b'HTC\x00'))
tfile.flush()
with self.assertWarnsRegex(UserWarning, 'Invalid TIFF tag'):
j = glymur.Jp2k(tfile.name)
self.assertEqual(j.box[-1].box_id, 'uuid')
def test_bad_tiff_header_byte_order_indication(self):
"""Only b'II' and b'MM' are allowed."""
with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile:
with open(self.jp2file, 'rb') as ifptr:
tfile.write(ifptr.read())
# Write L, T, UUID identifier.
tfile.write(struct.pack('>I4s', 52, b'uuid'))
tfile.write(b'JpgTiffExif->JP2')
tfile.write(b'Exif\x00\x00')
xbuffer = struct.pack('<BBHI', 74, 73, 42, 8)
tfile.write(xbuffer)
# We will write just a single tag.
tfile.write(struct.pack('<H', 1))
# 271 is the Make.
tfile.write(struct.pack('<HHI4s', 271, 2, 3, b'HTC\x00'))
tfile.flush()
regex = 'The byte order indication in the TIFF header '
with self.assertWarnsRegex(UserWarning, regex):
jp2 = glymur.Jp2k(tfile.name)
self.assertEqual(jp2.box[-1].box_id, 'uuid')

View file

@ -2,43 +2,13 @@
"""
Test suite specifically targeting JP2 box layout.
"""
# E1103: return value from read may be list or np array
# pylint: disable=E1103
# F0401: unittest2 is needed on python-2.6 (pylint on 2.7)
# pylint: disable=F0401
# R0902: More than 7 instance attributes are just fine for testing.
# pylint: disable=R0902
# R0904: Seems like pylint is fooled in this situation
# pylint: disable=R0904
# W0613: load_tests doesn't need to use ignore or loader arguments.
# pylint: disable=W0613
import os
import re
import struct
import sys
import tempfile
import warnings
import xml.etree.cElementTree as ET
import warnings
import unittest
if sys.hexversion < 0x03000000:
from StringIO import StringIO
else:
from io import StringIO
if sys.hexversion <= 0x03030000:
from mock import patch
else:
from unittest.mock import patch
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import lxml.etree as ET
import glymur
from glymur import Jp2k
@ -46,8 +16,12 @@ from glymur.jp2box import ColourSpecificationBox, ContiguousCodestreamBox
from glymur.jp2box import FileTypeBox, ImageHeaderBox, JP2HeaderBox
from glymur.jp2box import JPEG2000SignatureBox
from .fixtures import OPJ_DATA_ROOT, opj_data_file
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
from . import fixtures
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG)
class TestXML(unittest.TestCase):
"""Test suite for XML boxes."""
@ -171,8 +145,6 @@ class TestXML(unittest.TestCase):
u'<country>Россия</country>')
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
class TestJp2kBadXmlFile(unittest.TestCase):
"""Test suite for bad XML box situations"""
@ -213,12 +185,11 @@ class TestJp2kBadXmlFile(unittest.TestCase):
def tearDown(self):
pass
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
def test_invalid_xml_box(self):
"""Should be able to recover info from xml box with bad xml."""
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
with self.assertWarns(UserWarning):
jp2k = Jp2k(self._bad_xml_file)
self.assertEqual(len(w), 1)
self.assertEqual(jp2k.box[3].box_id, 'xml ')
self.assertEqual(jp2k.box[3].offset, 77)
@ -226,7 +197,7 @@ class TestJp2kBadXmlFile(unittest.TestCase):
self.assertIsNone(jp2k.box[3].xml)
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
@unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG)
class TestBadButRecoverableXmlFile(unittest.TestCase):
"""Test suite for XML box that is bad, but we can still recover the XML."""
@ -267,19 +238,17 @@ class TestBadButRecoverableXmlFile(unittest.TestCase):
def tearDownClass(cls):
os.unlink(cls._bad_xml_file)
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
def test_bad_xml_box_warning(self):
"""Should warn in case of bad XML"""
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
regex = 'A UnicodeDecodeError was encountered parsing an XML box'
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(self._bad_xml_file)
self.assertEqual(len(w), 1)
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
def test_recover_from_bad_xml(self):
"""Should be able to recover info from xml box with bad xml."""
with warnings.catch_warnings():
warnings.simplefilter("ignore")
with self.assertWarns(UserWarning):
jp2 = Jp2k(self._bad_xml_file)
self.assertEqual(jp2.box[3].box_id, 'xml ')
@ -289,3 +258,31 @@ class TestBadButRecoverableXmlFile(unittest.TestCase):
b'<test>this is a test</test>')
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
class TestXML_OpjDataRoot(unittest.TestCase):
"""Test suite for XML boxes, requires OPJ_DATA_ROOT."""
def test_bom(self):
"""Byte order markers are illegal in UTF-8. Issue 185"""
filename = opj_data_file(os.path.join('input',
'nonregression',
'issue171.jp2'))
msg = 'An illegal BOM \(byte order marker\) was detected and removed '
msg += 'from the XML contents in the box starting at byte offset \d+'
with self.assertWarnsRegex(UserWarning, re.compile(msg)):
jp2 = Jp2k(filename)
self.assertIsNotNone(jp2.box[3].xml)
def test_invalid_utf8(self):
"""Bad byte sequence that cannot be parsed."""
relname = '26ccf3651020967f7778238ef5af08af.SIGFPE.d25.527.jp2'
filename = opj_data_file(os.path.join('input',
'nonregression',
relname))
with self.assertWarns((UserWarning, UserWarning)):
jp2 = Jp2k(filename)
self.assertIsNone(jp2.box[3].box[1].box[1].xml)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,407 +0,0 @@
"""
The tests defined here roughly correspond to what is in the OpenJPEG test
suite.
"""
# Some test names correspond with openjpeg tests. Long names are ok in this
# case.
# pylint: disable=C0103
# All of these tests correspond to tests in openjpeg, so no docstring is really
# needed.
# pylint: disable=C0111
# This module is very long, cannot be helped.
# pylint: disable=C0302
# unittest fools pylint with "too many public methods"
# pylint: disable=R0904
# Some tests use numpy test infrastructure, which means the tests never
# reference "self", so pylint claims it should be a function. No, no, no.
# pylint: disable=R0201
# Many tests are pretty long and that can't be helped.
# pylint: disable=R0915
# asserWarns introduced in python 3.2 (python2.7/pylint issue)
# pylint: disable=E1101
# unittest2 is python2.6 only (pylint/python-2.7)
# pylint: disable=F0401
import re
import sys
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import warnings
import numpy as np
from glymur import Jp2k
import glymur
from .fixtures import OPENJP2_IS_V2_OFFICIAL, OPJ_DATA_ROOT
from .fixtures import mse, peak_tolerance, read_pgx, opj_data_file
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
@unittest.skipIf(re.match(r'''2.0.0''', glymur.version.openjpeg_version),
"Tests not introduced until 2.0.1")
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] == 1,
"Tests not introduced until 2.1")
class TestSuite2point1(unittest.TestCase):
"""Runs tests introduced in version 2.0+ or that pass only in 2.0+"""
def setUp(self):
pass
def tearDown(self):
pass
def test_NR_DEC_text_GBR_jp2_29_decode(self):
jfile = opj_data_file('input/nonregression/text_GBR.jp2')
with warnings.catch_warnings():
# brand is 'jp2 ', but has any icc profile.
warnings.simplefilter("ignore")
jp2 = Jp2k(jfile)
jp2.read()
self.assertTrue(True)
def test_NR_DEC_kodak_2layers_lrcp_j2c_31_decode(self):
jfile = opj_data_file('input/nonregression/kodak_2layers_lrcp.j2c')
Jp2k(jfile).read()
self.assertTrue(True)
def test_NR_DEC_kodak_2layers_lrcp_j2c_32_decode(self):
jfile = opj_data_file('input/nonregression/kodak_2layers_lrcp.j2c')
Jp2k(jfile).read(layer=2)
self.assertTrue(True)
def test_NR_DEC_issue104_jpxstream_jp2_33_decode(self):
jfile = opj_data_file('input/nonregression/issue104_jpxstream.jp2')
Jp2k(jfile).read()
self.assertTrue(True)
def test_NR_DEC_mem_b2b86b74_2753_jp2_35_decode(self):
jfile = opj_data_file('input/nonregression/mem-b2b86b74-2753.jp2')
Jp2k(jfile).read()
self.assertTrue(True)
def test_NR_DEC_gdal_fuzzer_unchecked_num_resolutions_jp2_36_decode(self):
f = 'input/nonregression/gdal_fuzzer_unchecked_numresolutions.jp2'
jfile = opj_data_file(f)
with warnings.catch_warnings():
# Invalid number of resolutions.
warnings.simplefilter("ignore")
j = Jp2k(jfile)
with self.assertRaises(IOError):
j.read()
def test_NR_DEC_gdal_fuzzer_check_number_of_tiles_jp2_38_decode(self):
relpath = 'input/nonregression/gdal_fuzzer_check_number_of_tiles.jp2'
jfile = opj_data_file(relpath)
with warnings.catch_warnings():
# Invalid number of tiles.
warnings.simplefilter("ignore")
j = Jp2k(jfile)
with self.assertRaises(IOError):
j.read()
def test_NR_DEC_gdal_fuzzer_check_comp_dx_dy_jp2_39_decode(self):
relpath = 'input/nonregression/gdal_fuzzer_check_comp_dx_dy.jp2'
jfile = opj_data_file(relpath)
with warnings.catch_warnings():
# Invalid subsampling value
warnings.simplefilter("ignore")
with self.assertRaises(IOError):
Jp2k(jfile).read()
def test_NR_DEC_file_409752_jp2_40_decode(self):
jfile = opj_data_file('input/nonregression/file409752.jp2')
with self.assertRaises(RuntimeError):
Jp2k(jfile).read()
def test_NR_DEC_issue188_beach_64bitsbox_jp2_41_decode(self):
# Has an 'XML ' box instead of 'xml '. Yes that is pedantic, but it
# really does deserve a warning.
relpath = 'input/nonregression/issue188_beach_64bitsbox.jp2'
jfile = opj_data_file(relpath)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(jfile).read()
self.assertEqual(len(w), 1)
def test_NR_DEC_issue206_image_000_jp2_42_decode(self):
jfile = opj_data_file('input/nonregression/issue206_image-000.jp2')
Jp2k(jfile).read()
self.assertTrue(True)
def test_NR_DEC_p1_04_j2k_43_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 0, 1024, 1024))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata)
def test_NR_DEC_p1_04_j2k_44_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(640, 512, 768, 640))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[640:768, 512:640])
def test_NR_DEC_p1_04_j2k_45_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(896, 896, 1024, 1024))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[896:1024, 896:1024])
def test_NR_DEC_p1_04_j2k_46_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(500, 100, 800, 300))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[500:800, 100:300])
def test_NR_DEC_p1_04_j2k_47_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 260, 600, 360))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[520:600, 260:360])
def test_NR_DEC_p1_04_j2k_48_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 260, 660, 360))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[520:660, 260:360])
def test_NR_DEC_p1_04_j2k_49_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 360, 600, 400))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[520:600, 360:400])
def test_NR_DEC_p1_04_j2k_50_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 0, 1024, 1024), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[0:256, 0:256])
def test_NR_DEC_p1_04_j2k_51_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(640, 512, 768, 640), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[160:192, 128:160])
def test_NR_DEC_p1_04_j2k_52_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(896, 896, 1024, 1024), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[224:352, 224:352])
def test_NR_DEC_p1_04_j2k_53_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(500, 100, 800, 300), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[125:200, 25:75])
def test_NR_DEC_p1_04_j2k_54_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 260, 600, 360), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[130:150, 65:90])
def test_NR_DEC_p1_04_j2k_55_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 260, 660, 360), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[130:165, 65:90])
def test_NR_DEC_p1_04_j2k_56_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 360, 600, 400), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[130:150, 90:100])
def test_NR_DEC_p1_04_j2k_57_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
tdata = jp2k.read(tile=63) # last tile
odata = jp2k.read()
np.testing.assert_array_equal(tdata, odata[896:1024, 896:1024])
def test_NR_DEC_p1_04_j2k_58_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
tdata = jp2k.read(tile=63, rlevel=2) # last tile
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(tdata, odata[224:256, 224:256])
def test_NR_DEC_p1_04_j2k_59_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
tdata = jp2k.read(tile=12) # 2nd row, 5th column
odata = jp2k.read()
np.testing.assert_array_equal(tdata, odata[128:256, 512:640])
def test_NR_DEC_p1_04_j2k_60_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
tdata = jp2k.read(tile=12, rlevel=1) # 2nd row, 5th column
odata = jp2k.read(rlevel=1)
np.testing.assert_array_equal(tdata, odata[64:128, 256:320])
def test_NR_DEC_jp2_36_decode(self):
lst = ('input',
'nonregression',
'gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc.patch.jp2')
jfile = opj_data_file('/'.join(lst))
with warnings.catch_warnings():
# Invalid component number.
warnings.simplefilter("ignore")
j = Jp2k(jfile)
with self.assertRaises(IOError):
j.read()
def test_NR_DEC_p1_06_j2k_70_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(9, 9, 12, 12), rlevel=1)
self.assertEqual(ssdata.shape, (1, 1, 3))
def test_NR_DEC_p1_06_j2k_71_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(10, 4, 12, 10), rlevel=1)
self.assertEqual(ssdata.shape, (1, 3, 3))
def test_NR_DEC_p1_06_j2k_72_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(3, 3, 9, 9), rlevel=1)
self.assertEqual(ssdata.shape, (3, 3, 3))
def test_NR_DEC_p1_06_j2k_73_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(4, 4, 7, 7), rlevel=1)
self.assertEqual(ssdata.shape, (2, 2, 3))
def test_NR_DEC_p1_06_j2k_74_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(4, 4, 5, 5), rlevel=1)
self.assertEqual(ssdata.shape, (1, 1, 3))
def test_NR_DEC_p1_06_j2k_75_decode(self):
# Image size would be 0 x 0.
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
with self.assertRaises((IOError, OSError)):
jp2k.read(area=(9, 9, 12, 12), rlevel=2)
def test_NR_DEC_p0_04_j2k_85_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 0, 256, 256))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[0:256, 0:256], ssdata)
def test_NR_DEC_p0_04_j2k_86_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 128, 128, 256))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[0:128, 128:256], ssdata)
def test_NR_DEC_p0_04_j2k_87_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(10, 50, 200, 120))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[10:200, 50:120], ssdata)
def test_NR_DEC_p0_04_j2k_88_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(150, 10, 210, 190))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[150:210, 10:190], ssdata)
def test_NR_DEC_p0_04_j2k_89_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(80, 100, 150, 200))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[80:150, 100:200], ssdata)
def test_NR_DEC_p0_04_j2k_90_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(20, 150, 50, 200))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[20:50, 150:200], ssdata)
def test_NR_DEC_p0_04_j2k_91_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 0, 256, 256), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[0:64, 0:64], ssdata)
def test_NR_DEC_p0_04_j2k_92_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 128, 128, 256), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[0:32, 32:64], ssdata)
def test_NR_DEC_p0_04_j2k_93_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(10, 50, 200, 120), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[3:50, 13:30], ssdata)
def test_NR_DEC_p0_04_j2k_94_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(150, 10, 210, 190), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[38:53, 3:48], ssdata)
def test_NR_DEC_p0_04_j2k_95_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(80, 100, 150, 200), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[20:38, 25:50], ssdata)
def test_NR_DEC_p0_04_j2k_96_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(20, 150, 50, 200), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[5:13, 38:50], ssdata)
if __name__ == "__main__":
unittest.main()

File diff suppressed because it is too large Load diff

View file

@ -2,37 +2,30 @@
The tests here do not correspond directly to the OpenJPEG test suite, but
seem like logical negative tests to add.
"""
# R0904: Not too many methods in unittest.
# pylint: disable=R0904
# unittest2 is python2.6 only (pylint/python-2.7)
# pylint: disable=F0401
import os
import re
import sys
import tempfile
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import unittest
import numpy as np
try:
import skimage.io
except ImportError:
pass
from .fixtures import OPJ_DATA_ROOT, opj_data_file, read_image
from .fixtures import NO_READ_BACKEND, NO_READ_BACKEND_MSG
from .fixtures import NO_SKIMAGE_FREEIMAGE_SUPPORT
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
from . import fixtures
from glymur import Jp2k
import glymur
@unittest.skipIf(re.match(r"""1\.[01234]""", glymur.version.openjpeg_version),
"Functionality not implemented for 1.3, 1.4")
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_OPJ_DATA_ROOT environment variable not set")
class TestSuiteNegative(unittest.TestCase):
class TestSuiteNegativeRead(unittest.TestCase):
"""Test suite for certain negative tests from openjpeg suite."""
def setUp(self):
@ -42,18 +35,6 @@ class TestSuiteNegative(unittest.TestCase):
def tearDown(self):
pass
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_psnr_with_cratios(self):
"""Using psnr with cratios options is not allowed."""
# Not an OpenJPEG test, but close.
infile = opj_data_file('input/nonregression/Bretagne1.ppm')
data = read_image(infile)
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
j = Jp2k(tfile.name, 'wb')
with self.assertRaises(IOError):
j.write(data, psnr=[30, 35, 40], cratios=[2, 3, 4])
def test_nr_marker_not_compliant(self):
"""non-compliant marker, should still be able to read"""
relpath = 'input/nonregression/MarkerIsNotCompliant.j2k'
@ -62,15 +43,14 @@ class TestSuiteNegative(unittest.TestCase):
jp2k.get_codestream(header_only=False)
self.assertTrue(True)
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
def test_nr_illegalclrtransform(self):
"""EOC marker is bad"""
relpath = 'input/nonregression/illegalcolortransform.j2k'
jfile = opj_data_file(relpath)
jp2k = Jp2k(jfile)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
with self.assertWarns(UserWarning):
codestream = jp2k.get_codestream(header_only=False)
self.assertEqual(len(w), 1)
# Verify that the last segment returned in the codestream is SOD,
# not EOC. Codestream parsing should stop when we try to jump to
@ -85,67 +65,80 @@ class TestSuiteNegative(unittest.TestCase):
jp2k.get_codestream(header_only=False)
self.assertTrue(True)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@unittest.skipIf(re.match("1.5|2", glymur.version.openjpeg_version) is None,
"Must have openjpeg 1.5 or higher to run")
@unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG)
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_OPJ_DATA_ROOT environment variable not set")
class TestSuiteNegativeWrite(unittest.TestCase):
"""Test suite for certain negative tests from openjpeg suite."""
def setUp(self):
self.jp2file = glymur.data.nemo()
self.j2kfile = glymur.data.goodstuff()
def tearDown(self):
pass
@unittest.skipIf(NO_SKIMAGE_FREEIMAGE_SUPPORT,
"Cannot read input image without scikit-image/freeimage")
def test_cinema2K_bad_frame_rate(self):
"""Cinema2k frame rate must be either 24 or 48."""
relfile = 'input/nonregression/X_5_2K_24_235_CBR_STEM24_000.tif'
infile = opj_data_file(relfile)
data = skimage.io.imread(infile)
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
with self.assertRaises(IOError):
Jp2k(tfile.name, data=data, cinema2k=36)
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
def test_psnr_with_cratios(self):
"""Using psnr with cratios options is not allowed."""
# Not an OpenJPEG test, but close.
infile = opj_data_file('input/nonregression/Bretagne1.ppm')
data = read_image(infile)
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
with self.assertRaises(IOError):
Jp2k(tfile.name,
data=data, psnr=[30, 35, 40], cratios=[2, 3, 4])
def test_code_block_dimensions(self):
"""don't allow extreme codeblock sizes"""
# opj_compress doesn't allow the dimensions of a codeblock
# to be too small or too big, so neither will we.
data = np.zeros((256, 256), dtype=np.uint8)
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
j = Jp2k(tfile.name, 'wb')
# opj_compress doesn't allow code block area to exceed 4096.
with self.assertRaises(IOError):
j.write(data, cbsize=(256, 256))
Jp2k(tfile.name, data=data, cbsize=(256, 256))
# opj_compress doesn't allow either dimension to be less than 4.
with self.assertRaises(IOError):
j.write(data, cbsize=(2048, 2))
Jp2k(tfile.name, data=data, cbsize=(2048, 2))
with self.assertRaises(IOError):
j.write(data, cbsize=(2, 2048))
Jp2k(tfile.name, data=data, cbsize=(2, 2048))
def test_exceeded_box(self):
"""should warn if reading past end of a box"""
# Verify that a warning is issued if we read past the end of a box
# This file has a palette (pclr) box whose length is impossibly
# short.
infile = os.path.join(OPJ_DATA_ROOT,
'input/nonregression/mem-b2ace68c-1381.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("ignore")
Jp2k(infile)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_precinct_size_not_p2(self):
"""precinct sizes should be powers of two."""
ifile = Jp2k(self.j2kfile)
data = ifile.read(rlevel=2)
data = ifile[::4, ::4]
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
ofile = Jp2k(tfile.name, 'wb')
with self.assertRaises(IOError):
ofile.write(data, psizes=[(13, 13)])
Jp2k(tfile.name, data=data, psizes=[(13, 13)])
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_cblk_size_not_power_of_two(self):
"""code block sizes should be powers of two."""
ifile = Jp2k(self.j2kfile)
data = ifile.read(rlevel=2)
data = ifile[::4, ::4]
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
ofile = Jp2k(tfile.name, 'wb')
with self.assertRaises(IOError):
ofile.write(data, cbsize=(13, 12))
Jp2k(tfile.name, data=data, cbsize=(13, 12))
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_cblk_size_precinct_size(self):
"""code block sizes should never exceed half that of precinct size."""
ifile = Jp2k(self.j2kfile)
data = ifile.read(rlevel=2)
data = ifile[::4, ::4]
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
ofile = Jp2k(tfile.name, 'wb')
with self.assertRaises(IOError):
ofile.write(data,
cbsize=(64, 64),
psizes=[(64, 64)])
if __name__ == "__main__":
unittest.main()
Jp2k(tfile.name, data=data, cbsize=(64, 64), psizes=[(64, 64)])

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,21 +1,24 @@
# This file is part of glymur, a Python interface for accessing JPEG 2000.
#
# http://glymur.readthedocs.org
#
# Copyright 2013 John Evans
#
# License: MIT
"""
This file is part of glymur, a Python interface for accessing JPEG 2000.
http://glymur.readthedocs.org
Copyright 2013 John Evans
License: MIT
"""
import sys
import numpy as np
from distutils.version import LooseVersion
from .lib import openjpeg as opj
from .lib import openjp2 as opj2
import lxml.etree
import numpy as np
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.5.11"
version = "0.8.0"
_sv = LooseVersion(version)
version_tuple = _sv.version
@ -46,10 +49,12 @@ OPENJPEG {openjpeg}
Python {python}
sys.platform {platform}
sys.maxsize {maxsize}
lxml {elxml}
numpy {numpy}
""".format(glymur=version,
openjpeg=openjpeg_version,
python=sys.version,
platform=sys.platform,
maxsize=sys.maxsize,
elxml=lxml.etree.__version__,
numpy=np.__version__)

View file

@ -1,4 +1,4 @@
from setuptools import setup, find_packages
from setuptools import setup
import os
import re
import sys
@ -11,24 +11,25 @@ kwargs = {'name': 'Glymur',
'url': 'https://github.com/quintusdias/glymur',
'packages': ['glymur', 'glymur.data', 'glymur.test', 'glymur.lib',
'glymur.lib.test'],
'package_data': {'glymur': ['data/*.jp2', 'data/*.j2k']},
'scripts': ['bin/jp2dump'],
'package_data': {'glymur': ['data/*.jp2',
'data/*.j2k',
'data/*.jpx']},
'entry_points': {
'console_scripts': ['jp2dump=glymur.command_line:main'],
},
'license': 'MIT',
'test_suite': 'glymur.test'}
instllrqrs = ['numpy>=1.4.1']
install_requires = ['numpy>=1.7.0', 'lxml>=3.0.0']
if sys.hexversion < 0x03030000:
instllrqrs.append('contextlib2>=0.4')
instllrqrs.append('mock>=1.0.1')
if sys.hexversion < 0x02070000:
instllrqrs.append('ordereddict>=1.1')
instllrqrs.append('unittest2>=0.5.1')
kwargs['install_requires'] = instllrqrs
install_requires.append('contextlib2>=0.4')
install_requires.append('mock>=1.0.1')
kwargs['install_requires'] = install_requires
clssfrs = ["Programming Language :: Python",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: Implementation :: CPython",
"License :: OSI Approved :: MIT License",
"Development Status :: 5 - Production/Stable",
@ -42,7 +43,7 @@ kwargs['classifiers'] = clssfrs
# Get the version string. Cannot do this by importing glymur!
version_file = os.path.join('glymur', 'version.py')
with open('glymur/version.py', 'rt') as fptr:
with open(version_file, 'rt') as fptr:
contents = fptr.read()
match = re.search('version\s*=\s*"(?P<version>\d*.\d*.\d*.*)"\n', contents)
kwargs['version'] = match.group('version')