在.NET中将元数据写入PNG图像

5

我看到有不少问题询问如何从图像中读取元数据,但是关于如何写入元数据的问题却没有那么多。基本上,我需要向我动态生成的PNG图像添加一个元数据项("ImageDescription")(创建一个位图对象并在其中过程性地生成所有内容)。

.NET中在将文件写入磁盘之前或之后添加图像元数据的最佳方法是什么?

3个回答

1

您可以使用System.Windows.Media.Imaging中的BitmapMetadata来编写iTXt值。 VB示例:

' Imports System.Windows.Media.Imaging
' Imports System.Windows.Media

Dim width = 256
Dim height = 256
Dim pngMetadata = New BitmapMetadata("png")

' PNG spec: http://www.libpng.org/pub/png/book/chapter11.html - Info on the iTXt chunk (and other custom metadata tags). 

pngMetadata.SetQuery("/iTXt/Keyword", "SomeKeyword".ToCharArray())
pngMetadata.SetQuery("/iTXt/TextEntry", "SomeValue")

Dim bitmap = New WriteableBitmap(width, height, 96, 96, PixelFormats.Gray8, Nothing)
Dim pixels = New Byte(width * height - 1) {}
For y = 0 To height - 1
    For x = 0 To width - 1
        pixels(y * width + x) = CByte(x)
    Next
Next

bitmap.WritePixels(New Int32Rect(0, 0, width, height), pixels, width, 0)
Dim encoder = New PngBitmapEncoder()
encoder.Frames.Add(BitmapFrame.Create(bitmap, Nothing, pngMetadata, Nothing))

Using stream = File.Create("c:\pngWithMetaData.png")
    encoder.Save(stream)
End Using

1
你可以使用FreeImage.NET库,我相信它既可以读取又可以写入PNG文件及其元数据。

谢谢,这看起来应该可以运行。只要我能让它似乎写出我想要的标签就好了。 - Sukasa

0

需要将一些简单的元数据写入至少 .png 和 .jpg 文件中,而不必将另一个第三方库拖入我的程序。几个小时后似乎什么都没用,因为所有文件类型都不同。

考虑过只是将其存储在图像旁边的文件中或保留一个小型的“数据库”来存储文件和所需数据。

对我来说,当我重新加载图像时,我只需要再次获取数据。该数据包含一个转换因子,告诉我多少像素等于1毫米。

剧透... 如果您不喜欢黑客,请立即离开。

基本上,在文件末尾以二进制形式写入“@Conv=”,然后是8字节的double值。

我的程序以二进制读取方式打开图像...定位到“hack”中总字节数减去结尾处,然后查找“@Conv=”。如果找到,则读取值。然后程序就可以在确定比例因子后选择保存,而不必每次打开时测量并输入值。

我有代码来读取/查询、更新和添加数据。

适用于 .png、.jpg 和可能其他类型。

我要处理的文件是复制的,而且是本地的。显然,如果文件被其他应用程序重新写入,数据就会丢失,但对于许多应用程序的任何元数据来说,这可能都是正确的。

最终,我存储了一些数据项,包括“原始”位置(以像素为单位)和图像的首选旋转(0、90、180、270)。

一些VB代码只是为了好玩。

Shared arr_magic As Byte() = {CByte(AscW("@"c)), CByte(AscW("C"c)), CByte(AscW("o"c)), CByte(AscW("n"c)), CByte(AscW("v"c)), CByte(AscW("2"c)), CByte(AscW("="c))}

Const metaSize As Integer = 8 + 4 + 4 + 4
Function FileCheckScale(fn As String, ByRef origin As Point, ByRef angle As Integer, update As Boolean) As Double
    Dim fr = New IO.StreamReader(fn)

    Dim br As New IO.BinaryReader(fr.BaseStream)

    fr.BaseStream.Seek(-(metaSize + arr_magic.Length), IO.SeekOrigin.End)

    For i = 0 To arr_magic.Length - 1
        If br.ReadByte() <> arr_magic(i) Then
            fr.Close()
            Return 0.0 ' <= 0 means not found
        End If
    Next

    Dim v As Double = br.ReadDouble

    If update Then
        origin.X = br.ReadInt32
        origin.Y = br.ReadInt32
        angle = br.ReadInt32
    End If

    fr.Close()

    Return v
End Function


Sub FileUpdateScale(fn As String, v As Double, origin As Point, angle As Integer)
    Dim fr = New IO.FileStream(fn, IO.FileMode.Open, IO.FileAccess.Write)

    Dim br As New IO.BinaryWriter(fr)

    fr.Seek(-(metaSize + arr_magic.Length), IO.SeekOrigin.End)

    br.Write(arr_magic)
    br.Write(v)
    br.Write(origin.X)
    br.Write(origin.Y)
    br.Write(angle)

    fr.Close()
End Sub

Sub FileAddScale(fn As String, v As Double, origin As Point, angle As Integer)
    Dim fr = New IO.StreamWriter(fn, True)
    Dim br As New IO.BinaryWriter(fr.BaseStream)

    fr.BaseStream.Seek(0, IO.SeekOrigin.End)

    br.Write(arr_magic)
    br.Write(v)
    br.Write(origin.X)
    br.Write(origin.Y)
    br.Write(angle)

    fr.Close()
End Sub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接