Metafileの部分拡大について

解決


アル  2009-04-19 02:42:58  No: 34058

こんにちは。

WMFのようなメタファイルの一部を拡大したいと思っています。

Meta := TMetafile.Create;
MetaCanvas := TMetafileCanvas.Create( Meta, 0 );

Meta.LoadFromFile('Map.wmf');

Image1.Canvas.CopyRect( Bounds(0,0,Image1.Width, Image1.Height),
                        MetaCanvas,
                        Bounds(100, 100,50, 50) );

MetaCanvas.Free;
Meta.Free;

今はこんな感じですが、Image1は真っ白になります。

いつもビットマップばかりだったので、苦戦しております。

どなたかご教授いただけると助かります。
よろしくお願いします。


みんみん  2009-04-19 08:18:35  No: 34059

TMetafileについてはあまり詳しくないのですが、

CopyRectのCanvas指定はTMetafileCanvasではダメなような
感じがするので、一度MetafileをBitmapにStretchDrawで描画して、
そのBitmapからImage1にコピーしたらいいと思いますよ。
var
  CutRect :TRect;
  Bitmap  :TBitmap;

ZoomRect :=Bounds(100, 100, 50, 50);
Meta := TMetafile.Create;
Meta.LoadFromFile('Map.wmf');

Bitmap :=TBitmap.Create;
try
  //2倍に拡大
  Bitmap.Width  :=Meta.Width  * 2;
  Bitmap.Height :=Meta.Height * 2;
  Bitmap.Canvas.StretchDraw(Rect(0, 0, Bitmap.Width, Bitmap.Height), Meta);
  Image1.Canvas.CopyRect(Rect(0,0,Image1.Width, Image1.Height),
                         Bitmap.Canvas,
                         Rect(ZoomRect.Left  * 2, ZoomRect.Top * 2,
                              ZoomRect.Right * 2, ZoomRect.Bottom * 2));
finally
  Bitmap.Free;
end;

Meta.Free;


アル  2009-04-19 17:32:08  No: 34060

ありがとうございます。

この方法だと拡大率によっては
かなり巨大なビットマップを用意しなければなりませんね。
メモリに取れないほどの大きさまで拡大するつもりだったので、
先に一部を切り取りたかったのですが、
何かよい方法はないでしょうか。


みんみん  2009-04-19 20:24:30  No: 34061

それでは、等倍サイズのBitmapにMetafileを描画しておいて
CopyRectで拡大コピーする方法ではどうでしょうか?

  Bitmap :=TBitmap.Create;
  try
    Bitmap.Width  :=Meta.Width;
    Bitmap.Height :=Meta.Height;
    Bitmap.Canvas.Draw(0, 0, Meta);
    Image1.Canvas.CopyRect(Bounds(0, 0,Image1.Width, Image1.Height),
                           Bitmap.Canvas,
                           ZoomRect);
  finally
    Bitmap.Free;
  end;

等倍サイズのBitmapも使えないとなると
かなり苦戦しそうな感じがします。


アル  2009-04-20 00:03:05  No: 34062

ご回答ありがとうございます。

試してみて、拡大することには成功しましたが、
これは結局単純なビットマップの拡大ですので、
メタファイルの売りであるところの
拡大でも画像劣化しない点が活きてきません。

元のWMFを分割するという方法も考えてはみたのですが、
これも拡大率によってはメモリを多量に消費しそうで……


toc  2009-04-20 02:00:38  No: 34063

> この方法だと拡大率によっては
> かなり巨大なビットマップを用意しなければなりませんね。
ん? コピーしたい範囲分のビットマップだけ用意すれば済むんじゃないですか?

たとば10倍に拡大して真ん中付近を切り取りたい場合
  Bitmap.Width  := Image1.Width;
  Bitmap.Height := Image1.Height;
  rc = Rect(0, 0, Meta.Width * 10, Meta.Height * 10);
  OffsetRect(rc, (Bitmap.Width - Meta.Width * 10) div 2, (Bitmap.Height - Meta.Height * 10) div 2);
  Bitmap.Canvas.StretchDraw(rc, Meta);
