2025/03/28

Notes - Excel 連携:#53)ディスプレイの拡大/縮小と画像サイズ

久しぶりに『Notes - Excel 連携』の連載の更新です。

この連載では、前回の画像のリサイズをはじめ、名前アイコンの作成やグラフの保存などで、画像として保存する方法を紹介してきました。私は日々の業務でこの機能を応用して、レポートのグラフ画像を作成しているのですが、 なんだか最近出力される画像が大きいことに気が付きました。

調査した結果、Excel から出力される画像のサイズは Windows のディスプレイの設定の拡大/縮小で指定した倍率に合わせてサイズが変化することがわかりました。

そういえば、最近は 150% で使うことが多いです。これは新しい PC の解像度が高く字が小さいためで、決して老眼のせいではありません(たぶん...)。それに、最近の Windows は拡大率を変更しても再起動などは不要ですから、アプリに応じて切り替えることも多くなっています。

このような背景から、設定次第で出力画像の解像度が変わるのは避けたいですよね。ということで、今回は、LotusScript で Windows の拡大率を取る方法についてまとめます。


今回の方針

初めに Google 先生に聞いてみたところ、いくつかヒントが出てきました。Windows API を使えば取得できるようです。

GetDeviceCaps 関数 (wingdi.h)

ただ、LotusScript で試してみたのですが、いつも同じ値が返り、残念ながら正確に判定できませんでした。

そこで、今回は、手持ちのテクニックで判定することにします。


判定方法

保存した画像ファイルが倍率に応じてサイズが変わる現象なので、出力した画像ファイルの Pixel を使って判定します。

前回の記事で、AddPicture メソッド を使って画像を呼び出し、サイズを取得する方法を紹介しました。ただ、この方法で呼び出した画像は、すでに倍率に応じて伸長されています。よって、Width や Height の値は、画像の Pixel 数の判定には使用できないことになります。

   '画像サイズ取得
   Dim dX As Double '画像の幅(ポイント)
   Dim dY As Double '画像の高さ(ポイント)
   Set oImage = oSheet.Shapes.AddPicture(sFN_In, msoFalse, msoTrue, 0, 0, -1, -1)
   dX = oImage.Width
   dY = oImage.Height


画像ファイルのリアルな Pixel 数の取得には、画像ファイルを直接参照するのが一番確実です。そこで、別の連載『DXL Step-by-Step』の『#13)イメージの形式とサイズの取得』で紹介した方法で横幅を取得することとします。


判定の流れは次の通りです。

  1. 横幅 750 Point の Chart オブジェクトを作成
  2. Chart オブジェクトを GIF ファイルとして保存(拡大率 100% なら 1000 Pixel)
  3. 画像をバイナリファイルとして開き、画像の幅(Pixel)を取得
  4. 画像の幅(Pixel)から拡大率を算出


サンプルプログラム

まずはエージェントのメインプログラムです。拡大率を取得する関数をコールして結果をメッセージで表示するだけです。

Option Declare

Use "lsXls"
Use "lsWindows"

Sub Initialize
   Dim iZoom As Integer

   iZoom = xGetDesktopZoom()
   MsgBox "デスクトップの拡大率 = " & CStr(iZoom) & " %", 64
End Sub

スクリプトライブラリは、これまで作成してきた lsXls を呼び出します。これは後述する関数内で定数を利用するためです。

また、lsWindows は画像ファイルを一時保存するため、Windows のテンポラリフォルダを取得する処理で使用しています。ライブラリの中身については、『Windows のテンポラリフォルダの取得』を参照ください。


◇ 拡大率の取得

先に記載した ”判定の流れ” にそった関数です(① ~ ④)。

画像のサイズを 750 Point と大きくしているのは Point - Pixel 変換時の誤差の影響を小さくすることが目的です。また、画像形式は、サイズが小さそうな上に、ファイルの最初のほうにサイズ情報がある GIF 形式を選択しました。

Function xGetDesktopZoom() As Integer
   Dim oXls As Variant
   Dim oSheet As Variant
   Dim oShape As Variant
   Dim sFN As String

   '画像ファイル名
   sFN = GetWinTmpPath()
   sFN = sFN & "Denaoshi" & Format(Now, "yyyymmddhhnnss") & ".GIF"

   'Excel の準備
   Set oXls = CreateObject("Excel.Application")
   Call oXls.Workbooks.Add
   Set oSheet = oXls.Workbooks(1).WorkSheets(1)

   '画像サイズ
   '倍率 100% の時、1 ピクセル = 0.75 ポイント

   Dim dX As Double '画像の幅と高さ(ポイント)
   dX = 750 '100% = 1000px

   '① Chart オブジェクトを作成
   Set oShape = xAddChart(oSheet, dX, 10) '高さはこだわらない

   '② GIF ファイルとして保存
   Call xSaveAsPicture(oShape, sFN)

   '③ 保存した画像の幅を取得
   Dim iX As Integer
   iX = xGetWidth_GIF(sFN)

   '④ デスクトップの拡大率を算出
   Dim dTmp As Double
   dTmp = dX / 0.75  '100% の時の画像サイズ
   xGetDesktopZoom = Int(iX/dTmp * 100 + .5)

   'Excel は保存せずに終了
   oXls.DisplayAlerts = False
   Call oXls.Workbooks(1).Close(False)

   '画像ファイルは削除
   Kill sFN
End Function

この関数では既存のサブ関数を利用しています。xAddChart と xSaveAsPicture 関数については、前回 掲載したコードをそのまま使用しています。


◇ GIF 画像の幅を取得

GIF ファイルの画像ファイルのフォーマットについては『#13)イメージの形式とサイズの取得』に記載しています。この記事で掲載した関数は、JPEG や PNG などの対応ていたので、GIF ファイルの画像幅だけを取得する関数に再編集しています。

Function xGetWidth_GIF(ByVal vsFN As String) As Integer
   Dim ns As New NotesSession
   Dim nst As NotesStream
   Dim vTmp As Variant

   Set nst = ns.CreateStream()
   Call nst.Open(vsFN)

   'GIF 画像幅取得
   nst.Position = 0

   vTmp = nst.Read(6) '空読み
   vTmp = nst.Read(4)

   '画像幅
   xGetWidth_GIF = CInt(vTmp(1)) * 256 + CInt(vTmp(0))
End Function


まとめ

エージェントを実行すると次のようにディスプレイの拡大率が表示されます。この値を係数として利用すれば、どのような環境でも安定したサイズの画像ファイルが生成できます。

今回の手法では、一時的に Excel を起動して拡大率を取得しています。決して、効率が良いとは言えないのですが、これが利点になることもあります。

マルチディスプレイの場合、それぞれで拡大率を指定できます。先の Windows API を利用する手法の場合、どのディスプレイかを指定することになるのですが、ノーツが利用しているディスプレイがよくわからないんです。

ところが、今回の手法であれば、ノーツが利用しているディスプレイの設定を自動的に取得してくれるので、細かなことは意識しなくていいということになります。


前回 Notes - Excel 連携


0 件のコメント:

コメントを投稿