グラフィックスの描画で描画範囲を制限 (クリップ) して描画したい - C#

グラフィックスの描画で描画範囲を制限して描画する(描画領域のクリップ)コードを紹介します。

概要

Graphicsオブジェクトを利用して画面描画をすると画面にグラフィックスや画像を描画できます。
通常はGraphicsオブジェクトのコントロールの全面に対して描画されますが、利用シーンによっては、一部の領域のみに描画し、外側には描画をさせたくない場合があります。 この記事ではグラフィックスオブジェクトの描画時に、描画領域を制限して、クリップして描画するコードを紹介します。

方法

Graphicsオブジェクトの描画領域を制限する場合は、GraphicsオブジェクトのSetClipメソッドを呼び出します。
クリップ領域を解除する場合は、ResetClipメソッドを呼び出します。

書式

SetClip

[Graphicsオブジェクト].SetClip([クリップする領域のRectangleオブジェクト]);

ResetClip

[Graphicsオブジェクト].ResetClip();

プログラム:クリップしないプログラム

はじめにクリップしない描画プログラムを実装します。

UI

下図のフォームを作成します。フォームにPanelを配置します。

コード

以下のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GraphicsClip
{
  public partial class FormClipSimple : Form
  {
    public FormClipSimple()
    {
      InitializeComponent();
    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
      Pen p = new Pen(Color.Blue, 2);
      Rectangle frameRect = new Rectangle(64,64,320,128);
      e.Graphics.DrawRectangle(p,frameRect);

      SolidBrush sb = new SolidBrush(Color.FromArgb(0xF0, 0xC0, 0xE0));
      e.Graphics.FillEllipse(sb, new Rectangle(-64,128,360,360));

      Pen lp = new Pen(Color.DarkSeaGreen, 4);
      e.Graphics.DrawLine(lp,new Point(0,180), new Point(480,0));

      Bitmap bmp = new Bitmap("image.png");
      e.Graphics.DrawImage(bmp, new Rectangle(220, 64,200,283));
    }
  }
}

解説

PanelコントロールのPaintイベントに以下の描画コードを実装しています。
Panelに以下の図形や画像が描画されます。

長方形を描画します。
  Pen p = new Pen(Color.Blue, 2);
  Rectangle frameRect = new Rectangle(64,64,320,128);
  e.Graphics.DrawRectangle(p,frameRect);

円を描画し塗りつぶします。
  SolidBrush sb = new SolidBrush(Color.FromArgb(0xF0, 0xC0, 0xE0));
  e.Graphics.FillEllipse(sb, new Rectangle(-64,128,360,360));

線を描画します。
  Pen lp = new Pen(Color.DarkSeaGreen, 4);
  e.Graphics.DrawLine(lp,new Point(0,180), new Point(480,0));

画像を読み込み画像をキャンバスに配置します。
  Bitmap bmp = new Bitmap("image.png");
  e.Graphics.DrawImage(bmp, new Rectangle(220, 64,200,283));

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。 描画内容がPanelコントロールに描画されています。

プログラム:描画領域をクリップする

コード

先のプログラムのコードを以下のコードに修正します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GraphicsClip
{
  public partial class FormClipSimple : Form
  {
    public FormClipSimple()
    {
      InitializeComponent();
    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
      Rectangle frameRect = new Rectangle(64,64,320,128);
      e.Graphics.SetClip(frameRect);

      Pen p = new Pen(Color.Blue, 2);
      e.Graphics.DrawRectangle(p,frameRect);


      SolidBrush sb = new SolidBrush(Color.FromArgb(0xF0, 0xC0, 0xE0));
      e.Graphics.FillEllipse(sb, new Rectangle(-64,128,360,360));

      Pen lp = new Pen(Color.DarkSeaGreen, 4);
      e.Graphics.DrawLine(lp,new Point(0,180), new Point(480,0));

      Bitmap bmp = new Bitmap("image.png");
      e.Graphics.DrawImage(bmp, new Rectangle(220, 64,200,283));

      e.Graphics.ResetClip();
    }
  }
}

解説

SetClipメソッドを呼び出し、描画領域をクリップします。
SetClipメソッドの第一引数にクリップする領域を与えます。青色の枠を描画する領域をクリップ範囲とします。
  e.Graphics.SetClip(frameRect);

  e.Graphics.ResetClip();

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。描画領域がクリップされていることが確認できます。
青色の枠の領域でクリップしていますが、青色枠の1ピクセルぶんはクリップ領域の内側になるため、青枠もクリップ領域内の1ピクセル幅の線は描画されます。

補足:クリップ前の描画

SetClipメソッド呼び出し前に描画した内容はクリップされずに描画されます。
    private void panel1_Paint(object sender, PaintEventArgs e)
    {
      Rectangle frameRect = new Rectangle(64,64,320,128);

      Pen p = new Pen(Color.Blue, 2);
      e.Graphics.DrawRectangle(p,frameRect);

      e.Graphics.SetClip(frameRect);

      SolidBrush sb = new SolidBrush(Color.FromArgb(0xF0, 0xC0, 0xE0));
      e.Graphics.FillEllipse(sb, new Rectangle(-64,128,360,360));

      Pen lp = new Pen(Color.DarkSeaGreen, 4);
      e.Graphics.DrawLine(lp,new Point(0,180), new Point(480,0));

      Bitmap bmp = new Bitmap("image.png");
      e.Graphics.DrawImage(bmp, new Rectangle(220, 64,200,283));

      e.Graphics.ResetClip();
    }

SetClipを呼び出す前に青色の枠を描画した場合の結果が下図です。青枠だけクリップ領域の外側が描画できています。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2023-01-20
iPentec all rights reserverd.