ラベル X3F の投稿を表示しています。 すべての投稿を表示
ラベル X3F の投稿を表示しています。 すべての投稿を表示

2010/02/22

データの構造にモノ申すっ・・・


・・・X3Fファイルのハナシ。


データ展開のカギとなる値を含むのは、選りにも選って、ファイルの先頭部分と末端部分に分かれている。
ツマり、画像やEXIFを適宜読み取るには、一旦全てのファイルをメモリへ読み込む必要性に迫られる。

エクスプローラで情報を表示するだけでも時間を要すると云う構造だ。
そもそも、EXIFをWindowsに提供する機能すら持たないフォーマットなので、
過去紹介したような、サムネイル表示プラグインツールが必要となる。

むしろ、それらで運用するだけなら、問題を認識することは無かったと思う。
そんな折、支障があるコトが判ったのは、VBScriptでEXIF抜きを試行した際だ。

データの先頭位置を記録しているのが、ファイルの末端部分だったってのが、致命的で、
先頭の1kB程度を読むだけで得られる撮影情報の先頭位置すらも、ココに記録されているのだ。
それら情報を適切に、全て見えるカタチにする為には、ファイルを最後まで取り込んで、
末端部分も確保する必要があるのだ。


   ナニ云ってるカナ? ADODBStreamで、スキップ読みすればイイだけだろ?


・・・と思うよね、やっぱり(´ヘ`;)
確かに その処理も、ローカルドライブで扱うには、そう大きな支障はないんだが、
ネットワークを介する場合、困ったことが起こる。

以前のログでも述べた通り、ADODBStreamでネットワークドライブ上のファイルを扱う場合、
その意図が無くとも、一旦ローカルのテンポラリフォルダへ全容量確保された後、処理に利用されるのだ。
・・・X3Fファイルのサイズは そう小さくない、縦しんば、GigabitEthernetを利用していたとしても、
大量のファイルから一気にEXIFを抜く、などと云った処理の場合、膨大な時間を要してしまう・・・
ファイルの数次第では、ローカルで処理しても同様の問題を抱えてしまい、実用性に掛ける結果に見舞われた。


   だったら、FileSystemObjectのTextStreamで、一部分抜粋読み出しで解決~


・・・とも考えるよな~ でも実際は、コレもダメだった。
部分読みには成功するのだが、文字コードとして処理できない部分が、強制的に置き換えられてしまい、
元の情報として機能しない破損データとなってしまうのだ。・・・なんか前置き長かったね(^_^;) ナニが云いたいのかってぇと、"X3Fデータの形式を改めろ" ってコト。


X3Fファイルの構造概略


  1.Headder
  2.JPEG FullSize 2640×1760
  3.CAMP -Unknowns-
  4.Property for EXIF Data
  5.RAW Data
  6.JPEG for Preview
  7.Directory
  8.Offset Directory


つー資料掲載のサイトがあった。
撮影後、本体内で出来たデータの順でファイルを書き込んでるのがロコツに判る、
しかしSD14からのデータを覗くに、かなり変えてある可能性が高い。が、1と7と8は、あの位置で間違いがナイ。

ツマり、8を読まないと、各データの先頭位置の情報を含む場所(7)も判らないし、
そのアト、7を読んで、ようやく各データの先頭位置が確保できる・・・ なんて毛唐な文法・・・(-_-;)


pdfのX3Fファイル仕様書によると、もっと大雑把なのがあったw


  1.Extended Header
  2.Data
  3.Directory
  4.Directory Pointer


・・・(´ヘ`;) やはりココは日本人らしく、使いやすい順序に並べ替えるべきだ!


  4.Directory Pointer
  3.Directory
  1.Extended Header
  2.Data


コレなら、ファイルの必要な部分にのみ適宜アクセスする処理を容易に構築できる。
3を固定長にすれば、4は不要になり、肝心の 2 の中身も、


  1.JPEG for Preview
  2.JPEG FullSize 2640×1760
  3.RAW Data


