Merge branch 'issue104' of https://github.com/quintusdias/glymur into issue104

Conflicts:
	glymur/_uuid_io/Exif.py
	glymur/_uuid_io/__init__.py
	glymur/jp2box.py
	glymur/test/test_jp2box_uuid.py
	glymur/test/test_jp2k.py
This commit is contained in:
jevans 2014-01-25 15:43:03 -05:00
commit 84c50c8499
11 changed files with 219 additions and 193 deletions

View file

@ -3,6 +3,7 @@
Handlers for Exif UUIDs. Be nice if we would find a standard for this. Handlers for Exif UUIDs. Be nice if we would find a standard for this.
""" """
import pprint import pprint
import re
import struct import struct
import sys import sys
import warnings import warnings

View file

@ -19,7 +19,6 @@ import os
import pprint import pprint
import struct import struct
import sys import sys
import traceback
import uuid import uuid
import warnings import warnings
import xml.etree.cElementTree as ET import xml.etree.cElementTree as ET
@ -563,11 +562,11 @@ class CodestreamHeaderBox(Jp2kBox):
box : list box : list
List of boxes contained in this superbox. List of boxes contained in this superbox.
""" """
def __init__(self, box=[], length=0, offset=-1): def __init__(self, box=None, length=0, offset=-1):
Jp2kBox.__init__(self, box_id='jpch', longname='Codestream Header') Jp2kBox.__init__(self, box_id='jpch', longname='Codestream Header')
self.length = length self.length = length
self.offset = offset self.offset = offset
self.box = box self.box = box if box is not None else []
def __repr__(self): def __repr__(self):
msg = "glymur.jp2box.CodestreamHeaderBox(box={0})".format(self.box) msg = "glymur.jp2box.CodestreamHeaderBox(box={0})".format(self.box)
@ -625,12 +624,12 @@ class CompositingLayerHeaderBox(Jp2kBox):
box : list box : list
List of boxes contained in this superbox. List of boxes contained in this superbox.
""" """
def __init__(self, box=[], length=0, offset=-1): def __init__(self, box=None, length=0, offset=-1):
Jp2kBox.__init__(self, box_id='jplh', Jp2kBox.__init__(self, box_id='jplh',
longname='Compositing Layer Header') longname='Compositing Layer Header')
self.length = length self.length = length
self.offset = offset self.offset = offset
self.box = [] self.box = box if box is not None else []
def __repr__(self): def __repr__(self):
msg = "glymur.jp2box.CompositingLayerHeaderBox(box={0})" msg = "glymur.jp2box.CompositingLayerHeaderBox(box={0})"
@ -1073,11 +1072,11 @@ class AssociationBox(Jp2kBox):
box : list box : list
List of boxes contained in this superbox. List of boxes contained in this superbox.
""" """
def __init__(self, box=[], length=0, offset=-1): def __init__(self, box=None, length=0, offset=-1):
Jp2kBox.__init__(self, box_id='asoc', longname='Association') Jp2kBox.__init__(self, box_id='asoc', longname='Association')
self.length = length self.length = length
self.offset = offset self.offset = offset
self.box = box self.box = box if box is not None else []
def __repr__(self): def __repr__(self):
msg = "glymur.jp2box.AssociationBox(box={0})".format(self.box) msg = "glymur.jp2box.AssociationBox(box={0})".format(self.box)
@ -1135,11 +1134,11 @@ class JP2HeaderBox(Jp2kBox):
box : list box : list
List of boxes contained in this superbox. List of boxes contained in this superbox.
""" """
def __init__(self, box=[], length=0, offset=-1): def __init__(self, box=None, length=0, offset=-1):
Jp2kBox.__init__(self, box_id='jp2h', longname='JP2 Header') Jp2kBox.__init__(self, box_id='jp2h', longname='JP2 Header')
self.length = length self.length = length
self.offset = offset self.offset = offset
self.box = box self.box = box if box is not None else []
def __repr__(self): def __repr__(self):
msg = "glymur.jp2box.JP2HeaderBox(box={0})".format(self.box) msg = "glymur.jp2box.JP2HeaderBox(box={0})".format(self.box)
@ -1621,11 +1620,11 @@ class ResolutionBox(Jp2kBox):
box : list box : list
List of boxes contained in this superbox. List of boxes contained in this superbox.
""" """
def __init__(self, box=[], length=0, offset=-1): def __init__(self, box=None, length=0, offset=-1):
Jp2kBox.__init__(self, box_id='res ', longname='Resolution') Jp2kBox.__init__(self, box_id='res ', longname='Resolution')
self.length = length self.length = length
self.offset = offset self.offset = offset
self.box = box self.box = box if box is not None else []
def __repr__(self): def __repr__(self):
msg = "glymur.jp2box.ResolutionBox(box={0})" msg = "glymur.jp2box.ResolutionBox(box={0})"
@ -2040,11 +2039,11 @@ class UUIDInfoBox(Jp2kBox):
box : list box : list
List of boxes contained in this superbox. List of boxes contained in this superbox.
""" """
def __init__(self, box=[], length=0, offset=-1): def __init__(self, box=None, length=0, offset=-1):
Jp2kBox.__init__(self, box_id='uinf', longname='UUIDInfo') Jp2kBox.__init__(self, box_id='uinf', longname='UUIDInfo')
self.length = length self.length = length
self.offset = offset self.offset = offset
self.box = box self.box = box if box is not None else []
def __repr__(self): def __repr__(self):
msg = "glymur.jp2box.UUIDInfoBox(box={0})".format(self.box) msg = "glymur.jp2box.UUIDInfoBox(box={0})".format(self.box)

