Merge branch 'issue254' into devel

This commit is contained in:
John Evans 2014-09-11 11:29:56 -04:00
commit 5c083a7f53
8 changed files with 205 additions and 143 deletions

View file

@ -1,34 +0,0 @@
#!/usr/bin/env python
import argparse
import sys
import glymur
description='Print JPEG2000 metadata.'
parser = argparse.ArgumentParser(description=description)
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 suppressed all details, 1 prints headers, 2 prints the full codestream'
parser.add_argument('-c', '--codestream',
help=chelp,
nargs=1,
type=int,
default=[0])
parser.add_argument('filename')
args = parser.parse_args()
if args.noxml:
glymur.set_printoptions(xml=False)
if args.short:
glymur.set_printoptions(short=True)
if args.codestream[0] == 0:
glymur.set_printoptions(codestream=False)
print_full_codestream = False
elif args.codestream[0] == 1:
print_full_codestream = False
else:
print_full_codestream = True
filename = args.filename
glymur.jp2dump(args.filename, codestream=print_full_codestream)

View file

@ -17,7 +17,7 @@ resolution level. ::
... display metadata?
=====================
There are two ways. From the unix command line, the script **jp2dump** is
There are two ways. From the command line, the script **jp2dump** is
available. ::
$ jp2dump /path/to/glymur/installation/data/nemo.jp2

View file

@ -27,10 +27,5 @@ but you should also be able to install Glymur via pip ::
$ pip install glymur
This will install a script **jp2dump** that can be used from the unix command
line for dumping JP2 metadata, so you should adjust your **$PATH**
environment variable 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 script **jp2dump** that can
be used from the command line line to print JPEG 2000 metadata.

View file

@ -9,7 +9,6 @@ __version__ = version.version
from .jp2k import Jp2k
from .jp2dump import jp2dump
from .jp2box import get_printoptions, set_printoptions
from .jp2box import get_parseoptions, set_parseoptions
from . import data

49
glymur/command_line.py Normal file
View file

@ -0,0 +1,49 @@
#!/usr/bin/env python
import argparse
import sys
from . import jp2dump, set_printoptions
def main():
description='Print JPEG2000 metadata.'
parser = argparse.ArgumentParser(description=description)
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 suppressed all details, '
chelp += '1 prints headers, 2 prints the full codestream'
parser.add_argument('-c', '--codestream',
help=chelp,
nargs=1,
type=int,
default=[0])
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)
print_full_codestream = False
elif codestream_level == 1:
print_full_codestream = False
else:
print_full_codestream = True
filename = args.filename
jp2dump(args.filename, codestream=print_full_codestream)

View file

