DOBON.NET DOBON.NETプログラミング掲示板過去ログ

写真の取得日付変更の件

環境/言語:[Windows7、VB2008Express]
分類:[.NET]

お世話になります。

写真をとってPCに移動すると、その写真のプロパティの詳細タブの中に、元の場所という項目があって、その中に取得日付という項目があります。
この「取得日付」がプログラムで変更できません。
撮影日付とか、作成日付、更新日付、アクセス日付等は変更できたのですが、この「取得日付」だけはID等を見つけることができませんでした。
削除する方法だけは探しだしたのですが、できればプログラムで変更したいです。

ご存知のかた、情報の載っているサイト情報でも結構ですので、お教え下さい。
とりあえず、jpeg/tiff/pngについては、System.Windows.Media.Imagingを使うことでどうにかできるようです。
使用するにはPresentationCore.dllを参照に追加する必要があります(それ以外にも必要かもしれませんが)。
手順としては、
1. BitmapDecoder.Createでファイルをロードする。
https://msdn.microsoft.com/ja-jp/library/system.windows.media.imaging.bitmapdecoder.aspx
 このとき、Uriだと書き込めないっぽいのでFileStreamを使います。
2. BitmapDecoder.Frames(0).CreateInPlaceBitmapMetadataWriterでInPlaceBitmapMetadataWriterを作成する。

設定先はファイル形式毎に手順が異なっていて、
a. jpegの場合: writer.SetQuery("/xmp/MicrosoftPhoto:DateAcquired", datetime.ToString("o"))
b. tiffの場合: writer.SetQuery("/ifd/{ushort=700}/MicrosoftPhoto:DateAcquired", datetime.ToString("o"))
c. png の場合: writer.DateTaken = datetime

で、最後に
writer.TrySave()
で保存します。
あ、
/xmp/MicrosoftPhoto:DateAcquired
とか
/ifd/{ushort=700}/MicrosoftPhoto:DateAcquired
は私が試した限りにおいてなので、ひょっとしたら何か別解があるかも知れません。
■No32807に返信(Hongliangさんの記事)
早速のご回答有難うございます。
昨日の時点で、回答されていたのはわかっていたのですが、用語がわからずに1文字1文字ネットで調べておりました。

結果、コードらしきものはできたのですが、写真のプロパティの詳細タブの「取得日時」に反映されず、困っています。

コードを提示しますので、どこが悪いかご指摘いただけるとありがたいのですが。

○参照設定
 ・PresentationCore
 ・WindowsBase
 ・System.Xml(Xamlが見つからないため)