View file

@ -11,6 +11,19 @@ import numpy as np
import glymur import glymur
# The Python XMP Toolkit may be used for XMP UUIDs, but only if available and
# if the version is at least 2.0.0.
try:
import libxmp
if hasattr(libxmp, 'version') and re.match(r'''[2-9].\d*.\d*''',
libxmp.version.VERSION):
from libxmp import XMPMeta
HAS_PYTHON_XMP_TOOLKIT = True
else:
HAS_PYTHON_XMP_TOOLKIT = False
except ImportError:
HAS_PYTHON_XMP_TOOLKIT = False
# Need to know of the libopenjp2 version is the official 2.0.0 release and NOT # Need to know of the libopenjp2 version is the official 2.0.0 release and NOT
# the 2.0+ development version. # the 2.0+ development version.
OPENJP2_IS_V2_OFFICIAL = False OPENJP2_IS_V2_OFFICIAL = False
@ -170,90 +183,96 @@ def read_pgx_header(pgx_file):
nemo_xmp_box = """UUID Box (uuid) @ (77, 3146) nemo_xmp_box = """UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP) UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data: UUID Data: <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<ns0:xmpmeta xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:ns3="http://ns.adobe.com/tiff/1.0/" xmlns:ns4="http://ns.adobe.com/exif/1.0/" xmlns:ns5="http://ns.adobe.com/photoshop/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="Exempi + XMP Core 5.1.2"> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Exempi + XMP Core 4.4.0">
<rdf:RDF> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""> <rdf:Description rdf:about=""
<ns2:CreatorTool>Google</ns2:CreatorTool> xmlns:xmp="http://ns.adobe.com/xap/1.0/">
<ns2:CreateDate>2013-02-09T14:47:53</ns2:CreateDate> <xmp:CreatorTool>Google</xmp:CreatorTool>
</rdf:Description> <xmp:CreateDate>2013-02-09T14:47:53</xmp:CreateDate>
<rdf:Description rdf:about=""> </rdf:Description>
<ns3:YCbCrPositioning>1</ns3:YCbCrPositioning> <rdf:Description rdf:about=""
<ns3:XResolution>72/1</ns3:XResolution> xmlns:tiff="http://ns.adobe.com/tiff/1.0/">
<ns3:YResolution>72/1</ns3:YResolution> <tiff:YCbCrPositioning>1</tiff:YCbCrPositioning>
<ns3:ResolutionUnit>2</ns3:ResolutionUnit> <tiff:XResolution>72/1</tiff:XResolution>
<ns3:Make>HTC</ns3:Make> <tiff:YResolution>72/1</tiff:YResolution>
<ns3:Model>HTC Glacier</ns3:Model> <tiff:ResolutionUnit>2</tiff:ResolutionUnit>
<ns3:ImageWidth>2592</ns3:ImageWidth> <tiff:Make>HTC</tiff:Make>
<ns3:ImageLength>1456</ns3:ImageLength> <tiff:Model>HTC Glacier</tiff:Model>
<ns3:BitsPerSample> <tiff:ImageWidth>2592</tiff:ImageWidth>
<rdf:Seq> <tiff:ImageLength>1456</tiff:ImageLength>
<rdf:li>8</rdf:li> <tiff:BitsPerSample>
<rdf:li>8</rdf:li> <rdf:Seq>
<rdf:li>8</rdf:li> <rdf:li>8</rdf:li>
</rdf:Seq> <rdf:li>8</rdf:li>
</ns3:BitsPerSample> <rdf:li>8</rdf:li>
<ns3:PhotometricInterpretation>2</ns3:PhotometricInterpretation> </rdf:Seq>
<ns3:SamplesPerPixel>3</ns3:SamplesPerPixel> </tiff:BitsPerSample>
<ns3:WhitePoint> <tiff:PhotometricInterpretation>2</tiff:PhotometricInterpretation>
<rdf:Seq> <tiff:SamplesPerPixel>3</tiff:SamplesPerPixel>
<rdf:li>1343036288/4294967295</rdf:li> <tiff:WhitePoint>
<rdf:li>1413044224/4294967295</rdf:li> <rdf:Seq>
</rdf:Seq> <rdf:li>1343036288/4294967295</rdf:li>
</ns3:WhitePoint> <rdf:li>1413044224/4294967295</rdf:li>
<ns3:PrimaryChromaticities> </rdf:Seq>
<rdf:Seq> </tiff:WhitePoint>
<rdf:li>2748779008/4294967295</rdf:li> <tiff:PrimaryChromaticities>
<rdf:li>1417339264/4294967295</rdf:li> <rdf:Seq>
<rdf:li>1288490240/4294967295</rdf:li> <rdf:li>2748779008/4294967295</rdf:li>
<rdf:li>2576980480/4294967295</rdf:li> <rdf:li>1417339264/4294967295</rdf:li>
<rdf:li>644245120/4294967295</rdf:li> <rdf:li>1288490240/4294967295</rdf:li>
<rdf:li>257698032/4294967295</rdf:li> <rdf:li>2576980480/4294967295</rdf:li>
</rdf:Seq> <rdf:li>644245120/4294967295</rdf:li>
</ns3:PrimaryChromaticities> <rdf:li>257698032/4294967295</rdf:li>
</rdf:Description> </rdf:Seq>
<rdf:Description rdf:about=""> </tiff:PrimaryChromaticities>
<ns4:ColorSpace>1</ns4:ColorSpace> </rdf:Description>
<ns4:PixelXDimension>2528</ns4:PixelXDimension> <rdf:Description rdf:about=""
<ns4:PixelYDimension>1424</ns4:PixelYDimension> xmlns:exif="http://ns.adobe.com/exif/1.0/">
<ns4:FocalLength>353/100</ns4:FocalLength> <exif:ColorSpace>1</exif:ColorSpace>
<ns4:GPSAltitudeRef>0</ns4:GPSAltitudeRef> <exif:PixelXDimension>2528</exif:PixelXDimension>
<ns4:GPSAltitude>0/1</ns4:GPSAltitude> <exif:PixelYDimension>1424</exif:PixelYDimension>
<ns4:GPSMapDatum>WGS-84</ns4:GPSMapDatum> <exif:FocalLength>353/100</exif:FocalLength>
<ns4:DateTimeOriginal>2013-02-09T14:47:53</ns4:DateTimeOriginal> <exif:GPSAltitudeRef>0</exif:GPSAltitudeRef>
<ns4:ISOSpeedRatings> <exif:GPSAltitude>0/1</exif:GPSAltitude>
<rdf:Seq> <exif:GPSMapDatum>WGS-84</exif:GPSMapDatum>
<rdf:li>76</rdf:li> <exif:DateTimeOriginal>2013-02-09T14:47:53</exif:DateTimeOriginal>
</rdf:Seq> <exif:ISOSpeedRatings>
</ns4:ISOSpeedRatings> <rdf:Seq>
<ns4:ExifVersion>0220</ns4:ExifVersion> <rdf:li>76</rdf:li>
<ns4:FlashpixVersion>0100</ns4:FlashpixVersion> </rdf:Seq>
<ns4:ComponentsConfiguration> </exif:ISOSpeedRatings>
<rdf:Seq> <exif:ExifVersion>0220</exif:ExifVersion>
<rdf:li>1</rdf:li> <exif:FlashpixVersion>0100</exif:FlashpixVersion>
<rdf:li>2</rdf:li> <exif:ComponentsConfiguration>
<rdf:li>3</rdf:li> <rdf:Seq>
<rdf:li>0</rdf:li> <rdf:li>1</rdf:li>
</rdf:Seq> <rdf:li>2</rdf:li>
</ns4:ComponentsConfiguration> <rdf:li>3</rdf:li>
<ns4:GPSLatitude>42,20.56N</ns4:GPSLatitude> <rdf:li>0</rdf:li>
<ns4:GPSLongitude>71,5.29W</ns4:GPSLongitude> </rdf:Seq>
<ns4:GPSTimeStamp>2013-02-09T19:47:53Z</ns4:GPSTimeStamp> </exif:ComponentsConfiguration>
<ns4:GPSProcessingMethod>NETWORK</ns4:GPSProcessingMethod> <exif:GPSLatitude>42,20.56N</exif:GPSLatitude>
</rdf:Description> <exif:GPSLongitude>71,5.29W</exif:GPSLongitude>
<rdf:Description rdf:about=""> <exif:GPSTimeStamp>2013-02-09T19:47:53Z</exif:GPSTimeStamp>
<ns5:DateCreated>2013-02-09T14:47:53</ns5:DateCreated> <exif:GPSProcessingMethod>NETWORK</exif:GPSProcessingMethod>
</rdf:Description> </rdf:Description>
<rdf:Description rdf:about=""> <rdf:Description rdf:about=""
<dc:Creator> xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<rdf:Seq> <photoshop:DateCreated>2013-02-09T14:47:53</photoshop:DateCreated>
<rdf:li>Glymur</rdf:li> </rdf:Description>
<rdf:li>Python XMP Toolkit</rdf:li> <rdf:Description rdf:about=""
</rdf:Seq> xmlns:dc="http://purl.org/dc/elements/1.1/">
</dc:Creator> <dc:Creator>
</rdf:Description> <rdf:Seq>
</rdf:RDF> <rdf:li>Glymur</rdf:li>
</ns0:xmpmeta>""" <rdf:li>Python XMP Toolkit</rdf:li>
</rdf:Seq>
</dc:Creator>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>"""
SimpleRDF = """<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'> SimpleRDF = """<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<rdf:Description rdf:about='Test:XMPCoreCoverage/kSimpleRDF' <rdf:Description rdf:about='Test:XMPCoreCoverage/kSimpleRDF'

