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.
This commit is contained in:
parent
185f4da073
commit
ff849df520
6 changed files with 456 additions and 160 deletions
|
|
@ -7,6 +7,7 @@ Wraps individual functions in openjp2 library.
|
|||
import ctypes
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
from .config import glymur_config
|
||||
|
||||
|
|
@ -138,6 +139,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.
|
||||
|
|
@ -201,6 +209,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.
|
||||
|
|
@ -392,6 +407,47 @@ 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]))
|
||||
msg += textwrap.indent(textstr, ' ' * 12)
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -433,6 +489,14 @@ class ImageCompType(ctypes.Structure):
|
|||
if _MINOR == '1':
|
||||
_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):
|
||||
"""Defines image data and characteristics.
|
||||
|
||||
|
|
@ -463,6 +527,27 @@ 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.
|
||||
|
|
@ -492,6 +577,13 @@ class ImageComptParmType(ctypes.Structure):
|
|||
# signed (1) / unsigned (0)
|
||||
("sgnd", 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 TccpInfo(ctypes.Structure):
|
||||
"""Tile-component coding parameters information.
|
||||
|
|
|
|||
144
glymur/lib/test/fixtures.py
Normal file
144
glymur/lib/test/fixtures.py
Normal 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"""
|
||||
77
glymur/lib/test/test_printing.py
Normal file
77
glymur/lib/test/test_printing.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# -*- 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('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)
|
||||
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue