写/读PNG元数据:没有保存/没有读取

时间:2018-01-13 20:08:47

标签: .net f#

我有两个功能:在PNG文件中写入和读取元数据。这是CDN的MSDN示例的适应性。没有错误,但没有写入任何内容(也请使用tweakpng工具检查)。我发现需要JPG填充,但PNG没有这样的信息。这段代码有什么问题? (我尝试了其他MetaKey值,也带有“/ Text / ...”前缀,没有成功。我也尝试读取现有的“key”(添加了tweakpng工具) - 没有(null)。我看到了MSDN示例之一,注释此代码不起作用,但没有其他示例......代码:

    open System.IO
    open System.Text
    open System.Security.Cryptography
    open System.Windows.Media.Imaging


    let MetaKey = "/tEXt/Description"
    let WriteMeta (path : string, a : int, from : b) =
        let data = sprintf "%d %d" a b
        use stm = new FileStream (path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
        let dec = new PngBitmapDecoder (stm, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default)
        let frm = dec.Frames.[0]
        let wr = frm.CreateInPlaceBitmapMetadataWriter ()
        let mutable res = false
        if wr.TrySave () then
            wr.SetQuery (MetaKey, data.ToCharArray())
            res <- true
        stm.Close ()
        res

    let ReadMeta (path : string) =
        use stm = new FileStream (path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
        let dec = new PngBitmapDecoder (stm, BitmapCreateOptions.None, BitmapCacheOption.Default)
        let met = dec.Frames.[0].Metadata :?> BitmapMetadata
        let data = met.GetQuery (MetaKey)
        let res =
            match data with
            | null -> None
            | obj -> Some <| obj.ToString ()
        stm.Close ()
        res

1 个答案:

答案 0 :(得分:1)

正如我发现的,由于MSDN文档,这是一个众所周知的问题:它只显示保留元数据但不保存回文件。此代码有效:

    let MetaKey = "/tEXt/Description"
    let WriteMeta (path : string, data : string) =
        let fip = new FileInfo (path)
        use stm = new FileStream (path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
        let dec = new PngBitmapDecoder (stm, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)
        let frm = dec.Frames.[0]
        let _met = frm.Metadata
        if _met = null then
            stm.Close ()
            false
        else
            let met = _met.Clone () :?> BitmapMetadata
            stm.Close ()
            fip.Delete ()
            met.SetQuery (MetaKey, data)
            let enc = new PngBitmapEncoder ()
            enc.Frames.Add (BitmapFrame.Create (frm, frm.Thumbnail, met, frm.ColorContexts))
            use stm' = File.Open (path, FileMode.Create, FileAccess.ReadWrite)
            enc.Save (stm')
            stm'.Close ()
            true

    let ReadMeta (path : string) =
        use stm = new FileStream (path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
        let dec = new PngBitmapDecoder (stm, BitmapCreateOptions.None, BitmapCacheOption.Default)
        let met = dec.Frames.[0].Metadata :?> BitmapMetadata
        if met = null then None
        else
            let data = met.GetQuery (MetaKey)
            let res =
                match data with
                | null -> None
                | obj -> Some <| obj.ToString ()
            stm.Close ()
            res