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

时间:2010-07-22 21:05:48

标签: .net vb.net png metadata system.drawing

我看到了一些关于如何从图像中读取元数据的问题,但我还没有看到很多人在询问如何编写元数据。基本上,我需要将一个元数据项(“ImageDescription”)添加到我正在动态生成的PNG图像中(创建一个Bitmap对象并在程序上生成其中的所有内容)。

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

3 个答案:

答案 0 :(得分:1)

你可以使用FreeImage.NET library,我认为它可以读取和写入PNG文件,以及它们的元数据。

答案 1 :(得分:0)

您可以使用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

答案 2 :(得分:0)

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

仅考虑将图像存储在图像旁边,或者保留文件和所需数据的小型“数据库”。

对我来说,重新加载图像时我只是再次需要数据。数据具有转换系数,可以告诉我多少像素= 1毫米。

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

基本上在文件的末尾,我用二进制“ @ Conv =”编写,然后是该值的8个字节的两倍。

我的程序以二进制读取的形式打开图像...搜寻末尾,然后减去我的“ hack”中的总字节数,并查找“ @ Conv =“。如果找到此值,它将读取值。然后,该程序可以选择确定比例因子后进行保存,而不必每次打开时都进行测量和输入值。

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

与.png,.jpg以及其他类型的字体配合得很好。

我要复制的文件是本地文件。显然,如果从其他应用程序重写文件,则数据将丢失,但是对于许多应用程序而言,任何元数据都可能是正确的。

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

一些vbcode只是用来踢球的。

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