2012-02-07 15 views
8

Jeśli mam TBitmap i chcę uzyskać przycięty obraz z tej bitmapy, czy mogę wykonać operację przycinania "na miejscu"? na przykład jeśli mam bitmapę o rozdzielczości 800x600, jak mogę ją zmniejszyć (przyciąć) tak, aby zawierała obraz 600x400 w środku, tj. wynikowa mapa TBitmap to 600x400 i składa się z prostokąta ograniczonego przez (100, 100) i (700 , 500) na oryginalnym obrazku?Delphi - jak przyciąć mapę bitową "na miejscu"?

Czy muszę przejść przez inną bitmapę lub czy można wykonać tę operację w oryginalnej bitmapie?

Odpowiedz

20

Można użyć BitBlt funkcję

spróbuj tego kodu.

procedure CropBitmap(InBitmap, OutBitMap : TBitmap; X, Y, W, H :Integer); 
begin 
    OutBitMap.PixelFormat := InBitmap.PixelFormat; 
    OutBitMap.Width := W; 
    OutBitMap.Height := H; 
    BitBlt(OutBitMap.Canvas.Handle, 0, 0, W, H, InBitmap.Canvas.Handle, X, Y, SRCCOPY); 
end; 

i można go używać w ten sposób

Var 
    Bmp : TBitmap; 
begin 
    Bmp:=TBitmap.Create; 
    try 
    CropBitmap(Image1.Picture.Bitmap, Bmp, 10,0, 150, 150); 
    //do something with the cropped image 
    //Bmp.SaveToFile('Foo.bmp'); 
    finally 
    Bmp.Free; 
    end; 
end; 

Jeśli chcesz użyć tej samej mapy bitowej, spróbuj tej wersji funkcji

procedure CropBitmap(InBitmap : TBitmap; X, Y, W, H :Integer); 
begin 
    BitBlt(InBitmap.Canvas.Handle, 0, 0, W, H, InBitmap.Canvas.Handle, X, Y, SRCCOPY); 
    InBitmap.Width :=W; 
    InBitmap.Height:=H; 
end; 

i wykorzystania w ten sposób

Var 
Bmp : TBitmap; 
begin 
    Bmp:=Image1.Picture.Bitmap; 
    CropBitmap(Bmp, 10,0, 150, 150); 
    //do somehting with the Bmp 
    Image1.Picture.Assign(Bmp); 
end; 
+0

Dzięki za to. Czy istnieje prosty sposób na osiągnięcie tego bez potrzeby drugiej bitmapy? W taki sam sposób jak rutyna 'Move' w Delphi obsługuje nakładające się źródło i miejsce docelowe, czy istnieje dwuwymiarowy odpowiednik? – rossmcm

+0

Możesz użyć funkcji Przenieś z właściwością ScanLine pliku TBitmap, ale musisz obliczyć rozmiar bajtów pikseli w zależności od BitsPerPixel –

+0

Sprawdź drugą opcję, która wykorzystuje tylko jedną bitmapę. – RRUZ

4

Wiem, że masz swoje zaakceptowana odpowiedź już, ale od kiedy napisałem swoją wersję (która używa opakowania VCL zamiast wywołania GDI), opublikuję ją tutaj zamiast po prostu ją wyrzucić.

procedure TForm1.FormClick(Sender: TObject); 
var 
    Source, Dest: TRect; 
begin 
    Source := Image1.Picture.Bitmap.Canvas.ClipRect; 
    { desired rectangle obtained by collapsing the original one by 2*2 times } 
    InflateRect(Source, -(Image1.Picture.Bitmap.Width div 4), -(Image1.Picture.Bitmap.Height div 4)); 
    Dest := Source; 
    OffsetRect(Dest, -Dest.Left, -Dest.Top); 
    { NB: raster data is preserved during the operation, so there is not need to have 2 bitmaps } 
    Image1.Picture.Bitmap.Canvas.CopyRect(Dest, Image1.Picture.Bitmap.Canvas, Source); 
    { and finally "truncate" the canvas } 
    Image1.Picture.Bitmap.Width := Dest.Right; 
    Image1.Picture.Bitmap.Height := Dest.Bottom; 
end;