编码 JPG 图像的元数据中字符之间的额外空字符

Extra null Char between characters in metadata encoding a JPG image

此线程是

的延续

但我现在考虑 JPEG 个文件,而不是 PNG 个文件。

我正在尝试根据名为 'sc_status' 的参数值写入元数据。我改编了 Jimi 的建议,该建议非常适合 PNG 个文件:

Imports System.Drawing.Imaging
Imports System.Text

'0x9286 = User Comments
Dim imageDescriptionPropItem = &H9286
' Property Type 2: null-terminated string
Dim PropertyTagTypeASCII As short = 2

Dim encoderParams As New EncoderParameters(1)
Dim ImgCodec = ImageCodecInfo.GetImageEncoders().
               FirstOrDefault(Function(enc) enc.FormatID = ImageFormat.Jpeg.Guid)
If ImgCodec Is Nothing Then
    Throw New FormatException("Invalid format")
End If
encoderParams.Param(0) = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 95L)

Dim imagePath = [Image Source Path]
Dim imageDestinationPath = [Image Destination Path]
Dim imageSourcePath = Image.FromStream(New MemoryStream(File.ReadAllBytes(imageSourcePath)))

Dim propItem As PropertyItem = DirectCast(FormatterServices.GetUninitializedObject(
    GetType(PropertyItem)), PropertyItem)

propItem.Id = imageDescriptionPropItem 
propItem.Type = PropertyTagTypeASCII

Dim description = String.Empty
Select Case sc_status
    Case 3
        description = "HQ" & ChrW(0)
    Case 5
        description = "LQ" & ChrW(0)
    Case Else
        description = "UQ" & ChrW(0)
End Select

' Length of the string including the terminator: mandatory
propItem.Value = Encoding.UTF8.GetBytes(description)
propItem.Len = propItem.Value.Length

imageSource.SetPropertyItem(propItem)
imageSource.Save(imageDestinationPath, ImgCodec, encoderParams)

元数据检查通过以下方式执行:

Dim imageEncoded = Image.FromStream(New MemoryStream(File.ReadAllBytes(imageDestinationPath)))
Dim propItemSaved = imageEncoded.GetPropertyItem(imageDescriptionPropItem)
Dim descr = Encoding.UTF8.GetString(propItemNew.Value).TrimEnd(ChrW(0))

我希望字节序列为 [72, 81, 0][76, 81, 0][85, 81, 0]。但是我得到 [72, 0, 81, 0, 0][76, 0, 81, 0, 0][85, 0, 81, 0, 0]。所以每个字符之间多了一个0字节,它提供了如下字符串:"L" & vbNullChar & "Q" & vbNullChar等等。

为什么要插入这些零以及如何去除这些零? 为什么它适用于 PNG 图片(使用图片描述道具 &H10E)而不是 JPEG 图片(使用用户评论道具 &H9286)?

非常感谢您的支持。

你设置错了PropertyItem.Type。
PropertyTagExifUserComment (0x9286) 将其类型定义为 PropertyTagTypeUndefined = 7,而您将其设置为 PropertyTagTypeASCII = 2,作为与 PropertyTagImageDescription PropertyItem 相关的类型。这些类型不以相同的方式存储数据:

The character code used in the PropertyTagExifUserComment tag is identified based on an ID code in a fixed 8-byte area at the start of the tag data area. The unused portion of the area is padded with null characters (0). ID codes are assigned by means of registration. Because the type is not ASCII, it is not necessary to use a NULL terminator.

不需要设置空终止符,但如果你这样做了,那也不是问题。

不幸的是,与 PropertyItem.Type 值相关的文档并不直接。这些在 gdiplusimaging.h 中定义。使用 PropertyItem.Type 描述作为参考。

让我们为这些 PropertyItems 类型定义一个枚举器,以简化其使用:

Public Enum PropertyItemType As Short
    PropertyTagTypeByte = 1
    PropertyTagTypeASCII = 2
    PropertyTagTypeShort = 3
    PropertyTagTypeLong = 4
    PropertyTagTypeRational = 5
    PropertyTagTypeUndefined = 7
    PropertyTagTypeSLONG = 9
    PropertyTagTypeSRational = 10
End Enum

因此代码更改为:

Dim propTagExifUserComment = &H9286

propItem.Id = propTagExifUserComment
propItem.Type = PropertyItemType.PropertyTagTypeUndefined
' [...]
Dim propItemSaved = imageSaved.GetPropertyItem(propTagExifUserComment)

期待这一点,代码保持不变。