2014/06/14(土) [n年前の日記]
#1 [libreoffice] OpenOffice/LibreOffice Writerでアルバムページを作成するマクロ
たぶんそれっぽく書けた、ような気がするので一応アップロード。
◎ 概要。 :
◎ 操作方法。 :
_album_make_macro_20140614.zip
をDL・解凍して、album_make.odt を、OpenOffice / LibreOffice Writer で開いてみてください。
「アルバムを挿入」ボタンそのものは、印刷には出ない設定にしてありますので、印刷時にわざわざボタンを削除しなくてもOKです。
- 「マクロを有効化するか?」と尋ねてくるので、有効を選びます。
- 「アルバムを挿入」ボタンを押せば、ダイアログが開きます。
- 「画像を追加」ボタンを押して、画像を選んでください。複数の画像を選択できます。
- 列数その他を入力して、「画像サイズ算出」ボタンを押してください。目標画像サイズが大雑把に計算されます。
- 「アルバム作成」ボタンを押せば、文書の最後に、表形式でアルバムが挿入されます。
「アルバムを挿入」ボタンそのものは、印刷には出ない設定にしてありますので、印刷時にわざわざボタンを削除しなくてもOKです。
◎ 動作確認環境。 :
- Windows7 x64
- LibreOffice Writer 4.2.4.2
- Apache OpenOffice Writer 4.1.0
◎ ソース。 :
ooo BASIC 部分は以下の通り。
_make_album.bas
ダイアログ部分は以下の通り。
_MakeAlbumDialog.xdl
一応、ソースの中身も列挙しておきます。実験用のコードも多々残ってますが…。
_make_album.bas
ダイアログ部分は以下の通り。
_MakeAlbumDialog.xdl
一応、ソースの中身も列挙しておきます。実験用のコードも多々残ってますが…。
OPTION EXPLICIT Public oDialog as Object Public oListBox as Object Public oField1 as Object Public oField2 as Object Public oField3 as Object Public oField4 as Object Sub Main ' 表示するダイアログを指定 DialogLibraries.LoadLibrary("Standard") oDialog = CreateUnoDialog(DialogLibraries.Standard.MakeAlbumDialog) oListBox = oDialog.getControl("ListBox1") oField1 = oDialog.getControl("Field1") oField2 = oDialog.getControl("Field2") oField3 = oDialog.getControl("Field3") oField4 = oDialog.getControl("Field4") ' ダイアログを表示 If oDialog.execute() = 1 Then ' OKボタンが押された Dim itemSize as Integer itemSize = oListBox.getItemCount() ' リストボックス項目数を取得 If itemSize > 0 Then Dim oDoc as Object Dim oTbl as Object Dim oUndoMng as Object oDoc = ThisComponent ' Undo制御 oUndoMng = oDoc.getUndoManager() ' undo コンテキストの開始 oUndoMng.enterUndoContext("Undo Make Album Macro") ' 表を新規作成 MakeNewtable(GetTableColSize(), itemSize, GetTableMargin()) oTbl = GetTable If IsEmpty(oTbl) Then MsgBox "表が見つかりません" Else ' 表内に要素を挿入 AccessRowColumns(oTbl, GetImageTargetSize()) End If ' undo コンテキストを終了 oUndoMng.leaveUndoContext() End If Else ' Cancelボタンが押された Exit Sub End If End Sub ' 表の列数を取得 Function GetTableColSize GetTableColSize = CInt(oField1.getText()) End Function ' 画像目標サイズを取得 Function GetImageTargetSize GetImageTargetSize = CInt(oField2.getText()) End Function ' 表の左右マージン値を取得 Function GetTableMargin GetTableMargin = CInt(oField3.getText()) End Function ' 画像の左右マージン値を取得 Function GetImageMargin GetImageMargin = CInt(oField4.getText()) End Function ' ---------------------------------------- ' ファイル選択ダイアログを開く Sub SelectFile Dim f as Object f = createUnoService("com.sun.star.ui.dialogs.FilePicker") f.initialize( Array(com.sun.star.ui.dialogs.TemplateDescription.FILEOPEN_SIMPLE)) ' ファイルの複数選択を可能にする f.setMultiSelectionMode(True) ' 表示フィルタを追加 f.appendFilter("All Files (*.*)", "*.*") f.appendFilter("Image File", "*.bmp;*.jpg;*.gif;*.png") f.setCurrentFilter("Image File") ' デフォルトフィルタを指定 If f.execute() = 1 Then ' 選択された Dim sz as Integer Dim i as Integer Dim sFilePath as String sz = Ubound(f.selectedFiles()) For i = 0 To sz Dim nCnt as Integer ' sFilePath = ConvertFromURL(f.selectedFiles(i)) sFilePath = f.selectedFiles(i) ' リストボックスに追加 nCnt = oListBox.getItemCount() oListBox.addItem(sFilePath, nCnt) Next i End If End Sub ' ---------------------------------------- ' 1セルの幅を大雑把に取得 Sub CalcImageSize Dim pw as Long Dim cols as Integer Dim iw as Long ' ページ横幅を取得 pw = GetPagePrintWidth() ' 表の左右マージン分を減らす pw = pw - (GetTableMargin() * 2) ' 表の列数を取得 cols = CInt(oField1.getText()) ' 列数で割る iw = pw / cols ' 画像の左右マージン分を減らす iw = iw - (GetImageMargin() * 2) ' 画像サイズ指定用 InputBox に代入 oField2.setText(CStr(iw)) End Sub ' ---------------------------------------- ' 最後に挿入した表を取得 Function GetTable Dim oDoc as Object Dim oTbls as Object oDoc = ThisComponent oTbls = oDoc.TextTables If oTbls.hasElements = False Then ' 表が無い GetTable = Empty Else ' 1つ目の表オブジェクトを取得する場合 ' oTbl = oTbls.getByIndex(0) ' 最後に挿入した表を取得する場合 GetTable = oTbls.getByIndex(oTbls.getCount() -1) End If End Function ' ---------------------------------------- ' 表を新規作成 ' Sub MakeNewTable(iCols as Integer, iCellMax as Integer, margin as Integer) Dim oDoc as Object Dim iRows as Integer Dim oTbl as Object Dim oCurs as Object ' 文書を新規作成する場合 ' Dim Dummy() ' oDoc = StarDesktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, Dummy()) ' 現在開いてる文書を対象にする場合 oDoc = ThisComponent ' 行数を算出 iRows = iCellMax / iCols If iCellMax - (iRows * iCols) > 0 Then iRows = iRows + 1 iRows = iRows * 2 ' 表オブジェクトを作成 oTbl = oDoc.createInstance("com.sun.star.text.TextTable") oTbl.setName("AlbumTable") oTbl.initialize(iRows, iCols) ' サイズを指定 oTbl.HoriOrient = 0 ' com.sun.star.text.HoriOrientation.NONE oTbl.LeftMargin = margin oTbl.RightMargin = margin ' 文書の最終位置に表オブジェクトを挿入 oDoc.Text.insertTextContent(oDoc.Text.getEnd(), oTbl, False) ' 枠線を設定 ' SetTableBorder(oTbl) End Sub ' ---------------------------------------- ' 表の枠線設定を変更する ' Sub SetTableBorder(oTbl) Dim border as Object border = oTbl.TableBorder border.TopLine.OuterLineWidth = 0 border.BottomLine.OuterLineWidth = 0 oTbl.TableBorder = border End Sub ' ---------------------------------------- ' 行と列にアクセスする ' Sub AccessRowColumns(oTbl as Object, iw as Long) Dim ridx as Integer Dim cidx as Integer Dim rcnt as Integer Dim ccnt as Integer Dim i as Integer i = 0 rcnt = oTbl.getRows.getCount() ' 行数 ccnt = oTbl.getColumns.getCount() ' 列数 For ridx = 1 to rcnt For cidx = 1 to ccnt Dim cellname as String Dim cell as Object cellname = Chr(64 + cidx) & ridx ' "A1" "B2" 等のセル名を生成 cell = oTbl.getCellByName(cellname) ' セルにアクセス If ridx mod 2 = 0 Then ' 作者名等記入欄 ' セル内を縦方向で上揃えにする cell.VertOrient = com.sun.star.text.VertOrientation.TOP Else ' 画像欄 If i < oListBox.getItemCount() Then ' 画像ファイル名をリストボックス内から取得 Dim sUrl as String oListBox.selectItemPos(i, True) sUrl = oListBox.getSelectedItem() ' セル内容を変更する例。行:列を挿入 ' cell.string = CStr(ridx) & " : " & CStr(cidx) ' 画像を挿入 InsertTextGraphic(oTbl, cidx - 1, ridx - 1, sUrl, iw) i = i + 1 End If ' セル内を縦方向でセンタリング cell.VertOrient = com.sun.star.text.VertOrientation.CENTER End If ' セル内を横方向でセンタリング cell.createTextCursor().paraAdjust = com.sun.star.style.ParagraphAdjust.CENTER Next Next End Sub ' ---------------------------------------- ' 画像を挿入 Sub InsertTextGraphic(oTbl, col, row, sUrl, iTargetSize) Dim oDoc as Object Dim dispather as Object Dim oText as Object Dim oViewCursor as Object Dim aSize Dim aArgs(0) As New com.sun.star.beans.PropertyValue Dim oGp as Object Dim oImage as Object Dim oTxtGrp as Object oDoc = ThisComponent oViewCursor = oDoc.getCurrentController().getViewCursor() oGp = CreateUnoService("com.sun.star.graphic.GraphicProvider") aArgs(0).Name = "URL" aArgs(0).Value = sUrl oImage = oGp.queryGraphic(aArgs) oTxtGrp = oDoc.createInstance("com.sun.star.text.TextGraphicObject") oTxtGrp.Graphic = oImage aSize = oImage.Size ' Print aSize.Width & " x " & aSize.Height Dim fScale as Double If aSize.Width > aSize.Height Then fScale = CDbl(iTargetSize) / aSize.Width Else fScale = CDbl(iTargetSize) / aSize.Height End If aSize.Width = CLng(aSize.Width * fScale) aSize.Height = CLng(aSize.Height * fScale) With oTxtGrp .setSize(aSize) .VertOrient = com.sun.star.text.VertOrientation.CENTER .HoriOrient = com.sun.star.text.HoriOrientation.CENTER ' .VertOrientRelation = com.sun.star.text.RelOrientation.PAGE_PRINT_AREA ' .HoriOrientRelation = com.sun.star.text.RelOrientation.PAGE_PRINT_AREA ' .Surround = com.sun.star.text.WrapTextMode.THROUGHT ' 画像を文字として挿入 .AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER End With Dim oCell as Object oCell = oTbl.getCellByPosition(col, row) ' 列、行で指定 ' oDoc.getCurrentController().select(oCell) oCell.getText.insertTextContent(oCell, oTxtGrp, True) End Sub ' 画像挿入のテスト Sub InsertTextGraphicTest Dim oTbl as Object Dim sUrl as String Dim fScale as Single sUrl = "file:///C:/home/Pictures/pub_pictures/pcd01.jpg" fScale = 2540.0 / 3 oTbl = GetTable InsertTextGraphic(oTbl, 0, 0, sUrl, fScale) End Sub ' ---------------------------------------- ' 表内のカーソル位置を取得、その1 Sub GetPosInTable Dim oDoc as Object Dim oTbl as Object Dim oVCur as Object Dim oCurCell as Object Dim oDisp as String oDoc = ThisComponent oVCur = oDoc.getCurrentController().getViewCursor() If IsEmpty(oVCur.TextTable) Then Print "The cursor is NOT in a table" Else oTbl = oVCur.TextTable oDisp = "The cursor is in cell " & oVCur.Cell.CellName Msgbox(oDisp, 0, "Curor Position in Table") End If End Sub Function InTable Dim oDoc as Object Dim oVCur as Object oDoc = ThisComponent oVCur = oDoc.getCurrentController().getViewCursor() If IsEmpty(oVCur.TextTable) Then CheckPosInTable = Empty Else CheckPosInTable = oVCur.Cell End If End Function ' ---------------------------------------- ' 表内に画像を文字として挿入してみる例 Sub InsertGraphicToTbl Dim oDoc as Object Dim oTbl as Object Dim oImage as Object Dim oCell as Object Dim sUrl as String sUrl = "file:///C:/home/Pictures/pub_pictures/pcd02.jpg" oDoc = ThisComponent oTbl = GetTable oImage = oDoc.createInstance("com.sun.star.text.GraphicObject") oImage.GraphicURL = sUrl oImage.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER oImage.Width = 3000 oImage.Height = 3000 oCell = oTbl.getCellByPosition(0,0) oCell.getText.insertTextContent( oCell, oImage, False ) End Sub ' ---------------------------------------- ' 画像をリンク形式で挿入する例 Sub InsertTextGraphicLink(sUrl as String, enableChara as Boolean) Dim oDoc as Object Dim oViewCursor as Object Dim oImage as Object Dim aSize As New com.sun.star.awt.Size oDoc = ThisComponent oViewCursor = oDoc.getCurrentController().getViewCursor() aSize.Width = 2000 aSize.Height = 2000 oImage = oDoc.createInstance("com.sun.star.text.TextGraphicObject") oImage.GraphicURL = sUrl oImage.Size = aSize If enableChara Then ' 画像を文字として挿入 oImage.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER End If ' 表内には挿入できない oDoc.Text.insertTextContent(oViewCursor, oImage, False) End Sub Sub InsertTextGraphicLinkTest InsertTextGraphicLink("file:///C:/home/Pictures/pub_pictures/pcd03.jpg", True) End Sub ' ---------------------------------------- ' 画像のサイズを取得 ' ' OOoBasic/Generic/Image - ...? ' http://hermione.s41.xrea.com/pukiwiki/index.php?OOoBasic%2FGeneric%2FImage Function GetImageSize(sUrl) Dim oGP as Object Dim oSFA as Object Dim oImgInput as Object Dim oGraphic as Object Dim aSizePixel as Object Dim aSize(2) as Integer oGP = CreateUnoService("com.sun.star.graphic.GraphicProvider") oSFA = CreateUnoService("com.sun.star.ucb.SimpleFileAccess") oImgInput = oSFA.openFileRead(sUrl) Dim aImgDesc(0) As New com.sun.star.beans.PropertyValue aImgDesc(0).Name = "InputStream" aImgDesc(0).Value = oImgInput oGraphic = oGP.queryGraphic(aImgDesc) aSizePixel = oGraphic.SizePixel aSize(0) = aSizePixel.Width aSize(1) = aSizePixel.Height oImgInput.closeInput() GetImageSize = aSize End Function Sub GetImageSizeTest Dim ret(2) as Integer ret = GetImageSize("file://C:/home/Pictures/pub_pictures/pcd09.jpg") msgbox "Width x height = " & CStr(ret(0)) & " x " & CStr(ret(1)) End Sub ' ---------------------------------------- ' 表の幅を取得してみるテスト ' ' 表を新規作成した場合、巨大な値しか返ってこない… Sub GetCellSize Dim oDoc as Object Dim oTbl as Object Dim csize as Integer Dim w as Integer Dim tw as Long Dim margin as Long margin = 100 oDoc = ThisComponent oTbl = GetTable ' print oTbl.TableColumnRelativeSum If False Then ' 表の幅を、左マージン・右マージン指定により設定し直す oTbl.HoriOrient = com.sun.star.text.HoriOrientation.NONE oTbl.LeftMargin = margin oTbl.RightMargin = margin End If ' 列数を取得 csize = oTbl.getColumns.getCount() ' 表の幅を取得 tw = oTbl.Width ' tw = oTbl.RelativeWidth Dim oTblColSeps oTblColSeps = oTbl.TableColumnSeparators ' print "ColumnSeparators (1) = " & oTblColSeps(1).Position w = tw / csize - 400 print "Table Width = " & tw & " cell w = " & w End Sub ' ---------------------------------------- ' ページの印刷可能範囲の横幅を取得 Function GetPagePrintWidth Dim oDoc As Object Dim oStyleFamilies As Object Dim oPageStyles As Object Dim oPageStyle As Object Dim pagePrintWidth as Long oDoc = ThisComponent oStyleFamilies = oDoc.StyleFamilies oPageStyles = oStyleFamilies.getByName("PageStyles") oPageStyle = oPageStyles.getByName("Standard") pagePrintWidth = oPageStyle.Width - oPageStyle.LeftMargin - oPageStyle.RightMargin ' print pagePrintWidth GetPagePrintWidth = pagePrintWidth End Function ' ---------------------------------------- ' ページスタイルを取得してみるテスト Sub pagestylescontainer_elements Dim oDoc As Object Dim oStyleFamilies As Object Dim oPageStyles As Object Dim oPageStyle As Object Dim aStyleNames() As String Dim i As Integer Dim str as String Dim pagePrintWidth as Long oDoc = ThisComponent oStyleFamilies = oDoc.StyleFamilies oPageStyles = oStyleFamilies.getByName("PageStyles") aStyleNames() = oPageStyles.getElementNames() str = "" For i = 0 To UBound(aStyleNames()) str = str & aStyleNames(i) & Chr(10) Next i MsgBox str oPageStyle = oPageStyles.getByName("Standard") print "page width = " & oPageStyle.Width print "page left margin = " & oPageStyle.LeftMargin print "page right margin = " & oPageStyle.RightMargin pagePrintWidth = oPageStyle.Width - oPageStyle.LeftMargin - oPageStyle.RightMargin print "page width = " & oPageStyle.Width & " print width = " & pagePrintWidth End Sub
◎ 参考ページ。 :
_Macroの一歩(「Macro使い」への8分間)
_OSS( Open Source Software )でいこう!!「 OpenOffice.org / LibreOfficeを使おう編 」
_OpenOffice.org Basic - Wikibooks
_OOoBasic - ...?
_[Solved] Writer macro to insert an image into a table cell (View topic) - Apache OpenOffice Community Forum
_OpenOffice.org BASIC プログラミングガイド - Apache OpenOffice Wiki
_文書ドキュメント: テキスト以外のオブジェクト - Apache OpenOffice Wiki
_LibreOffice Calc Basic fun!!!: リストボックスを操作する (1)
_System-9 - Libre Office Basic マクロ 1
_System-9 - Libre Office Basic マクロ 6
_グローバル変数を使用してマクロを分かりやすくする LibreOffice Calc Basic:ubuntu10-12 LibreOffice4:So-netブログ
_Service TextTable
_OSS( Open Source Software )でいこう!!「 OpenOffice.org / LibreOfficeを使おう編 」
_OpenOffice.org Basic - Wikibooks
_OOoBasic - ...?
_[Solved] Writer macro to insert an image into a table cell (View topic) - Apache OpenOffice Community Forum
_OpenOffice.org BASIC プログラミングガイド - Apache OpenOffice Wiki
_文書ドキュメント: テキスト以外のオブジェクト - Apache OpenOffice Wiki
_LibreOffice Calc Basic fun!!!: リストボックスを操作する (1)
_System-9 - Libre Office Basic マクロ 1
_System-9 - Libre Office Basic マクロ 6
_グローバル変数を使用してマクロを分かりやすくする LibreOffice Calc Basic:ubuntu10-12 LibreOffice4:So-netブログ
_Service TextTable
◎ まだ分かってない点。 :
どう書けばいいのか分からなくて結局諦めてしまったのですが、LibreOffice Writer 上で、表(TextTable)の横幅、もしくはセルの横幅が取得できないという問題が残っていて。セル一つ分の横幅を取得したいけどやり方が分からず。であれば、表の横幅を列数で割れば求められるかな、と思ったのだけど、これも上手く行かず。
表を新規作成して挿入した直後、.Width で表の横幅を取得すると、とんでもなく大きな値(Long値)が返ってきてしまう。これでは計算に使えない…。ややこしいことに、マウスで表の外枠をちょっとでもドラッグして表のサイズを変更した後なら、Integer で収まる値が返ってくるようになる。どうしてこんなことになるのか…。訳が分かりません。
仕方ないので、ページ横幅やページ余白から、表の横幅を大雑把に求めて誤魔化してみたけれど。表の横幅、もしくはセルの横幅を取得できればもっとすっきり書けそう。
困ったことに、「openoffice cell width」等で検索しても、Openoffice Calc (表計算ソフト)の情報ばかり出てきてしまう。Calc じゃなくて Writer(ワープロソフト)上でどう書けばいいのかを知りたいのだけど…。
表を新規作成して挿入した直後、.Width で表の横幅を取得すると、とんでもなく大きな値(Long値)が返ってきてしまう。これでは計算に使えない…。ややこしいことに、マウスで表の外枠をちょっとでもドラッグして表のサイズを変更した後なら、Integer で収まる値が返ってくるようになる。どうしてこんなことになるのか…。訳が分かりません。
仕方ないので、ページ横幅やページ余白から、表の横幅を大雑把に求めて誤魔化してみたけれど。表の横幅、もしくはセルの横幅を取得できればもっとすっきり書けそう。
困ったことに、「openoffice cell width」等で検索しても、Openoffice Calc (表計算ソフト)の情報ばかり出てきてしまう。Calc じゃなくて Writer(ワープロソフト)上でどう書けばいいのかを知りたいのだけど…。
◎ 分かった点をメモ。 :
ダイアログ上で、OKボタン、キャンセルボタンを押した際に違う値が返ってくる、と解説ページには書いてあったのだけど。そのOKボタン、キャンセルボタンってどれよ…。と思ったら、フツーにボタンを配置して、ボタンの種類を、OK/キャンセルに設定すればよかったようで。
Writer上の表・セルの中で、縦方向にセンタリング(中央揃え)をする方法が分からなかったのだけど。
Writer上の表・セルの中で、縦方向にセンタリング(中央揃え)をする方法が分からなかったのだけど。
cell.VertOrient = com.sun.star.text.VertOrientation.CENTERといった指定でできるらしい、とメモ。
[ ツッコむ ]
以上、1 日分です。