コレならPhotoPRO等でのサムネイル表示も、不要な部分を読み込む必要から開放され、高速化が可能になる。
1の記録破損問題さえ解決できればな~Ψ(`∀´)Ψ


しかし、管理の利便性を向上させる為にも、一考の価値、あると思うのだがねぇ・・・(´ヘ`;)

2010/01/03

アレ対応版・・・


前の版で困難だった、ネットワークドライブ/フォルダ上のファイルアクセスも容易にする為、
対象ファイル読み込み処理だけ、ADODB.Streamから FileSystemObject.OpenTextFileに差し替えました。

以前のログにも記述した通り、ADODB.Streamでは、どう処理の順序を変えても、
ネットワーク先からローカルドライブへ、無条件にテンポラリってしまい、
大量のファイルを連続処理するのはおろか、1つのファイルだけでも多大な時間を要していたのです。

で、今朝・・・ つーか深夜だけどw 夜通しでFSO版を試作してみて、その問題の解消に至りました。
やっぱり餅は餅屋、ファイルアクセスなら、DB向けオブジェクト使うより、FSOってコトですかね・・・(^_^;)
って、書き込みとかはADOのままですケドww以下はアーカイブです。

X3FSIR.zip βReleaseArchive - 20100103 0739 launch -
▲ を、右クリックしてファイルとして保存してください。


とは云え まだまだ、

     アクマで暫定版デスから。結局こんなん出ました~w

'***** ↓↓↓ScriptTitle↓↓↓ *********************************************************
' X3FSIR.vbs - X3F ShootingInformationsReader
' FoveonX3 RAWファイルから、撮影情報を文字列として取得する。

' - Created by LazwardFox -

'

' Update -------- ----
' Release
' Update
' βRelease
' Update 20100103 0706 Source読み込み部のみ、ADODB.Streamから
' FileSystemObject.OpenTextFileに差し替えるコトで、
' ファイルへのアクセスを最小限化、LANファイルアクセス対応へ。
' Update 20091231 1814 0byteファイルに因るエラーへ対策。
' Update 20091231 0425 処理集約の誤りを修正。
' Update 20091230 0315 複数ファイル指定に暫定対応。
' Update 20091230 0130 撮影日時文字列化処理追加/テキストデータの範囲可変に対応。
' αRelease 20091226 2150 単一ファイル取得版、データも内容のまま列挙。
' 日本語/最適化準備中。
' DevStart 20091226 2040

'***** ↓↓↓ ObjectDecralations ↓↓↓ *************************************************
Option Explicit
Public My, Parameters, Fs, objADO ', MySh, objSMTP, objMx
Set My = WScript
With My
Set Parameters = .Arguments ' パラメーター取得
If Parameters.Count <= 0 Then ' パラメータなし起動の無効化
.Quit
End If

Set Fs = .CreateObject("Scripting.FileSystemObject")
Set objADO = .CreateObject("ADODB.Stream")
'Set MySh = .CreateObject("WScript.Shell")
'Set objSMTP = .CreateObject("CDO.Message") ' SMTP Object
'Set objMx = .CreateObject("MSXML2.XMLHTTP") ' URL Check
End With

