| 1 | {
|
|---|
| 2 | /**************************************************************************\
|
|---|
| 3 | bgrawinbitmap.pas
|
|---|
| 4 | -----------------
|
|---|
| 5 | This unit should NOT be added to the 'uses' clause.
|
|---|
| 6 | It contains accelerations for Windows. Notably, it
|
|---|
| 7 | provides direct access to bitmap data.
|
|---|
| 8 |
|
|---|
| 9 | ****************************************************************************
|
|---|
| 10 | * *
|
|---|
| 11 | * This file is part of BGRABitmap library which is distributed under the *
|
|---|
| 12 | * modified LGPL. *
|
|---|
| 13 | * *
|
|---|
| 14 | * See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
|---|
| 15 | * for details about the copyright. *
|
|---|
| 16 | * *
|
|---|
| 17 | * This program is distributed in the hope that it will be useful, *
|
|---|
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|---|
| 20 | * *
|
|---|
| 21 | ****************************************************************************
|
|---|
| 22 | }
|
|---|
| 23 |
|
|---|
| 24 | unit BGRAWinBitmap;
|
|---|
| 25 |
|
|---|
| 26 | {$mode objfpc}{$H+}
|
|---|
| 27 |
|
|---|
| 28 | interface
|
|---|
| 29 |
|
|---|
| 30 | uses
|
|---|
| 31 | Classes, SysUtils, BGRALCLBitmap, Windows, Graphics, GraphType;
|
|---|
| 32 |
|
|---|
| 33 | type
|
|---|
| 34 | { TBGRAWinBitmap }
|
|---|
| 35 |
|
|---|
| 36 | TBGRAWinBitmap = class(TBGRALCLBitmap)
|
|---|
| 37 | private
|
|---|
| 38 | procedure AlphaCorrectionNeeded;
|
|---|
| 39 | protected
|
|---|
| 40 | DIB_SectionHandle: HBITMAP;
|
|---|
| 41 | FReversed: boolean;
|
|---|
| 42 | function DIBitmapInfo(AWidth, AHeight: integer): TBitmapInfo;
|
|---|
| 43 |
|
|---|
| 44 | procedure ReallocData; override;
|
|---|
| 45 | procedure FreeData; override;
|
|---|
| 46 |
|
|---|
| 47 | procedure RebuildBitmap; override;
|
|---|
| 48 | procedure FreeBitmap; override;
|
|---|
| 49 |
|
|---|
| 50 | procedure Init; override;
|
|---|
| 51 | function GetBitmap: TBitmap; override;
|
|---|
| 52 |
|
|---|
| 53 | public
|
|---|
| 54 | procedure LoadFromBitmapIfNeeded; override;
|
|---|
| 55 | procedure Draw(ACanvas: TCanvas; x, y: integer; Opaque: boolean=True); overload; override;
|
|---|
| 56 | procedure Draw(ACanvas: TCanvas; Rect: TRect; Opaque: boolean = True); overload; override;
|
|---|
| 57 | procedure DataDrawOpaque(ACanvas: TCanvas; ARect: TRect; AData: Pointer;
|
|---|
| 58 | ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer); override;
|
|---|
| 59 | procedure GetImageFromCanvas(CanvasSource: TCanvas; x, y: integer); override;
|
|---|
| 60 | end;
|
|---|
| 61 |
|
|---|
| 62 | implementation
|
|---|
| 63 |
|
|---|
| 64 | uses BGRADefaultBitmap, BGRABitmapTypes;
|
|---|
| 65 |
|
|---|
| 66 | type
|
|---|
| 67 | { TWinBitmapTracker }
|
|---|
| 68 |
|
|---|
| 69 | TWinBitmapTracker = class(TBitmap)
|
|---|
| 70 | protected
|
|---|
| 71 | FUser: TBGRAWinBitmap;
|
|---|
| 72 | procedure Changed(Sender: TObject); override;
|
|---|
| 73 | public
|
|---|
| 74 | constructor Create(AUser: TBGRAWinBitmap); overload;
|
|---|
| 75 | end;
|
|---|
| 76 |
|
|---|
| 77 | procedure TWinBitmapTracker.Changed(Sender: TObject);
|
|---|
| 78 | begin
|
|---|
| 79 | if FUser <> nil then
|
|---|
| 80 | FUser.AlphaCorrectionNeeded;
|
|---|
| 81 | inherited Changed(Sender);
|
|---|
| 82 | end;
|
|---|
| 83 |
|
|---|
| 84 | constructor TWinBitmapTracker.Create(AUser: TBGRAWinBitmap);
|
|---|
| 85 | begin
|
|---|
| 86 | FUser := AUser;
|
|---|
| 87 | inherited Create;
|
|---|
| 88 | end;
|
|---|
| 89 |
|
|---|
| 90 | { TBGRAWinBitmap }
|
|---|
| 91 |
|
|---|
| 92 | procedure TBGRAWinBitmap.FreeData;
|
|---|
| 93 | begin
|
|---|
| 94 | if DIB_SectionHandle <> 0 then
|
|---|
| 95 | begin
|
|---|
| 96 | DeleteObject(DIB_SectionHandle);
|
|---|
| 97 | FData := nil;
|
|---|
| 98 | DIB_SectionHandle := 0;
|
|---|
| 99 | end;
|
|---|
| 100 | end;
|
|---|
| 101 |
|
|---|
| 102 | procedure TBGRAWinBitmap.RebuildBitmap;
|
|---|
| 103 | begin
|
|---|
| 104 | if FBitmap = nil then
|
|---|
| 105 | begin
|
|---|
| 106 | FBitmap := TWinBitmapTracker.Create(self);
|
|---|
| 107 | FBitmap.Handle := DIB_SectionHandle;
|
|---|
| 108 | end;
|
|---|
| 109 | end;
|
|---|
| 110 |
|
|---|
| 111 | procedure TBGRAWinBitmap.FreeBitmap;
|
|---|
| 112 | begin
|
|---|
| 113 | if FBitmap <> nil then
|
|---|
| 114 | begin
|
|---|
| 115 | FBitmap.Handle := 0;
|
|---|
| 116 | FBitmap.Free;
|
|---|
| 117 | FBitmap := nil;
|
|---|
| 118 | end;
|
|---|
| 119 | end;
|
|---|
| 120 |
|
|---|
| 121 | procedure TBGRAWinBitmap.Init;
|
|---|
| 122 | begin
|
|---|
| 123 | inherited Init;
|
|---|
| 124 | FLineOrder := riloBottomToTop;
|
|---|
| 125 | end;
|
|---|
| 126 |
|
|---|
| 127 | function TBGRAWinBitmap.GetBitmap: TBitmap;
|
|---|
| 128 | begin
|
|---|
| 129 | Result:=inherited GetBitmap;
|
|---|
| 130 | if (LineOrder = riloTopToBottom) and not FReversed then
|
|---|
| 131 | begin
|
|---|
| 132 | VerticalFlip;
|
|---|
| 133 | FReversed:= true;
|
|---|
| 134 | end;
|
|---|
| 135 | end;
|
|---|
| 136 |
|
|---|
| 137 | procedure TBGRAWinBitmap.LoadFromBitmapIfNeeded;
|
|---|
| 138 | begin
|
|---|
| 139 | if FReversed then
|
|---|
| 140 | begin
|
|---|
| 141 | FReversed := false;
|
|---|
| 142 | VerticalFlip;
|
|---|
| 143 | end;
|
|---|
| 144 | if FAlphaCorrectionNeeded then
|
|---|
| 145 | begin
|
|---|
| 146 | DoAlphaCorrection;
|
|---|
| 147 | end;
|
|---|
| 148 | end;
|
|---|
| 149 |
|
|---|
| 150 | procedure TBGRAWinBitmap.Draw(ACanvas: TCanvas; x, y: integer; Opaque: boolean);
|
|---|
| 151 | begin
|
|---|
| 152 | if self = nil then exit;
|
|---|
| 153 | Draw(ACanvas, Classes.Rect(x,y,x+Width,y+Height), Opaque);
|
|---|
| 154 | end;
|
|---|
| 155 |
|
|---|
| 156 | procedure TBGRAWinBitmap.Draw(ACanvas: TCanvas; Rect: TRect; Opaque: boolean);
|
|---|
| 157 | var
|
|---|
| 158 | info: TBITMAPINFO;
|
|---|
| 159 | begin
|
|---|
| 160 | if (self = nil) or (Width = 0) or (Height = 0) then exit;
|
|---|
| 161 | if TBGRAPixel_RGBAOrder then SwapRedBlue;
|
|---|
| 162 | if Opaque then
|
|---|
| 163 | begin
|
|---|
| 164 | info := DIBitmapInfo(Width, Height);
|
|---|
| 165 | if LineOrder = riloTopToBottom then
|
|---|
| 166 | StretchDIBits(ACanvas.Handle, Rect.Left, Rect.Bottom, Rect.Right -
|
|---|
| 167 | Rect.Left, Rect.Top - Rect.Bottom,
|
|---|
| 168 | 0, 0, Width, Height, Data, info, DIB_RGB_COLORS, SRCCOPY)
|
|---|
| 169 | else
|
|---|
| 170 | StretchDIBits(ACanvas.Handle, Rect.Left, Rect.Top, Rect.Right -
|
|---|
| 171 | Rect.Left, Rect.Bottom - Rect.Top,
|
|---|
| 172 | 0, 0, Width, Height, Data, info, DIB_RGB_COLORS, SRCCOPY);
|
|---|
| 173 | end
|
|---|
| 174 | else
|
|---|
| 175 | begin
|
|---|
| 176 | if Empty then exit;
|
|---|
| 177 | if LineOrder = riloTopToBottom then VerticalFlip;
|
|---|
| 178 | LoadFromBitmapIfNeeded;
|
|---|
| 179 | ACanvas.StretchDraw(Rect, Bitmap);
|
|---|
| 180 | if LineOrder = riloTopToBottom then VerticalFlip;
|
|---|
| 181 | end;
|
|---|
| 182 | if TBGRAPixel_RGBAOrder then SwapRedBlue;
|
|---|
| 183 | end;
|
|---|
| 184 |
|
|---|
| 185 | procedure TBGRAWinBitmap.DataDrawOpaque(ACanvas: TCanvas; ARect: TRect;
|
|---|
| 186 | AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer);
|
|---|
| 187 | var
|
|---|
| 188 | info: TBITMAPINFO;
|
|---|
| 189 | IsFlipped: boolean;
|
|---|
| 190 | Temp: TBGRAPtrBitmap;
|
|---|
| 191 | begin
|
|---|
| 192 | Temp := nil;
|
|---|
| 193 | IsFlipped := False;
|
|---|
| 194 | if ALineOrder = riloTopToBottom then
|
|---|
| 195 | begin
|
|---|
| 196 | Temp := TBGRAPtrBitmap.Create(AWidth, AHeight, AData);
|
|---|
| 197 | Temp.VerticalFlip;
|
|---|
| 198 | IsFlipped := True;
|
|---|
| 199 | end;
|
|---|
| 200 | if TBGRAPixel_RGBAOrder then
|
|---|
| 201 | begin
|
|---|
| 202 | if Temp = nil then
|
|---|
| 203 | Temp := TBGRAPtrBitmap.Create(AWidth, AHeight, AData);
|
|---|
| 204 | Temp.SwapRedBlue;
|
|---|
| 205 | end;
|
|---|
| 206 |
|
|---|
| 207 | info := DIBitmapInfo(AWidth, AHeight);
|
|---|
| 208 | StretchDIBits(ACanvas.Handle, ARect.Left, ARect.Top, ARect.Right -
|
|---|
| 209 | ARect.Left, ARect.Bottom - ARect.Top,
|
|---|
| 210 | 0, 0, AWidth, AHeight, AData, info, DIB_RGB_COLORS, SRCCOPY);
|
|---|
| 211 |
|
|---|
| 212 | if Temp <> nil then
|
|---|
| 213 | begin
|
|---|
| 214 | if TBGRAPixel_RGBAOrder then Temp.SwapRedBlue;
|
|---|
| 215 | if IsFlipped then
|
|---|
| 216 | Temp.VerticalFlip;
|
|---|
| 217 | Temp.Free;
|
|---|
| 218 | end;
|
|---|
| 219 | end;
|
|---|
| 220 |
|
|---|
| 221 | procedure TBGRAWinBitmap.AlphaCorrectionNeeded; inline;
|
|---|
| 222 | begin
|
|---|
| 223 | FAlphaCorrectionNeeded := True;
|
|---|
| 224 | end;
|
|---|
| 225 |
|
|---|
| 226 | function TBGRAWinBitmap.DIBitmapInfo(AWidth, AHeight: integer): TBitmapInfo;
|
|---|
| 227 | begin
|
|---|
| 228 | with {%H-}Result.bmiHeader do
|
|---|
| 229 | begin
|
|---|
| 230 | biSize := sizeof(Result.bmiHeader);
|
|---|
| 231 | biWidth := AWidth;
|
|---|
| 232 | biHeight := AHeight;
|
|---|
| 233 | biPlanes := 1;
|
|---|
| 234 | biBitCount := 32;
|
|---|
| 235 | biCompression := BI_RGB;
|
|---|
| 236 | biSizeImage := 0;
|
|---|
| 237 | biXPelsPerMeter := 0;
|
|---|
| 238 | biYPelsPerMeter := 0;
|
|---|
| 239 | biClrUsed := 0;
|
|---|
| 240 | biClrImportant := 0;
|
|---|
| 241 | end;
|
|---|
| 242 | end;
|
|---|
| 243 |
|
|---|
| 244 | procedure TBGRAWinBitmap.ReallocData;
|
|---|
| 245 | var
|
|---|
| 246 | ScreenDC: HDC;
|
|---|
| 247 | info: TBitmapInfo;
|
|---|
| 248 | begin
|
|---|
| 249 | FreeData;
|
|---|
| 250 | if (Width <> 0) and (Height <> 0) then
|
|---|
| 251 | begin
|
|---|
| 252 | ScreenDC := GetDC(0);
|
|---|
| 253 | info := DIBitmapInfo(Width, Height);
|
|---|
| 254 | DIB_SectionHandle := CreateDIBSection(ScreenDC, info, DIB_RGB_COLORS, FData, 0, 0);
|
|---|
| 255 |
|
|---|
| 256 | if (NbPixels > 0) and (FData = nil) then
|
|---|
| 257 | raise EOutOfMemory.Create('TBGRAWinBitmap.ReallocBitmap: Windows error ' +
|
|---|
| 258 | IntToStr(GetLastError));
|
|---|
| 259 |
|
|---|
| 260 | ReleaseDC(0, ScreenDC);
|
|---|
| 261 | end;
|
|---|
| 262 | InvalidateBitmap;
|
|---|
| 263 | end;
|
|---|
| 264 |
|
|---|
| 265 | procedure TBGRAWinBitmap.GetImageFromCanvas(CanvasSource: TCanvas; x, y: integer);
|
|---|
| 266 | begin
|
|---|
| 267 | self.Canvas.CopyRect(Classes.rect(0, 0, Width, Height), CanvasSource,
|
|---|
| 268 | Classes.rect(X, Y, X + Width, Y + Height));
|
|---|
| 269 | end;
|
|---|
| 270 |
|
|---|
| 271 | end.
|
|---|
| 272 |
|
|---|