動的画像(グラフ)の表示

このページでは、以下の帳票を作成します。

この帳票の上半分には花の画像と名前が一覧で表示されており、下半分にはグラフの画像が表示されています。 いずれも、表示される画像の内容は動的に決まります。

画像とグラフのサンプル
サンプルについて
完成したサンプルが example フォルダ内に以下の名前で含まれています。 帳票定義ファイル: example_image.rrpt ソースコード: ExampleImage.cs、ExampleImage.vb、ExampleImage.java

イメージローダというオブジェクトを利用することで、動的な画像を表示することが可能になります。

帳票の出力時、あらかじめImageLoaderMapというメンバにイメージローダを格納しておくと、 [画像]要素を描画する際に呼び出されるので、そのタイミングで表示したい画像データを選択または生成して返すことができます。 イメージローダから画像を取得できなかった場合は、[画像]プロパティに設定された静的な画像がもしあればそれを表示します。

ImageLoaderMapはハッシュなので、複数のイメージローダを設定することができます。 要素がどのイメージローダを利用するかは [キー] というプロパティで指定することができます。 [キー]を省略した場合、イメージローダは利用されません。

イメージローダはレンダラ毎に用意された以下のインターフェースを満たす必要があります。 さらに、それぞれのインターフェースには標準実装クラス(後述)が用意されています。

レンダラ イメージローダの
インターフェース/標準実装クラス
PdfRenderer IPdfImageLoader
PdfImageLoader
XlsRenderer IXlsImageLoader
XlsImageLoader
XlsxRenderer
(Javaのみ)
IXlsxImageLoader
XlsxImageLoader
Printer IGdiImageLoader
GdiImageLoader

イメージローダを利用するには標準実装クラスを利用する方法と、 独自のイメージローダクラスを実装する方法の2通りがあります。 今回のサンプルでは両方の方法で画像を帳票に表示してみます。

イメージローダの標準実装クラス

サンプル帳票の上にある花の写真と名前の一覧は、あらかじめ複数の画像をロードしておき、 データの値に応じて表示する画像をその中から選択するという方法で表示しています。 このような場合はイメージローダの標準実装クラスを利用することができます。

まず、この帳票には以下のデータを与えます。 [code]列の値によって表示される画像が選択されるようにします。

  // C#

  private static DataTable getDataTable()
  {
      DataTable ret = new DataTable();
      ret.Columns.Add("code", typeof(int));
      ret.Columns.Add("name", typeof(String));
      ret.Rows.Add(1, "ハクサンイチゲ");
      ret.Rows.Add(2, "ニッコウキスゲ");
      ret.Rows.Add(3, "チングルマ");
      ret.Rows.Add(4, "コマクサ");
      return ret;
  }
  ' VisualBasic

  Private Function getDataTable() As DataTable
      Dim ret As New DataTable
      ret.Columns.Add("code", GetType(Integer))
      ret.Columns.Add("name", GetType(String))
      ret.Rows.Add(1, "ハクサンイチゲ")
      ret.Rows.Add(2, "ニッコウキスゲ")
      ret.Rows.Add(3, "チングルマ")
      ret.Rows.Add(4, "コマクサ")
      Return ret
  End Function

表示される候補となる画像はImageMapというオブジェクトに登録しておきます。 ImageMapは [jp.co.systembase.report.renderer] という名前空間に定義されています。

  // C#

  // イメージマップを生成します
  private static ImageMap getImageMap()
  {
      ImageMap ret = new ImageMap();
      ret.Add(1, new Bitmap("report\\image1.jpg"));
      ret.Add(2, new Bitmap("report\\image2.jpg"));
      ret.Add(3, new Bitmap("report\\image3.jpg"));
      ret.Add(4, new Bitmap("report\\image4.jpg"));
      return ret;
  }
  ' VisualBasic

  ' イメージマップを生成します
  Private Function getImageMap() As ImageMap
      Dim ret As New ImageMap
      ret.Add(1, New Bitmap("report\image1.jpg"))
      ret.Add(2, New Bitmap("report\image2.jpg"))
      ret.Add(3, New Bitmap("report\image3.jpg"))
      ret.Add(4, New Bitmap("report\image4.jpg"))
      Return ret
  End Function

花の画像を表示する要素の[式]プロパティには ".code" と指定します。 これにより、[code]列の値が画像を選択するキーとなります。 さらに、利用するイメージローダを指定するキーとして [キー] プロパティに "image" と指定します。