みたいにすれば必要な範囲だけ描画されると思うのですが。


monaa  2009-04-20 02:23:49  No: 34064

メタファイルは拡大してもメモリのサイズは変わりません。
そのためメタファイルを一度全部拡大してしまい、
ほしいところだけ描画すれば目的の動作になります。

procedure TForm1.Button1Click(Sender: TObject);
var
  str:string;
  mFile  :TMetafile;
  mCanvas:TMetafileCanvas;
  rate,left,right,top,bottom,rL,rT : Integer;
  bmp: TBitmap;
begin
  mFile := TMetafile.Create;
  mFile.Width:=20;
  mFile.Height:=20;
  mCanvas:=TMetafileCanvas.Create(mFile,0);
  mCanvas.Font.Height := 20;
  str := '薔';
  TextOut(mCanvas.Handle,0,0,@str[1],1);
  mCanvas.Free;
  //メタファイルサイズは H20 W20
  //水平 5-15 を拡大して表示
  //垂直 5-15 を拡大して表示
  rate  := 20; //20倍
  left  :=  5;
  right := 15;
  top   :=  5;
  bottom:= 15;

  bmp:=TBitmap.Create;
  bmp.Width := (right - left)*rate;
  bmp.Height:= (bottom- top )*rate;
  rL := left*rate*-1;
  rT := top*rate*-1;
  bmp.Canvas.StretchDraw(
    Rect(rL,rT,
         mFile.Width * rate + rL,
         mFile.Height* rate + rT),mFile);

  Canvas.Draw(0,0,bmp);
  bmp.Free;
  mFile.Free;
end;


monaa  2009-04-20 02:26:04  No: 34065

あら、サンプル書いているうちに書き込みありましたね。
重複失礼しました。


KHE00221  2009-04-20 02:27:31  No: 34066

1781x2203 の .WMF を 

if OpenPictureDialog1.Execute = True then
begin
  Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
  Image1.Width  := Image1.Picture.Width  * 10000;
  Image1.Height := Image1.Picture.Height * 10000;
end;

で表示できるから別に部分拡大しなくても良い気がするけど?


アル  2009-04-20 04:11:15  No: 34067

たくさんのレスありがとうございます。

tocさまの方法でうまくいきました。
メタファイルは拡大してもメモリは使わないのですね。
勉強になりました。


Mr.XRAY  2009-04-20 07:14:00  No: 34068

Mr.XRAYです.解決済みというこですが,ついでに.

>メタファイルは拡大してもメモリは使わないのですね。

描画情報が格納されているだけですから,基本的にそうなります.

メタファイルをTImageに描画する際,DrawやStretchDrawの場合,TImgaeの拡大に伴い,
描画した画像はギザギザになります.これは内部での描画がビットマップだからです.
一方,Image1.Picture.Assigngならばなりません.

すぐに確認できるサンプルを用意してあります.もし必要なら試してください.
http://mrxray.on.coocan.jp/Delphi/plSamples/172_MetaFile_BasicTest.htm

それから,メタファイルの部分拡大したメタファイルの取得ですが,
マッピングという方法を利用すると可能です.
以下のコードでは,簡単のために,範囲指定ではなく,拡大して,その部分を保存
しています.
範囲指定するには,換算が必要です.

保存したメタファイルを,イメージを表示するアプリで開き,拡大してみてください.
まさにメタファイルであることが確認できます.

//=============================================================================
//  メタファイルの一部を切取ったメタファイルを作成
//
//  TImageを2つ.共にStretchをTrueに(画像が大きい時も確認可能にするため)
//  TButtonを1つ
//
//  任意の範囲だけを取出すには,
//  SetWindowExtExとSetViewPortOrgExの引数値に工夫が必要
//  ここでは簡単にするため,倍率で設定
//=============================================================================
procedure TForm1.Button4Click(Sender: TObject);
Var
  Meta       : TMetafile;
  MetaCanvas : TMetafileCanvas;
  AWidth     : Integer;
  AHeight    : Integer;
  R          : Integer;
