StretchBltのやりかた

解決


Kヨシオ  2008-02-04 17:35:56  No: 29655  IP: 192.*.*.*

画像をimage1にロードしてimage2に縮小するところでうまくいかなくてお助けを。下記のコードでやってみると「ビットマップを持っている時のみイメージの変更が可能です」と出てしまいます。  ソースの元ネタはhttp://delphi.livedoor.biz/archives/50602241.html
なのですが同じようにやっても動きません。(画像のロードだけはできています)  何が原因か教えてください。(D6  パーソナル)

procedure TForm1.Button1Click(Sender: TObject);

var
w,h,w1,h1:integer;
kfile:string;

begin

 kfile:='c:\mypictures\2008\801\thumbnail\t_imgp2597.jpg';
 image1.picture.LoadFromFile(kfile);

                        w:=form1.image1.picture.Width;
                        h:=form1.image1.picture.Height;

                        w1:=round(w*0.8);
                        h1:=round(h*0.8);

SetStretchBltMode(form1.image2.Canvas.Handle, HALFTONE);

                        StretchBlt(form1.image2.Canvas.Handle,
                        0, 0, w1, h1,
                        form1.image1.Canvas.Handle,
                        0, 0, w, h,
                        SRCCOPY);

end;

編集 削除
KHE00221  2008-02-04 17:44:12  No: 29656  IP: 192.*.*.*

>何が原因か教えてください。(D6  パーソナル)

ロードしている画像が JPEG だから

編集 削除
Kヨシオ  2008-02-04 19:27:59  No: 29657  IP: 192.*.*.*

KHE00221様、回答をありがとうございました。
確かにサンプルのコードはBMPでした。これと同じようなものをいくつか作ってみたのですがいずれも失敗でしたが原因は画像がJPEGであるとは知りませんでした。JPEGをBMPのように縮小して保存するのが最終目的なのですがどのようにすれば良いか教えてください。

編集 削除
DEKO  2008-02-05 02:22:43  No: 29658  IP: 192.*.*.*

参考になれば。
http://homepage1.nifty.com/ht_deko/tech001.html#tech018

編集 削除
Kヨシオ  2008-02-05 11:27:45  No: 29659  IP: 192.*.*.*

DEKO様、ご回答をありがとうございました。サンプルを試した結果見事画像の縮小はできました。

しかし縮小された画像は電線などが途切れ途切れになっておりました。できれば画質向上のためHALFTONEモードを入れたい、多数の画像をバッチで処理したいので進行がわかるように作業中の画像を表示するようにしたい、などを希望しております。方法がありましたらよろしくお願いします。

編集 削除
辛口一献  2008-02-05 11:34:38  No: 29660  IP: 192.*.*.*

>方法がありましたらよろしくお願いします。
他人のサンプルを丸写ししてるだけじゃ、いつまでも初心者マークは取れないよ。
その程度の応用は、まず自分でやってみたらどう?

編集 削除
junki  URL  2008-02-05 15:54:46  No: 29661  IP: 192.*.*.*

画像を滑らかに縮小・拡大するには、ピクセルの間を補間する必要があります。
有名なのは、バイリニア・バイキュービックなどです。参考になるページを
挙げておきます。

http://junki.lix.jp/delphigr/041Resize1.htm
http://junki.lix.jp/delphigr/042Resize2.htm
http://junki.lix.jp/delphigr/044Resize3.htm

編集 削除
Kヨシオ  2008-02-07 12:08:54  No: 29662  IP: 192.*.*.*

辛口一献様、junki様  ご回答をありがとうございました。
ご紹介いただいたサイトを拝見し、各ピクセルの周囲の情報を取り入れて補完する方法は勉強になりました。

計画しているソフトは最近のデジカメで撮った写真のサイズがあまりにも大きいのであまり重要ではないものはバッチで縮小して保存して整理しようとVBで作り、上手く動いています。かなりコンパクトなものなのでランタイムが不要なDELPHIに移植しようと挑戦を始めたものです。縮小の場合はSet StretchBltMode  をHALFTONEに指定するとスムーズな画像となりほぼ満足できるのでStretchBltをこのAPIを使えば簡単にできるのではないかと思って試したのですが理解不足でした。VBのようにPicture(Image)に一度ロードしてしまえばBMPでもJPGでも同じように処理できるものと思っていたのが間違いでした。補完方法に関しては開発言語に係わらず普遍的な技術ですので勉強になりました。お手数をお掛けしました。

編集 削除
叩けよさらば開かれん  2008-02-09 14:29:10  No: 29663  IP: 192.*.*.*

HALFTONEを使ったFunc_Aの縮小方法でもかなりイケルけど、
髪の毛や眼など、線や細かい部分では、Func_Bの方がイイね。

type
  PAryRGBTr = ^TAryRGBTr;
  TAryRGBTr = array[0..$1FFF] of TRGBTriple;
const
  RATE = 0.3000;        // 縮小率
  PATH = 'C:\My Documents\My Pictures\';

// HALFTONEを指定してStretchBlt関数
procedure TForm1.Func_A(Jpg: TJPEGImage);
var
  w, h, w1, h1: Integer;