イメージローダの標準実装クラスは、コンストラクタの引数にImageMapオブジェクトを受け取ることができます。 生成したイメージローダのオブジェクトは "image" というキーで ImageLoaderMap に登録します。 なお、ここではプレビュー表示を行う場合の例のみを示しますが、 exampleフォルダ以下のサンプルプロジェクトには、 PDF, Excel(XLS) 出力を行う場合の例も含まれています。

  // C#

  // イメージマップを生成します
  ImageMap imageMap = getImageMap();

  ...

  // プレビュー画面表示
  {
      Printer printer = new Printer(pages);

      // イメージローダを登録します
      printer.ImageLoaderMap.Add("image", new GdiImageLoader(imageMap));
      printer.ImageLoaderMap.Add("graph", new GdiGraphImageLoader());

      FmPrintPreview preview = new FmPrintPreview(printer);
      preview.StartUpZoomFit = true;
      preview.ShowDialog();
  }
  ' VisualBasic

  ' イメージマップを生成します
  Dim imageMap As ImageMap = getImageMap()

  ...

  ' プレビュー画面表示
  With Nothing
      Dim printer As New Printer(pages)

      ' イメージローダを登録します
      printer.ImageLoaderMap.Add("image", New GdiImageLoader(imageMap))
      printer.ImageLoaderMap.Add("graph", New GdiGraphImageLoader())

      Dim preview As New FmPrintPreview(printer)
      preview.StartUpZoomFit = True
      preview.ShowDialog()
  End With

イメージローダの実装(グラフの表示)

この帳票の下の部分にに表示されているグラフの画像は、実行時に生成しています。 このように、画像をあらかじめ用意しておくことができない場合はイメージローダのクラスを独自に実装し、 その中で画像を生成します。

実装する必要があるのは GetImage(param) という1つのメソッドのみです。 このメソッドの引数 param には要素の[式]を評価して得られた値が渡されるので、 その値を元に画像を生成して返します。 (ただし、今回の例では簡単のため、固定の内容のグラフ画像を生成しています)

なお、レンダラは画像を取得する必要が生じるたびに GetImage メソッドを呼ぶので、 同じ画像が何度も生成されないように、生成した画像はキャッシュされるよう実装してください。

以下に、直接印刷・プレビューのレンダラから利用可能なイメージローダの実装を示します。 この中でgetGraphImageというメソッドを呼んでいますが、これはグラフの画像を生成して返すメソッドです。 本題から外れるのでその内容は示しませんが、exampleフォルダ以下のサンプルプロジェクトには完全な実装があります。 さらにPDF,Excel(XLS)レンダラ向けのイメージローダの実装もサンプルプロジェクトに含まれています。

  // C#

  // グラフの画像を直接印刷・プレビューに埋め込むためのイメージローダ
  private class GdiGraphImageLoader : IGdiImageLoader
  {
      // 画像をキャッシュするためのDictionary
      private Dictionary<Object, Image> cachedImage = new Dictionary<object, Image>();
      public Image GetImage(object param)
      {
          if (param == null)
          {
              return null;
          }
          // 画像がキャッシュになければ生成します
          if (!this.cachedImage.ContainsKey(param))
          {
              this.cachedImage.Add(param, getGraphImage(param));
          }
          return this.cachedImage[param];
      }
  }
  ' VisualBasic

  ' グラフの画像を直接印刷・プレビューに埋め込むためのイメージローダ
  Private Class GdiGraphImageLoader
      Implements IGdiImageLoader
      ' 画像をキャッシュするためのDictionary
      Private cachedImage As New Dictionary(Of Object, Image)
      Public Function GetImage(param As Object) As Image Implements IGdiImageLoader.GetImage
          If param Is Nothing Then
              Return Nothing
          End If
          ' 画像がキャッシュになければ生成します
          If Not Me.cachedImage.ContainsKey(param) Then
              Me.cachedImage.Add(param, getGraphImage(param))
          End If
          Return Me.cachedImage(param)
      End Function
  End Class

グラフを表示するための要素のプロパティは、 [キー]を"graph"とし、[式]を"'example'"としておきます。

イメージローダのオブジェクトを生成し、"graph"というキーでImageLoaderMapに登録します。 これで、帳票出力時には先ほど実装したGetImageメソッドが "example" という文字列を引数として呼ばれるようになります。

  // C#

  // プレビュー画面表示
  {
      Printer printer = new Printer(pages);

      // イメージローダを登録します
      printer.ImageLoaderMap.Add("image", new GdiImageLoader(imageMap));
      printer.ImageLoaderMap.Add("graph", new GdiGraphImageLoader());

      FmPrintPreview preview = new FmPrintPreview(printer);
      preview.StartUpZoomFit = true;
      preview.ShowDialog();
  }
  ' VisualBasic

  ' プレビュー画面表示
  With Nothing
      Dim printer As New Printer(pages)

      ' イメージローダを登録します
      printer.ImageLoaderMap.Add("image", New GdiImageLoader(imageMap))
      printer.ImageLoaderMap.Add("graph", New GdiGraphImageLoader())

      Dim preview As New FmPrintPreview(printer)
      preview.StartUpZoomFit = True
      preview.ShowDialog()
  End With