此线程是保存 PNG 图像后元数据中额外字符/字节的延续
但我现在考虑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 相关的类型。这些类型以不同的方式存储数据:
PropertyTagExifUserComment 标记中使用的字符代码是 根据开头固定 8 字节区域中的 ID 代码进行识别 标记数据区域。该区域的未使用部分填充为 null 字符 (0)。ID代码通过注册方式分配。 由于类型不是 ASCII,因此无需使用 NULL 终结者。
没有必要设置 null 终止符,但如果这样做,那也不是问题。
不幸的是,文档相对于PropertyItem.Type
值并不简单。这些在gdiplusimaging.h
中定义。使用 PropertyItem.Type 说明作为参考。
让我们为这些属性项类型定义一个枚举器,以简化其使用:
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)
期望这一点,代码保持不变。