begin
  Image1.Picture.Bitmap.Assign(Jpg);
  w := Image1.Picture.Width;
  h := Image1.Picture.Height;
  w1 := Round(w * RATE);
  h1 := Round(h * RATE);
  Image2.Picture.Bitmap.Width := w1;
  Image2.Picture.Bitmap.Height := h1;
  SetStretchBltMode(Image2.Canvas.Handle, HALFTONE);
  StretchBlt(Image2.Canvas.Handle, 0, 0, w1, h1, Image1.Canvas.Handle, 0, 0, w, h, SRCCOPY);
  Image2.Invalidate;
end;

// 独自のリサイズ関数
procedure TForm1.Func_B(Jpg: TJPEGImage);
 //------------------------------------------
 procedure ResizeBmp(SrcBmp, DstBmp: TBitmap);
 var
  x, y: Integer;
  xP, yP, xD, yD: Integer;
  w1, w2, w3, w4: Integer;
  zz, nz, iz, tt: Integer;
  DstGaps: Integer;
  SrcLine1, SrcLine2, DstLine: PAryRGBTr;
 begin
  SrcBmp.PixelFormat := pf24Bit;
  DstBmp.PixelFormat := pf24Bit;
  if (SrcBmp.Width = DstBmp.Width) and (SrcBmp.Height = DstBmp.Height) then begin
   DstBmp.Assign(SrcBmp);
  end else begin
   DstLine := DstBmp.ScanLine[0];
   DstGaps := PChar(DstBmp.ScanLine[1]) - PChar(DstLine);
   xD := MulDiv(Pred(SrcBmp.Width), $10000, DstBmp.Width);
   yD := MulDiv(Pred(SrcBmp.Height), $10000, DstBmp.Height);
   yP := 0;
   for y := 0 to Pred(DstBmp.Height) do begin
    xP := 0;
    SrcLine1 := SrcBmp.ScanLine[yP shr 16];
    if (yP shr 16 < Pred(SrcBmp.Height)) then begin
     SrcLine2 := SrcBmp.ScanLine[Succ(yP shr 16)]
    end else begin
     SrcLine2 := SrcBmp.ScanLine[yP shr 16];
    end;
    nz := Succ(yP and $FFFF);
    iz := Succ((not yP) and $FFFF);
    for x := 0 to Pred(DstBmp.Width) do begin
     tt := xP shr 16;
     zz := xP and $FFFF;
     w2 := MulDiv(zz, iz, $10000);
     w1 := iz - w2;
     w4 := MulDiv(zz, nz, $10000);
     w3 := nz - w4;
     DstLine[x].rgbtRed := (SrcLine1[tt].rgbtRed * w1 + SrcLine1[tt + 1].rgbtRed * w2
       + SrcLine2[tt].rgbtRed * w3 + SrcLine2[tt + 1].rgbtRed * w4) shr 16;
     DstLine[x].rgbtGreen := (SrcLine1[tt].rgbtGreen * w1 + SrcLine1[tt + 1].rgbtGreen * w2
       + SrcLine2[tt].rgbtGreen * w3 + SrcLine2[tt + 1].rgbtGreen * w4) shr 16;
     DstLine[x].rgbtBlue := (SrcLine1[tt].rgbtBlue * w1 + SrcLine1[tt + 1].rgbtBlue * w2
       + SrcLine2[tt].rgbtBlue * w3 + SrcLine2[tt + 1].rgbtBlue * w4) shr 16;
     Inc(xP, xD);
    end;
    Inc(yP, yD);
    DstLine := PAryRGBTr(PChar(DstLine) + DstGaps);
   end;
  end;
 end;
 //------------------------------------------
var
  w, h: Integer;
begin
  Image1.Picture.Bitmap.Assign(Jpg);
  w := Image1.Picture.Width;
  h := Image1.Picture.Height;
  Image2.Picture.Bitmap.Width := Round(w * RATE);
  Image2.Picture.Bitmap.Height := Round(h * RATE);
  ResizeBmp(Image1.Picture.Bitmap, Image2.Picture.Bitmap);
  Image2.Invalidate;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Jpg: TJPEGImage;
  sr: TSearchRec;
begin
 Jpg := TJPEGImage.Create;
 try
  if FindFirst(PATH +'*.jpg', faArchive, sr) <> 0 then exit;
  repeat
   Caption := sr.Name;
   Jpg.LoadFromFile(PATH + sr.Name);
   Func_A(Jpg);
   Application.ProcessMessages; Sleep(1000);
   Func_B(Jpg);
   Jpg.Assign(Image2.Picture.Bitmap);
// Jpg.SaveToFile('T_'+ sr.Name);
   Application.ProcessMessages; Sleep(1000);
   if GetKeyState(VK_ESCAPE) < 0 then break;
  until FindNext(sr) <> 0;
  FindClose(sr);
 finally
  Jpg.Free;
 end;
end;

編集 削除
Kヨシオ  2008-02-10 18:46:56  No: 29664  IP: 192.*.*.*

叩けよさらば開かれん様  大変な労作をありがとうございました。
まずFunc_AでJpegをStretchBltで変形するという所期の目的が達成でき、おかげさまで永い間試行錯誤してきたバッチ処理のソフトができました。Jpegを読み込んで変形するという基本動作に必要なプロセスが習得できました。現時点ではFunc_Bは「アドレス違反」というメッセージが出てしまっていますが縮小が目的ですのでとりあえずはStretchBltで十分満足する結果が得られておりますのでFunc_Bは今後の勉強課題にしたいと思います。ありがとうございました。ご親切に感謝します。

編集 削除