'***** ↓↓↓ Decralations ↓↓↓ *************************************************
'Public ThisScriptFull, ThisScript, Start
Const vbWq = """"

' Const - Letters
Dim vbWCrLf, vbTc, vbNullB
vbWCrLf = vbCrLf & vbCrLf
vbTc = vbTab & vbCrLf
vbNullB = chr(&h00)

' Const - Date/Times


'***** ↓↓↓ LocalDecralations ↓↓↓ *************************************************
Dim X3FSet

'***** ↓↓↓MainRoutine↓↓↓ *********************************************************
'On Error Resume Next

'X3FSet = Array("X3F",, 264, 1500, "VERSION_BF", "BURST", "TIME", "1970/1/1")
X3FSet = Array("X3F",, 0, 1800, "VERSION_BF", "BURST", "TIME", "1970/1/1")
BPS Parameters, X3FSet


' ----- ExitProcess
Set Fs = Nothing
Set objADO = Nothing
My.Quit

'***** ↓↓↓Functions↓↓↓ *********************************************************
' X3FSIs
'------------------------------------
' Binary Pickup to Strings
' バイナリファイル中 範囲を指定し、任意の文字列群を抽出する。

' - Created by LazwardFox -

' Fs、objADO、cnvDateTime

' Update
' Release
' βRelease
' Update 20091231 1814 0byteファイルに因るエラーへ対策。
' Update 20091231 0425 処理集約の誤りを修正。
' Update 20091230 0315 複数ファイル指定に暫定対応。
' αRelease 20091230 0300
' DevStart 20091230 0200 X3FSIsを汎用用途向けに修正。

' BPS (
' arFileNames - 対象ファイル群配列。
' ,arSet - 動作パラメータを、下記スキーマ準拠の配列で指定。
' )


' ▼▼ arSet Schema ▼▼▼▼▼

' = Array(strEx, SaveFileName, StartBit, ReadByte, Firstkey, Lastkey, strTimeKey, BaseDate)

' arSet
' (0) {strEx} 対象拡張子 (String)
' (1) {SaveFileName} 保存ファイル名 (String)
' (2) StartBit 読み取り先頭位置(Bit) (Number)
' (3) ReadByte 読み込み範囲(byte) (Number)
' (4) Firstkey 先頭キー名 (String)
' (5) Lastkey 最終キー名 (String)
' (6) {strTimeKey} 時間キー名 (String)
' (7) {BaseDate} 時間変換基日付文字列("y/m/d") (String)


Function BPS(arFileNames, arSet)
Dim kNothing, iADO, strTarget, Pc, fKey, rSource, rHeader, lHeader
Dim pResult, arResult, rUnits, sResult
kNothing = String(5, vbNullB) ' キーも値も存在しない範囲の、データ排除向け
Set iADO = objADO
For Each strTarget In arFileNames
If Fs.GetExtensionName(strTarget) = arSet(0) Then
arSet(1) = Replace(strTarget,"." & arSet(0),".txt") ' < 暫定
Set rSource = Fs.OpenTextFile(strTarget,1) ' 対象ファイルを読み取りモードで開く
With rSource
' ファイルから指定範囲をメモリへ取得
If arSet(2) > 0 Then
.Skip(arSet(2)) ' 先頭位置をセット
End If
rHeader = .Read(arSet(3)) ' 指定範囲を取得
End With
Set rSource = Nothing
With iADO
If LenB(rHeader) > 0 Then
' Convert to PlainText
rHeader = CStr(rHeader) ' 次処理に備え、文字列データ化
rHeader = Replace(rHeader, "SECc", "") ' 無効キー排除
rHeader = Replace(rHeader, kNothing, "") ' 無効範囲の消去
.Type = 2 ' AccessMode - Text
.Charset = "_autodetect" '"Shift_JIS" "Unicode" "utf-8"
.Open
.Position = 0
.WriteText = rHeader
lHeader = .Position ' 取得データ長
rHeader = ""
For Pc = 1 To lHeader Step 2
.Position = Pc
pResult = pResult & .ReadText(1)
Next
.Close
arResult = Split(pResult, vbNullB) ' 配列化。
pResult = ""
For Each sResult In arResult
If sResult = arSet(4) Or fKey > 0 Then ' スタートキー
If fKey = 4 Then ' 日付データ変換
sResult = cnvDateTime(arSet(7), sResult)
End If
rUnits = rUnits & sResult ' 値書き込み
' ▼ 末尾符号/キー検出処理 ▼▼▼▼▼
If fKey < 2 Then
If sResult = arSet(5) Then ' 終了キー
fKey = 5
ElseIf sResult = arSet(6) Then ' 時刻値変換対象
fKey = 4
Else
fKey = 3
End If
rUnits = rUnits & "," ' キー末尾処理
Else
rUnits = rUnits & vbCrLf ' データ末尾処理
If fKey = 5 Then ' 処理終了
Exit For
End If
fKey = 1
End If
' ▲ 末尾符号/キー検出処理 ▲▲▲▲▲
End If
sResult = ""
Next
arResult = ""
fKey = 0
' 指定ファイルへ書き込み
.Type = 2 ' AccessMode - Text
.Charset = "_autodetect"
.Open
.Position = 0
.WriteText rUnits
.SaveToFile arSet(1), 2
End If
.Close
End With
rUnits = "" ' < 暫定
End If
Next
Set iADO = Nothing
End Function

'------------------------------------
' cnvDateTime
' 秒整数で構成された日時データを、Windowsシリアル値に変換。
' 基準日の異なる値の変換にも対応。

' - Created by LazwardFox -

'

' Update
' Release
' βRelease 20091230 0300
' αRelease 20091229 1635
' DevStart 20091229 1500

' cnvDateTime (
' strBaseDate - "y/m/d"形式の日付文字列、基準日を指定。
' ,SourceDateTime - Secベースの経過時間を表す整数
' )

Function cnvDateTime(strBaseDate, SourceDateTime)
Dim sDate
sDate = DateValue(strBaseDate)
cnvDateTime = (((SourceDateTime / 60) / 60) / 24) + sDate
End Function




< ファイルの一部へのみアクセスするなら、FileSystemObject(FSO) >

2009/12/30

またかいっ・・・


先の おでかけ撮影のトキにもヤられた、SD14の撮影データ破損。
今朝の就寝前定点撮影データも完全ロスト・・・ もう勘弁して(-_-;)

CFメーカー/商品問わず こんな症状出るようなら、新たにCFを買い足すとしても躊躇する罠・・・(´ヘ`;)

取り敢えずChkDskで回復させたが、確保できた.chkファイルの拡張子をX3F変え、
そのままSIGMA PhotoProで現像を試みたトコロで、余程 運が良くない限り、現像は出来ない。
しかし、面白いコトがついさっき判った。
前ログ公開のスクリプトで、正常なファイルと同様に撮影情報が取得できたのだワw

確かに、元々から、完全に全ての情報を取得できないスクリプトだったワケだが、
Header破損しているファイルからも、正常なファイルからのモノと変わらないデータを抜き出せたコトに驚いている。

・・・でも、現像は出来ないんだよなぁ(;_;)
RAW内のメインデータの範囲を取得する手段があれば復元できそうだが、
その情報を格納しているハズのFooterも死んでるコトが多いし、
当然ファイル内で一番規模の大きいメインデータの破損も考えられるワケだから、
結局安直には解決できん・・・(´ヘ`;)


ま、撮影のログだけでも簡単に確保できたので、ヨシとするしかナイ罠・・・

なんだか・・・


・・・またまた遅延。 真に おきつねさまくおりてぃww


って アレ、まだ完成はしていない。


・・・先のを うpしたアトに気付いたコトなのだが、今回、スクリプトの対象としているトコロのX3Fファイルってのは、
どうやらカメラ側の設定次第で、付随するデータの開始位置も変ってしまうようで、
文字列として抽出する範囲固定で処理しているようなブツでは、うまく対応できないと云う罠(-_-;)

また、撮影日時の値も、秒で構成された小数点以下の値を使わない整数で表されている上、
基準日時が通常端末とは異なる1970/01/01と云う仕様。
・・・Longで表されるシリアル値で、且つ 1900/01/01を基準として動作するVBScriptの日付関数では、
単純に そのまま代入して使うと云うワケには逝かなかった。

今回は、それらの点への対応と、オブジェクトの再利用など、処理の流れを大幅に見直し効率化を図り、且つ
暫定ではあるが、複数ファイルドロップも可能にした。


・・・ただ、カメラの設定項目で、SIGMA PhotoProでも抽出でき、撮影データと深く関わりのある、
露出補正/コントラスト/彩度/シャープネス は、あれらテキストとは、独立したBitで記録されているらしく、
今回の版でも取り出せてない。

そのヘン、X3Fファイルのデータ形式について物色したら、意外に単純でない項目があって、
仕様の通りの処理していては、ファイルの全領域を読み込む必要性に迫られてしまう・・・
コレは、ネットワークドライブを多用している おきつねさま的には、非常~にヨロしくない(´ヘ`;)
なので、実機サンプル撮影後のデータを比較解析し、詳細が判明し次第、スクリプトに反映させるコトとした。


ま、今回のでも、前の版よりは、全然マシではあるモノの、以下は やっぱり、
まだまだ アクマでサンプルですから・・・m(_ _)mスクリプトは、散々コソコソ差し替えつつも、何気にメドイさんだったんで
アーカイブせずに放置していたのだが、取り敢えず、うpしますたm(_ _)m


X3FSIR_a.zip αReleaseArchive - 20100103 0723 Update -
▲ を、右クリックしてファイルとして保存してください。晒し者w

'***** ↓↓↓ScriptTitle↓↓↓ *********************************************************
' X3FSIR_a.vbs - X3F ShootingInformationsReader
' FoveonX3 RAWファイルから、撮影情報を文字列として取得する。

' - Created by LazwardFox -

'

' Update -------- ----
' Release
' Update
' βRelease
' Update 20100103 0603 変数整理。
' Update 20091231 1814 0byteファイルに因るエラーへ対策。
' Update 20091231 0425 処理集約の誤りを修正。
' Update 20091230 0315 複数ファイル指定に暫定対応。
' Update 20091230 0130 撮影日時文字列化処理追加/テキストデータの範囲可変に対応。
' αRelease 20091226 2150 単一ファイル取得版、データも内容のまま列挙。
' 日本語/最適化準備中。
' DevStart 20091226 2040

'***** ↓↓↓ ObjectDecralations ↓↓↓ *************************************************
Option Explicit
Public My, Parameters, Fs, objADO ', MySh, objSMTP, objMx
Set My = WScript
With My
Set Parameters = .Arguments ' パラメーター取得
If Parameters.Count <= 0 Then ' パラメータなし起動の無効化
.Quit
End If

Set Fs = .CreateObject("Scripting.FileSystemObject")
Set objADO = .CreateObject("ADODB.Stream")
'Set MySh = .CreateObject("WScript.Shell")
'Set objSMTP = .CreateObject("CDO.Message") ' SMTP Object
'Set objMx = .CreateObject("MSXML2.XMLHTTP") ' URL Check
End With

'***** ↓↓↓ Decralations ↓↓↓ *************************************************
'Public ThisScriptFull, ThisScript, Start
Const vbWq = """"

