Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2012年11月23日] [更新 2012年11月28日] GDI+ 関係サンプル
GDI+ 関係サンプル 
G190_画像のモザイク処理
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro
G190_GDIPlus_Mosaic.zip [625 KB] 2012年11月28日版 (EXE 同梱)







画像のモザイク処理


画像をモザイク化するサンプルです.画像にパスワード等が表示されている場合,それをモザイク化する時に役に立つかも知れません.原理的なことは,コードのコメントを参考にしてください.

このサンプルの TMyPanel クラスには,モザイクを描画する領域と,モザイクのサイズを設定するプロパティを実装しています.もちろん,他のサンプルと同じように,表示する画像ファイルを指定するプロパティもあります.
このモザイクのサンプルは,フォームのサイズを変更しても,表示サイズは変わりません.


図1
設計時画面
図2
モザイクなし
図3
モザイクあり

リスト1
画像の一部にモザイクを描画するテスト
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, ComCtrls, StdCtrls, GDIPOBJ, GDIPAPI;

type
  TMyPanel = class(TPanel)
  private
    FImageFilePath : String;
    FMosaicRect    : TRect;
    FMosaicSize    : Integer;
    procedure SetImageFilePath(const Value: String);
    procedure SetMosaicRect(const Value: TRect);
    procedure SetMosaicSize(const Value: Integer);
  protected
    procedure Paint; override;
    function Mosaic(bmp: TBitmap; TargetRect: TRect; ASize: Integer):Boolean;
  public
    constructor Create(AOwner: TComponent); override;
    property ImageFilePath : String  read FImageFilePath write SetImageFilePath;
    property MosaicRect    : TRect   read FMosaicRect    write SetMosaicRect;
    property MosaicSize    : Integer read FMosaicSize    write SetMosaicSize;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
    MyPanel : TMyPanel;
  protected

  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Self.Caption := 'GDI+  モザイク処理';

  //TMyPanelを生成して配置
  MyPanel := TMyPanel.Create(Self);
  with MyPanel do begin
    Parent      := Self;
    Left        := 5;
    Top         := 35;
    Width       := 320;
    Height      := 240;
    Color       := clWhite;

    ParentBackground := False;
    DoubleBuffered   := True;

    //表示する画像ファイル名
    ImageFilePath := 'dogs018.jpg';
  end;
end;

//=============================================================================
//  モザイクを表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LLeft : Integer;
  LTop  : Integer;
begin
  if not Assigned(MyPanel) then exit;

  LLeft := 40;
  LTop  := 60;
  MyPanel.MosaicSize := 10;
  MyPanel.MosaicRect := Rect(LLeft, LTop, LLeft + 120, LTop + 90);
end;

//=============================================================================
//  モザイクを表示しない
//  本サンプルのTMyPanelでは,モザイク領域を空にすると表示しないようになっている
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  if not Assigned(MyPanel) then exit;
  MyPanel.MosaicRect := Rect(0, 0, 0, 0);
end;

{ TMyPanel }

//-----------------------------------------------------------------------------
//  コンストラクタのCreate処理
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
  inherited;
  SetRectEmpty(FMosaicRect);
  FMosaicSize := 8;
end;

//-----------------------------------------------------------------------------
//  ImageFilePathプロパティの設定用メソッド
//  表示する画像を変更したらTMyPanelを再描画
//-----------------------------------------------------------------------------
procedure TMyPanel.SetImageFilePath(const Value: String);
begin
  FImageFilePath := Value;
  Invalidate;
end;

//-----------------------------------------------------------------------------
//  MosaicRectのプロパティ設定用メソッド
//  モザイクにする領域が変更になったら再描画
//-----------------------------------------------------------------------------
procedure TMyPanel.SetMosaicRect(const Value: TRect);
begin
  if EqualRect(FMosaicRect, Value) = False then begin
    FMosaicRect := Value;
    Invalidate;
  end;
end;

//-----------------------------------------------------------------------------
//  MosaicSizeのプロパティ設定用メソッド
//  モザイクのサイズが変更されたら再描画
//-----------------------------------------------------------------------------
procedure TMyPanel.SetMosaicSize(const Value: Integer);
begin
  if FMosaicSize <> Value then begin
    FMosaicSize := Value;
    Invalidate;
  end;
end;

//-----------------------------------------------------------------------------
//  モザイク化関数
//  引数で指定するbmp(ビットマップ)の指定領域(TargetRect)をモザイク画像にする
//  モザイクのサイズはASixeで指定する
//  結果は,引数のbmpに格納される
//-----------------------------------------------------------------------------
function TMyPanel.Mosaic(bmp: TBitmap; TargetRect: TRect;
  ASize: Integer): Boolean;