View file

@ -894,9 +894,9 @@ class TestRepr(unittest.TestCase):
tree = ET.ElementTree(elt) tree = ET.ElementTree(elt)
box = glymur.jp2box.XMLBox(xml=tree) box = glymur.jp2box.XMLBox(xml=tree)
regexp = "glymur.jp2box.XMLBox" regexp = r"""glymur.jp2box.XMLBox"""
regexp += "\(xml=<(xml.etree.ElementTree.){0,1}ElementTree object " regexp += r"""\(xml=<(xml.etree.ElementTree.){0,1}ElementTree object """
regexp += "at 0x([a-f0-9]*)>\)" regexp += """at 0x([a-f0-9]*)>\)"""
if sys.hexversion < 0x03000000: if sys.hexversion < 0x03000000:
self.assertRegexpMatches(repr(box), regexp) self.assertRegexpMatches(repr(box), regexp)
@ -927,9 +927,9 @@ class TestRepr(unittest.TestCase):
# Since the raw_data parameter is a sequence of bytes which could be # Since the raw_data parameter is a sequence of bytes which could be
# quite long, don't bother trying to make it conform to eval(repr()). # quite long, don't bother trying to make it conform to eval(repr()).
regexp = "glymur.jp2box.UUIDBox\(" regexp = r"""glymur.jp2box.UUIDBox\("""
regexp += "the_uuid=UUID\('00000000-0000-0000-0000-000000000000'\),\s" regexp += """the_uuid=UUID\('00000000-0000-0000-0000-000000000000'\),\s"""
regexp += "raw_data=<byte\sarray\s10\selements>\)" regexp += """raw_data=<byte\sarray\s10\selements>\)"""
if sys.hexversion < 0x03000000: if sys.hexversion < 0x03000000:
self.assertRegexpMatches(repr(box), regexp) self.assertRegexpMatches(repr(box), regexp)

