2023/11/05

DXL Step-by-Step:#9)DXL 内の画像のダウンロード

DXL 活用の調査・検証で、実現できたことや発見したことご紹介する『DXL Step-by-Step』シリーズの第 9 回です。

今回はイメージリソース(設計要素) から 画像を取り出す方法についてまとめます。


画像ファイルの状態

まず、前回確認したイメージリソースの DXL で画像データは次のように文字列で表されていました。

画像データであるバイナリーデータが Base64 でエンコードした状態となっています。メールの添付ファイル(MIME)と同様ですね。


Base64 のデコード

エンコードされた画像ファイル(=文字列)を Base64 でデコードすれば、画像データが取得できます。では、どうやってデコードするのでしょうか?

私が DXL に出会うきっかけとなった OpenNTF の LotusScript Gold Collection プロジェクトで公開されている DB 内で関数化されていました。今回はこれを拝借します。

私が作ったコードではないので、関数全体をコメント付きでそのまま転載します。

%REM
   Sub Base64ToBinary
   Description: Given a string of base64-encoded data, write into a binary stream we are passed.
      This is done rather than creating the stream here and returning it, so that you can
   stream directly into a file if you choose.
%END REM

Sub Base64ToBinary(strBase64$, streamOut As NotesStream)
   ' Given a string of base64 encoded data, this routine decodes and writes the original binary data into a NotesStream
   Dim doc As NotesDocument
   Dim mime As NotesMIMEEntity
   Dim streamIn As NotesStream
   Dim db As NotesDatabase
   Dim session As New NotesSession

   Set db = session.CurrentDatabase
   Set doc = db.CreateDocument
   Set mime = doc.CreateMIMEEntity("Body") ' the mime classes already know how to do this conversion,
   Set streamIn = session.CreateStream
   Call streamIn.WriteText(strBase64)
   streamIn.Position = 0
   Call mime.SetContentFromText(streamIn, "binary", ENC_BASE64)
   Call mime.GetContentAsBytes(streamOut, True) ' decode as you stream out the data.
End Sub

デコードは NotesMIMEEntity クラスを活用して実行しているようです。このクラスは、今回初めて利用したので詳細はわかりかねるのですが、SetContentFromText メソッドで、エンコード文字列をデコードしつつ NotesMIMEEntity のオブジェクトに取り込み、GetContentAsBytes メソッドでバイナリデータとして抽出しているようです。


サンプルプログラム

それでは、上記関数も活用しつつ、イメージリソースからファイルを抽出するプログラムを作成します。

まず、メインルーチンです。前回のコードの DXL を保存する部分を画像ファイルをダウンロードする新しい関数を指定しています。

Option Declare
Private xns As NotesSession

Sub Initialize
   Dim ndb As NotesDatabase
   Dim ndAgent As NotesDocument

   Set xns = New NotesSession
   Set ndb = xns.CurrentDatabase

   Dim nnc As NotesNoteCollection
   Set nnc = ndb.CreateNoteCollection(False)
   nnc.SelectImageResources = True
   nnc.SelectionFormula = xGetFormula("TitleS.PNG")
   Call nnc.BuildCollection()

   Dim dprs As NotesDOMParser
   If nnc.Count > 0 Then
      Set ndAgent = ndb.GetDocumentByID(nnc.GetFirstNoteID)
      Set dprs = xGetDOMParser(ndAgent)

      Call xDownloadImage(dprs, "d:\denaoshi.png")
   End If
End Sub


続いて、画像ファイルをダウンロードするメインルーチンです。まず、png エレメントノードを取得して、Base64 でエンコードされた画像データを sB64 変数に代入しています(赤字)。png ノードの直下にエンコード文字列があります。この場合、最初の子ノードがテキストノードとなるため、このようはコードになっています。

Function xDownloadImage(vdprs As NotesDOMParser, ByVal vsFP As String) As Boolean
   'DOM ツリーのルートを取得
   Dim ddn As NotesDOMDocumentNode
   Set ddn = vdprs.Document

   'ImageResource エレメントの取得
   Dim denImage As NotesDOMElementNode
   Set denImage = ddn.DocumentElement

   '画像ファイルダウンロード
   Dim denPNG As NotesDOMElementNode
   Dim dnl As NotesDOMNodeList
   Dim dtn As NotesDOMTextNode
   Dim nst As NotesStream
   Dim sB64 As String

   Set dnl = denImage.GetElementsByTagName("png")
   If dnl.NumberOfEntries > 0 Then
      Set denPNG = dnl.GetItem(1)
      Set dtn = denPNG.FirstChild


      'エンコードされた画像データ取得
      sB64 = dtn.NodeValue

      'ファイルとして保存
      Set nst = xns.CreateStream()
      Call Base64ToBinary(sB64, nst)
      Call StreamToImageFile(nst, vsFP)

   End If
End Function

取得したエンコード文字列をファイルに変換しているのは青字の部分です。事前に紹介した関数を使用して、エンコード文字列をバイナリデータに変換し、NotesStream にセットしています。それを ファイルに出力する関数 StreamToImageFile に渡しています。


StreamToImageFile 関数は次の通りです。ファイルを NotesStream で開いて、イメージデータの NotesStream から ファイルの NotesStream に渡しています。

Sub StreamToImageFile(vnstImage As NotesStream, ByVal vsFP As String)
   Dim nstOut As NotesStream

   On Error Resume Next
   Kill vsFP '存在してたら削除

   Set nstOut = xns.CreateStream()
   Call nstOut.Open(vsFP)

   vnstImage.Position = 0
   Do Until vnstImage.Position >= vnstImage.Bytes
      Call nstOut.Write(vnstImage.Read(16000))
   Loop
End Sub

NotesStream クラスの使い方ってなんとなく抽象的で、つかみどころがなく苦手です。

ファイルみたいなもので、Position を使って、ファイル内を行ったり来たりできるということなのでしょうね。このコードを書いていてそんな気がしてきました。


実行結果とまとめ

このプログラムを実行すると次のように画像ファイルが出力されます。



ノーツでノーツアプリを作っているだけでは、ノーツ以外の知識以外が身に付きにくいですよね。今回初めて Base64 について調べることになりました。DXL は、LotusScript でノーツアプリを作っているだけではあるのですが、少しだけ外の世界を見るきっかけとなりました...


前回 DXL Step-by-Step 次回

0 件のコメント:

コメントを投稿