○コード
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        '画像ファイルデータをStreamで開く
        Dim imageFileStrm As New FileStream(TextBox1.Text, _
            FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
        'BitmapDecoderを作成する
        Dim decoder As BitmapDecoder = BitmapDecoder.Create(imageFileStrm, _
            BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default)
        Dim writer As InPlaceBitmapMetadataWriter = decoder.Frames(0).CreateInPlaceBitmapMetadataWriter()
        Dim d, f As String
        Dim dt As DateTime
        d = "2004/08/24 20:23:06"
        f = "yyyy/MM/dd HH:mm:ss"
        dt = DateTime.ParseExact(d, f, Nothing)
        If writer.TrySave() = True Then
            writer.SetQuery("/xmp/MicrosoftPhoto:DateAcquired", dt.ToString("o"))
        End If
        imageFileStrm.Close()
    End Sub

    Private Sub TextBox1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragDrop
        'コントロール内にドロップされたとき実行される
        'ドロップされたすべてのファイル名を取得する
        Dim fileName As String() = CType( _
            e.Data.GetData(DataFormats.FileDrop, False), _
            String())
        TextBox1.Text = fileName(0)
    End Sub

    Private Sub TextBox1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragEnter
        'コントロール内にドラッグされたとき実行される
        If e.Data.GetDataPresent(DataFormats.FileDrop) Then
            'ドラッグされたデータ形式を調べ、ファイルのときはコピーとする
            e.Effect = DragDropEffects.Copy
        Else
            'ファイル以外は受け付けない
            e.Effect = DragDropEffects.None
        End If
    End Sub

○参照URL
 ・http://www.atmarkit.co.jp/fdotnet/dotnettips/203dateparse/dateparse.html
 ・https://msdn.microsoft.com/ja-jp/library/system.windows.media.imaging.bitmapframe.createinplacebitmapmetadatawriter(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb
 ・http://dobon.net/vb/dotnet/control/droppedfile.html
 ・http://dobon.net/vb/dotnet/graphics/selectactiveframe.html
 ・http://dobon.net/vb/dotnet/string/datetimeformat.html

以上です。
なにとぞ、ご指南ください。
InPlaceBitmapMetadataWriterのMSDNサンプルを元にお書きになったと思うのですが、

> If writer.TrySave() = True Then
>     writer.SetQuery("/xmp/MicrosoftPhoto:DateAcquired", dt.ToString("o"))
> End If

この部分、TrySaveはSetQueryの後です(一応私も先の投稿で明示したんですが)。
普通に考えて、Saveしてから値を設定しても意味ないですよね。
■No32810に返信(Hongliangさんの記事)
> InPlaceBitmapMetadataWriterのMSDNサンプルを元にお書きになったと思うのですが、
> この部分、TrySaveはSetQueryの後です(一応私も先の投稿で明示したんですが)。
> 普通に考えて、Saveしてから値を設定しても意味ないですよね。

全く仰るとおりです。
        If writer.TrySave() = True Then
            writer.SetQuery("/xmp/MicrosoftPhoto:DateAcquired", dt.ToString("o"))
        End If
と
        writer.SetQuery("/xmp/MicrosoftPhoto:DateAcquired", dt.ToString("o"))
        writer.TrySave()
の両方を試してみましたが、どちらも反映されなかったので、MSDNサンプルが正しいのかなと思って、そのままにしてしまいました。

お叱りを頂いて、おそらくdt.ToString("o")の部分が機能していないのかなと思って、空文字列""にしてみたところ、
「取得日時」設定済みのファイルでは「取得日時」が消えたので、dt.ToString("o")の部分に問題があることに確信が持てました。
手元に「取得日付」が設定されたものがなかったために、確認が遅れました。

ToString()の書式もよくわかなかったために、かたっぱしから下記参照URLの書式を入れていったところ、
小文字のs("s")で設定日付が反映されたため、この部分を書き換える必要があったことがわかりました。
Windows7の32bitと64bitの両方で試してみましたが、どちらも"s"で設定でき"o"では設定できませんでした。なぜかは不明です。

とにかく、いろいろをご迷惑をお掛けしつつ、設定できるコードが完成しました。
親切なご指南ありがとうございました。

最後になりましたが、完成したコードと参照URLを上げておきます。
ありがとうございました。

○写真の取得日付を設定するコード(jpg対象)
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        '画像ファイルデータをStreamで開く
        Dim imageFileStrm As New FileStream(TextBox1.Text, _
            FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
        'BitmapDecoderを作成する
        Dim decoder As BitmapDecoder = BitmapDecoder.Create(imageFileStrm, _
            BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default)
        Dim writer As InPlaceBitmapMetadataWriter = decoder.Frames(0).CreateInPlaceBitmapMetadataWriter()
        Dim d, f As String
        Dim dt As DateTime
        d = "2004/08/24 20:23:06"
        f = "yyyy/MM/dd HH:mm:ss"
        dt = DateTime.ParseExact(d, f, Nothing)
        writer.SetQuery("/xmp/MicrosoftPhoto:DateAcquired", dt.ToString("s"))
        Dim Ret as Boolean = writer.TrySave()
        imageFileStrm.Close()
    End Sub

    Private Sub TextBox1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragDrop
        'コントロール内にドロップされたとき実行される
        'ドロップされたすべてのファイル名を取得する
        Dim fileName As String() = CType( _
            e.Data.GetData(DataFormats.FileDrop, False), _
            String())
        TextBox1.Text = fileName(0)
    End Sub

    Private Sub TextBox1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragEnter
        'コントロール内にドラッグされたとき実行される
        If e.Data.GetDataPresent(DataFormats.FileDrop) Then
            'ドラッグされたデータ形式を調べ、ファイルのときはコピーとする
            e.Effect = DragDropEffects.Copy
        Else
            'ファイル以外は受け付けない
            e.Effect = DragDropEffects.None
        End If
    End Sub

○参照URL
 ・ToString 標準の日時書式指定文字列
  http://dobon.net/vb/dotnet/string/datetimeformat.html
 ・その他
 ・http://www.atmarkit.co.jp/fdotnet/dotnettips/203dateparse/dateparse.html
 ・https://msdn.microsoft.com/ja-jp/library/system.windows.media.imaging.bitmapframe.createinplacebitmapmetadatawriter(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb
 ・http://dobon.net/vb/dotnet/control/droppedfile.html
 ・http://dobon.net/vb/dotnet/graphics/selectactiveframe.html
 ・http://dobon.net/vb/dotnet/string/datetimeformat.html
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板