保存 PNG 图像后元数据中的额外 characters/bytes
Extra characters/bytes in metadata after saving a PNG image
我正在尝试创建要存储在 PNG 图像文件中的元数据,具体取决于名为 sc_status
的参数值。
代码如下:
Dim qualityParam As Object
Dim encoderParams As Object = New Imaging.EncoderParameters(1)
Dim ImgCodec As Imaging.ImageCodecInfo
ImgCodec = GetEncoderInfo("image/png")
qualityParam = New Imaging.EncoderParameter(Imaging.Encoder.ColorDepth, 32L)
encoderParams.Param(0) = qualityParam
'---
' img_src Image is created here
' file_name String is created here
'---
' Creating the PropertyItem
Dim propit As Imaging.PropertyItem = CType(System.Runtime.Serialization.FormatterServices.GetUninitializedObject(GetType(Imaging.PropertyItem)), Imaging.PropertyItem)
propit.Id = 270 '0x010E = Image description
propit.Type = 2
If sc_status = 3 Then
propit.Value = System.Text.Encoding.UTF8.GetBytes("HQ")
ElseIf sc_status = 5 Then
propit.Value = System.Text.Encoding.UTF8.GetBytes("LQ")
Else
propit.Value = System.Text.Encoding.UTF8.GetBytes("UQ")
End If
' Storing the PropertyItem
img_src.SetPropertyItem(propit)
' Saving png
img_src.Save(file_name, ImgCodec, encoderParams)
当我查看 PNG 块中存储的内容时,我希望字节序列为 [72, 81, 0]
或 [76, 81, 0]
或 [85, 81, 0]
,对应于字符串 "LQ"
、"HQ"
、"UQ"
加上自动添加到 PNG 块末尾的 vbNullChar
。
但出于我忽略的原因,我有时会有更长的字节序列,例如[72, 81, 28, 8, 1, 0]
这给出了 - 在使用 System.Text.Encoding.UTF8.GetString()
之后 - 字符串:
HQ & ChrW(28) & vbBack & ChrW(1) & vbNullChar
或有时[72, 81, 22, 8, 1, 0]
,或有时[72, 81, 19, 8, 1, 0]
,或有时[72, 81, 23, 8, 1, 0]
。
我不明白为什么在 img_src.Save()
过程中有时会在元数据中添加额外的字节。
我究竟做错了什么?非常欢迎任何帮助!
PropertyTagImageDescription 被定义为空终止的 ASCII 字符串 (PropertyTagTypeASCII
)。
如文档中所述,PropertyItem.Type PropertyTagTypeASCII:
Specifies that Value
is a null-terminated ASCII string. If you set the
type data member to ASCII type, you should set the Len
property to the
length of the string including the null terminator. For example, the
string "Hello"
would have a length of 6.
一些细节:
PropertyItem.Value
属性将数据存储为字节数组。即使文档引用 ASCII 字符串,存储 UTF-8 编码字符串的字节,检索调用 Encoding.UTF8.GetBytes()
,也不是 forbidden 虽然。只需终止字符串并设置正确的存储字节数:如前所述 Value
仅存储字节。
PropertyItem.Len
属性必须设置为字符串的长度,也就是字节的长度,也就是Value
属性.
► 没有理由将类型定义为 Object
,如:
Dim qualityParam As Object
Dim encoderParams As Object = New Imaging.EncoderParameters(1)
声明这些类型。
示例实现,使用 UTF-8 编码字符串:
Imports System.Drawing.Imaging
Imports System.Text
'0x010E = Image description
Dim imageDescriptionPropItem = &H10E
' 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.Png.Guid)
If ImgCodec Is Nothing Then
Throw New FormatException("Invalid format")
End If
encoderParams.Param(0) = New EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 32L)
Dim imagePath = [Image Source Path]
Dim imageDestinationPath = [Image Destination Path]
Dim imageSource = Image.FromStream(
New MemoryStream(File.ReadAllBytes(imageSourcePath)), False, False)
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"
Case 5
description = "LQ"
Case 100
' Test string, in Russian :)
description = "Тестовая строка"
Case Else
description = "UQ"
End Select
' Length of the string including the terminator: mandatory
propItem.Value = Encoding.UTF8.GetBytes(description & ChrW(0))
propItem.Len = propItem.Value.Length
imageSource.SetPropertyItem(propItem)
imageSource.Save(imageDestinationPath, ImgCodec, encoderParams)
' Load it back, to check what's what
Dim imageEncoded = Image.FromStream(New MemoryStream(File.ReadAllBytes(imageDestinationPath)))
Dim propItemSaved = imageEncoded.GetPropertyItem(imageDescriptionPropItem)
Dim descr = Encoding.UTF8.GetString(propItemSaved.Value).TrimEnd(ChrW(0))
我正在尝试创建要存储在 PNG 图像文件中的元数据,具体取决于名为 sc_status
的参数值。
代码如下:
Dim qualityParam As Object
Dim encoderParams As Object = New Imaging.EncoderParameters(1)
Dim ImgCodec As Imaging.ImageCodecInfo
ImgCodec = GetEncoderInfo("image/png")
qualityParam = New Imaging.EncoderParameter(Imaging.Encoder.ColorDepth, 32L)
encoderParams.Param(0) = qualityParam
'---
' img_src Image is created here
' file_name String is created here
'---
' Creating the PropertyItem
Dim propit As Imaging.PropertyItem = CType(System.Runtime.Serialization.FormatterServices.GetUninitializedObject(GetType(Imaging.PropertyItem)), Imaging.PropertyItem)
propit.Id = 270 '0x010E = Image description
propit.Type = 2
If sc_status = 3 Then
propit.Value = System.Text.Encoding.UTF8.GetBytes("HQ")
ElseIf sc_status = 5 Then
propit.Value = System.Text.Encoding.UTF8.GetBytes("LQ")
Else
propit.Value = System.Text.Encoding.UTF8.GetBytes("UQ")
End If
' Storing the PropertyItem
img_src.SetPropertyItem(propit)
' Saving png
img_src.Save(file_name, ImgCodec, encoderParams)
当我查看 PNG 块中存储的内容时,我希望字节序列为 [72, 81, 0]
或 [76, 81, 0]
或 [85, 81, 0]
,对应于字符串 "LQ"
、"HQ"
、"UQ"
加上自动添加到 PNG 块末尾的 vbNullChar
。
但出于我忽略的原因,我有时会有更长的字节序列,例如[72, 81, 28, 8, 1, 0]
这给出了 - 在使用 System.Text.Encoding.UTF8.GetString()
之后 - 字符串:
HQ & ChrW(28) & vbBack & ChrW(1) & vbNullChar
或有时[72, 81, 22, 8, 1, 0]
,或有时[72, 81, 19, 8, 1, 0]
,或有时[72, 81, 23, 8, 1, 0]
。
我不明白为什么在 img_src.Save()
过程中有时会在元数据中添加额外的字节。
我究竟做错了什么?非常欢迎任何帮助!
PropertyTagImageDescription 被定义为空终止的 ASCII 字符串 (PropertyTagTypeASCII
)。
如文档中所述,PropertyItem.Type PropertyTagTypeASCII:
Specifies that
Value
is a null-terminated ASCII string. If you set the type data member to ASCII type, you should set theLen
property to the length of the string including the null terminator. For example, the string"Hello"
would have a length of 6.
一些细节:
PropertyItem.Value
属性将数据存储为字节数组。即使文档引用 ASCII 字符串,存储 UTF-8 编码字符串的字节,检索调用Encoding.UTF8.GetBytes()
,也不是 forbidden 虽然。只需终止字符串并设置正确的存储字节数:如前所述Value
仅存储字节。PropertyItem.Len
属性必须设置为字符串的长度,也就是字节的长度,也就是Value
属性.
► 没有理由将类型定义为 Object
,如:
Dim qualityParam As Object
Dim encoderParams As Object = New Imaging.EncoderParameters(1)
声明这些类型。
示例实现,使用 UTF-8 编码字符串:
Imports System.Drawing.Imaging
Imports System.Text
'0x010E = Image description
Dim imageDescriptionPropItem = &H10E
' 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.Png.Guid)
If ImgCodec Is Nothing Then
Throw New FormatException("Invalid format")
End If
encoderParams.Param(0) = New EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 32L)
Dim imagePath = [Image Source Path]
Dim imageDestinationPath = [Image Destination Path]
Dim imageSource = Image.FromStream(
New MemoryStream(File.ReadAllBytes(imageSourcePath)), False, False)
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"
Case 5
description = "LQ"
Case 100
' Test string, in Russian :)
description = "Тестовая строка"
Case Else
description = "UQ"
End Select
' Length of the string including the terminator: mandatory
propItem.Value = Encoding.UTF8.GetBytes(description & ChrW(0))
propItem.Len = propItem.Value.Length
imageSource.SetPropertyItem(propItem)
imageSource.Save(imageDestinationPath, ImgCodec, encoderParams)
' Load it back, to check what's what
Dim imageEncoded = Image.FromStream(New MemoryStream(File.ReadAllBytes(imageDestinationPath)))
Dim propItemSaved = imageEncoded.GetPropertyItem(imageDescriptionPropItem)
Dim descr = Encoding.UTF8.GetString(propItemSaved.Value).TrimEnd(ChrW(0))