@ -455,7 +455,9 @@ Contiguous Codestream Box (jp2c) @ (3223, 1132296)
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
CME marker segment @ (3305, 37)
"Created by OpenJPEG version 2.0.0"'''
nemo_dump_full = dump.format(_indent(nemo_xmp))
nemo_with_codestream_header = dump.format(_indent(nemo_xmp))
#nemo_dump_full = dump.format(_indent(nemo_xmp))
nemo_dump_short = r"""JPEG 2000 Signature Box (jP ) @ (0, 12)
File Type Box (ftyp) @ (12, 20)
@ -651,7 +653,7 @@ number_list_box = r"""Number List Box (nlst) @ (-1, 0)
Association[2]: compositing layer 0"""
goodstuff = r"""Codestream:
goodstuff_codestream_header = r"""Codestream:
SOC marker segment @ (0, 0)
SIZ marker segment @ (2, 47)
Profile: no profile
@ -686,3 +688,80 @@ goodstuff = r"""Codestream:
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

@ -31,7 +31,7 @@ else:
import lxml.etree as ET
import glymur
from glymur import Jp2k
from glymur import Jp2k, command_line
from . import fixtures
from .fixtures import OPJ_DATA_ROOT, opj_data_file
from .fixtures import text_gbr_27, text_gbr_33, text_gbr_34
@ -107,74 +107,6 @@ class TestPrinting(unittest.TestCase):
with self.assertRaises(TypeError):
glymur.set_printoptions(hi='low')
def test_propts_no_codestream_then_no_xml(self):
"""Verify printed output when codestream=False and xml=False, #162"""
# The print options should be persistent across invocations.
glymur.set_printoptions(codestream=False)
glymur.set_printoptions(xml=False)
with patch('sys.stdout', new=StringIO()) as fake_out:
glymur.jp2dump(self.jp2file)
actual = fake_out.getvalue().strip()
# Get rid of the filename line, as it is not set in stone.
lst = actual.split('\n')
lst = lst[1:]
actual = '\n'.join(lst)
self.assertEqual(actual, fixtures.nemo_dump_no_codestream_no_xml)
def test_printopt_no_codestr_or_xml(self):
"""Verify printed output when codestream=False and xml=False"""
glymur.set_printoptions(codestream=False, xml=False)
with patch('sys.stdout', new=StringIO()) as fake_out:
glymur.jp2dump(self.jp2file)
actual = fake_out.getvalue().strip()
# Get rid of the filename line, as it is not set in stone.
lst = actual.split('\n')
lst = lst[1:]
actual = '\n'.join(lst)
self.assertEqual(actual, fixtures.nemo_dump_no_codestream_no_xml)
def test_printoptions_no_codestream(self):
"""Verify printed output when codestream=False"""
glymur.set_printoptions(codestream=False)
with patch('sys.stdout', new=StringIO()) as fake_out:
glymur.jp2dump(self.jp2file)
actual = fake_out.getvalue().strip()
# Get rid of the filename line, as it is not set in stone.
lst = actual.split('\n')
lst = lst[1:]
actual = '\n'.join(lst)
self.assertEqual(actual, fixtures.nemo_dump_no_codestream)
def test_printoptions_no_xml(self):
"""Verify printed output when xml=False"""
glymur.set_printoptions(xml=False)
with patch('sys.stdout', new=StringIO()) as fake_out:
glymur.jp2dump(self.jp2file)
actual = fake_out.getvalue().strip()
# Get rid of the filename line, as it is not set in stone.
lst = actual.split('\n')
lst = lst[1:]
actual = '\n'.join(lst)
expected = fixtures.nemo_dump_no_xml
self.assertEqual(actual, expected)
def test_printoptions_short(self):
"""Verify printed output when short=True"""
glymur.set_printoptions(short=True)
with patch('sys.stdout', new=StringIO()) as fake_out:
glymur.jp2dump(self.jp2file)
actual = fake_out.getvalue().strip()
# Get rid of the filename line, as it is not set in stone.
lst = actual.split('\n')
lst = lst[1:]
actual = '\n'.join(lst)
self.assertEqual(actual, fixtures.nemo_dump_short)
def test_asoc_label_box(self):
"""verify printing of asoc, label boxes"""
# Construct a fake file with an asoc and a label box, as
@ -228,32 +160,6 @@ class TestPrinting(unittest.TestCase):
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
def test_jp2dump(self):
"""basic jp2dump test"""
with patch('sys.stdout', new=StringIO()) as fake_out:
glymur.jp2dump(self.jp2file)
actual = fake_out.getvalue().strip()
# Get rid of the filename line, as it is not set in stone.
lst = actual.split('\n')
lst = lst[1:]
actual = '\n'.join(lst)
self.assertEqual(actual, fixtures.nemo_dump_full)
def test_entire_file(self):
"""verify output from printing entire file"""
j = glymur.Jp2k(self.jp2file)
with patch('sys.stdout', new=StringIO()) as fake_out:
print(j)
actual = fake_out.getvalue().strip()
# Get rid of the filename line, as it is not set in stone.
lst = actual.split('\n')
lst = lst[1:]
actual = '\n'.join(lst)
self.assertEqual(actual, fixtures.nemo_dump_full)
def test_coc_segment(self):
"""verify printing of COC segment"""
j = glymur.Jp2k(self.jp2file)
@ -1113,5 +1019,71 @@ class TestPrintingOpjDataRoot(unittest.TestCase):
self.assertTrue(True)
if __name__ == "__main__":
unittest.main()
class TestJp2dump(unittest.TestCase):
"""Tests for verifying how jp2dump console script works."""
def setUp(self):
self.jpxfile = glymur.data.jpxfile()
self.jp2file = glymur.data.nemo()
self.j2kfile = glymur.data.goodstuff()
# Reset printoptions for every test.
glymur.set_printoptions(short=False, xml=True, codestream=True)
def tearDown(self):
pass
def run_jp2dump(self, args):
sys.argv = args
with patch('sys.stdout', new=StringIO()) as fake_out:
command_line.main()
actual = fake_out.getvalue().strip()
# Remove the file line, as that is filesystem-dependent.
lines = actual.split('\n')
actual = '\n'.join(lines[1:])
return actual
def test_default_nemo(self):
"""Should be able to dump a JP2 file's metadata with no codestream."""
actual = self.run_jp2dump(['', self.jp2file])
self.assertEqual(actual, fixtures.nemo_dump_no_codestream)
def test_codestream_0(self):
"""Verify dumping with -c 0, supressing all codestream details."""
actual = self.run_jp2dump(['', '-c', '0', self.jp2file])
self.assertEqual(actual, fixtures.nemo_dump_no_codestream)
def test_codestream_1(self):
"""Verify dumping with -c 1, print just the header."""
actual = self.run_jp2dump(['', '-c', '1', self.jp2file])
self.assertEqual(actual, fixtures.nemo_with_codestream_header)
def test_codestream_2(self):
"""Verify dumping with -c 2, full details."""
with patch('sys.stdout', new=StringIO()) as fake_out:
sys.argv = ['', '-c', '2', self.j2kfile]
command_line.main()
actual = fake_out.getvalue().strip()
self.assertIn(fixtures.goodstuff_with_full_header, actual)
def test_codestream_invalid(self):
"""Verify dumping with -c 3, not allowd."""
with self.assertRaises(ValueError):
sys.argv = ['', '-c', '3', self.jp2file]
command_line.main()
def test_short(self):
"""Verify dumping with -s, short option."""
actual = self.run_jp2dump(['', '-s', self.jp2file])
self.assertEqual(actual, fixtures.nemo_dump_short)
def test_suppress_xml(self):
"""Verify dumping with -x, suppress XML."""
actual = self.run_jp2dump(['', '-x', self.jp2file])
self.assertEqual(actual, fixtures.nemo_dump_no_codestream_no_xml)

View file

@ -12,7 +12,9 @@ kwargs = {'name': 'glymur',
'packages': ['glymur', 'glymur.data', 'glymur.test', 'glymur.lib',
'glymur.lib.test'],
'package_data': {'glymur': ['data/*.jp2', 'data/*.j2k', 'data/*.jpx']},
'scripts': ['bin/jp2dump'],
'entry_points': {
'console_scripts': ['jp2dump=glymur.command_line:main'],
},
'license': 'MIT',
'test_suite': 'glymur.test'}