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):
|
||||
"""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):
|
||||
"""Parse a superbox (box consisting of nothing but other boxes.
|
||||
|
|
@ -617,8 +618,8 @@ class FileTypeBox(Jp2kBox):
|
|||
self.brand = 'jp2 '
|
||||
if 'minor_version' not in kwargs.keys():
|
||||
self.minor_version = 0
|
||||
if 'compatibility_box' not in kwargs.keys():
|
||||
self.compatibility_box = ['jp2 ']
|
||||
if 'compatibility_list' not in kwargs.keys():
|
||||
self.compatibility_list = ['jp2 ']
|
||||
|
||||
def __str__(self):
|
||||
lst = [Jp2kBox.__str__(self),
|
||||
|
|
@ -629,6 +630,18 @@ class FileTypeBox(Jp2kBox):
|
|||
|
||||
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
|
||||
def _parse(f, id, offset, length):
|
||||
"""Parse JPEG 2000 file type box.
|
||||
|
|
@ -876,6 +889,21 @@ class JP2HeaderBox(Jp2kBox):
|
|||
msg += ''.join(strs)
|
||||
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
|
||||
def _parse(f, id, offset, length):
|
||||
"""Parse JPEG 2000 header box.
|
||||
|
|
@ -938,6 +966,13 @@ class JPEG2000SignatureBox(Jp2kBox):
|
|||
msg = msg.format(*self.signature)
|
||||
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
|
||||
def _parse(f, id, offset, length):
|
||||
"""Parse JPEG 2000 signature box.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ import numpy as np
|
|||
|
||||
from .codestream import Codestream
|
||||
from .core import progression_order
|
||||
from .jp2box import Jp2kBox
|
||||
from .core import SRGB
|
||||
from .jp2box import *
|
||||
from .lib import openjp2 as opj2
|
||||
|
||||
_cspace_map = {'rgb': opj2._CLRSPC_SRGB,
|
||||
|
|
@ -398,6 +399,26 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
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):
|
||||
"""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_write import TestSuiteWrite as suitew
|
||||
from .test_opj_suite_neg import TestSuiteNegative as suiteneg
|
||||
from .test_jp2box import TestJp2Boxes as box
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import doctest
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
import pkg_resources
|
||||
|
||||
import glymur
|
||||
from glymur import Jp2k
|
||||
from glymur.jp2box import *
|
||||
|
||||
|
||||
|
|
@ -18,6 +20,26 @@ def load_tests(loader, tests, ignore):
|
|||
"Missing openjp2 library.")
|
||||
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):
|
||||
self.jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||
"data/nemo.jp2")
|
||||
|
|
@ -35,7 +57,7 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
b = glymur.jp2box.FileTypeBox()
|
||||
self.assertEqual(b.brand, 'jp2 ')
|
||||
self.assertEqual(b.minor_version, 0)
|
||||
self.assertEqual(b.compatibility_box, ['jp2 '])
|
||||
self.assertEqual(b.compatibility_list, ['jp2 '])
|
||||
|
||||
def test_default_ImageHeaderBox(self):
|
||||
# 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.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__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue