Starting on the _write method.
This commit is contained in:
parent
c03f0caedf
commit
19336fc15e
4 changed files with 89 additions and 5 deletions
|
|
@ -63,7 +63,8 @@ class Jp2kBox(object):
|
||||||
def _write(self, f):
|
def _write(self, f):
|
||||||
"""Must be implemented in a subclass.
|
"""Must be implemented in a subclass.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError("Not supported for this box.")
|
msg = "Not supported for {0} box.".format(self.longname)
|
||||||
|
raise NotImplementedError(msg)
|
||||||
|
|
||||||
def _parse_superbox(self, f):
|
def _parse_superbox(self, f):
|
||||||
"""Parse a superbox (box consisting of nothing but other boxes.
|
"""Parse a superbox (box consisting of nothing but other boxes.
|
||||||
|
|
@ -617,8 +618,8 @@ class FileTypeBox(Jp2kBox):
|
||||||
self.brand = 'jp2 '
|
self.brand = 'jp2 '
|
||||||
if 'minor_version' not in kwargs.keys():
|
if 'minor_version' not in kwargs.keys():
|
||||||
self.minor_version = 0
|
self.minor_version = 0
|
||||||
if 'compatibility_box' not in kwargs.keys():
|
if 'compatibility_list' not in kwargs.keys():
|
||||||
self.compatibility_box = ['jp2 ']
|
self.compatibility_list = ['jp2 ']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
lst = [Jp2kBox.__str__(self),
|
lst = [Jp2kBox.__str__(self),
|
||||||
|
|
@ -629,6 +630,18 @@ class FileTypeBox(Jp2kBox):
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
def _write(self, f):
|
||||||
|
"""Write a File Type box to file.
|
||||||
|
"""
|
||||||
|
length = 16 + 4*len(self.compatibility_list)
|
||||||
|
f.write(struct.pack('>I', length))
|
||||||
|
f.write('ftyp'.encode())
|
||||||
|
f.write(self.brand.encode())
|
||||||
|
f.write(struct.pack('>I', self.minor_version))
|
||||||
|
|
||||||
|
for item in self.compatibility_list:
|
||||||
|
f.write(item.encode())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse(f, id, offset, length):
|
def _parse(f, id, offset, length):
|
||||||
"""Parse JPEG 2000 file type box.
|
"""Parse JPEG 2000 file type box.
|
||||||
|
|
@ -876,6 +889,21 @@ class JP2HeaderBox(Jp2kBox):
|
||||||
msg += ''.join(strs)
|
msg += ''.join(strs)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
def _write(self, f):
|
||||||
|
"""Write a JP2 Header box to file.
|
||||||
|
"""
|
||||||
|
# Write the contained boxes, then come back and write the length.
|
||||||
|
orig_pos = f.tell()
|
||||||
|
f.write(struct.pack('>I', 0))
|
||||||
|
f.write('jp2h'.encode())
|
||||||
|
for box in self.box:
|
||||||
|
box._write(f)
|
||||||
|
|
||||||
|
end_pos = f.tell()
|
||||||
|
f.seek(orig_pos)
|
||||||
|
f.write(struct.pack('>I', end_pos - orig_pos))
|
||||||
|
f.seek(end_pos)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse(f, id, offset, length):
|
def _parse(f, id, offset, length):
|
||||||
"""Parse JPEG 2000 header box.
|
"""Parse JPEG 2000 header box.
|
||||||
|
|
@ -938,6 +966,13 @@ class JPEG2000SignatureBox(Jp2kBox):
|
||||||
msg = msg.format(*self.signature)
|
msg = msg.format(*self.signature)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
def _write(self, f):
|
||||||
|
"""Write a JPEG 2000 Signature box to file.
|
||||||
|
"""
|
||||||
|
f.write(struct.pack('>I', 12))
|
||||||
|
f.write(self.id.encode())
|
||||||
|
f.write(struct.pack('>BBBB', *self.signature))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse(f, id, offset, length):
|
def _parse(f, id, offset, length):
|
||||||
"""Parse JPEG 2000 signature box.
|
"""Parse JPEG 2000 signature box.
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ import numpy as np
|
||||||
|
|
||||||
from .codestream import Codestream
|
from .codestream import Codestream
|
||||||
from .core import progression_order
|
from .core import progression_order
|
||||||
from .jp2box import Jp2kBox
|
from .core import SRGB
|
||||||
|
from .jp2box import *
|
||||||
from .lib import openjp2 as opj2
|
from .lib import openjp2 as opj2
|
||||||
|
|
||||||
_cspace_map = {'rgb': opj2._CLRSPC_SRGB,
|
_cspace_map = {'rgb': opj2._CLRSPC_SRGB,
|
||||||
|
|
@ -398,6 +399,26 @@ class Jp2k(Jp2kBox):
|
||||||
|
|
||||||
self._parse()
|
self._parse()
|
||||||
|
|
||||||
|
def tojp2(self, filename):
|
||||||
|
"""Write a codestream, wrapping it in the JP2 format.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
filename : str
|
||||||
|
JP2 file to be created from a raw codestream.
|
||||||
|
"""
|
||||||
|
boxes = [JPEG2000SignatureBox(),
|
||||||
|
FileTypeBox(),
|
||||||
|
JP2HeaderBox(),
|
||||||
|
ContiguousCodestreamBox()]
|
||||||
|
boxes[2].box = [ImageHeaderBox(height=1456,
|
||||||
|
width=2592,
|
||||||
|
num_components=3),
|
||||||
|
ColourSpecificationBox(colorspace=SRGB)]
|
||||||
|
with open(filename, 'wb') as fp:
|
||||||
|
for box in boxes:
|
||||||
|
box._write(fp)
|
||||||
|
|
||||||
def read(self, reduce=0, layer=0, area=None, tile=None, verbose=False):
|
def read(self, reduce=0, layer=0, area=None, tile=None, verbose=False):
|
||||||
"""Read a JPEG 2000 image.
|
"""Read a JPEG 2000 image.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,4 @@ from .test_printing import TestPrinting as printing
|
||||||
from .test_opj_suite import TestSuite as suite
|
from .test_opj_suite import TestSuite as suite
|
||||||
from .test_opj_suite_write import TestSuiteWrite as suitew
|
from .test_opj_suite_write import TestSuiteWrite as suitew
|
||||||
from .test_opj_suite_neg import TestSuiteNegative as suiteneg
|
from .test_opj_suite_neg import TestSuiteNegative as suiteneg
|
||||||
|
from .test_jp2box import TestJp2Boxes as box
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import doctest
|
import doctest
|
||||||
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
import glymur
|
import glymur
|
||||||
|
from glymur import Jp2k
|
||||||
from glymur.jp2box import *
|
from glymur.jp2box import *
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -18,6 +20,26 @@ def load_tests(loader, tests, ignore):
|
||||||
"Missing openjp2 library.")
|
"Missing openjp2 library.")
|
||||||
class TestJp2Boxes(unittest.TestCase):
|
class TestJp2Boxes(unittest.TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
# We need a raw codestream, so use the one in nemo.jp2.
|
||||||
|
jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||||
|
"data/nemo.jp2")
|
||||||
|
j = Jp2k(jp2file)
|
||||||
|
c = [box for box in j.box if box.id == 'jp2c'][0]
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(suffix='.jp2', delete=False) as ofile:
|
||||||
|
with open(jp2file, 'rb') as ifile:
|
||||||
|
# Everything up until the jp2c box.
|
||||||
|
ifile.seek(c.offset+8)
|
||||||
|
ofile.write(ifile.read(c.length))
|
||||||
|
|
||||||
|
cls.raw_codestream = ofile.name
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
os.unlink(cls.raw_codestream)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.jp2file = pkg_resources.resource_filename(glymur.__name__,
|
self.jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||||
"data/nemo.jp2")
|
"data/nemo.jp2")
|
||||||
|
|
@ -35,7 +57,7 @@ class TestJp2Boxes(unittest.TestCase):
|
||||||
b = glymur.jp2box.FileTypeBox()
|
b = glymur.jp2box.FileTypeBox()
|
||||||
self.assertEqual(b.brand, 'jp2 ')
|
self.assertEqual(b.brand, 'jp2 ')
|
||||||
self.assertEqual(b.minor_version, 0)
|
self.assertEqual(b.minor_version, 0)
|
||||||
self.assertEqual(b.compatibility_box, ['jp2 '])
|
self.assertEqual(b.compatibility_list, ['jp2 '])
|
||||||
|
|
||||||
def test_default_ImageHeaderBox(self):
|
def test_default_ImageHeaderBox(self):
|
||||||
# Should be able to instantiate an image header box.
|
# Should be able to instantiate an image header box.
|
||||||
|
|
@ -85,5 +107,10 @@ class TestJp2Boxes(unittest.TestCase):
|
||||||
self.assertEqual(b.id, 'jp2c')
|
self.assertEqual(b.id, 'jp2c')
|
||||||
self.assertEqual(b.main_header, [])
|
self.assertEqual(b.main_header, [])
|
||||||
|
|
||||||
|
def test_tojp2(self):
|
||||||
|
j = Jp2k(self.raw_codestream)
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||||
|
j.tojp2(tfile.name)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue