イメージビューワー(3)

VB SampleImageViewer 3 : SubForm
 画像ビューワーの3回目です。今回は、元画像を表示するサブフォーム・クラスを作成します。
 サブフォームは、サムネールのファイル名をクリックすると呼び出され、画像を元の大きさで表示します。今回は、同時に複数のフォームが立ち上がるようにしています。
 また、フォームには、画像の拡大/縮小、及び回転/反転の機能を付け加えています。GDI+ では、この他にも、トリムや保存などの機能を比較的簡単に追加することができます。
 なお、今回で画像ビューワの基本部分は完成となります。
【INDEX】
Page 1 [本編] プロジェクトの概観 / メインフォームの設計 / フォルダツリーの作成
Page 2 [本編] サムネールの設計 / サムネールの作成 / 画像サイズの設定 / 画像一覧の表示
»Page3 [本編] サブフォームの設計 / 元画像の表示 / 画像の拡大・縮小 / 画像の回転・反転
Page 4 [拡張編] 画像の保存 / 画像への枠入れ・文字入れ / 画像のトリミング
Page 5 [番外編] スライドショー / マニュアル・スライド / フィットモード / オート・スライド
(作成環境 : Visual Basic .net 2002 / Framework SDK 1.0)

●サブフォームの設計

 フォームは、まずメニュー用のツールバー (TB1) とパネル (PN1) を配置し、パネル上に画像を描画するピクチャボックス (PIC1) を、ツールバー上にはボタン(下記参照)を、さらにボタン用のイメージリスト (IL1) を設置します。
 以下は変更した各コントロールのプロパティ値です。

・ PN1... AutoScroll : True / Dock : Fill / BackColor : 51,51,51 / BorderStyle : Fixed3D
・ PIC1... (なし)
・ TB1... Appearance : Flat / ImageList : IL1 / ShowToolTips : True
・ IL1 ... ImageSize : 24,24 / ColorDepth : Depth24Bit
  * 右図参照(数字はImageIndex)
  * アイコン置き場はこちら
・ ToolBarButton
 - tbLarger... ToolTipText : 拡大 / ImageIndex : 0
 - tbSmaller... ToolTipText : 縮小 / ImageIndex : 1
 - tbRotateL... ToolTipText : 左に回転 / ImageIndex : 2
 - tbRotateR... ToolTipText : 右に回転 / ImageIndex : 3
 - tbFlipX... ToolTipText : 左右反転 / ImageIndex : 4
 - tbFlipY... ToolTipText : 上下反転 / ImageIndex : 5
 - tbReload... ToolTipText : 再読み込み / ImageIndex : 6
| ▲TOP |

●元画像の表示
  基本的な関数は、下記の5つです。まず、@コンストラクタでファイル名を受け取り、コントロールの配置が終わった ALoadイベントで BInitialImage 関数を呼び出して元画像を取得し、さらにピクチャボックスに描画を行う CDrawImage 関数を呼び出します。
関数種類機能
・ Newコンストラクタ(オーバーロード)ファイルを取得してインスタンスを初期化
・ OnLoadイベント元画像を表示するよう関数の呼び出し
・ OnClosingイベント保持していたイメージの破棄
・ InitializeImageユーザー定義元画像を取得してメモリ上に保持
・ DrawImageユーザー定義元画像を指定の描画サイズで描画
 描画の方法には様々考えられますが、ここでは、元画像を別に保持 (m_image) し、描画用に用意したイメージに指定した倍率 (m_scale) で描画、さらに、描画用イメージをピクチャボックスの Image プロパティに設定しています。この方法ですと、拡大・縮小時の画質の劣化が抑えられます。また、' PIC1.Image ' で表示画像を取り出せますので、保存やトリム、文字入れなど、画像操作の機能追加が容易になります。
 ちなみに、描画の際には、補間モード (InterpolationMode) を高画質のものに指定しています。モードによって、画質や描画速度に差が出ますので、いろいろ試してみるといいと思います。
SubForm.vb (フォームデザイナのコードは省略しています)

' 内部変数
Private m_path As String = ""        ' ファイルのフルパス
Private m_image As Image              ' イメージオブジェクト(元画像)
Private m_scale As Single              ' スケール(表示倍率)

' コンストラクタ(パス名を指定)
Public Sub New(ByVal path As String)
    MyBase.New()
    InitializeComponent()
    m_path = path    ' ファイル名を格納
End Sub

' フォームのロードイベント Protected Overrides Sub OnLoad(ByVal e As System.EventArgs) if m_path <> "" Then InitializeImage() ' 元画像の表示 End Sub ' フォームのアンロードイベント Protected Overrides Sub OnClosing(ByVal e As System.ComponentModel.CancelEventArgs) If Not IsNothing(m_image) Then m_image.Dispose() ' イメージの破棄 End Sub
' 画像の初期化 Public Sub InitializeImage() If IO.File.Exists(m_path) = False Then ' ファイルが見つからない時 MessageBox.Show("ファイル [" & m_path & "] が見つかりませんでした。", _ "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error) Else ' 初期化処理 m_scale = 1.0F ' スケール(表示倍率)を1.0倍に初期化 m_image = New Bitmap(m_path) ' 元画像の取得 Me.Text = m_path ' タイトルバーにファイル名を表示 DrawImage() ' 描画 End If End Sub
' ピクチャボックスへの描画 Private Sub DrawImage() If IsNothing(m_image) Then Exit Sub Cursor.Current = Cursors.WaitCursor ' カーソルを待機状態にする ' 描画領域、描画用のイメージ、グラフィックオブジェクトを作成 Dim r As New RectangleF(0, 0, m_image.Width * m_scale, m_image.Height * m_scale) Dim m As New Bitmap(CInt(r.Width), CInt(r.Height)) Dim g As Graphics = Graphics.FromImage(m) ' 補間モードを指定してメモリ上(m)に描画 g.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic g.DrawImage(m_image, r) ' 元画像を指定領域の大きさに合わせて描画 g.Dispose() ' ピクチャボックス(PIC1)の設定 With PIC1 ' 既存のイメージを破棄 If Not IsNothing(.Image) Then .Image.Dispose() ' 位置とサイズの設定(SizeMode を AutoSize にした時は不要) .Left = PN1.AutoScrollPosition.X .Top = PN1.AutoScrollPosition.Y .Width = m.Width .Height = m.Height ' イメージを取り込み .Image = m End With Cursor.Current = Cursors.Default ' カーソルの形状を元に戻す End Sub

* InterpolationMode列挙体
 ・ Bicubic ... 双三次補間
 ・ Bilinear ... 双一次補間
 ・ Default ... 既定のモード
 ・ High ... 高品質補間
 ・ HighQualityBicubic ... 高品質双三次補間
 ・ HighQualityBilinear ... 高品質双一次補間
 ・ Invalid ... QualityMode(レンダリングの品質)のInvalidと等価
 ・ Low ... 低品質補間
 ・ NearestNeighbor ... 最近傍補間

| ▲TOP |

●画像の拡大・縮小
 画像の拡大・縮小は、画質の劣化を防ぐため、常に元画像 (m_image) から行います。この時、描画の際 (DrawImage関数) の補間モードに高画質のモードを指定すると、画質の劣化が少なくて済むので、かなりきれいな画像を見ることができます。
 コーディングでは、拡大/縮小率を設定する必要があります。ここでは 0.2 (m_ratio) に固定し、現在のスケール(表示倍率)は 変数 (m_scale) に格納しています。また、拡大/縮小しすぎないよう、最大/最小サイズを、あらかじめ定数 (nMinSize, nMaxSize) で設定しています。
 定義する関数は、ChangeScale 関数のみです。描画サイズを仮算出してチェックを行い、描画関数 (DrawImage) を呼び出しています。
' 内部変数/定数
Private m_ratio As Single = 0.2           ' 拡大/縮小率
Const nMinSize As Integer = 32         ' イメージ縮小時の最小サイズ
Const nMaxSize As Integer = 16384   ' イメージ拡大時の最大サイズ

' イメージの拡大・縮小
Private Sub ChangeScale(ByVal ratio As Single)
    ' スケールの算出(現在のスケール×拡大/縮小率)
    Dim f As Single = m_scale * ratio 

    ' 最小サイズ以上最大サイズ以下なら描画
    If m_image.Width * f >= nMinSize AndAlso m_image.Height * f >= nMinSize AndAlso _
       m_image.Width * f <= nMaxSize AndAlso m_image.Height * f <= nMaxSize Then
          m_scale = f         ' 算出したスケールを格納
          DrawImage()        ' 描画
    End If
End Sub    
(画像の加工)
| ▲TOP |

●画像の回転・反転
 画像の回転も反転も、RotateFlip メソッドで行います。指定する引数には、RotateFlipType 列挙体から選択します。これは、90度ごとの回転 (Rotate) と、上下反転/左右反転 (Flip) の組み合わせで構成されています。
 設定する関数は、CgangeState ユーザー関数のみです。この関数では、元画像 m_image を直接回転または反転させ、描画のために DrawImage 関数を呼び出しています。
【RotateFlipType列挙体】
・RotateNoneFlipX : 回転なし+左右反転 ・RotateNoneFlipY : 回転なし+上下反転
・RotateNoneFlipXY : 回転なし+左右反転+上下反転・RotateNoneFlipNone : 回転なし+反転なし
・Rotate90FlipX : 90度回転+左右反転 ・Rotate90FlipY : 90度回転+上下反転
・Rotate90FlipXY : 90度回転+左右反転+上下反転・Rotate90FlipNone : 90度回転+反転なし
・Rotate180FlipX : 180度回転+左右反転 ・Rotate180FlipY : 180度回転+上下反転
・Rotate180FlipXY : 180度回転+左右反転+上下反転・Rotate180FlipNone : 180度回転+反転なし
・Rotate270FlipX : 270度回転+左右反転 ・Rotate270FlipY : 270度回転+上下反転
・Rotate270FlipXY : 270度回転+左右反転+上下反転・Rotate270FlipNone : 270度回転+反転なし
(回転はすべて右回りの度数) 
' イメージの回転
Private Sub ChangeState(ByVal state As RotateFlipType)
    If Not IsNothing(m_image) Then
        m_image.RotateFlip(state)     ' イメージを回転・反転
        DrawImage()                        ' 描画
    End If
End Sub    

 最後に、ツールバーメニューを以下のようにコーディングして、きちんと動作すれば、今回のアプリケーションは完成です。まだまだ不満が残る仕様だと思いますが、ここまでくれば、もうひと工夫で、トリム・文字入れ・画像への描画・保存・スライドショーなど、様々な機能を追加することができます。興味のある方は、自分なりのアレンジを加えて、より実用的な画像ビューワーを目指してください。
' ツールバーボタンのクリックイベント
Private Sub TB1_ButtonClick(ByVal sender As Object, _
            ByVal e As ToolBarButtonClickEventArgs) Handles TB1.ButtonClick
    If  e.Button Is tbLarger Then
        ChangeScale(1 + m_ratio)                                     ' 拡大
    ElseIf e.Button Is tbSmaller Then
        ChangeScale(1 - m_ratio)                                     ' 縮小
    ElseIf e.Button Is tbRotateL Then
        ChangeState(RotateFlipType.Rotate270FlipNone)    ' 左に回転
    ElseIf e.Button Is tbRotateR Then
        ChangeState(RotateFlipType.Rotate90FlipNone)      ' 右に回転
    ElseIf e.Button Is tbFlipX Then
        ChangeState(RotateFlipType.RotateNoneFlipX)       ' 左右反転
    ElseIf e.Button Is tbFlipY Then
        ChangeState(RotateFlipType.RotateNoneFlipY)       ' 上下反転
    ElseIf e.Button Is tbReload Then
        InitializeImage()                                        ' 元画像の読み込み
    End If
End Sub    

| ■HOME | ◆プログラムTop | ▲ページの先頭 |