' Const - Letters
Dim vbWCrLf, vbTc, vbNullB
vbWCrLf = vbCrLf & vbCrLf
vbTc = vbTab & vbCrLf
vbNullB = chr(&h00)

' Const - Date/Times


'***** ↓↓↓ LocalDecralations ↓↓↓ *************************************************
Dim X3FSet

'***** ↓↓↓MainRoutine↓↓↓ *********************************************************
'On Error Resume Next

'X3FSet = Array("X3F",, 264, 1500, "VERSION_BF", "BURST", "TIME", "1970/1/1")
X3FSet = Array("X3F",, 0, 1764, "VERSION_BF", "BURST", "TIME", "1970/1/1")
BPS Parameters, X3FSet


' ----- ExitProcess
Set Fs = Nothing
Set objADO = Nothing
My.Quit

'***** ↓↓↓Functions↓↓↓ *********************************************************
' X3FSIs
'------------------------------------
' Binary Pickup to Strings
' バイナリファイル中 範囲を指定し、任意の文字列群を抽出する。

' - Created by LazwardFox -

' Fs、objADO、cnvDateTime

' Update
' Release
' βRelease
' Update 20091231 1814 0byteファイルに因るエラーへ対策。
' Update 20091231 0425 処理集約の誤りを修正。
' Update 20091230 0315 複数ファイル指定に暫定対応。
' αRelease 20091230 0300
' DevStart 20091230 0200 X3FSIsを汎用用途向けに修正。