type
  TRGBQArray = array [0..High(Integer) div 4 - 1] of RGBQUAD;
  PRGBQArray = ^TRGBQArray;

var
  LTargetWidth  : Integer;
  LTargetHeight : Integer;
  LStartYPos    : Integer;
  LEndYPos      : Integer;
  LStartXPos    : Integer;
  LEndXPos      : Integer;
  LPosY         : Integer;
  LPosX         : Integer;
  LLoopY        : Integer;
  LLoopX        : Integer;
  LRValue       : integer;
  LGValue       : integer;
  LBValue       : integer;
  LpQuadArray   : PRGBQArray;
  Ldx           : Integer;
  Ldy           : Integer;
begin
  Result := False;
  if ASize < 2 then exit;

  bmp.Canvas.Lock;
  bmp.PixelFormat := pf32bit;
  LTargetWidth    := TargetRect.Right  - TargetRect.Left;
  LTargetHeight   := TargetRect.Bottom - TargetRect.Top;

  for LPosY := 0 to (LTargetHeight div ASize)  do begin
    for LPosX := 0 to (LTargetWidth div ASize) do begin

      LRValue := 0;
      LGValue := 0;
      LBValue := 0;

      LStartYPos := TargetRect.Top  + LPosY * ASize;
      LEndYPos   := TargetRect.Top  + LPosY * ASize + ASize - 1;
      LStartXPos := TargetRect.Left + LPosX * ASize;
      LEndXPos   := TargetRect.Left + LPosX * ASize + ASize - 1;

      //ASize領域内のR,G,B値を加算して...
      Ldy := 0;
      for LLoopY := LStartYPos to LEndYPos do begin
        if LLoopY > (TargetRect.Bottom - 1) then Continue;

        LpQuadArray := bmp.ScanLine[LLoopY];
        Ldx := 0;
        for LLoopX := LStartXPos to LEndXPos do begin
          if LLoopX > (TargetRect.Right - 1) then Continue;
          LRValue := LRValue + LpQuadArray[LLoopX].rgbRed;
          LGValue := LGValue + LpQuadArray[LLoopX].rgbGreen;
          LBValue := LBValue + LpQuadArray[LLoopX].rgbBlue;
          Ldx := Ldx + 1;
        end;
        Ldy := Ldy + 1;
      end;
      if (Ldx = 0) or (Ldy = 0) then Continue;

      //面積で平均化した値にする
      LRValue := LRValue div (Ldx * Ldy);
      LGValue := LGValue div (Ldx * Ldy);
      LBValue := LBValue div (Ldx * Ldy);

      //ASizeの領域内を全て平均化した色にする
      for LLoopY := LStartYPos to LEndYPos do begin
        if LLoopY > (TargetRect.Bottom - 1) then Continue;

        LpQuadArray := bmp.ScanLine[LLoopY];
        for LLoopX := LStartXPos to LEndXPos do begin
          if LLoopX > (TargetRect.Right - 1) then Continue;
          LpQuadArray[LLoopX].rgbRed   := LRValue;
          LpQuadArray[LLoopX].rgbGreen := LGValue;
          LpQuadArray[LLoopX].rgbBlue  := LBValue;
        end;
      end;
    end;
  end;

  bmp.Canvas.Unlock;
  Result := True;
end;

//-----------------------------------------------------------------------------
//  TMyPanelクラスのPaintメソッド
//  実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
  LGPGraphic : TGPGraphics;
  LGPImage   : TGPImage;
  LBitmap    : TBitmap;
begin
  inherited;

  //画像ファイルを指定してTGPImageのオブジェクトを生成
  LGPImage := TGPImage.Create(FImageFilePath);

  //表示用のビットマップを生成
  LBitmap := TBitmap.Create;
  try
    //そのビットマップのサイズを表示領域にあわせる
    LBitmap.SetSize(ClientWidth, ClientHeight);

    //TGPGraphicsのオブジェクトを生成.表示用のビットマップCanvasを描画先とする
    LGPGraphic := TGPGraphics.Create(LBitmap.Canvas.Handle);
    //表示用のビットマップのCanvasに描画
    //TCanvasのStretchDrawに相当する
    LGPGraphic.DrawImage(
                LGPImage,
                MakeRect(0, 0, ClientWidth, ClientHeight),
                0,
                0,
                LGPImage.GetWidth,
                LGPImage.GetHeight,
                UnitPixel);

   //モザイク処理
   if not IsRectEmpty(FMosaicRect) then begin
     Mosaic(LBitmap, FMosaicRect, FMosaicSize);
   end;
   //ビットマップをこのコントロールのCanvasに描画
   Canvas.Draw(0, 0, LBitmap);
  finally
    LBitmap.Free;
  end;

  //Createしたオブジェクトは解放処理する
  LGPImage.Free;
  LGPGraphic.Free;
end;

end.