2023/11/07

DXL Step-by-Step:#10)イメージリソースの新規作成

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

イメージリソース(設計要素)の読み込みについて、第 8 回第 9 回 で紹介しました。今回は、イメージリソースを新規作成する方法についてまとめます。

DXL を利用すれば、設計要素も新規作成できるようになります。これは、通常の NotesObjectClass だけではできないことなので DXL で Notes アプリの可能性が広がる部分となりますね。


Base64 のエンコード

DXL 内の画像データは、Base64 でエンコードされていました。今回は、イメージリソースに画像データを渡すことになるので、画像データ(バイナリファイル)を Base64 でエンコードされた文字列に変換する必要があります。

前回紹介したデコードと同じく OpenNTF の LotusScript Gold Collection プロジェクトに関数がありました。次のようなコードです。

%REM
   Function StreamToBase64
   Description: Convert a binary NotesStream to a string of Base64 data.
      The output can be used as part of DXL data for importing.
%END REM

Function StreamToBase64(streamIn As NotesStream) As String
   On Error GoTo theOldWay
   ' ReadEncoded function is not documented. In case it doesn't work have a backup.
   StreamToBase64 = Replace(streamIn.ReadEncoded(ENC_BASE64, 76), Chr$(13), "")
Exit Function

theOldWay:
   Dim session As New NotesSession
   Dim db As NotesDatabase
   Dim doc As NotesDocument
   Dim mime As NotesMIMEEntity

   Set db = session.CurrentDatabase
   Set doc = db.CreateDocument
   Set mime = doc.CreateMIMEEntity("Body")
   streamIn.Position = 0
   Call mime.SetContentFromBytes(streamIn, "image/gif", ENC_NONE)
   mime.EncodeContent(ENC_BASE64)

   StreamToBase64 = Replace(mime.ContentAsText, Chr$(13), "")
End Function

この関数は、なかなか興味深いですね。

コード内のコメントにも記載がありますが、ReadEncoded というヘルプに記載のないメソッドを使用しています。確かに最新の 12.0.2 のデザイナーヘルプを見ても NotesStream クラスにそのようなメソッドは記載されていません。この OpenNTF のプロジェクト、きっと、Notes/Domino 開発の ”中の人” かその周辺の方の業物なのでしょうね...

そして、この関数には保険がかかっています。万一このメソッドでエラーが発生した場合に備えて、エラー処理の中(theOldWay)に Plan B が記述されています。こちらは、デコードと同様の方法で実現されており、NotesMIMEEntity クラスを活用して変換しています。


サンプルプログラム

上記関数を利用しながら、イメージリソースを新規作成します。次のようなプログラムを作成しました。

まず、メインルーチンです。DXL をコントロールするために NotesDOMParser のオブジェクトを作成し、これに DXL をセットする xSetDXL 関数と 設計要素としてを保存する xImportDXL 関数をコールしています。

Sub Initialize
   Dim dprs As NotesDOMParser
   Dim ndb As NotesDatabase

   Set xns = New NotesSession
   Set ndb = xns.CurrentDatabase

   Set dprs = xns.CreateDOMParser()
   Call xSetDXL(dprs, "d:\denaoshi.png", "denaoshi2.png")

   Call xImportDXL(dprs, DXLIMPORTOPTION_CREATE)

End Sub


次はイメージリソースの DXL を生成するための xSetDXL 関数です。作成する DXL は最低限のタグだけとしています。まず、画像ファイルを NotesStream で開き、それを Base64 の文字列に変換して、<png> タグを作成しています。