begin
   Image1.Stretch := True;
   Image2.Stretch := True;

   //拡大率
   R := 3;
   Meta := TMetafile.Create;
   try
     //対象のメタファイル画像
     Meta.LoadFromFile('000.emf');
     //元の画像を確認表示
     Image1.Picture.Assign(Meta);

     MetaCanvas := TMetafileCanvas.Create( Meta, 0 );

     AWidth  := Meta.Width;
     AHeight := Meta.Height;

     //マッピング設定
     SetMapMode       (MetaCanvas.Handle,MM_ANISOTROPIC);
     SetWindowExtEx   (MetaCanvas.Handle,AWidth div R, AHeight div R, nil);
     SetViewPortExtEx (MetaCanvas.Handle,AWidth, AHeight, nil);
     //描画原点を移動
     //ここでは元の画像の右から30,上から50
     SetViewPortOrgEx(MetaCanvas.Handle,-30*R,-50*R,nil);

     //描画
     MetaCanvas.Draw(0,0,Meta);;

     //描画終了
     MetaCanvas.Free;

     //確認表示(このImage2に表示されている範囲が保存される
     //ただし,Image2のStretchはTrueとしているので縦横比は正確でない
     Image2.Picture.Assign(Meta);
     //保存
     Meta.SaveToFile('TestOut.emf');
   finally
     FreeAndNil(Meta);
   end;
end;


Mr.XRAY  2009-04-20 14:50:50  No: 34069

Mr.XRAYです.

う〜ん.この方法には無理がありますね.
やはり,他の方のレスのやり方がいいでしょう.
迷わせてしまって,申し訳ありませんでした.


アル  2009-04-20 21:59:23  No: 34070

詳しくありがとうございます。
とても参考になります。

試してみましたが、
切り取ったメタファイルって
ほとんどファイルサイズ変わらないんですね
復活させることも可能なんでしょうか。


Mr.XRAY  2009-04-20 22:44:41  No: 34071

Mr.XRAYです.

メタファイルのサイズというのは,コードの Meta.Width 等のことでしょうか.
例えば,ビットマップのサイズ(幅)というと,
      Bitmap.Width
のことを意味していると思いますが,これは,ピクセル数のことです.
メタファイルのサイズとは,意味が違います.

メタファイルというのは,
(0,0) から (200,500)  まで,直線で,これこれの色と太さで描画せよ
というような情報が格納されています.
つまり,メタファイルのサイズというのは,そのような情報の格納サイズと考えてください.
これは,他のベクター方式の画像ファイルにも言えることです.

ビットマップでしたら,どこから,どこまでのピクセルを切取った画像とういことが可能です.
メタファイルの場合は,情報の格納サイズみたいなものですから,
通常のファイル等と同じで,ファイルのサイズの一部分を切取るということはできません.
(明らかに,意味不明ですよね?)

他の方のレスにあるように,ビットマップを介して,その一部を描画というのはできます.

メタファイルの一部分を取出しても,描画情報の格納サイズですから,それほど変化が
ない場合もあります. 

>復活させることも可能なんでしょうか。     

すみません.意味がわかりません.


Mr.XRAY  2009-04-20 22:47:58  No: 34072

>メタファイルの一部分を取出しても,描画情報の格納サイズですから,それほど変化が
>ない場合もあります. 

ファイルそのもののサイズも同様です.


Mr.XRAY  2009-04-20 22:55:02  No: 34073

>そのような情報の格納サイズと考えてください.

本当は違います.格納サイズの一種です.
描画に関する長さと高さ関係の情報なんですが,
それは,ネット上や書籍で調べてみてください.

*私のサイトには,これに関しての説明記事はありません,あしからず.


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加