From b6a17d60f1a4e5bbf388c30d0c290fb749381c4d Mon Sep 17 00:00:00 2001 From: John Evans Date: Wed, 5 Mar 2014 21:17:35 -0500 Subject: [PATCH] Starting to implement cinema2k support. #139 Need to add scikit-image with freeimage backend in order to read 16-bit TIFFs. --- glymur/jp2k.py | 61 ++++++++++++++++++++++++++++- glymur/test/test_conformance.py | 54 ++++++++++++++++--------- glymur/test/test_opj_suite_write.py | 10 +++++ 3 files changed, 106 insertions(+), 19 deletions(-) diff --git a/glymur/jp2k.py b/glymur/jp2k.py index 6db0198..04fa23e 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -219,6 +219,63 @@ class Jp2k(Jp2kBox): cparams.tcp_numlayers = 1 cparams.cp_disto_alloc = 1 + if 'cinema2K' in kwargs: + cparams.cp_rsiz = kwargs['cinema2K'] + # No tiling + cparams.tile_size_on = opj2.FALSE + cparams.cp_tdx = 1 + cparams.cp_tdy = 1 + + # One tile part for each component. + cparams.tp_cflag = ord('C') + cparams.tp_on = 1 + + # tile and image shall be as (0,0) + cparams.cp_tx0 = 0 + cparams.cp_ty0 = 0 + cparams.image_offset_x0 = 0 + cparams.image_offset_y0 = 0 + + # Codeblock size = 32 * 32 + cparams.cblockw_init = 32 + cparams.cblockh_init = 32 + + # code block style, no mode switch enabled. + cparams.mode = 0 + + # no ROI + cparams.roi_compno = -1 + + # no subsampling + cparams.subsampling_dx = 1 + cparams.subsampling_dy = 1 + + # 9-7 transform + cparams.irreversible = 1 + + # number of layers + if cparams.tcp_layers > 1: + # TODO: warning or error + cparams.tcp_numlayers = 1 + + if cparams.numresolution > 6: + # TODO: warning or error + cparams.numresolution = 6 + + # precincts + cparams.csty |= 0x01 + cparams.res_spec = cparams.numresolution - 1 + for j in range(cparams.res_spec): + cparams.prcw_init[i] = 256 + cparams.prch_init[i] = 256 + + # Progression order shall be CPRL + cparams.prog_order = PROGRESSION_ORDER['CPRL'] + + # progression order changes not allowed for 2K + cparams.numpocs = 0 + return cparams + if 'cbsize' in kwargs: cparams.cblockw_init = kwargs['cbsize'][1] cparams.cblockh_init = kwargs['cbsize'][0] @@ -340,6 +397,8 @@ class Jp2k(Jp2kBox): Image data to be written to file. cbsize : tuple, optional Code block size (DY, DX). + cinema2K : int, optional + either 24 or 48 colorspace : str, optional Either 'rgb' or 'gray'. cratios : iterable @@ -473,7 +532,7 @@ class Jp2k(Jp2kBox): def _write_openjp2(self, img_array, verbose=False, **kwargs): """ - Write JPEG 2000 file using OpenJPEG 1.5 interface. + Write JPEG 2000 file using OpenJPEG 2.0 interface. """ cparams, colorspace = self._process_write_inputs(img_array, **kwargs) diff --git a/glymur/test/test_conformance.py b/glymur/test/test_conformance.py index 8f4496d..765f2f6 100644 --- a/glymur/test/test_conformance.py +++ b/glymur/test/test_conformance.py @@ -11,6 +11,7 @@ import os from os.path import join import re import sys +import tempfile import unittest import glymur @@ -27,6 +28,41 @@ except KeyError: OPJ_DATA_ROOT = None +@unittest.skipIf(sys.hexversion < 0x03020000, + "Requires features introduced in 3.2 (assertWarns)") +class TestSuiteConformance(unittest.TestCase): + """Test suite for conformance.""" + + def setUp(self): + self.j2kfile = glymur.data.goodstuff() + + def tearDown(self): + pass + + @unittest.skipIf(re.match(r"""1\.[0123]""", + glymur.version.openjpeg_version) is not None, + "Needs 1.3+ to catch this.") + def test_truncated_eoc(self): + """Has one byte shaved off of EOC marker.""" + with open(self.j2kfile, 'rb') as ifile: + data = ifile.read() + with tempfile.NamedTemporaryFile(suffix='.j2k') as ofile: + ofile.write(data[:-1]) + ofile.flush() + + j2k = Jp2k(ofile.name) + with self.assertWarns(UserWarning): + codestream = j2k.get_codestream(header_only=False) + + # 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): + j2k.read(rlevel=-1) + + @unittest.skipIf(FORMAT_CORPUS_DATA_ROOT is None, "FORMAT_CORPUS_DATA_ROOT environment variable not set") @unittest.skipIf(sys.hexversion < 0x03020000, @@ -34,24 +70,6 @@ except KeyError: 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 self.assertWarns(UserWarning): - codestream = j2k.get_codestream(header_only=False) - - # 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): - j2k.read(rlevel=-1) - @unittest.skipIf(re.match(r"""1\.[01234]""", glymur.version.openjpeg_version) is not None, "Needs 1.4+ to catch this.") diff --git a/glymur/test/test_opj_suite_write.py b/glymur/test/test_opj_suite_write.py index 22a99e3..07d623f 100644 --- a/glymur/test/test_opj_suite_write.py +++ b/glymur/test/test_opj_suite_write.py @@ -38,6 +38,16 @@ class TestSuiteWrite(unittest.TestCase): def tearDown(self): pass + @unittest.skip("Cannot read input image using PILLOW???") + def test_NR_ENC_X_4_2K_24_185_CBR_WB_000_tif_15_encode(self): + relfile = 'input/nonregression/X_4_2K_24_185_CBR_WB_000.tif' + import pdb; pdb.set_trace() + infile = opj_data_file(relfile) + data = read_image(infile) + with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: + j = Jp2k(tfile.name, 'wb') + j.write(data, 'cinema2K', 24) + def test_NR_ENC_Bretagne1_ppm_1_encode(self): """NR-ENC-Bretagne1.ppm-1-encode""" infile = opj_data_file('input/nonregression/Bretagne1.ppm')