Potrzebuję malować po Canvas
komponentu wiele wyciętych fragmentów z grafiki PNG (32-bitowa głębia), zachowując przezroczystość; Malowanych fragmentów może być nawet setki, więc potrzebuję efektywnego algorytmu;
Napisałem więc kod testowy, który do tego celu używa metody TCanvas.CopyRect
i wszystko malowane jest prawidłowo; Jednak czas malowania jest tragicznie długi, dlatego że wymieniona metoda wykonuje kupę zbędnych operacji, jak sprawdzanie źródła, rozmiarów fragmentu, a do tego używa funkcji StretchBlt
:
procedure TCanvas.CopyRect(const Dest: TRect; SrcCanvas: TCanvas;
const Source: TRect);
var
SH, SW, DH, DW: Integer;
Begin
if SrcCanvas= nil then exit;
SH := Source.Bottom - Source.Top;
SW := Source.Right - Source.Left;
if (SH=0) or (SW=0) then exit;
DH := Dest.Bottom - Dest.Top;
DW := Dest.Right - Dest.Left;
if (Dh=0) or (DW=0) then exit;
SrcCanvas.RequiredState([csHandleValid]);
Changing;
RequiredState([csHandleValid]);
StretchBlt(FHandle, Dest.Left, Dest.Top, DW, DH,
SrcCanvas.FHandle, Source.Left, Source.Top, SW, SH, CopyMode);
Changed;
end;
kod pobrany z modułu canvas.inc
ze źródeł LCL
Wszystkie dodatkowe operacje (sprawdzenia) są tak jak napisałem zbędne, dlatego że nie ma mowy o tym, abym czegoś nie dopilnował - podał kanwę wskazującą na Nil, czy błędne rozmiary wycinków; Dlatego też samo sprawdzanie trzeba ominąć; Dodatkowo, wszystkie grafiki PNG posiadają 32-bitową głębię kolorów, malowany fragment nigdy nie będzie rozciągany lub zmniejszany, więc StretchBlt
jest nadmiarowy, a nawet sama klasa TPortableNetworkGraphic
to także przerost formy nad treścią;
Niestety kanwa komponentu nie daje dostępu do fizycznej pamięci z zapisaną mapą pikseli, jak to można uzyskać za pomocą metody ScanLine
w klasie TPortableNetworkGraphic
, czy nawet TBitmap
; Szkoda, bo można by ręcznie w pętli mieszać składowe pikseli, co było o wiele szybsze, niż używanie do tego tylu metod i zbędnych operacji;
Tak więc potrzebuję sposobu na jak najbardziej optymalne przekopiowanie fragmentu obrazu PNG do kanwy komponentu; Nie musi to być wykonane uniwersalnym (multiplatformowym) kodem - może być to wykonane w WinAPI za pomocą kontekstu urządzenia (DC
); Również nie muszę w ogóle korzystać z grafiki PNG - wystarczy mi już zapisana w pliku amorficznym gotowa i nieskompresowana mapa 32-bitowych pikseli - będzie prościej, bo czas ładowania jej do pamięci i tak będzie króciutki;
Ma ktoś jakiś pomysł?
Spróbuję później użyć bezpośrednio funkcji BitBlt
- być może będzie szybsza, bo nie będzie rozciągania sprawdzała, no i pozostałych, w moim przypadku zbędnych rzeczy.