我正在使用 Apache Commons Imaging (Sanselan) 将 EXIF 元数据写入 JPEG,并且至少在 Sanselan 的 0.97 版本中,存在一些与字符集/编码相关的错误。EXIF 2.2 标准要求类型字段的编码UNDEFINED
以 8 字节 ASCII“签名”为前缀,描述以下内容的编码。我要写入的字段/标签是UserComment
EXIF 标签。
Windows 期望内容以 UTF16 编码,因此写入 JPEG 的字节必须包含(单字节)ASCII 字符和后跟(双字节)Unicode 字符的组合。此外,虽然UserComment
似乎不需要它,但我注意到内容通常是“空填充”到均匀长度。
这是我用来创建和编写标签的代码:
String textToSet = "Test";
byte[] ASCIIMarker = new byte[]{ 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00 }; // spells out "UNICODE"
byte[] comment = textToSet.getBytes("UnicodeLittle");
// pad with \0 if (total) length is odd (or is \0 byte automatically added by arraycopy?)
int pad = (ASCIIMarker.length + comment.length) % 2;
byte[] bytesComment = new byte[ASCIIMarker.length + comment.length + pad];
System.arraycopy(ASCIIMarker, 0, bytesComment, 0, ASCIIMarker.length);
System.arraycopy(comment, 0, bytesComment, ASCIIMarker.length, comment.length);
if (pad > 0) bytesComment[bytesComment.length-1] = 0x00;
TiffOutputField exif_comment = new TiffOutputField(TiffConstants.EXIF_TAG_USER_COMMENT,
TiffFieldTypeConstants.FIELD_TYPE_UNDEFINED, bytesComment.length - pad, bytesComment);
然后,当我从 JPEG 中读取标签时,我执行以下操作:
String textRead;
TiffField field = jpegMetadata.findEXIFValue(TiffConstants.EXIF_TAG_USER_COMMENT);
if (field != null) {
textRead= new String(field.getByteArrayValue(), "UnicodeLittle");
}
让我感到困惑的是:写入 JPEG 的字节以 8 个 ASCII 字节为前缀,显然需要“剥离”这些字节,以便比较写入的内容和读取的内容:
if (textRead != null) {
if (textToSet.equals(textRead)) { // expecting this to FAIL
print "Equal";
} else {
print "Not equal";
if (textToSet.equals(textRead.substring(5))) { // this works
print "Equal after all...";
}
}
}
但是为什么substring(5)
,而不是…… substring(8)
?如果是 4,我可能会认为 4 个双字节 (UTF-16) 符号总共 8 个字节,但它只有在我去掉5 个字节时才有效。这是否表明我没有bytesComment
正确创建有效负载(字节数组)?
PS!我将更新到 2016 年发布的 Apache Commons Imaging RC 1.0,并希望修复了这些错误,但我仍然想了解为什么在我使用 0.97 达到这一点后它仍然有效 :-)