' BPS (
' arFileNames - 対象ファイル群配列。
' ,arSet - 動作パラメータを、下記スキーマ準拠の配列で指定。
' )


' ▼▼ arSet Schema ▼▼▼▼▼

' = Array(strEx, SaveFileName, StartBit, ReadByte, Firstkey, Lastkey, strTimeKey, BaseDate)

' arSet
' (0) {strEx} 対象拡張子 (String)
' (1) {SaveFileName} 保存ファイル名 (String)
' (2) StartBit 読み取り先頭位置(Bit) (Number)
' (3) ReadByte 読み込み範囲(byte) (Number)
' (4) Firstkey 先頭キー名 (String)
' (5) Lastkey 最終キー名 (String)
' (6) {strTimeKey} 時間キー名 (String)
' (7) {BaseDate} 時間変換基日付文字列("y/m/d") (String)


Function BPS(arFileNames, arSet)
Dim kNothing, iADO, strTarget, Pc, fKey, rSource
Dim lHeader, pResult, arResult, rUnits, sResult
kNothing = String(5, vbNullB) ' キーも値も存在しない範囲の、データ排除向け
Set iADO = objADO
For Each strTarget In arFileNames
If Fs.GetExtensionName(strtarget) = arSet(0) Then
arSet(1) = Replace(strtarget,"." & arSet(0),".txt") ' < 暫定
With iADO
' ファイルから指定範囲をメモリへ取得
.Type = 1 ' AccessMode - Binary
.Open
.LoadFromFile strTarget ' 対象ファイル
.Position = arSet(2) ' 先頭位置をセット
rSource = .Read(arSet(3)) ' 指定範囲を取得
If .Position > 0 Then ' 20091231 1814
.Close
' Convert to PlainText
rSource = CStr(rSource) ' 次処理に備え、文字列データ化
rSource = Replace(rSource, kNothing, "") ' 無効範囲の消去
.Type = 2 ' AccessMode - Text
.Charset = "_autodetect" ' "Shift_JIS" "utf-8" "Unicode"
.Open
.Position = 0
.WriteText = rSource
lHeader = .Position ' 取得データ長
rSource = ""
For Pc = 0 To lHeader
.Position = Pc
pResult = pResult & .ReadText(1)
Next
.Close
arResult = Split(pResult, vbNullB) ' 配列化。
pResult = ""
For Each sResult In arResult
If sResult = arSet(4) Or fKey > 0 Then ' スタートキー
If fKey = 4 Then ' 日付データ変換
sResult = cnvDateTime(arSet(7), sResult)
End If
rUnits = rUnits & sResult ' 値書き込み
If fKey < 2 Then ' ▼ 末尾符号/キー検出処理 ▼▼▼▼▼
If sResult = arSet(5) Then ' 終了キー
fKey = 5
ElseIf sResult = arSet(6) Then ' 時刻値変換対象
fKey = 4
Else
fKey = 3
End If
rUnits = rUnits & "," ' キー末尾処理
Else
rUnits = rUnits & vbCrLf ' データ末尾処理
If fKey = 5 Then ' 処理終了
Exit For
End If
fKey = 1
End If ' ▲ 末尾符号/キー検出処理 ▲▲▲▲▲
End If
sResult = ""
Next
arResult = ""
fKey = 0
' 指定ファイルへ書き込み
.Type = 2 ' AccessMode - Text
.Charset = "_autodetect"
.Open
.Position = 0
.WriteText rUnits
.SaveToFile arSet(1), 2
End If
.Close
End With
rUnits = "" ' < 暫定
End If
Next
Set iADO = Nothing
End Function

'------------------------------------
' cnvDateTime
' 秒整数で構成された日時データを、Windowsシリアル値に変換。
' 基準日の異なる値の変換にも対応。

' - Created by LazwardFox -

'

' Update
' Release
' βRelease 20091230 0300
' αRelease 20091229 1635
' DevStart 20091229 1500

' cnvDateTime (
' strBaseDate - "y/m/d"形式の日付文字列、基準日を指定。
' ,SourceDateTime - Secベースの経過時間を表す整数
' )

Function cnvDateTime(strBaseDate, SourceDateTime)
Dim sDate
sDate = DateValue(strBaseDate)
cnvDateTime = (((SourceDateTime / 60) / 60) / 24) + sDate
End Function