问题描述
我正在尝试创建元数据以存储在PNG图像文件中,具体取决于名为 sc_status
的参数的值.
I am trying to create metadata to be stored in a PNG Image file, depending on the value of a parameter called 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"
加上 vbNullChar
,该代码会自动添加到PNG块的末尾.
When I have a look at what is stored in the PNG chunks, I expect to have in byte sequence [72, 81, 0]
or [76, 81, 0]
or [85, 81, 0]
, corresponding to the string "LQ"
,"HQ"
,"UQ"
plus the vbNullChar
which is automatically added at the end of the PNG chunk.
但是出于某种原因我忽略了,有时我有一个较长的字节序列,例如 [72,81,28,8,1,0]
在使用 System.Text.Encoding.UTF8.GetString()
后给出-字符串:
But for a reason I ignore, I sometimes have a longer byte sequence, e.g. [72, 81, 28, 8, 1, 0]
which gives - after using System.Text.Encoding.UTF8.GetString()
- the string:
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()
过程中在元数据中添加额外的字节.
我究竟做错了什么?任何帮助都非常欢迎!
I don't understand why sometimes extra bytes are added in the metadata during the img_src.Save()
procedure.
What am I doing wrong? Any help is very welcome!
推荐答案
PropertyTagImageDescription 被定义为以空值结尾的ASCII字符串( PropertyTagTypeASCII
).
如文档中所述, PropertyItem.Type PropertyTagTypeASCII:
PropertyTagImageDescription is defined as a null-terminated ASCII string (PropertyTagTypeASCII
).
As described in the Documentation, PropertyItem.Type PropertyTagTypeASCII:
一些细节:
-
PropertyItem.Value
属性将 data 存储为字节数组.即使文档引用了 ASCII字符串,存储了以UTF-8编码的字符串的字节(通过调用Encoding.UTF8.GetBytes()
进行检索),也不是禁止.只需终止字符串并设置正确的存储字节数即可:如所述Value
仅存储字节. - 必须将
PropertyItem.Len
属性设置为字符串的长度,也就是字节的长度,即Value
属性.
- The
PropertyItem.Value
property stores data as a byte array. Even though the Docs refer to an ASCII string, storing the bytes of a UTF-8 encoded strings, retrieved callingEncoding.UTF8.GetBytes()
, is no forbidden though. Just terminate the string and set the correct number of bytes stored: as mentionedValue
store just bytes. - The
PropertyItem.Len
property must be set to the length of the string, so to the length of the byte, thus the length of theValue
property.
►没有理由将类型定义为 Object
,如下所示:
► There's no reason to define the Types as Object
, as in:
Dim qualityParam As Object
Dim encoderParams As Object = New Imaging.EncoderParameters(1)
声明这些类型的含义.
使用UTF-8编码的字符串的示例实现:
Sample implementation, using UTF-8 encoded strings:
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图片后,元数据中的额外字符/字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!