本文介绍了保存PNG图片后,元数据中的额外字符/字节的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建元数据以存储在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 calling Encoding.UTF8.GetBytes(), is no forbidden though. Just terminate the string and set the correct number of bytes stored: as mentioned Value 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 the Value 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图片后,元数据中的额外字符/字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 23:58
查看更多