Function xSetDXL( _
         vdprs As NotesDOMParser, _
         ByVal vsFilePath As String, _
         ByVal vsResourceName As String)

   Dim ddn As NotesDOMDocumentNode
   Dim denNew As NotesDOMElementNode
   Dim denDoc As NotesDOMElementNode
   Dim denItem As NotesDOMElementNode
   Dim dtnNew As NotesDOMTextNode

   Dim nst As NotesStream

   '画像ファイルを開く
   Set nst = xns.CreateStream()
   Call nst.Open(vsFilePath)


   'イメージリソースのエレメント作成
   Set ddn = vdprs.Document
   Set denNew = ddn.CreateElementNode("imageresource")
   Call denNew.SetAttribute("name", vsResourceName)
   Set denDoc = ddn.AppendChild(denNew)

   '画像イメージの追加
   '--------------------

   Set denNew = ddn.CreateElementNode("png")
   Set denItem = denDoc.AppendChild(denNew)
   '画像データセット
   Set dtnNew = ddn.CreateTextNode(StreamToBase64(nst))
   Call denItem.AppendChild(dtnNew)
   Set denNew = ddn.CreateElementNode("text")

   'フィールドの追加
   '--------------------
   '$FileSize

   Call xAppendField(ddn, "$FileSize", nst.Bytes)

   '$MimeType
   Call xAppendField(ddn, "$MimeType", "image/png")
End Function

その後必要なフィールドである $FileSize と $MimeType を作成しています。ファイルサイズは、NotesStream クラスの Bytes プロパティで取得しています。これは便利ですね。


フィールドを作成する関数は次の通りです。第 4 回 で紹介したフィールドを作成する関数 xAppendField_Text を少し改造し、テキストに限らず数値でも利用できるようにしました。具体的には、セットする値 vvValue を Variant 型に変更し、関数内で型をチェックして、型に合わせたタグを生成し、値をセットしています。

Function xAppendField( _
         vddn As NotesDOMDocumentNode, _
         ByVal vsFldName As String, _
         ByVal vvValue As Variant) As Boolean

   Dim sType As String

   '型判定
   If IsArray(vvValue) Then
      '配列は未対応
   Else
      If TypeName(vvValue) = "STRING" Then sType = "text"
      If TypeName(vvValue) = "INTEGER" Then sType = "number"
      If TypeName(vvValue) = "LONG" Then sType = "number"
      If TypeName(vvValue) = "SINGLE" Then sType = "number"
      If TypeName(vvValue) = "DOUBLE" Then sType = "number"

   End If
   If sType = "" Then Exit Function '未対応のため中断

   'document ノード取得
   Dim denCur As NotesDOMElementNode
   Set denCur = vddn.DocumentElement

   'item ノード作成とフィールド名の指定
   Dim denNew As NotesDOMElementNode
   Set denNew = vddn.CreateElementNode("item")
   Call denNew.SetAttribute("name", vsFldName)
   Set denCur = denCur.AppendChild(denNew)

   '値のノードと値のセット
   Dim dtnNew As NotesDOMTextNode
   Set denNew = vddn.CreateElementNode(sType)
   Set denCur = denCur.AppendChild(denNew)
   Set dtnNew = vddn.CreateTextNode(CStr(vvValue))
   Call denCur.AppendChild(dtnNew)
End Function

日付や配列にはまだ対応できていませんので、実用化するにはまだ改善が必要ですね。


最後は DXL を設計要素として保存する関数です。第 4 回 で文書を保存する関数として紹介した xImportDXL とほぼ同様なのですが、今回は設計要素なので DesignImportOption プロパティを使用しています。

Function xImportDXL(vdprs As NotesDOMParser, ByVal viOption As Integer) As Boolean
   'DXL の抽出準備
   Dim nst As NotesStream
   Set nst = xns.CreateStream()
   Call vdprs.SetOutput(nst)
   Call vdprs.Serialize()

   '保存(インポート)
   Dim ndb As NotesDatabase
   Dim dimp As NotesDXLImporter
   Set ndb = xns.CurrentDatabase
   Set dimp = xns.CreateDXLImporter()
   dimp.DesignImportOption = viOption
   Call dimp.Import(nst.ReadText(), ndb)
End Function

今回は設計要素の新規作成ですのでこの viOption には、DXLIMPORTOPTION_CREATE が指定されています(この関数をコールしているメインルーチンを参照)。


実行結果

このプログラムを実行すると次のように設計要素が作成されます。


前回 DXL Step-by-Step 次回

0 件のコメント:

コメントを投稿