Q&A

  • [질문]보이지 않는 scrollbox 안의 내용을 이미지로 저장?
안녕하세요?

보이지 않는 scrollbox 영역에 있는 모든 내용을

하나의 이미지 파일로 저장하려고 하는데

어케 해야하는지 감이 안잡힙니다.

아래와 같이 하면 보이는 보분은 이미지로 캡춰가 잘 되지만....


여기서 더 이상 진도가 못나가고 있습니다.

주말동안 인터넷을 누비고 찾아 다녔지만 결국 해결하지 못했습니다.

여러 고수님들의 많은 지도 편달과 도움을 부탁드립니다.

미리 감사드립니다...



procedure Tform1.Button1Click(Sender: TObject);
var dc : HDC;
iBmp : TBitmap;
begin
dc := GetDC(scrollbox1.Handle);

iBmp := TBitmap.Create;
iBmp.Width := scrollbox1.Width;
iBmp.Height := scrollbox1.Height+1000;

BitBlt(iBmp.Canvas.Handle, 0, 0, iBmp.Width, iBmp.Height, dc, 0, 0, SRCCOPY);

iBmp.SaveToFile('c:\mymymy.bmp');
iBmp.Free;

ReleaseDC(scrollbox1.Handle, dc);

end;
4  COMMENTS
  • Profile
    장성호 2008.11.24 21:26

    ScrollBox의 안보이는 영역에 control의 이미지까지 캡쳐 하는것은 위방법으로는 안됩니다.


    [보통 컨트롤 캡쳐할때]
    보통 컨트롤의 화면을 캡쳐할때 위방식을 이용합니다만

    vcl에서 제공하는 방법중에 PaintTo라는 메소드가 있습니다.


    procedure TForm1.Button1Click(Sender: TObject);
    var
    bmp: TBitmap;
    begin
    bmp:=TBitmap.create;
    bmp.width:=Panel1.Width;
    bmp.Height:=Panel1.Height;
    Panel1.PaintTo(bmp.Canvas.Handle,0,0 ); //함수1 DC를 넘기기도하고
    Panel1.PaintTo(bmp.Canvas,0,0 ); //함수2 Canvas를 넘길수도 있음

    end;



    PaintTo 함수는 TWinControl에 있는 함수로써 모든 핸들이 있는 control에 사용할수 있습니다.

    그런데 Controls유닛에서 TWinControl.PaintTo 함수를 살펴보면

    WM_PAINT 메세지를 보내면서 wParam으로 dc를 보내서 캡쳐하는 합니다.
    Perform(WM_PAINT, DC, 0); //

    즉 직접 코딩하다면
    Panal1.Perform(WM_PAINT, bmp.Canvas.Handle, 0); //뭐 이런식이 되죠


    [GetFormImage 함수를 보면..]

    VCL에는 GetFormImage라는 함수가 있습니다.
    이 함수의 동작으로 보면

    1. bitmap을 자신의 크기만큼 생성하고
    2. 자신을 bitmap에 그리고
    3. 자신위에 있는 모든 control에 루프를 돌리면서 PaintTo를 호출합니다.

    이 GetFormImage를 GetPanelImage함수를 만들어 본적이 있죠
    http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=753


    [ScrollBox 안보이는 영역까지 캡쳐]

    위 GetFormImage함수의 원리를 이용하여
    ScrollBox위에 이미지를 캡쳐하려면

    1. bitmap을 생성하다
    2. bitmap의 크기를 scrollbox의 안보이는 크기까지 계산해서 잡는다.
    (ScrollBox.HorzScrollBar.Range , ScrollBox.VertScrollBar.Range)

    3. scrollbox를 bitmap에 그린다.

    4. scrollbox위에 있는 모든 control에 offset을 계산해서 PaintTo를 호출해준다.


    이 원리로 한번 해보십시요
    하다가 안되면 Naver에서 GetScrollBoxImage를 검색해보세요

    그럼..

  • Profile
    윤창훈 2008.11.25 13:25
    안녕하세요? 장성호님...
    우선 이문제를 해결할 수 있어 진심으로 감사드립니다.
    이렇게 도움을 받으니 세상에는 너무 고마운분이 많고 혼자가 아니구나 라는 생각이 듭니다. ^^

    위에서 설명해주신 내용으로는 저의 내공으로 인하여 너무 어려웠는데
    알려주신 여러 함수를 토대로 지구를 돌면서 찾다가 드뎌 해결할 수 있었습니다.

    아직도 정확한 함수의 쓰임은 모르겠지만
    정확히 원하는 바가 해결되어
    다른분들도 저와 같은 고민을 하시는 분이 있을것 같기에
    여기에 그 내용을 쓰도록 하도록 하겠습니다.

    다시한번 감사드리며 항상 행운이 함께 하시길 ~~


    ===================================================================
    내용 : scrollbox의 모든 내용( 보이지 않는 부분을 포함)을 이미지 저장....
    ===================================================================

    procedure Tform1.PaintControl( aControl: TWinControl; aCanvas: TCanvas; offsetx, offsety: Integer );
    begin
    SaveDC( aCanvas.handle );
    try
    SetWindowOrgEx( aCanvas.handle, - (acontrol.left + offsetx), - (acontrol.top + offsety), nil );
    acontrol.perform( WM_PRINT, acanvas.handle, PRF_CHILDREN or PRF_CLIENT or PRF_NONCLIENT or PRF_ERASEBKGND );
    finally
    RestoreDC( aCanvas.handle, - 1 );
    end;
    end;


    procedure Tform1.Button1Click(Sender: TObject);
    var
    bmp: TBitmap;
    i: integer;
    begin

    bmp := TBitmap.Create;
    try
    bmp.width := scrollbox1.HorzScrollBar.Range;
    bmp.height := scrollbox1.VertScrollBar.Range;

    bmp.canvas.lock;
    SetMapMode( bmp.canvas.handle, MM_ISOTROPIC );
    SetWindowExtEx( bmp.canvas.handle, 400, 400, nil );
    SetViewportExtEx( bmp.canvas.handle, 400, 400, nil );
    try
    SetWindowOrgEx( bmp.canvas.handle, - scrollbox1.HorzScrollBar.Position, - scrollbox1.VertScrollBar.POsition, nil );
    scrollbox1.perform( WM_PAINT, bmp.canvas.handle, 1 );
    SetWindowOrgEx( bmp.canvas.handle, 0, 0, nil );
    for i := 0 to scrollbox1.controlcount - 1 do
    if scrollbox1.Controls[i] is TWincontrol then
    Paintcontrol(TWincontrol(scrollbox1.Controls[i]), bmp.canvas, scrollbox1.horzscrollBar.Position, scrollbox1.vertScrollBar.Position );
    finally
    bmp.canvas.unlock;
    end;

    bmp.SaveToFile('c:\test.bmp');
    finally
    bmp.free;
    end;

    end;

  • Profile
    장성호 2008.11.25 19:56
    와우~! 좋네요

    제가 만들어 쓰던것보다 코드가 짧네요...

    한가지.. ScrollBox 자체는 흰색으로 그려지네요
    ScrollBox를 그대로 배경으로 넣으려면 위코드에 두줄만 추가하면 될듯..


    procedure Tform1.PaintControl( aControl: TWinControl; aCanvas: TCanvas; offsetx, offsety: Integer );
    begin
    SaveDC( aCanvas.handle );
    try
    SetWindowOrgEx( aCanvas.handle, - (acontrol.left + offsetx), - (acontrol.top + offsety), nil );
    acontrol.perform( WM_PRINT, acanvas.handle, PRF_CHILDREN or PRF_CLIENT or PRF_NONCLIENT or PRF_ERASEBKGND );
    finally
    RestoreDC( aCanvas.handle, - 1 );
    end;
    end;

    procedure Tform1.Button1Click(Sender: TObject);
    var
    bmp: TBitmap;
    i: integer;
    begin

    bmp := TBitmap.Create;
    try
    bmp.width := scrollbox1.HorzScrollBar.Range;
    bmp.height := scrollbox1.VertScrollBar.Range;

    bmp.canvas.lock;
    SetMapMode( bmp.canvas.handle, MM_ISOTROPIC );
    SetWindowExtEx( bmp.canvas.handle, 400, 400, nil );
    SetViewportExtEx( bmp.canvas.handle, 400, 400, nil );
    try
    SetWindowOrgEx( bmp.canvas.handle, - scrollbox1.HorzScrollBar.Position, - scrollbox1.VertScrollBar.POsition, nil );

    { 요기에 두줄 추가 }
    bmp.Canvas.Brush := scrollbox1.Brush;
    bmp.Canvas.FillRect(Rect(0,0,bmp.width,bmp.height));

    scrollbox1.perform( WM_PAINT, bmp.canvas.handle, 1 );
    SetWindowOrgEx( bmp.canvas.handle, 0, 0, nil );
    for i := 0 to scrollbox1.controlcount - 1 do
    if scrollbox1.Controls[i] is TWincontrol then
    Paintcontrol(TWincontrol(scrollbox1.Controls[i]), bmp.canvas, scrollbox1.horzscrollBar.Position, scrollbox1.vertScrollBar.Position );
    finally
    bmp.canvas.unlock;
    end;

    bmp.SaveToFile('c:\test.bmp');
    finally
    bmp.free;
    end;

    end;


    그럼
  • Profile
    윤창훈 2008.11.26 10:30
    ㅋㅋ
    넵~ 그렇군요..
    감사합니다~~