プロが教える店舗&オフィスのセキュリティ対策術

簡単に、指定Folderにある、*.JPGファイルの、
撮影日時を読みだす、VBA関数 or Excel関数をお教えて下さい。
(VBA初心者です)
下記の自作Codeは、見様見真似で書いたものです。
VBA関数:FileDateTime(パラメータ)で読みだした「日付時刻」は、
画像の「更新日時」でした。
**** お願 ***
Q1: 一行のCodoで、原画の「撮影日時」を読みす、関数・Codeを教えて下さい。
Q2: 関数が無ければ、それに代わる、Codeはどんなものが良いのでしょうか??
**** 自作Code ***
myFolder = "C:\Users\myName\ピクチャ\3000年JPG写真"
myJPG = Dir(myFolder & "\" & "*.jpg")
MsgBox ”読み出した日付時刻=” & FileDateTime(myFolder & "\" & myJPG)
以上 宜しくお願いいたします。

質問者からの補足コメント

  • <追加のお願い 2016/12/14>
    neKo_deuxさん、GooUserラックさん、こんばんは。
    参考URLのご紹介や参考Codeを書いて頂きましたが、
    VBA初心者には、数日は努力してみましたが、先に進めません。
    WEBの「Exif Read DLL版」を解凍しましが上手く使えません。
    VBAのコードウインドウに貼り付ければ実行できる、完結文を頂けませんでしょうか?
    *****
    私のJPG画像の保存場所(フルPath )=C:¥sample1.JPGです。
    このsample1.JPGを仮ホルダに貼り付けて確認すると、
    「日付時刻」、「作成日時」、「更新日時」、「撮影日時」は表示されています。
    MsgBox "sample1.JPGの撮影日時=" & myJPGYMT文で、「撮影日時」を得たいのですが?。
    宜しくお願いします。

      補足日時:2016/12/14 00:51
  • neKo_deuxさん、こんばんは。<追加のお尋ね 2016/12/15>

    MsgBox "写真撮影日時 =" & MyDateTimeOriginal(myFoldr & "\" & myJPG) ''ユーザー定義関数
    MsgBox "このCodoはFunctionの中の記述: Function MyDateTimeOriginalに入りました。
    作業を開始します" で、Functionを参照している事は確認できました!

    しかし、戻り値の写真撮影日時=00:00:00でした。
    Codeの、「Set objJpeg = New JpegExif」が機能していないのでしょうか?
    リンクが上手くいっていないようです。
    クラスモジュールの「JpegExif」のCodoを検索しても、「New JpegExif」はヒットしませんでした。

      補足日時:2016/12/15 00:23
  • 使用した画像2枚 #01 と#02

    「VBAで、JPG写真の撮影日時を読み出す」の補足画像3
      補足日時:2016/12/15 12:20
  • #02 自分で撮影した、紅葉の写真

    「VBAで、JPG写真の撮影日時を読み出す」の補足画像4
      補足日時:2016/12/15 12:22
  • *****
    4.3 #P1でVBA関数で書き出した、Sample1.JPGの更新日時は、2016/11/18 11:02
    4.4 #P1・#p2でユーザー定義関数で書き出した、Sample1.JPGの撮影日時は、1999/12/31
    ******
    5.#P3内の不可解は動き----#P3内に、追跡様に沢山書きこんだMsgBoxの内容
    5.1 上記4.3の更新日時を書き出しご、4.4でユーザー定義関数を呼び出した時
    5.1.1 #P3の仮行番号=44が実行されました。#44のCODE

      補足日時:2016/12/17 20:45
  • '仮行番号=44 インスタンスが作成される時に、Initializeイベントが発生する
    Private Sub Class_Initialize()
    cEndian = 1
    MsgBox "現在、CODE : Private Sub Class_Initialize()で、cEndian = 1を実行した直後、 仮行番号=44です。"
    MsgBox "現在、CODE : Private Sub Class_Initialize()で、取得した値 cEndian =" & cEndian ''その結果の表示は、cEndian=1でした。
    End Sub
    *******
    5.2 次いで実行されたのは、仮行番号=187でした。
    '仮行番号= 187 ***** メソッド *****
    '******

      補足日時:2016/12/17 20:58
  • Public Function InitSet(ByVal fullPath As String) As Integer
    Dim ret As Integer
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    If fso.FileExists(fullPath) Then
    With fso.GetFile(fullPath)
    cName = .Name
    cPath = .Path 'ファイル名も含めたフルパス
    cDateTimeLastModified = .DateLastModified
    End With

      補足日時:2016/12/17 21:04
  • ret = readJPEG()
    Else
    ret = -1
    End If
    Set fso = Nothing
    InitSet = ret
    MsgBox "現在、Public Function InitSet(ByVal fullPath As String) As Integerにいます。 CODE : InitSet = retを実行直後です。 仮行番号=187"
    MsgBox "現在、Public Function InitSet(ByVal fullPath As String) As Integerにいます。 CODE : InitSet = " & ret '' その結果は、InitSet=-1
    End Function

      補足日時:2016/12/17 21:06
  • 5.4 再度、仮行番号=44と仮行番号=187が繰り返し実行されました。---なぜか解明できていません????
    5.5 この後、書き出された情報は、4.4で記した、Sample1.JPGの撮影日時は、1999/12/31、でした。
    6.#p3の撮影日時の書き出し文:仮行番号=83は無視されて実行されない居ません----なぜか解明できていません????
    '仮行番号=83 *撮影日付
    Public Property Get DateTimeOriginal() As Date
    DateTimeOriginal = cDateTimeOriginal
    MsgBox "現在 クラスモジュールJpegExif内の撮影日付を取得するCodeの次の行:仮行番号=83にいます。"

      補足日時:2016/12/17 21:09
  • MsgBox "現在 クラスモジュールJpegExif内の撮影日付を取得するプログラム実行時に、CODE : DateTimeOriginal = cDateTimeOriginalは,実行されていません!"
    MsgBox "現在 クラスモジュールJpegExif内の撮影日付を取得するプログラム実行時の、cdateTimeOriginal = " & cDateTimeOriginal ''機能せず???
    End Property
    以上が現状報告ですが、なぜ、エクスプローラでは書き出せる、写真撮影日=2016年11月18日、11:02が、
    ユーザー定義関数で書き出せないのでしょうか?。何かヒントを頂けませんでしょうか?
    標準モジュールとクラスモジュールの連携、膨大な行数の複雑なVBAプログラムで、
    VBA初心者には、上手くデバッグできません。願いいたします。以上 ぎりぎりOK

      補足日時:2016/12/17 21:21

A 回答 (7件)

JpegExifのクラスモジュールは問題ないです。


サイトの中でも動作確認してるでしょうし、自分のところでも動作しています。


> cdateTimeOriginal = " & cDateTimeOriginal ''機能せず???

その前のInitSetが失敗してるからです。
失敗の原因は、帰ってきた日付の値(1999年)からすると、指定したファイルが無いからです。


Dir関数使わずに、

MsgBox "MyDateTimeOriginal()=" & MyDateTimeOriginal("c:\_Temp\sample.jpg")

とか、分かりやすいフォルダやファイルを直接指定では。
    • good
    • 0
この回答へのお礼

neKo_deuxさん,こんばんは。やっと解決できました!!!
辛坊強く何回もアドバイスを頂き、大変有難う御座いました。
極力単純化し、やっと成功したCodeを貼り、お礼に代えさせて頂きます。
*** 標準モジュールに記述したCode
Sub SJとneko_deuxさん合成Code()'''''''''''''写真の撮影日時の読み取り
Dim myJPG As String
myJPG = "C:\TEMP\Sample1.JPG"
MsgBox "VBA関数 FileDateTime()=" & FileDateTime(myJPG) '''''''''''読み出し値 2016/11/18 11:02:12=更新日時
MsgBox "MyDateTimeOrigina() =" & MyDateTimeOriginal(myJPG) '読み出し値 2016/11/18 11:02:12=撮影日時
End Sub
***
Function MyDateTimeOriginal(strfilepath As String) As Date''''''''ユーザー定義関数の参照文
Dim objJpeg As Object
Set objJpeg = New JpegExif
If objJpeg.InitSet(strfilepath) >= 0 Then
MyDateTimeOriginal = objJpeg.DateTimeOriginal
End If
End Function
********* 注:WEBで入手した、ユーザー定義関数JpegExifは、クラスモジュールにコピペ
15年ぶりにVBAに触り、大きな遠回りをしましたが、暖かくご支援頂き、
得る事が多く、このお尋ねは本当に良い機会になりました。
一括画像縮小Softを使うと、使用日が更新日時になり、更新日時=撮影日時を前提としていた自作のSoft が、
使えなくなっていました。このユーザー定義関数:JpegExifを使い、
撮影日時を読み取る様に自作プログラムを修正してみます。本当に有難う御座いました。
(いまだに、どこの記述に誤りがあったのか釈然としませんが、単純化の過程で解消された様です)

お礼日時:2016/12/19 01:29

No.5の回答で、1箇所違ってました。


Select Caseの中の、
 Default
  ↓
 Case Else
でないと、エラーになるハズ。

--
> この、1999/12/31は、Case1で、ファイルが存在しないに当たります。

元々のコードの、
myFolder = "C:\Users\myName\ピクチャ\3000年JPG写真"

の指定が間違っているハズ。
myJPGが空白だったらエラー表示とか中断した方が良いかも。
元々の質問のコードで、ファイルの更新日時は取得できるんでしょうか?

・エクスプローラで対象のフォルダを表示
・対象画像を右クリック-[プロパティ]を表示
・最初の「全般」タブ、「場所」に表示されているフォルダのパスをマウスでドラッグして選択してコピー
・VBAのコードに貼り付け
してみてください。
「VBAで、JPG写真の撮影日時を読み出す」の回答画像6
    • good
    • 0
この回答へのお礼

neKo_deuxさん,こんばんは。< 解答No.6へのお礼と、追加のお尋ね 2016/12/17 土曜日 >
度々、ご回答を頂き、重ねて御礼申し上げます。
完成間近と思いますが、対象ファイルの情報が読み出せません。今一度、アドバイスをお願いたします。
少し長文で規定文字数オーバーのため、オーバーした分は追加コメントにかけるかトライしてみます。
上手く全文が送れなければ、残念ながら、今回のお尋ねは未解決で諦めます。
*
1.現在アドバイスを頂いている、VBAプログラムの再確認
1.1 #P1:自作のVBA関数を利用した写真の更新日時の書き出し
1.2 #P2:neKo_deuxさんに書いて頂いた、JpegExifの呼び出し
1.3 #P3:GooUserラックさんからご紹介頂いた、btic.jpで公開されているJpegExif
**
2.VBAプロジェクトエクスプローラの内容
2.1 標準モジュール:#P1を記述し、その後ろに、#P2をコピペ
2.2 クラスモジュール:neKo_deuxさんのアドバイスによる#P3の必要部分をコピペ
***
3.読み出し対象のJEG写真
3.1 保存した写真名:Sample1.JPG
3.2 エクスプローラで確認したSample1.JPGのプロパティ
3.2.1 タグ全般で読み取った場所は、C:\TEMP
3.2.2 タグ全般で読み取った更新日時は、2016年11月18日、11:02:12
3.2.3 詳細タグで読み取った撮影日時は、2016年11月18日、11:02
****
4.#P1+#P2を実行して確認できた現象---クラスモジュールの#P3も呼び出して実行
4.1 #P2のSelect Case文のDefaultはエラー表示があり、Elseの書き換えて実行
4.2 解答No.5でご指摘の写真の保存状況確認は、上記3.の通り、再確認してあります。
*****
4.2までで、文字数オーバーです。4.2以降、コメントで追加してみます。

お礼日時:2016/12/17 20:32

> しかし、戻り値の写真撮影日時=00:00:00でした。



指定したファイルが存在しない場合などもそういう結果になります。
関数の返す値が日付型なので、
・指定したファイルが存在しなかった
・指定したファイルにExif情報が無かった
を区別していないです。

元々の質問のコードでファイルの更新日時が取得できるなら、ファイル指定は問題ないハズなんですが、一度元に戻してみて更新日時が取れるか確認してみるとか。

あるいは、ファイルの置き場所がマイドキュメントの中とかですと、
・元々の質問にあったFileDateTime関数は、日本語や空白の入ったファイルパスでも処理できる。
・JpegExifクラスで使用しているScripting.FileSystemObjectなんかは、うまく処理できない。
とか。(あんまり聞いた事ないですが。)
ファイルの置き場所をマイドキュメント以外で試してみては。
(自分は、C:\_Tempなんかのフォルダを作って確認しました。)


貼り付けした関数を修正して、

' 撮影日時取得
' ret 撮影日時
' 2002/12/31 23:59:59 : JpegファイルであるがExifではない (画像サイズは取得できる)
' 1999/12/31 23:59:59 : ファイルが存在しない
' 1998/12/31 23:59:59 : (存在はするが)オープンできない
' 1997/12/31 23:59:59 : Jpegファイルではない
' 1989/12/31 23:59:59 : 格納データのフォーマットにエラーがある
Function MyDateTimeOriginal(strfilepath As String) As Date
 Dim objJpeg As Object
 Dim res As Integer

 Set objJpeg = New JpegExif
 res = objJpeg.InitSet(strfilepath)
 Select Case res
  Case 2
   MyDateTimeOriginal = DateValue("2002/12/31 23:59:59")
  Case -1
   MyDateTimeOriginal = DateValue("1999/12/31 23:59:59")
  Case -2
   MyDateTimeOriginal = DateValue("1998/12/31 23:59:59")
  Case -3
   MyDateTimeOriginal = DateValue("1997/12/31 23:59:59")
  Case -11
   MyDateTimeOriginal = DateValue("1989/12/31 23:59:59")
  Default
   MyDateTimeOriginal = objJpeg.DateTimeOriginal
 End Select
End Function

で、帰ってきた年でエラー内容は確認できるようになるハズ。
あんまり上手くない方法ですが。

--
> 補足コメントに、参考画像 2枚を貼りました。

残念ながら、このサイトにアップロードする際に、Exif情報が落ちています。
これは、サイト内に画像をアップロードする際の仕様です。
多分、画像のサイズも変わっちゃってますし。

画像で添付されているエクスプローラでの確認方法でOK、画像自体は問題ないと思います。

残念ながら、サイトの規約で、そういったファイルを直接やり取りする事、そういうサイトへ誘導する事は禁止されているので、対象画像に関してこれ以上手助けするのは難しいです。
    • good
    • 0
この回答へのお礼

neKo_deuxさん、こんばんは。< 御礼 と 追加のお尋ね 2016/12/17 >
***外出していて、御礼が遅くなり、失礼いたしました。

***現在、追試して確認した事項です。

1.教えて!Gooのサイトでの、画像の取り扱い注意事項を教えて頂き、有難う御座いました。
2.WEBで、クラスモジュールの事を初め検索し、概要を学びました。
3.標準モジュールのCode:「Set objJpeg=New JpegExif」の「New」が、
_コードモジュールの「JpegExif」を参照するキーワードであると理解できました。
4.画像、Sample1を、C:\Tempに貼り、頂いた改良Codeをコピぺし、実行しました。その結果の書き出し:
4.1 「ファイル名=C:\Temp\Sample1.JPG」
4.2 「更新日時=2016/11/18 11:02」・・・VBA関数使用
4.3 「撮影日時=1999/12/31______」・・・貼って頂いた、Function のCode使用
4.4 この、1999/12/31は、Case1で、ファイルが存在しないに当たります。

***撮影日時の読み出しは難作業と理解できました。
5.1 初心者はこの辺りでギブアップが落としどころでしょうか?
5.2 Case-1のファイルが存在しないの対応策を、ご教授頂けますでしょうか?

お礼日時:2016/12/17 00:42

> しかし、戻り値の写真撮影日時=00:00:00でした。



エラーが出なければ、コードは問題ないと思います。

そもそも、写真にExif情報が含まれていなければ、当然ながら撮影日時は取り出せません。
試しに、下記のオリンパスのサイトの「サンプル写真1」を右クリック-[対象をファイルに保存]し、ファイル指定して再度確認してみてください。

OLYMPUS STYLUS TG-2 Tough|コンパクトデジタルカメラ|オリンパスイメージング
https://www.olympus-imaging.jp/product/compact/t …

自分のところでは「2013/03/09 11:42:01」って撮影時刻がしっかり取り出せました。

--
質問内容から、デジカメなどから取り込んだ写真だと思っていましたが。

どこかからダウンロードした写真なんかだと、撮影した場所なんかまでExif情報に含まれちゃう事があるので、最近はExif情報自体が削除されているかも。
あるいは、画像編集ソフト等で編集した際に、Exif情報を削除して保存するソフトもあります。
    • good
    • 0
この回答へのお礼

neKo_deuxさん、こんにちわ。<お礼と追加のお尋ね 2016/12/15>
度々、ご回答を頂、大変有難う御座います。
***
貼付画像の通り、ご案内のOlympusサイからJPGをコペピし、
また自分で撮影したCanonのJPGと並べてみました。エクスプローラでフォルダーを表示すると、
両画像とも、日付時刻・作成日時・更新日時・撮影日時は、明確に読み取れています。
***
残念ながら、両画像共、この試作Codoでは、読み出した撮影日時をワークシートに書き出すと、、
YYYY/MM/DD HH:MMタイプで、撮影日時=1900/1/0 0:00でした。 デフォルト値? 初期値?
最後のお願いですが、neKo_deuxさんが貼付の画像#02の読み出した時、撮影日時はどんなでしょうか?
なお、クラスモジュールの「JpegExif」と、この「Set objJpeg=New JpegExif」のリックする関係が理解できません。
どういう仕組みなのでしょうか?
***
補足コメントに、参考画像 2枚を貼りました。

お礼日時:2016/12/15 12:17

> VBAのコードウインドウに貼り付ければ実行できる、完結文を頂けませんでしょうか?



・クラスのコードの貼り付け
・関数のコードの貼り付け
を行う必要があります。

--
まず、クラスのコードの貼り付け、クラスの作成。

・ExcelからAlt+F11でVBEditorを起動します。
・左側上段のプロジェクトエクスプローラのウィンドウ、開いているブックを右クリック-[挿入]-[クラスモジュール]
 ->開いているブックに「Class1」が追加され、クラスのコードを入力するウィンドウが表示されます。
 ウィンドウタイトルが「~Class1(コード)」となっているハズ。
・No.1さんが紹介してくれた下記のサイトの頭から1/4あたりの、
 「最後に、少々長いですがJpegExifクラスのプログラムコードをご披露します。苦労の様が暴露されます。」
 以下のグレーの部分をコピペ。前後の空白削ると623行あるハズ。

Exif情報の読み出し
http://www.btinc.jp/vba_labo/study1.html

・左側下段のプロパティウィンドウで、「オブジェクト名」を
 Class1
  から
 JpegExif
 に変更します。
 ->左側上段のプロジェクトエクスプローラのブック内のクラス名もJpegExifに変わるハズ。

以上でクラスが登録されました。

--
関数のコードの貼り付けと使用方法

> **** 自作Code ***
> myFolder = "C:\Users\myName\ピクチャ\3000年JPG写真"
> myJPG = Dir(myFolder & "\" & "*.jpg")
> MsgBox ”読み出した日付時刻=” & FileDateTime(myFolder & "\" & myJPG)

のコードの先頭(末尾でもどこでも構いません)に、No.2の回答で書いた以下の関数をコピペ。

Function MyDateTimeOriginal(strfilepath As String) As Date
 Dim objJpeg As Object

 Set objJpeg = New JpegExif
 If objJpeg.InitSet(strfilepath) >= 0 Then
  MyDateTimeOriginal = objJpeg.DateTimeOriginal
 End If
End Function

使用方法はFileDateTimeに近くしているので、上の自作コードの3行目のみ変更して、

myFolder = "C:\Users\myName\ピクチャ\3000年JPG写真"
myJPG = Dir(myFolder & "\" & "*.jpg")
MsgBox ”読み出した日付時刻=” & MyDateTimeOriginal(myFolder & "\" & myJPG)

で良いハズ。
    • good
    • 0
この回答へのお礼

neKo_deuxさん、GooUserラックさん、こんばんは。

ちんぷんかんぷんのVBA初心者に、3回ものご回答を頂き有難う御座いました。
#3のご回答で記述して頂いた手順に沿って、コーディングを致しました。
****
VBAProject(撮影日時 Code合成.xlms)
--Microsoft Excel Objects
-----ThisWorkbook←←ここに、自作CodeとFunction MyDateTimeOriginalをコピぺ。
--クラスモジュール
-----JpegExif ←←← ここに、No.1さんご紹介の、「最後に、少々長いJpegExifクラスの全Codoをコピペ。
****
大分完成に近づいた様な気がしますが、戻り値の撮影日時=00:00:00です。
改めて、質問者のコメントで問題点をお伺い致しますが、宜しくお願いいたします。

お礼日時:2016/12/14 23:41

> Q1: 一行のCodoで、原画の「撮影日時」を読みす、関数・Codeを教えて下さい。



ユーザー定義のそういう関数があればOKです。
No.1さんの紹介しているサイトを参考にすると、

Function MyDateTimeOriginal(strfilepath As String) As Date
 Dim objJpeg As Object

 Set objJpeg = New JpegExif
 If objJpeg.InitSet(strfilepath) >= 0 Then
  MyDateTimeOriginal = objJpeg.DateTimeOriginal
 End If
End Function

で確認できました。
関数モジュールを使用するために、参考サイトの後半7割くらいのクラスモジュールのコードをJpegExifクラスとして登録する必要があります。
    • good
    • 0
この回答へのお礼

neKo_deuxさん;追加のコメント、有難う御座いました。

参照URLのSoftを試行して確認までして頂き、感涙です!
あるFolder内の数百枚の画像で、イレギュラーの写真が数件有っても、
前回の教えて!Gooで、教えて頂いたフリーSoftの「F6 Exif」や「TouchExif 1.1」で、
撮影日時や更新日時を手動で変更し、時系列のイレギュラーは解消できていました。
しかし数百枚の写真の一括変換で更新日時がすべて同一のSoft使用日時なってしまっては、
手動で書き直しはもはや不可能です!!!
****
自作ソフトでは、どうしても原画の「撮影日時」の読み出しが必須になりました。
VBAを触るのは、15年ぶりですが、これから、自作Softに、
「JpegExifクラスとして登録」ができるかどうかトライしてみます。
また、行き詰ったら、手取り足取りで、ご教授願います。

お礼日時:2016/12/12 16:52

一応確認します。


読み出したいのは「撮影日時」ですか?それとも「ファイル更新日時」ですか?
「撮影日時」は標準では得ることができません。独自でファイルを解析するものを作らないといけないので簡単には出来ません。以下のサイトで独自プログラムを公表しているようなのでそちらを使ってみてはいかがでしょうか?
http://www.btinc.jp/vba_labo/study1.html
念の為言っておきますが「撮影日時」は「Exif情報」に書かれているので「Exif情報」が無いJPGファイルでは得ることができません。
    • good
    • 0
この回答へのお礼

GooUserラックさん、早速、コメントを頂き有難う御座いました。

私の読み取りたいのは、写真の「撮影日時」です。
カメラで撮影してPCに取り込んた写真を見よう見まねで自作した写真整理Softで、
時系列的に編集しています。最近気づいたのですが、何ら加工してない写真では、
読み取った「更新日時」=「撮影日時」のため問題は起きませんでした。
***
最近、蓄積写真の容積が肥大し、一括画像圧縮Softを購入し、TEST中です。
このSoftは、「撮影日時」は削除しない設定もできます。
但し、圧縮後はSoft使用日時が更新日時になるため、
「更新日時」≠「撮影日時」となり、
自作の写真整理Softが役立たなくなっています。
***
「撮影日時」を読み出す簡単な関数コードは無いのですね。
自信はありませんが、ご紹介頂いたURLの解読にチャレンジしてみます。

お礼日時:2016/12/12 09:16

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています