我正在开发Android应用程序,该应用程序应该使用Google Camera的新深度图生成功能.
谷歌基本上描述了这里使用的元数据
我可以访问大多数元数据,但遗憾的是最重要的数据被编码为extendedXmp,我无法获得任何XMP解析库来正确解析它!
我尝试过Commons-Imaging,元数据提取器以及最近的Adobes XMPCore
XMPCore可能能够处理扩展版本,但没有文档如何让它来解析JPG文件中的数据,它假设原始XMP数据要传递
是否有正确的XMP解析实现,包括JPG文件的扩展部分,或者我只是做错了什么?
这是我的尝试:
使用Commons-Imaging:
try { String imageParser = new JpegImageParser().getXmpXml(new ByteSourceInputStream(imageStream, "img.jpg"), new HashMap()); Log.v(TAG, imageParser); } catch (ImageReadException e1) { // TODO Auto-generated catch block e1.printStackTrace(); }
使用元数据提取器
Metadata metadata = ImageMetadataReader.readMetadata( new BufferedInputStream(imageStream), false); XmpDirectory xmp = metadata .getDirectory(XmpDirectory.class); XMPMeta xmpMeta = xmp.getXMPMeta(); String uri = "http://ns.google.com/photos/1.0/depthmap/"; Log.v(TAG, xmpMeta.doesPropertyExist(uri, "GDepth:Format") + " " ); try { XMPProperty hasExtendedXMP = xmpMeta.getProperty("http://ns.adobe.com/xmp/note/", "xmpNote:HasExtendedXMP"); Log.v(TAG, hasExtendedXMP.getValue().toString() + " " + new String(Base64.decode(hasExtendedXMP.getValue().toString(), Base64.DEFAULT))); } catch (XMPException e) { e.printStackTrace(); }
dragon66.. 7
最初,Adobe并未预期XMP数据长度将超过一个JPEG段(约64K)的限制,并且他们的XMP规范声明XMP数据必须合二为一.后来当他们发现单个JPEG APP1段不足以容纳XMP数据时,他们改变了他们的规范,以允许整个XMP数据的多个APP1段.数据分为两部分:标准XMP和ExtendedXMP.标准XMP部件是带有包装器的"普通"XMP结构,而ExtendedXMP部件没有包装器.ExtendedXMP数据可以进一步划分为多个APP1.
以下引用来自Adobe XMP规范第3部分,适用于ExtendedXMP块作为JPEG APP1:
每个块在单独的APP1标记段内写入JPEG文件.每个ExtendedXMP标记段包含:
以空值终止的签名字符串" http://ns.adobe.com/xmp/extension/ ".
128位GUID存储为32字节ASCII十六进制字符串,资本AF,无空终止.GUID是完整ExtendedXMP序列化的128位MD5摘要.
ExtendedXMP序列化的全长,为32位无符号整数
该部分的偏移量为32位无符号整数.
ExtendedXMP的一部分
我们可以看到除了以null结尾的字符串作为ExtendedXMP数据的id之外,还有一个GUID应该与在标准XMP部分中找到的值相同.偏移量用于连接ExtendedXMP的不同部分 - 因此ExtendedXMP APP1的顺序可能甚至不是有序的.然后是实际的数据部分,这就是为什么@Matt的答案需要一些方法来修复字符串.还有另一个值 - ExtendedXMP序列化的全长,它有两个用途:检查数据的完整性以及提供用于连接数据的缓冲区大小.
当我们找到一个ExtendedXMP段时,我们需要将当前数据与其他ExtendedXMP段连接起来,最后得到整个ExtendedXMP数据.然后,我们将两个XML树连接在一起(同样从标准XMP部件中删除GUID)以检索整个XMP数据.
我在Java中创建了一个库icafe,它可以提取和插入XMP以及ExtendedXMP.ExtendedXMP的一个用例是Google的深度图数据,实际上是作为元数据隐藏在实际图像中的灰度图像,而在JPEG的情况下,作为XMP数据.深度图图像可以用于例如模糊原始图像.深度图数据通常很大,必须分成标准和扩展的XMP部分.整个数据是Base64编码的,可以是PNG格式.
以下是示例图像和提取的深度图:
原始图像来自这里.
注意:最近我发现另一个网站谈论Google Cardboard Camera应用程序,它可以利用JPEG XMP数据中嵌入的图像和音频.ICAFE现在支持从这些图像中提取图像和音频.可以通过以下调用在此处找到示例用法JPEGTweaker.extractDepthMap()
最初,Adobe并未预期XMP数据长度将超过一个JPEG段(约64K)的限制,并且他们的XMP规范声明XMP数据必须合二为一.后来当他们发现单个JPEG APP1段不足以容纳XMP数据时,他们改变了他们的规范,以允许整个XMP数据的多个APP1段.数据分为两部分:标准XMP和ExtendedXMP.标准XMP部件是带有包装器的"普通"XMP结构,而ExtendedXMP部件没有包装器.ExtendedXMP数据可以进一步划分为多个APP1.
以下引用来自Adobe XMP规范第3部分,适用于ExtendedXMP块作为JPEG APP1:
每个块在单独的APP1标记段内写入JPEG文件.每个ExtendedXMP标记段包含:
以空值终止的签名字符串" http://ns.adobe.com/xmp/extension/ ".
128位GUID存储为32字节ASCII十六进制字符串,资本AF,无空终止.GUID是完整ExtendedXMP序列化的128位MD5摘要.
ExtendedXMP序列化的全长,为32位无符号整数
该部分的偏移量为32位无符号整数.
ExtendedXMP的一部分
我们可以看到除了以null结尾的字符串作为ExtendedXMP数据的id之外,还有一个GUID应该与在标准XMP部分中找到的值相同.偏移量用于连接ExtendedXMP的不同部分 - 因此ExtendedXMP APP1的顺序可能甚至不是有序的.然后是实际的数据部分,这就是为什么@Matt的答案需要一些方法来修复字符串.还有另一个值 - ExtendedXMP序列化的全长,它有两个用途:检查数据的完整性以及提供用于连接数据的缓冲区大小.
当我们找到一个ExtendedXMP段时,我们需要将当前数据与其他ExtendedXMP段连接起来,最后得到整个ExtendedXMP数据.然后,我们将两个XML树连接在一起(同样从标准XMP部件中删除GUID)以检索整个XMP数据.
我在Java中创建了一个库icafe,它可以提取和插入XMP以及ExtendedXMP.ExtendedXMP的一个用例是Google的深度图数据,实际上是作为元数据隐藏在实际图像中的灰度图像,而在JPEG的情况下,作为XMP数据.深度图图像可以用于例如模糊原始图像.深度图数据通常很大,必须分成标准和扩展的XMP部分.整个数据是Base64编码的,可以是PNG格式.
以下是示例图像和提取的深度图:
原始图像来自这里.
注意:最近我发现另一个网站谈论Google Cardboard Camera应用程序,它可以利用JPEG XMP数据中嵌入的图像和音频.ICAFE现在支持从这些图像中提取图像和音频.可以通过以下调用在此处找到示例用法JPEGTweaker.extractDepthMap()