View file

@ -35,7 +35,9 @@ if sys.hexversion <= 0x03030000:
else: else:
from unittest.mock import patch from unittest.mock import patch
from libxmp import XMPMeta from .fixtures import HAS_PYTHON_XMP_TOOLKIT, OPJ_DATA_ROOT
if HAS_PYTHON_XMP_TOOLKIT:
from libxmp import XMPMeta
import glymur import glymur
from glymur import Jp2k from glymur import Jp2k

View file

@ -30,13 +30,14 @@ import warnings
import numpy as np import numpy as np
import pkg_resources import pkg_resources
import libxmp
from libxmp import XMPMeta
import glymur import glymur
from glymur import Jp2k from glymur import Jp2k
from .fixtures import OPENJP2_IS_V2_OFFICIAL from .fixtures import HAS_PYTHON_XMP_TOOLKIT, OPENJP2_IS_V2_OFFICIAL
if HAS_PYTHON_XMP_TOOLKIT:
import libxmp
from libxmp import XMPMeta
from .fixtures import OPJ_DATA_ROOT, opj_data_file from .fixtures import OPJ_DATA_ROOT, opj_data_file
@ -362,6 +363,8 @@ class TestJp2k(unittest.TestCase):
self.assertEqual(ET.tostring(jp2k.box[3].xml.getroot()), self.assertEqual(ET.tostring(jp2k.box[3].xml.getroot()),
b'<test>this is a test</test>') b'<test>this is a test</test>')
@unittest.skipIf(not HAS_PYTHON_XMP_TOOLKIT,
"Requires Python XMP Toolkit >= 2.0")
def test_xmp_attribute(self): def test_xmp_attribute(self):
"""Verify the XMP packet in the shipping example file can be read.""" """Verify the XMP packet in the shipping example file can be read."""
j = Jp2k(self.jp2file) j = Jp2k(self.jp2file)

View file

@ -1,10 +1,12 @@
# This file is part of glymur, a Python interface for accessing JPEG 2000. """
# This file is part of glymur, a Python interface for accessing JPEG 2000.
# http://glymur.readthedocs.org
# http://glymur.readthedocs.org
# Copyright 2013 John Evans
# Copyright 2013 John Evans
# License: MIT
License: MIT
"""
import sys import sys
import numpy as np import numpy as np