1// SPDX-License-Identifier: LGPL-3.0-linking-exception
2{$IFDEF INCLUDE_INTERFACE}
3{$UNDEF INCLUDE_INTERFACE}
4type
5{=== TBGRACustomBitmap ===}
6
7  { TBGRACustomBitmap }
8  {* This is the base class for ''TBGRABitmap''. It is the direct parent of
9     ''TBGRADefaultBitmap'' class, which is the parent of the diverse
10     implementations. A bitmap can be used as a scanner using the interface
11     ''IBGRAScanner'' }
12  TBGRACustomBitmap = class(specialize TGenericUniversalBitmap<TBGRAPixel,TBGRAPixelColorspace>,IBGRAScanner)
13  protected
14    FXorMask: TBGRACustomBitmap;
15
16    { accessors to properies }
17     procedure SetXorMask(AValue: TBGRACustomBitmap);
18
19     function GetAverageColor: TColor; virtual; abstract;
20     function GetAveragePixel: TBGRAPixel; virtual; abstract;
21
22     //FreePascal drawing routines
23     {$IFDEF BGRABITMAP_USE_FPCANVAS}function GetCanvasFP: TFPImageCanvas; virtual; abstract;{$ENDIF}
24     function GetCanvasDrawModeFP: TDrawMode; virtual; abstract;
25     procedure SetCanvasDrawModeFP(const AValue: TDrawMode); virtual; abstract;
26
27     //GUI bitmap object
28     function GetBitmap: TBitmap; virtual; abstract;
29     function GetCanvas: TCanvas; virtual; abstract;
30     function GetCanvasOpacity: byte; virtual; abstract;
31     procedure SetCanvasOpacity(AValue: byte); virtual; abstract;
32     function GetCanvasAlphaCorrection: boolean; virtual; abstract;
33     procedure SetCanvasAlphaCorrection(const AValue: boolean); virtual; abstract;
34
35     procedure Init; override;
36     function InternalNew: TBGRACustomBitmap; override;
37
38     procedure InternalArc(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; AOptions: TArcOptions; ADrawChord: boolean = false; ATexture: IBGRAScanner = nil); overload;
39     procedure InternalArc(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; AOptions: TArcOptions; ADrawChord: boolean = false; ATexture: IBGRAScanner = nil); overload; virtual; abstract;
40     procedure InternalArcInRect(r: TRect; StartAngleRad,EndAngleRad: Single; ABorderColor : TBGRAPixel; w: single; AFillColor: TBGRAPixel; AOptions: TArcOptions; ADrawChord: boolean = false; ATexture: IBGRAScanner = nil);
41     procedure InternalFillArcInRect(r: TRect; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel; AOptions: TArcOptions; ATexture: IBGRAScanner = nil);
42
43  public
44     {** Resample filter is used when resizing the bitmap. See [[BGRABitmap Miscellaneous types#Images and resampling|resampling types]] }
45     ResampleFilter : TResampleFilter;
46
47     {** Scan interpolation filter is used when the bitmap is used
48         as a scanner (interface ''IBGRAScanner'') }
49     ScanInterpolationFilter: TResampleFilter;
50     ScanMaskChannel: TChannel;
51
52     {** Cursor position for mouse pointer }
53     HotSpot: TPoint;
54
55     { ** Free reference to xor mask }
56     procedure DiscardXorMask; virtual;
57     { ** Allocate xor mask }
58     procedure NeedXorMask; virtual;
59     {** Xor mask to be applied when image is drawn }
60     property XorMask: TBGRACustomBitmap read FXorMask write SetXorMask;
61
62     {** Average color of the image }
63     property AverageColor: TColor Read GetAverageColor;
64     {** Average color (including alpha) of the image }
65     property AveragePixel: TBGRAPixel Read GetAveragePixel;
66
67     {** Canvas compatible with FreePascal }
68     {$IFDEF BGRABITMAP_USE_FPCANVAS}property CanvasFP: TFPImageCanvas read GetCanvasFP;{$ENDIF}
69
70     {** Draw mode to used when image is access using FreePascal functions
71         and ''Colors'' property }
72     property CanvasDrawModeFP: TDrawMode read GetCanvasDrawModeFP write SetCanvasDrawModeFP;
73
74     {** Bitmap in a format compatible with the current GUI.
75         Don't forget to call ''InvalidateBitmap'' before using it
76         if you changed something with direct pixel access (''Scanline''
77         and ''Data'') }
78     property Bitmap: TBitmap Read GetBitmap;
79     {** Canvas provided by the GUI }
80     property Canvas: TCanvas Read GetCanvas;
81     {** Opacity to apply to changes made using GUI functions, provided
82         ''CanvasAlphaCorrection'' is set to ''True'' }
83     property CanvasOpacity: byte Read GetCanvasOpacity Write SetCanvasOpacity;
84     {** Specifies if the alpha values must be corrected after GUI access
85         to the bitmap }
86     property CanvasAlphaCorrection: boolean Read GetCanvasAlphaCorrection Write SetCanvasAlphaCorrection;
87
88  protected {----------- pen style accessors ----------------}
89     function GetPenJoinStyle: TPenJoinStyle; virtual; abstract;
90     procedure SetPenJoinStyle(const AValue: TPenJoinStyle); virtual; abstract;
91     function GetPenMiterLimit: single; virtual; abstract;
92     procedure SetPenMiterLimit(const AValue: single); virtual; abstract;
93     function GetPenStyle: TPenStyle; virtual; abstract;
94     procedure SetPenStyle(const AValue: TPenStyle); virtual; abstract;
95     function GetCustomPenStyle: TBGRAPenStyle; virtual; abstract;
96     procedure SetCustomPenStyle(const AValue: TBGRAPenStyle); virtual; abstract;
97
98     function GetArrowEndRepeat: integer; virtual; abstract;
99     function GetArrowStartRepeat: integer; virtual; abstract;
100     procedure SetArrowEndRepeat(AValue: integer); virtual; abstract;
101     procedure SetArrowStartRepeat(AValue: integer); virtual; abstract;
102     function GetArrowEndOffset: single; virtual; abstract;
103     function GetArrowStartOffset: single; virtual; abstract;
104     procedure SetArrowEndOffset(AValue: single); virtual; abstract;
105     procedure SetArrowStartOffset(AValue: single); virtual; abstract;
106     function GetArrowEndSize: TPointF; virtual; abstract;
107     function GetArrowStartSize: TPointF; virtual; abstract;
108     procedure SetArrowEndSize(AValue: TPointF); virtual; abstract;
109     procedure SetArrowStartSize(AValue: TPointF); virtual; abstract;
110
111  public {----------- pen style ----------------}
112     {** How to join segments. See [[BGRABitmap Types imported from Graphics|BGRAGraphics]] }
113     property JoinStyle: TPenJoinStyle read GetPenJoinStyle Write SetPenJoinStyle;
114     {** Limit for the extension of the segments when joining them
115         with ''pjsMiter'' join style, expressed in multiples of the width
116         of the pen }
117     property JoinMiterLimit: single read GetPenMiterLimit Write SetPenMiterLimit;
118     {** Pen style. See [[BGRABitmap Types imported from Graphics|BGRAGraphics]] }
119     property PenStyle: TPenStyle read GetPenStyle Write SetPenStyle;
120     {** Custom pen style. See [[BGRABitmap Geometry types|geometric types]] }
121     property CustomPenStyle: TBGRAPenStyle read GetCustomPenStyle write SetCustomPenStyle;
122
123     {** Size of arrows at the start of the line }
124     property ArrowStartSize: TPointF read GetArrowStartSize write SetArrowStartSize;
125     {** Size of arrows at the end of the line }
126     property ArrowEndSize: TPointF read GetArrowEndSize write SetArrowEndSize;
127     {** Offset of the arrow from the start of the line }
128     property ArrowStartOffset: single read GetArrowStartOffset write SetArrowStartOffset;
129     {** Offset of the arrow from the end of the line }
130     property ArrowEndOffset: single read GetArrowEndOffset write SetArrowEndOffset;
131     {** Number of times to repeat the starting arrow }
132     property ArrowStartRepeat: integer read GetArrowStartRepeat write SetArrowStartRepeat;
133     {** Number of times to repeat the ending arrow }
134     property ArrowEndRepeat: integer read GetArrowEndRepeat write SetArrowEndRepeat;
135
136     procedure ArrowStartAsNone; virtual; abstract;
137     procedure ArrowStartAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); virtual; abstract;
138     procedure ArrowStartAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); virtual; abstract;
139     procedure ArrowStartAsTail; virtual; abstract;
140
141     procedure ArrowEndAsNone; virtual; abstract;
142     procedure ArrowEndAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); virtual; abstract;
143     procedure ArrowEndAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); virtual; abstract;
144     procedure ArrowEndAsTail; virtual; abstract;
145
146  protected {-------------------font style accessors------------------------}
147     function GetFontAntialias: Boolean;
148     procedure SetFontAntialias(const AValue: Boolean);
149     function GetFontRenderer: TBGRACustomFontRenderer; virtual; abstract;
150     procedure SetFontRenderer(AValue: TBGRACustomFontRenderer); virtual; abstract;
151     function GetFontHeight: integer; virtual; abstract;
152     procedure SetFontHeight(AHeight: integer); virtual; abstract;
153     function GetFontFullHeight: integer; virtual; abstract;
154     procedure SetFontFullHeight(AHeight: integer); virtual; abstract;
155     function GetFontVerticalAnchorOffset: single; virtual; abstract;
156     function GetFontPixelMetric: TFontPixelMetric; virtual; abstract;
157
158     function GetFontRightToLeftFor(AText: string): boolean;
159
160  public {-------------------font style------------------------}
161     {** Specifies the font to use. Unless the font renderer accept otherwise,
162         the name is in human readable form, like 'Arial', 'Times New Roman', ... }
163     FontName: string;
164     {** Specifies the set of styles to be applied to the font.
165         These can be ''fsBold'', ''fsItalic'', ''fsStrikeOut'', ''fsUnderline''.
166         So the value [''fsBold'',''fsItalic''] means that the font must be bold and italic.
167         See [[BGRABitmap Miscellaneous types|miscellaneous types]] }
168     FontStyle: TFontStyles;
169
170     {** Specifies the quality of rendering. Default value is ''fqSystem''.
171         See [[BGRABitmap Miscellaneous types|miscellaneous types]] }
172     FontQuality : TBGRAFontQuality;
173
174     {** Specifies the rotation of the text, for functions that support text rotation.
175         It is expressed in tenth of degrees, positive values going counter-clockwise. }
176     FontOrientation: integer;
177
178     {** Specifies how the font is vertically aligned relative to the start coordinate.
179         See [[BGRABitmap Miscellaneous types|miscellaneous types]]}
180     FontVerticalAnchor: TFontVerticalAnchor;
181
182     {** Specifies the base direction of the text (cf Unicode). By default, it is
183         automatically determined by the first strongly oriented character.
184         You can specify another base direction here however it is not taken
185         into account by the LCL on Linux. }
186     FontBidiMode: TFontBidiMode;
187
188     {** Specifies the height of the font in pixels without taking into account
189         additional line spacing. A negative value means that it is the
190         full height instead (see below) }
191     property FontHeight: integer Read GetFontHeight Write SetFontHeight;
192
193     {** Specifies the height of the font in pixels, taking into account the
194         additional line spacing defined for the font }
195     property FontFullHeight: integer read GetFontFullHeight write SetFontFullHeight;
196
197     {** Simplified property to specify the quality (see ''FontQuality'') }
198     property FontAntialias: Boolean read GetFontAntialias write SetFontAntialias;
199
200     property FontVerticalAnchorOffset: single read GetFontVerticalAnchorOffset;
201
202     {** Returns measurement for the current font in pixels }
203     property FontPixelMetric: TFontPixelMetric read GetFontPixelMetric;
204
205     {** Specifies the font renderer. When working with the LCL,
206         by default it is an instance of ''TLCLFontRenderer'' of
207         unit ''BGRAText''. Other renderers are provided in ''BGRATextFX''
208         unit and ''BGRAVectorize'' unit. Additionally, ''BGRAFreeType''
209         provides a renderer independent from the LCL.
210       *
211       * Once you assign a renderer, it will automatically be freed when
212         the bitmap is freed. The renderers may provide additional styling
213         for the font, not accessible with the properties in this class
214       *
215       * See [[BGRABitmap tutorial Font rendering|font rendering]]}
216     property FontRenderer: TBGRACustomFontRenderer read GetFontRenderer write SetFontRenderer;
217
218  public
219     constructor Create(AFPImage: TFPCustomImage); overload; virtual; abstract;
220     constructor Create(ABitmap: TBitmap; AUseTransparent: boolean = true); overload; virtual; abstract;
221     constructor Create(AFilename: string); overload; virtual; abstract;
222     constructor Create(AFilename: string; AIsUtf8Filename: boolean); overload; virtual; abstract;
223     constructor Create(AFilename: string; AIsUtf8Filename: boolean; AOptions: TBGRALoadingOptions); overload; virtual; abstract;
224     constructor Create(AStream: TStream); overload; virtual; abstract;
225
226     function NewBitmap: TBGRACustomBitmap; overload; override;
227     function NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap; overload; override;
228     function NewBitmap(AWidth, AHeight: integer; const Color: TBGRAPixel): TBGRACustomBitmap; overload; override;
229     function NewBitmap(AWidth, AHeight: integer; AColor: Pointer): TBGRACustomBitmap; overload; override;
230     function NewBitmap(Filename: string): TBGRACustomBitmap; overload; virtual; abstract;
231     function NewBitmap(Filename: string; AIsUtf8: boolean): TBGRACustomBitmap; overload; virtual; abstract;
232     function NewBitmap(Filename: string; AIsUtf8: boolean; AOptions: TBGRALoadingOptions): TBGRACustomBitmap; overload; virtual; abstract;
233     function NewBitmap(AFPImage: TFPCustomImage): TBGRACustomBitmap; overload; virtual; abstract;
234
235     procedure LoadFromStream(AStream: TStream; AHandler: TFPCustomImageReader; AOptions: TBGRALoadingOptions); override;
236
237     {==== Reference counting ====}
238
239     {** Adds a reference (this reference count is not the same as
240         the reference count of an interface, it changes only by
241         explicit calls) }
242     function NewReference: TBGRACustomBitmap; override;
243     {** Returns an object with a reference count equal to 1. Duplicate
244         this bitmap if necessary }
245     function GetUnique: TBGRACustomBitmap; override;
246     function Duplicate(DuplicateProperties: Boolean = False): TBGRACustomBitmap; overload; override;
247     function Duplicate(DuplicateProperties, DuplicateXorMask: Boolean): TBGRACustomBitmap; overload; virtual;
248     procedure CopyPropertiesTo(ABitmap: TCustomUniversalBitmap); override;
249     function GetPart(const ARect: TRect): TBGRACustomBitmap; override;
250
251     function CreateBrushTexture(ABrushStyle: TBrushStyle; APatternColor, ABackgroundColor: TBGRAPixel;
252                 AWidth: integer = 8; AHeight: integer = 8; APenWidth: single = 1): TBGRACustomBitmap; override;
253
254     {** Can only be called with an existing instance of ''TBGRACustomBitmap''.
255         Sets the dimensions of an existing ''TBGRACustomBitmap'' instance. }
256     procedure SetSize(AWidth, AHeight: integer); override;
257
258     {==== Retrieve image from system ====}
259
260     {** Gets the content of the specified device context }
261     procedure LoadFromDevice(DC: HDC); overload; virtual; abstract;
262     {** Gets the content from the specified rectangular area of a device context }
263     procedure LoadFromDevice(DC: HDC; ARect: TRect); overload; virtual; abstract;
264     {** Fills the content with a screenshot of the primary monitor }
265     procedure TakeScreenshotOfPrimaryMonitor; virtual; abstract;
266     {** Fills the content with a screenshot of the specified rectangular area of the desktop
267         (it can be from any screen) }
268     procedure TakeScreenshot(ARect: TRect); virtual; abstract;
269     {** For more methods, see derived class [[TBGRABitmap class|TBGRABitmap]] }
270
271     {==== Drawing functions ====}
272
273     {Pixel functions}
274     procedure SetPixel(x, y: int32or64; c: TColor); overload; virtual; abstract;
275     procedure XorPixel(x, y: int32or64; const c: TBGRAPixel); overload; virtual; abstract;
276     procedure DrawPixel(x, y: int32or64; const c: TBGRAPixel; ADrawMode: TDrawMode); overload; override;
277     procedure FastBlendPixel(x, y: int32or64; const c: TBGRAPixel); virtual; abstract;
278     function GetPixel256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; virtual; abstract;
279     function GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; overload; virtual; abstract;
280     function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; overload; virtual; abstract;
281     function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; overload; virtual; abstract;
282     function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; overload; virtual; abstract;
283     function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; overload; virtual; abstract;
284
285     {Line primitives}
286     procedure XorHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract;
287     procedure DrawHorizLine(x, y, x2: int32or64; ec: TExpandedPixel); overload; virtual; abstract;
288     procedure DrawHorizLine(x, y, x2: int32or64; texture: IBGRAScanner); overload;
289     procedure FastBlendHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract;
290     procedure DrawHorizLineDiff(x, y, x2: int32or64; c, compare: TBGRAPixel; maxDiff: byte); virtual; abstract;
291     procedure HorizLineDiff(x, y, x2: int32or64; const ABrush: TUniversalBrush; ACompare: TBGRAPixel; AMaxDiffW: word); virtual; abstract;
292
293     procedure XorVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract;
294     procedure DrawVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract;
295     procedure FastBlendVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract;
296
297     {==== Rectangles, ellipses and path (floating point coordinates) ====}
298     {* These functions use the current pen style/cap/join. The parameter ''w''
299        specifies the width of the line and the base unit for dashes
300      * The coordinates are pixel-centered, so that when filling a rectangle,
301        if the supplied values are integers, the border will be half transparent.
302        If you want the border to be completely filled, you can subtract/add
303        0.5 to the coordinates to include the remaining thin border.
304        See [[BGRABitmap tutorial 13|coordinate system]]. }
305
306     {==== Multi-shape fill ====}
307
308     {** Draws and fill a polyline using current pen style/cap/join in one go.
309         The stroke is stricly over the fill even if partially transparent.
310         ''fillcolor'' specifies a color to fill the polygon formed by the points }
311     procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); overload; virtual; abstract;
312     {** Draws a filled polygon using current pen style/cap/join in one go.
313         The stroke is stricly over the fill even if partially transparent.
314         The polygon is always closed. You don't need to set the last point
315         to be the same as the first point. }
316     procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); overload; virtual; abstract;
317
318     procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single; back: TBGRAPixel); overload; virtual; abstract;
319     procedure EllipseAntialias(AOrigin, AXAxis, AYAxis: TPointF; c: TBGRAPixel; w: single; back: TBGRAPixel); overload; virtual; abstract;
320
321     procedure DrawPath(APath: IBGRAPath; AStrokeColor: TBGRAPixel; AWidth: single; AFillColor: TBGRAPixel); overload; virtual; abstract;
322     procedure DrawPath(APath: IBGRAPath; AStrokeTexture: IBGRAScanner; AWidth: single; AFillColor: TBGRAPixel); overload; virtual; abstract;
323     procedure DrawPath(APath: IBGRAPath; AStrokeColor: TBGRAPixel; AWidth: single; AFillTexture: IBGRAScanner); overload; virtual; abstract;
324     procedure DrawPath(APath: IBGRAPath; AStrokeTexture: IBGRAScanner; AWidth: single; AFillTexture: IBGRAScanner); overload; virtual; abstract;
325
326     procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeColor: TBGRAPixel; AWidth: single; AFillColor: TBGRAPixel); overload; virtual; abstract;
327     procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeTexture: IBGRAScanner; AWidth: single; AFillColor: TBGRAPixel); overload; virtual; abstract;
328     procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeColor: TBGRAPixel; AWidth: single; AFillTexture: IBGRAScanner); overload; virtual; abstract;
329     procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeTexture: IBGRAScanner; AWidth: single; AFillTexture: IBGRAScanner); overload; virtual; abstract;
330
331     {==== Gradient/textured polygons ====}
332
333     procedure FillTriangleLinearColor(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); overload; virtual; abstract;
334     procedure FillTriangleLinearColorAntialias(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); overload; virtual; abstract;
335     procedure FillTriangleLinearMapping(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; TextureInterpolation: Boolean= True); overload; virtual; abstract;
336     procedure FillTriangleLinearMappingLightness(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; light1,light2,light3: word; TextureInterpolation: Boolean= True); overload; virtual; abstract;
337     procedure FillTriangleLinearMappingAntialias(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF); overload; virtual; abstract;
338
339     procedure FillQuadLinearColor(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); overload; virtual; abstract;
340     procedure FillQuadLinearColorAntialias(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); overload; virtual; abstract;
341     procedure FillQuadLinearMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; TextureInterpolation: Boolean= True; ACulling: TFaceCulling = fcNone; ACropToPolygon: boolean = true); overload; virtual; abstract;
342     procedure FillQuadLinearMappingLightness(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; light1,light2,light3,light4: word; TextureInterpolation: Boolean= True); overload; virtual; abstract;
343     procedure FillQuadLinearMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACulling: TFaceCulling = fcNone); overload; virtual; abstract;
344     procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ADrawMode: TDrawMode = dmDrawWithTransparency); overload; virtual; abstract;
345     procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect; ADrawMode: TDrawMode = dmDrawWithTransparency); overload; virtual; abstract;
346     procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); overload; virtual; abstract;
347     procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); overload; virtual; abstract;
348     procedure FillQuadAffineMapping(Orig,HAxis,VAxis: TPointF; AImage: TBGRACustomBitmap; APixelCenteredCoordinates: boolean = true; ADrawMode: TDrawMode = dmDrawWithTransparency; AOpacity: byte = 255); virtual; abstract;
349     procedure FillQuadAffineMappingAntialias(Orig,HAxis,VAxis: TPointF; AImage: TBGRACustomBitmap; APixelCenteredCoordinates: boolean = true; AOpacity: byte = 255); virtual; abstract;
350
351     procedure FillEllipseLinearColorAntialias(x, y, rx, ry: single; outercolor, innercolor: TBGRAPixel); overload; virtual; abstract;
352     procedure FillEllipseLinearColorAntialias(AOrigin, AXAxis, AYAxis: TPointF; outercolor, innercolor: TBGRAPixel); overload; virtual; abstract;
353
354     procedure FillPolyLinearColor(const points: array of TPointF; AColors: array of TBGRAPixel);  overload; virtual; abstract;
355     procedure FillPolyLinearMapping(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean); overload; virtual; abstract;
356     procedure FillPolyLinearMappingLightness(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; lightnesses: array of word; TextureInterpolation: Boolean); overload; virtual; abstract;
357     procedure FillPolyPerspectiveMapping(const points: array of TPointF; const pointsZ: array of single; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean; zbuffer: psingle = nil); overload; virtual; abstract;
358     procedure FillPolyPerspectiveMappingLightness(const points: array of TPointF; const pointsZ: array of single; texture: IBGRAScanner; texCoords: array of TPointF; lightnesses: array of word; TextureInterpolation: Boolean; zbuffer: psingle = nil); overload; virtual; abstract;
359
360     procedure Arc(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; AColor: TBGRAPixel; w: single; ADrawChord: boolean; AFillColor: TBGRAPixel); overload;
361     procedure Arc(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; AColor: TBGRAPixel; w: single; ADrawChord: boolean; AFillColor: TBGRAPixel); overload;
362     procedure FillChord(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; AFillColor: TBGRAPixel); overload;
363     procedure FillChord(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel); overload;
364     procedure FillChord(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; texture: IBGRAScanner); overload;
365     procedure FillChord(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; texture: IBGRAScanner); overload;
366     procedure FillChordInRect(const ARect: TRect; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel); overload;
367     procedure FillChordInRect(const ARect: TRect; StartAngleRad,EndAngleRad: Single; texture: IBGRAScanner); overload;
368
369     procedure Pie(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; AColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel); overload;
370     procedure Pie(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; AColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel); overload;
371     procedure FillPie(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; AFillColor: TBGRAPixel); overload;
372     procedure FillPie(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel); overload;
373     procedure FillPie(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; texture: IBGRAScanner); overload;
374     procedure FillPie(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; texture: IBGRAScanner); overload;
375     procedure FillPieInRect(const ARect: TRect; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel); overload;
376     procedure FillPieInRect(const ARect: TRect; StartAngleRad,EndAngleRad: Single; texture: IBGRAScanner); overload;
377
378     procedure RectangleAntialias(x, y, x2, y2: single; c: TBGRAPixel; w: single; back: TBGRAPixel); overload; virtual; abstract;
379     procedure RectangleWithin(x1,y1,x2,y2: single; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; APixelCenteredCoordinates: boolean = true); overload;
380     procedure RectangleWithin(r: TRect; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel); overload;
381
382     procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; w: single; options: TRoundRectangleOptions = []); overload; virtual; abstract;
383     procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; pencolor: TBGRAPixel; w: single; fillcolor: TBGRAPixel; options: TRoundRectangleOptions = []); overload; virtual; abstract;
384     procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; penTexture: IBGRAScanner; w: single; fillTexture: IBGRAScanner; options: TRoundRectangleOptions = []); overload; virtual; abstract;
385     procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; w: single; options: TRoundRectangleOptions = []); overload; virtual; abstract;
386
387     procedure FillRect(r: TRect; texture: IBGRAScanner; mode: TDrawMode; ditheringAlgorithm: TDitheringAlgorithm); overload; virtual;
388     procedure FillRect(r: TRect; texture: IBGRAScanner; mode: TDrawMode; AScanOffset: TPoint; ditheringAlgorithm: TDitheringAlgorithm); overload; virtual;
389     procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode; ditheringAlgorithm: TDitheringAlgorithm); overload; virtual;
390     procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode; AScanOffset: TPoint; ditheringAlgorithm: TDitheringAlgorithm); overload; virtual; abstract;
391
392     procedure TextOutCurved(ACursor: TBGRACustomPathCursor; const sUTF8: string; AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; abstract;
393     procedure TextOutCurved(ACursor: TBGRACustomPathCursor; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; abstract;
394     procedure TextOutCurved(APath: IBGRAPath; const sUTF8: string; AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single); overload; virtual;
395     procedure TextOutCurved(APath: IBGRAPath; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single); overload; virtual;
396     procedure TextRect(ARect: TRect; x, y: integer; const sUTF8: string; style: TTextStyle; c: TBGRAPixel); overload; virtual; abstract;
397     procedure TextRect(ARect: TRect; x, y: integer; const sUTF8: string; style: TTextStyle; texture: IBGRAScanner); overload; virtual; abstract;
398     procedure TextMultiline(x,y: single; const sUTF8: string; c: TBGRAPixel; AAlign: TBidiTextAlignment = btaLeftJustify; AVertAlign: TTextLayout = tlTop; AParagraphSpacing: single = 0); overload;
399     procedure TextMultiline(x,y: single; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TBidiTextAlignment = btaLeftJustify; AVertAlign: TTextLayout = tlTop; AParagraphSpacing: single = 0); overload;
400     procedure TextMultiline(ALeft,ATop,AWidth: single; const sUTF8: string; c: TBGRAPixel; AAlign: TBidiTextAlignment = btaNatural; AVertAlign: TTextLayout = tlTop; AParagraphSpacing: single = 0); overload; virtual; abstract;
401     procedure TextMultiline(ALeft,ATop,AWidth: single; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TBidiTextAlignment = btaNatural; AVertAlign: TTextLayout = tlTop; AParagraphSpacing: single = 0); overload; virtual; abstract;
402     function TextSize(const sUTF8: string): TSize; overload; virtual; abstract;
403     function TextAffineBox(const sUTF8: string): TAffineBox; virtual; abstract;
404     function TextSize(const sUTF8: string; AMaxWidth: integer): TSize; overload; virtual; abstract;
405     function TextSize(const sUTF8: string; AMaxWidth: integer; ARightToLeft: boolean): TSize; overload; virtual; abstract;
406     function TextFitInfo(const sUTF8: string; AMaxWidth: integer): integer; virtual; abstract;
407     function TextSizeMultiline(const sUTF8: string; AMaxWidth: single = EmptySingle; AParagraphSpacing: single = 0): TSize; virtual; abstract;
408
409     { Draw the UTF8 encoded string, (x,y) being the top-left corner by default. The color c or texture is used to fill the text.
410       The value of FontOrientation is taken into account, so that the text may be rotated. }
411     procedure TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel; align: TAlignment); overload; virtual;
412     procedure TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner; align: TAlignment); overload; virtual;
413     procedure TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel); overload; virtual;
414     procedure TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel; ARightToLeft: boolean); overload; virtual;
415     procedure TextOut(x, y: single; const sUTF8: string; c: TColor); overload; virtual;
416     procedure TextOut(x, y: single; const sUTF8: string; c: TColor; ARightToLeft: boolean); overload; virtual;
417     procedure TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner); overload; virtual;
418     procedure TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner; ARightToLeft: boolean); overload; virtual;
419     procedure TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel; align: TAlignment; ARightToLeft: boolean); overload; virtual; abstract;
420     procedure TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner; align: TAlignment; ARightToLeft: boolean); overload; virtual; abstract;
421     procedure TextOut(x, y: single; const sUTF8: string; AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; abstract;
422     procedure TextOut(x, y: single; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; abstract;
423
424     { Overrides the font orientation with the parameter orientationTenthDegCCW }
425     procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel); overload; virtual;
426     procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel; align: TAlignment); overload; virtual;
427     procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel; align: TAlignment; ARightToLeft: boolean); overload; virtual; abstract;
428     procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner); overload; virtual;
429     procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner; align: TAlignment); overload; virtual;
430     procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner; align: TAlignment; ARightToLeft: boolean); overload; virtual; abstract;
431
432     { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary.
433       The position depends on the specified horizontal alignment halign and vertical alignement valign.
434       The color c or texture is used to fill the text. No rotation is applied. }
435     procedure TextRect(ARect: TRect; const sUTF8: string; halign: TAlignment; valign: TTextLayout; c: TBGRAPixel); overload; virtual;
436     procedure TextRect(ARect: TRect; const sUTF8: string; halign: TAlignment; valign: TTextLayout; texture: IBGRAScanner); overload; virtual;
437
438     //-------------------------- computing path ------------------------------------
439
440     {Spline}
441     function ComputeClosedSpline(const APoints: array of TPointF; AStyle: TSplineStyle): ArrayOfTPointF; virtual; abstract;
442     function ComputeOpenedSpline(const APoints: array of TPointF; AStyle: TSplineStyle): ArrayOfTPointF; virtual; abstract;
443     function ComputeBezierCurve(const curve: TCubicBezierCurve): ArrayOfTPointF; overload; virtual; abstract;
444     function ComputeBezierCurve(const curve: TQuadraticBezierCurve): ArrayOfTPointF; overload; virtual; abstract;
445     function ComputeBezierSpline(const spline: array of TCubicBezierCurve): ArrayOfTPointF; overload; virtual; abstract;
446     function ComputeBezierSpline(const spline: array of TQuadraticBezierCurve): ArrayOfTPointF; overload; virtual; abstract;
447
448     {can be accessed via Pen property}
449     function ComputeWidePolyline(const points: array of TPointF; w: single): ArrayOfTPointF; overload; virtual; abstract;
450     function ComputeWidePolyline(const points: array of TPointF; w: single; ClosedCap: boolean): ArrayOfTPointF; overload; virtual; abstract;
451     function ComputeWidePolygon(const points: array of TPointF; w: single): ArrayOfTPointF; virtual; abstract;
452
453     function ComputeEllipse(x,y,rx,ry: single): ArrayOfTPointF; overload; deprecated;
454     function ComputeEllipse(x,y,rx,ry,w: single): ArrayOfTPointF; overload; deprecated;
455     function ComputeEllipseContour(x,y,rx,ry: single; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract;
456     function ComputeEllipseContour(AOrigin, AXAxis, AYAxis: TPointF; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract;
457     function ComputeEllipseBorder(x,y,rx,ry,w: single; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract;
458     function ComputeEllipseBorder(AOrigin, AXAxis, AYAxis: TPointF; w: single; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract;
459     function ComputeArc65536(x,y,rx,ry: single; start65536,end65536: word; quality: single = 1): ArrayOfTPointF; virtual; abstract;
460     function ComputeArcRad(x,y,rx,ry: single; startRad,endRad: single; quality: single = 1): ArrayOfTPointF; virtual; abstract;
461     function ComputeRoundRect(x1,y1,x2,y2,rx,ry: single; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract;
462     function ComputeRoundRect(x1,y1,x2,y2,rx,ry: single; options: TRoundRectangleOptions; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract;
463     function ComputePie65536(x,y,rx,ry: single; start65536,end65536: word; quality: single = 1): ArrayOfTPointF; virtual; abstract;
464     function ComputePieRad(x,y,rx,ry: single; startRad,endRad: single; quality: single = 1): ArrayOfTPointF; virtual; abstract;
465
466     {Filling}
467
468     // compatibility: take into account ClipRect
469     procedure Fill(texture: IBGRAScanner); overload; virtual;
470     procedure Fill(texture: IBGRAScanner; mode: TDrawMode); overload; override;
471
472     procedure Fill(c: TBGRAPixel; start, Count: integer); overload; virtual; abstract;
473     procedure DrawPixels(c: TBGRAPixel; start, Count: integer); virtual; abstract;
474     procedure AlphaFill(alpha: byte; start, Count: integer); overload; virtual; abstract;
475     procedure ReplaceColor(before, after: TColor); overload; virtual; abstract;
476     procedure ReplaceColor(ARect: TRect; before, after: TColor); overload; virtual; abstract;
477     procedure FloodFill(X, Y: integer; Color: TBGRAPixel;
478       mode: TFloodfillMode; Tolerance: byte = 0); overload; virtual;
479     procedure FloodFill(X, Y: integer; const Brush: TUniversalBrush;
480       Progressive: boolean; ToleranceW: Word = $00ff); overload; virtual;
481     procedure ParallelFloodFill(X, Y: integer; Dest: TCustomUniversalBitmap; Color: TBGRAPixel;
482       mode: TFloodfillMode; Tolerance: byte = 0; DestOfsX: integer = 0; DestOfsY: integer = 0); overload; virtual; abstract;
483     procedure ParallelFloodFill(X, Y: integer; Dest: TCustomUniversalBitmap; const Brush: TUniversalBrush;
484       Progressive: boolean; ToleranceW: Word = $00ff; DestOfsX: integer = 0; DestOfsY: integer = 0); overload; virtual; abstract;
485     procedure GradientFill(x, y, x2, y2: integer; c1, c2: TBGRAPixel;
486       gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode;
487       gammaColorCorrection: boolean = True; Sinus: Boolean=False;
488       ditherAlgo: TDitheringAlgorithm = daNearestNeighbor); overload; virtual; abstract;
489     procedure GradientFill(x, y, x2, y2: integer; gradient: TBGRACustomGradient;
490       gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode;
491       Sinus: Boolean=False;
492       ditherAlgo: TDitheringAlgorithm = daNearestNeighbor); overload; virtual; abstract;
493
494     {Canvas drawing functions}
495     procedure DataDrawTransparent(ACanvas: TCanvas; Rect: TRect;
496       AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer); virtual; abstract;
497     procedure DataDrawOpaque(ACanvas: TCanvas; ARect: TRect; AData: Pointer;
498       ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer); virtual; abstract;
499     procedure GetImageFromCanvas(CanvasSource: TCanvas; x, y: integer); virtual; abstract;
500     procedure Draw(ACanvas: TCanvas; x, y: integer; Opaque: boolean = True); overload; virtual; abstract;
501     procedure Draw(ACanvas: TCanvas; Rect: TRect; Opaque: boolean = True); overload; virtual; abstract;
502     procedure DrawPart(ARect: TRect; ACanvas: TCanvas; x, y: integer; Opaque: boolean); overload; virtual;
503     procedure DrawPart(ARect: TRect; ACanvas: TCanvas; ATargetRect: TRect; Opaque: boolean); overload; virtual;
504     function GetPtrBitmap(Top,Bottom: Integer): TBGRACustomBitmap; virtual; abstract;
505     function MakeBitmapCopy(BackgroundColor: TColor): TBitmap; virtual; abstract;
506
507     {BGRA bitmap functions}
508     procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadePosition: byte; mode: TDrawMode = dmDrawWithTransparency); overload; virtual; abstract;
509     procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadeMask: IBGRAScanner; mode: TDrawMode = dmDrawWithTransparency); overload; virtual; abstract;
510     procedure PutImage(x, y: integer; Source: TBitmap; mode: TDrawMode; AOpacity: byte = 255); overload;
511     procedure StretchPutImage(ARect: TRect; Source: TBitmap; mode: TDrawMode; AOpacity: byte = 255); overload;
512     procedure StretchPutImage(ARect: TRect; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); overload; virtual; abstract;
513     procedure StretchPutImageProportionally(ARect: TRect; AHorizAlign: TAlignment; AVertAlign: TTextLayout; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255);
514     procedure PutImageSubpixel(x, y: single; Source: TBGRACustomBitmap; AOpacity: byte = 255);
515     procedure PutImagePart(x,y: integer; Source: TBGRACustomBitmap; SourceRect: TRect; mode: TDrawMode; AOpacity: byte = 255);
516     procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload;
517     procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte=255); overload;
518     procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); overload;
519     procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); overload;
520     procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload;
521     procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOpacity: Byte=255; ACorrectBlur: Boolean = false; APixelCenteredCoords: boolean = true); overload;
522     procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte=255; APixelCenteredCoords: boolean = true); overload;
523     procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255; APixelCenteredCoords: boolean = true); overload;
524     procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255; APixelCenteredCoords: boolean = true); overload; virtual; abstract;
525     procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte=255; ACorrectBlur: Boolean = false; APixelCenteredCoords: boolean = true); overload;
526     function GetImageAffineBounds(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap): TRect; overload;
527     function GetImageAffineBounds(Origin,HAxis,VAxis: TPointF; ASourceWidth, ASourceHeight: integer; const ASourceBounds: TRect; AClipOutput: boolean = true): TRect; overload;
528     function GetImageAffineBounds(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; APixelCenteredCoords: boolean = true): TRect; overload;
529     function GetImageAffineBounds(AMatrix: TAffineMatrix; ASourceBounds: TRect; AClipOutput: boolean = true; APixelCenteredCoords: boolean = true): TRect; overload; virtual; abstract;
530     class function IsAffineRoughlyTranslation(AMatrix: TAffineMatrix; ASourceBounds: TRect): boolean; virtual; abstract;
531     procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false; ACorrectBlur: Boolean = false); overload;
532     procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false; ACorrectBlur: Boolean = false); overload;
533     procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; AResampleFilter: TResampleFilter; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false); overload;
534     procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AResampleFilter: TResampleFilter; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false); overload;
535     procedure ComputeImageAngleAxes(x,y,w,h,angle: single; imageCenterX,imageCenterY: single; ARestoreOffsetAfterRotation: boolean;
536       out Origin,HAxis,VAxis: TPointF);
537     function GetImageAngleBounds(x,y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single = 0; imageCenterY: single = 0; ARestoreOffsetAfterRotation: boolean = false): TRect;
538     procedure Blend(AColor: TBGRAPixel; AOperation: TBlendOperation; AIgnoreDestAlpha: boolean = false); virtual;
539     procedure BlendOver(AColor: TBGRAPixel; AOperation: TBlendOperation; AOpacity: byte = 255; ALinearBlend: boolean = false; AIgnoreDestAlpha: boolean = false); virtual;
540     procedure BlendRect(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AIgnoreDestAlpha: boolean = false); overload;
541     procedure BlendRect(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AExcludeChannels: TChannels); overload; virtual; abstract;
542     procedure BlendRectOver(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AOpacity: byte = 255; ALinearBlend: boolean = false; AIgnoreDestAlpha: boolean = false); overload;
543     procedure BlendRectOver(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AOpacity: byte; ALinearBlend: boolean; AExcludeChannels: TChannels); overload; virtual; abstract;
544     procedure BlendImage(x, y: integer; ASource: TBGRACustomBitmap; AOperation: TBlendOperation); overload; virtual; abstract;
545     procedure BlendImage(ADest: TRect; ASource: IBGRAScanner; AOffsetX, AOffsetY: integer; AOperation: TBlendOperation); overload; virtual; abstract;
546     procedure BlendImageOver(x, y: integer; ASource: TBGRACustomBitmap; AOperation: TBlendOperation; AOpacity: byte = 255; ALinearBlend: boolean = false); overload; virtual; abstract;
547     procedure BlendImageOver(ADest: TRect; ASource: IBGRAScanner; AOffsetX, AOffsetY: integer; AOperation: TBlendOperation; AOpacity: byte = 255; ALinearBlend: boolean = false); overload; virtual; abstract;
548     function Resample(newWidth, newHeight: integer;
549       mode: TResampleMode = rmFineResample): TBGRACustomBitmap; virtual; abstract;
550
551     //masks
552     procedure FillMask(x,y: integer; AMask: TCustomUniversalBitmap; ATexture: IBGRAScanner; ADrawMode: TDrawMode); overload; override;
553     procedure FillMask(x,y: integer; AMask: TCustomUniversalBitmap; ATexture: IBGRAScanner; ADrawMode: TDrawMode; AOpacity: byte); overload; virtual; abstract;
554     procedure EraseMask(x,y: integer; AMask: TBGRACustomBitmap; alpha: byte=255); virtual; abstract;
555     procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ARGBOrder: boolean = true); overload; virtual; abstract;
556     procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ARGBOrder: boolean = true); overload; virtual; abstract;
557     function GetMaskFromAlpha: TBGRACustomBitmap; virtual; abstract;
558     function GetImageBoundsWithin(const ARect: TRect; Channel: TChannel = cAlpha; ANothingValue: Byte = 0): TRect; overload; override;
559     function GetImageBoundsWithin(const ARect: TRect; Channels: TChannels; ANothingValue: Byte = 0): TRect; overload; override;
560
561     {inplace filters}
562     procedure Negative; virtual; abstract;
563     procedure NegativeRect(ABounds: TRect); virtual; abstract;
564     procedure LinearNegative; virtual; abstract;
565     procedure LinearNegativeRect(ABounds: TRect); virtual; abstract;
566     procedure InplaceGrayscale(AGammaCorrection: boolean = true); overload; virtual; abstract;
567     procedure InplaceGrayscale(ABounds: TRect; AGammaCorrection: boolean = true); overload; virtual; abstract;
568     procedure InplaceNormalize(AEachChannel: boolean = True); overload; virtual; abstract;
569     procedure InplaceNormalize(ABounds: TRect; AEachChannel: boolean = True); overload; virtual; abstract;
570     procedure ConvertToLinearRGB; virtual; abstract;
571     procedure ConvertFromLinearRGB; virtual; abstract;
572     procedure SwapRedBlue; overload; virtual; abstract;
573     procedure SwapRedBlue(ARect: TRect); overload; virtual; abstract;
574     procedure GrayscaleToAlpha; virtual; abstract;
575     procedure AlphaToGrayscale; virtual; abstract;
576     procedure VerticalFlip(ARect: TRect); overload; override;
577     procedure HorizontalFlip(ARect: TRect); overload; override;
578     procedure RotateUDInplace(ARect: TRect); overload; override;
579
580     {Filters}
581     function RotateCW: TBGRACustomBitmap; override;
582     function RotateCCW: TBGRACustomBitmap; override;
583     function RotateUD: TBGRACustomBitmap; override;
584     function FilterSmartZoom3(Option: TMedianOption): TBGRACustomBitmap; virtual; abstract;
585     function FilterMedian(Option: TMedianOption): TBGRACustomBitmap; virtual; abstract;
586     function FilterSmooth: TBGRACustomBitmap; virtual; abstract;
587     function FilterSharpen(Amount: single = 1): TBGRACustomBitmap; overload; virtual; abstract;
588     function FilterSharpen(ABounds: TRect; Amount: single = 1): TBGRACustomBitmap; overload; virtual; abstract;
589     function FilterContour(AGammaCorrection: boolean = false): TBGRACustomBitmap; virtual; abstract;
590     function FilterPixelate(pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear): TBGRACustomBitmap; virtual; abstract;
591     function FilterBlurRadial(radius: single; blurType: TRadialBlurType): TBGRACustomBitmap; overload; override;
592     function FilterBlurRadial(const ABounds: TRect; radius: single; blurType: TRadialBlurType): TBGRACustomBitmap; overload; override;
593     function FilterBlurRadial(radiusX, radiusY: single; blurType: TRadialBlurType): TBGRACustomBitmap; overload; override;
594     function FilterBlurRadial(const ABounds: TRect; radiusX, radiusY: single; blurType: TRadialBlurType): TBGRACustomBitmap; overload; override;
595     function FilterBlurMotion(distance: single; angle: single; oriented: boolean): TBGRACustomBitmap; overload; override;
596     function FilterBlurMotion(const ABounds: TRect; distance: single; angle: single; oriented: boolean): TBGRACustomBitmap; overload; override;
597     function FilterCustomBlur(mask: TCustomUniversalBitmap): TBGRACustomBitmap; overload; override;
598     function FilterCustomBlur(const ABounds: TRect; mask: TCustomUniversalBitmap): TBGRACustomBitmap; overload; override;
599     function FilterEmboss(angle: single; AStrength: integer= 64; AOptions: TEmbossOptions = []): TBGRACustomBitmap; overload; virtual; abstract;
600     function FilterEmboss(angle: single; ABounds: TRect; AStrength: integer= 64; AOptions: TEmbossOptions = []): TBGRACustomBitmap; overload; virtual; abstract;
601     function FilterEmbossHighlight(FillSelection: boolean): TBGRACustomBitmap; overload; virtual; abstract;
602     function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel): TBGRACustomBitmap; overload; virtual; abstract;
603     function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel; var Offset: TPoint): TBGRACustomBitmap; overload; virtual; abstract;
604     function FilterGrayscale: TBGRACustomBitmap; overload; virtual; abstract;
605     function FilterGrayscale(ABounds: TRect): TBGRACustomBitmap; overload; virtual; abstract;
606     function FilterNormalize(eachChannel: boolean = True): TBGRACustomBitmap; overload; virtual; abstract;
607     function FilterNormalize(ABounds: TRect; eachChannel: boolean = True): TBGRACustomBitmap; overload; virtual; abstract;
608     function FilterRotate(origin: TPointF; angle: single; correctBlur: boolean = false): TBGRACustomBitmap; virtual; abstract;
609     function FilterAffine(AMatrix: TAffineMatrix; correctBlur: boolean = false): TBGRACustomBitmap; virtual; abstract;
610     function FilterSphere: TBGRACustomBitmap; virtual; abstract;
611     function FilterTwirl(ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; overload; virtual; abstract;
612     function FilterTwirl(ABounds: TRect; ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; overload; virtual; abstract;
613     function FilterCylinder: TBGRACustomBitmap; virtual; abstract;
614     function FilterPlane: TBGRACustomBitmap; virtual; abstract;
615
616     //IBGRAScanner
617     function ScanAtIntegerExpanded(X,Y: integer): TExpandedPixel; override;
618     function ScanNextExpandedPixel: TExpandedPixel; override;
619     function ScanAtExpanded(X,Y: Single): TExpandedPixel; override;
620     function ProvidesScanline(ARect: TRect): boolean; override;
621     function GetScanlineAt(X, Y: integer): PBGRAPixel; override;
622     procedure ScanNextMaskChunk(var ACount: integer; out AMask: PByteMask; out AStride: integer); override;
623     function ScanAtIntegerMask(X,Y: integer): TByteMask; override;
624     function ScanAtMask(X,Y: Single): TByteMask; override;
625  end;
626
627type
628  TBGRABitmapAny = class of TBGRACustomBitmap;  //used to create instances of the same type (see NewBitmap)
629
630var
631  BGRABitmapFactory : TBGRABitmapAny;
632{$ENDIF}
633
634{$IFDEF INCLUDE_IMPLEMENTATION}
635{$UNDEF INCLUDE_IMPLEMENTATION}
636function InternalGetImageBoundsWithin(ASourceBitmap: TBGRACustomBitmap; ASourceTexture: IBGRAScanner;
637  const ARect: TRect; Channels: TChannels; ANothingValue: Byte): TRect;
638var
639  minx, miny, maxx, maxy: integer;
640  xb, xb2, yb: integer;
641  p:      PLongWord;
642  colorMask, colorZeros: LongWord;
643  actualRect: TRect;
644  pixelBuffer: TBGRAPixelBuffer;
645begin
646  pixelBuffer := nil;
647  if ASourceBitmap <> nil then
648  begin
649    actualRect := TRect.Intersect(ARect, rect(0,0,ASourceBitmap.Width,ASourceBitmap.Height));
650  end
651  else if ASourceTexture <> nil then
652  begin
653    actualRect := ARect;
654    AllocateBGRAPixelBuffer(pixelBuffer, ARect.Right-ARect.Left)
655  end
656  else
657  begin
658    result := EmptyRect;
659    exit;
660  end;
661  maxx := actualRect.Left-1;
662  maxy := actualRect.Top-1;
663  minx := actualRect.Right;
664  miny := actualRect.Bottom;
665  colorMask := 0;
666  colorZeros := 0;
667  if cBlue in Channels then
668  begin
669    colorMask := colorMask or LongWord(BGRA(0,0,255,0));
670    colorZeros:= colorZeros or LongWord(BGRA(0,0,ANothingValue,0));
671  end;
672  if cGreen in Channels then
673  begin
674    colorMask := colorMask or LongWord(BGRA(0,255,0,0));
675    colorZeros:= colorZeros or LongWord(BGRA(0,ANothingValue,0,0));
676  end;
677  if cRed in Channels then
678  begin
679    colorMask := colorMask or LongWord(BGRA(255,0,0,0));
680    colorZeros:= colorZeros or LongWord(BGRA(ANothingValue,0,0,0));
681  end;
682  if cAlpha in Channels then
683  begin
684    colorMask := colorMask or LongWord(BGRA(0,0,0,255));
685    colorZeros:= colorZeros or LongWord(BGRA(0,0,0,ANothingValue));
686  end;
687  colorMask := NtoLE(colorMask);
688  colorZeros := NtoLE(colorZeros);
689  for yb := actualRect.Top to actualRect.Bottom-1 do
690  begin
691    if ASourceBitmap <> nil then
692      p := PLongWord(ASourceBitmap.ScanLine[yb])+actualRect.Left
693    else
694    begin
695      p := @pixelBuffer[0];
696      ASourceTexture.ScanMoveTo(actualRect.Left,actualRect.Top);
697      ASourceTexture.ScanPutPixels(PBGRAPixel(p),ARect.Right-ARect.Left, dmSet);
698    end;
699    for xb := actualRect.Left to actualRect.Right - 1 do
700    begin
701      if (p^ and colorMask) <> colorZeros then
702      begin
703        if xb < minx then
704          minx := xb;
705        if yb < miny then
706          miny := yb;
707        if xb > maxx then
708          maxx := xb;
709        if yb > maxy then
710          maxy := yb;
711
712        inc(p, actualRect.Right-1-xb);
713        for xb2 := actualRect.Right-1 downto xb+1 do
714        begin
715          if (p^ and colorMask) <> colorZeros then
716          begin
717            if xb2 > maxx then
718              maxx := xb2;
719            break;
720          end;
721          dec(p);
722        end;
723        break;
724      end;
725      Inc(p);
726    end;
727  end;
728  if minx > maxx then
729  begin
730    Result.left   := 0;
731    Result.top    := 0;
732    Result.right  := 0;
733    Result.bottom := 0;
734  end
735  else
736  begin
737    Result.left   := minx;
738    Result.top    := miny;
739    Result.right  := maxx + 1;
740    Result.bottom := maxy + 1;
741  end;
742end;
743
744{ TBGRACustomBitmap }
745
746function TBGRACustomBitmap.GetFontAntialias: Boolean;
747begin
748  result := FontQuality <> fqSystem;
749end;
750
751procedure TBGRACustomBitmap.SetFontAntialias(const AValue: Boolean);
752begin
753  if AValue and not FontAntialias then
754    FontQuality := fqFineAntialiasing
755  else if not AValue and (FontQuality <> fqSystem) then
756    FontQuality := fqSystem;
757end;
758
759procedure TBGRACustomBitmap.SetXorMask(AValue: TBGRACustomBitmap);
760begin
761  if FXorMask=AValue then Exit;
762  if (AValue.Width <> Width) or (AValue.Height <> Height) then
763    raise exception.Create('Dimension mismatch');
764  DiscardXorMask;
765  FXorMask:=AValue;
766end;
767
768procedure TBGRACustomBitmap.Init;
769begin
770  inherited Init;
771  ScanMaskChannel:= cGreen;
772end;
773
774function TBGRACustomBitmap.GetFontRightToLeftFor(AText: string): boolean;
775begin
776  case FontBidiMode of
777    fbmAuto: result := IsRightToLeftUTF8(AText);
778    fbmRightToLeft: result := true;
779  else
780    {fbmLeftToRight}
781    result := false;
782  end;
783end;
784
785function TBGRACustomBitmap.NewBitmap: TBGRACustomBitmap;
786begin
787  Result:=inherited NewBitmap as TBGRACustomBitmap;
788end;
789
790function TBGRACustomBitmap.NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap;
791begin
792  Result:=inherited NewBitmap(AWidth, AHeight) as TBGRACustomBitmap;
793end;
794
795function TBGRACustomBitmap.NewBitmap(AWidth, AHeight: integer;
796  const Color: TBGRAPixel): TBGRACustomBitmap;
797begin
798  Result:=inherited NewBitmap(AWidth, AHeight, Color) as TBGRACustomBitmap;
799end;
800
801function TBGRACustomBitmap.NewBitmap(AWidth, AHeight: integer; AColor: Pointer
802  ): TBGRACustomBitmap;
803begin
804  Result:=inherited NewBitmap(AWidth, AHeight, AColor) as TBGRACustomBitmap;
805end;
806
807function TBGRACustomBitmap.InternalNew: TBGRACustomBitmap;
808begin
809  Result:= BGRABitmapFactory.Create;
810end;
811
812procedure TBGRACustomBitmap.DiscardXorMask;
813begin
814  if Assigned(FXorMask) then
815  begin
816    if FXorMask is TBGRACustomBitmap then
817    begin
818      TBGRACustomBitmap(FXorMask).FreeReference;
819      FXorMask := nil;
820    end else
821      FreeAndNil(FXorMask);
822  end;
823end;
824
825procedure TBGRACustomBitmap.NeedXorMask;
826begin
827  if FXorMask = nil then
828    FXorMask := BGRABitmapFactory.Create(Width,Height);
829end;
830
831function TBGRACustomBitmap.NewReference: TBGRACustomBitmap;
832begin
833  result := TBGRACustomBitmap(inherited NewReference);
834end;
835
836function TBGRACustomBitmap.GetUnique: TBGRACustomBitmap;
837begin
838  result := TBGRACustomBitmap(inherited GetUnique);
839end;
840
841function TBGRACustomBitmap.Duplicate(DuplicateProperties: Boolean): TBGRACustomBitmap;
842begin
843  result := TBGRACustomBitmap(inherited Duplicate(DuplicateProperties));
844end;
845
846function TBGRACustomBitmap.Duplicate(DuplicateProperties,
847  DuplicateXorMask: Boolean): TBGRACustomBitmap;
848begin
849  result := Duplicate(DuplicateProperties);
850  if DuplicateXorMask and Assigned(XorMask) then
851    result.XorMask := FXorMask.Duplicate(True);
852end;
853
854procedure TBGRACustomBitmap.CopyPropertiesTo(ABitmap: TCustomUniversalBitmap);
855var
856  other: TBGRACustomBitmap;
857begin
858  inherited CopyPropertiesTo(ABitmap);
859  if ABitmap is TBGRACustomBitmap then
860  begin
861    other := TBGRACustomBitmap(ABitmap);
862    other.CanvasOpacity := CanvasOpacity;
863    other.CanvasDrawModeFP := CanvasDrawModeFP;
864    other.PenStyle := PenStyle;
865    other.CustomPenStyle := CustomPenStyle;
866    other.FontName := FontName;
867    other.FontHeight := FontHeight;
868    other.FontStyle := FontStyle;
869    other.FontQuality := FontQuality;
870    other.FontOrientation := FontOrientation;
871    other.FontVerticalAnchor:= FontVerticalAnchor;
872    other.FontBidiMode:= FontBidiMode;
873    other.LineCap := LineCap;
874    other.JoinStyle := JoinStyle;
875    other.ResampleFilter := ResampleFilter;
876    other.ScanInterpolationFilter:= ScanInterpolationFilter;
877    other.HotSpot := HotSpot;
878  end;
879end;
880
881function TBGRACustomBitmap.GetPart(const ARect: TRect): TBGRACustomBitmap;
882begin
883  result := TBGRACustomBitmap(inherited GetPart(ARect));
884end;
885
886function TBGRACustomBitmap.CreateBrushTexture(ABrushStyle: TBrushStyle;
887  APatternColor, ABackgroundColor: TBGRAPixel; AWidth: integer;
888  AHeight: integer; APenWidth: single): TBGRACustomBitmap;
889begin
890  result := TBGRACustomBitmap(inherited CreateBrushTexture(ABrushStyle, APatternColor, ABackgroundColor, AWidth,AHeight,APenWidth));
891end;
892
893procedure TBGRACustomBitmap.SetSize(AWidth, AHeight: integer);
894begin
895  if (AWidth <> Width) or (AHeight <> Height) then
896  begin
897    inherited SetSize(AWidth, AHeight);
898    DiscardXorMask;
899  end;
900end;
901
902procedure TBGRACustomBitmap.InternalArc(cx, cy, rx, ry: single;
903  const StartPoint, EndPoint: TPointF; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; AOptions: TArcOptions;
904  ADrawChord: boolean; ATexture: IBGRAScanner);
905var angle1,angle2: single;
906begin
907  if (rx = 0) or (ry = 0) then exit;
908  angle1 := arctan2(-(StartPoint.y-cy)/ry,(StartPoint.x-cx)/rx);
909  angle2 := arctan2(-(EndPoint.y-cy)/ry,(EndPoint.x-cx)/rx);
910  if angle1 = angle2 then angle2 := angle1+2*Pi;
911  InternalArc(cx,cy,rx,ry, angle1,angle2,
912              ABorderColor,w,AFillColor, AOptions, ADrawChord, ATexture);
913end;
914
915procedure TBGRACustomBitmap.InternalArcInRect(r: TRect; StartAngleRad,
916  EndAngleRad: Single; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; AOptions: TArcOptions;
917  ADrawChord: boolean; ATexture: IBGRAScanner);
918var
919  temp: LongInt;
920begin
921  if r.right = r.left then exit;
922  if r.bottom = r.top then exit;
923  if r.right < r.left then
924  begin
925    temp := r.left;
926    r.left := r.right;
927    r.right := temp;
928  end;
929  if r.Bottom < r.Top then
930  begin
931    temp := r.Top;
932    r.Top := r.Bottom;
933    r.Bottom := temp;
934  end;
935  InternalArc((r.left+r.right-1)/2,(r.top+r.bottom-1)/2,
936             (r.right-r.left-1)/2,(r.bottom-r.top-1)/2,
937             StartAngleRad,EndAngleRad,
938             ABorderColor,w,AFillColor,
939             AOptions, ADrawChord, ATexture);
940end;
941
942procedure TBGRACustomBitmap.InternalFillArcInRect(r: TRect; StartAngleRad,
943  EndAngleRad: Single; AFillColor: TBGRAPixel; AOptions: TArcOptions;
944  ATexture: IBGRAScanner);
945var
946  temp: LongInt;
947begin
948  if r.right = r.left then exit;
949  if r.bottom = r.top then exit;
950  if r.right < r.left then
951  begin
952    temp := r.left;
953    r.left := r.right;
954    r.right := temp;
955  end;
956  if r.Bottom < r.Top then
957  begin
958    temp := r.Top;
959    r.Top := r.Bottom;
960    r.Bottom := temp;
961  end;
962  InternalArc((r.left+r.right-1)/2,(r.top+r.bottom-1)/2,
963             (r.right-r.left)/2,(r.bottom-r.top)/2,
964             StartAngleRad,EndAngleRad,
965             BGRAPixelTransparent,0,AFillColor,
966             AOptions, False, ATexture);
967end;
968
969procedure TBGRACustomBitmap.DrawPixel(x, y: int32or64; const c: TBGRAPixel;
970  ADrawMode: TDrawMode);
971begin
972  case ADrawMode of
973  dmSet: SetPixel(x,y,c);
974  dmSetExceptTransparent: if c.alpha = 255 then SetPixel(x,y,c);
975  dmLinearBlend: FastBlendPixel(x,y,c);
976  dmDrawWithTransparency: DrawPixel(x,y,c);
977  dmXor: XorPixel(x,y,c);
978  end;
979end;
980
981procedure TBGRACustomBitmap.LoadFromStream(AStream: TStream;
982  AHandler: TFPCustomImageReader; AOptions: TBGRALoadingOptions);
983var
984  OldDrawMode: TDrawMode;
985begin
986  { LoadFromStream uses TFPCustomImage routine, which uses
987    Colors property to access pixels. That's why the
988    FP drawing mode is temporarily changed to load
989    bitmaps properly }
990  OldDrawMode := CanvasDrawModeFP;
991  CanvasDrawModeFP := dmSet;
992  DiscardXorMask;
993  try
994    inherited LoadFromStream(AStream, AHandler, AOptions);
995  finally
996    CanvasDrawModeFP := OldDrawMode;
997  end;
998end;
999
1000{ Look for a pixel considering the bitmap is repeated in both directions }
1001procedure TBGRACustomBitmap.DrawHorizLine(x, y, x2: int32or64;
1002  texture: IBGRAScanner);
1003begin
1004  HorizLine(x,y,x2,texture,dmDrawWithTransparency);
1005end;
1006
1007procedure TBGRACustomBitmap.Arc(cx, cy, rx, ry: single; const StartPoint,
1008  EndPoint: TPointF; AColor: TBGRAPixel; w: single; ADrawChord: boolean;
1009  AFillColor: TBGRAPixel);
1010begin
1011  InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,AColor,w,AFillColor,[aoFillPath],ADrawChord);
1012end;
1013
1014procedure TBGRACustomBitmap.Arc(cx, cy, rx, ry: single; StartAngleRad,
1015  EndAngleRad: Single; AColor: TBGRAPixel; w: single; ADrawChord: boolean;
1016  AFillColor: TBGRAPixel);
1017begin
1018  InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,AColor,w,AFillColor,[aoFillPath],ADrawChord);
1019end;
1020
1021procedure TBGRACustomBitmap.FillChord(cx, cy, rx, ry: single; const StartPoint,
1022  EndPoint: TPointF; AFillColor: TBGRAPixel);
1023begin
1024  InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,BGRAPixelTransparent,0,AFillColor,[aoFillPath]);
1025end;
1026
1027procedure TBGRACustomBitmap.FillChord(cx, cy, rx, ry: single; StartAngleRad,
1028  EndAngleRad: Single; AFillColor: TBGRAPixel);
1029begin
1030  InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,BGRAPixelTransparent,0,AFillColor,[aoFillPath]);
1031end;
1032
1033procedure TBGRACustomBitmap.FillChord(cx, cy, rx, ry: single; const StartPoint,
1034  EndPoint: TPointF; texture: IBGRAScanner);
1035begin
1036  InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,BGRAPixelTransparent,0,BGRAWhite,[aoFillPath],False,texture);
1037end;
1038
1039procedure TBGRACustomBitmap.FillChord(cx, cy, rx, ry: single; StartAngleRad,
1040  EndAngleRad: Single; texture: IBGRAScanner);
1041begin
1042  InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,BGRAPixelTransparent,0,BGRAWhite,[aoFillPath],False,texture);
1043end;
1044
1045procedure TBGRACustomBitmap.FillChordInRect(const ARect: TRect; StartAngleRad,
1046  EndAngleRad: Single; AFillColor: TBGRAPixel);
1047begin
1048  InternalFillArcInRect(ARect,StartAngleRad,EndAngleRad,AFillColor,[aoFillPath]);
1049end;
1050
1051procedure TBGRACustomBitmap.FillChordInRect(const ARect: TRect; StartAngleRad,
1052  EndAngleRad: Single; texture: IBGRAScanner);
1053begin
1054  InternalFillArcInRect(ARect,StartAngleRad,EndAngleRad,BGRAWhite,[aoFillPath],texture);
1055end;
1056
1057procedure TBGRACustomBitmap.Pie(cx, cy, rx, ry: single; const StartPoint,
1058  EndPoint: TPointF; AColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel);
1059begin
1060  InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,AColor,w,AFillColor,[aoFillPath,aoPie]);
1061end;
1062
1063procedure TBGRACustomBitmap.Pie(cx, cy, rx, ry: single; StartAngleRad,
1064  EndAngleRad: Single; AColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel);
1065begin
1066  InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,AColor,w,AFillColor,[aoFillPath,aoPie]);
1067end;
1068
1069procedure TBGRACustomBitmap.FillPie(cx, cy, rx, ry: single; const StartPoint,
1070  EndPoint: TPointF; AFillColor: TBGRAPixel);
1071begin
1072  InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,BGRAPixelTransparent,0,AFillColor,[aoFillPath,aoPie]);
1073end;
1074
1075procedure TBGRACustomBitmap.FillPie(cx, cy, rx, ry: single; StartAngleRad,
1076  EndAngleRad: Single; AFillColor: TBGRAPixel);
1077begin
1078  InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,BGRAPixelTransparent,0,AFillColor,[aoFillPath,aoPie]);
1079end;
1080
1081procedure TBGRACustomBitmap.FillPie(cx, cy, rx, ry: single; const StartPoint,
1082  EndPoint: TPointF; texture: IBGRAScanner);
1083begin
1084  InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,BGRAPixelTransparent,0,BGRAWhite,[aoFillPath,aoPie],False,texture);
1085end;
1086
1087procedure TBGRACustomBitmap.FillPie(cx, cy, rx, ry: single; StartAngleRad,
1088  EndAngleRad: Single; texture: IBGRAScanner);
1089begin
1090  InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,BGRAPixelTransparent,0,BGRAWhite,[aoFillPath,aoPie],False,texture);
1091end;
1092
1093procedure TBGRACustomBitmap.FillPieInRect(const ARect: TRect; StartAngleRad,
1094  EndAngleRad: Single; AFillColor: TBGRAPixel);
1095begin
1096  InternalFillArcInRect(ARect,StartAngleRad,EndAngleRad,AFillColor,[aoFillPath,aoPie]);
1097end;
1098
1099procedure TBGRACustomBitmap.FillPieInRect(const ARect: TRect; StartAngleRad,
1100  EndAngleRad: Single; texture: IBGRAScanner);
1101begin
1102  InternalFillArcInRect(ARect,StartAngleRad,EndAngleRad,BGRAWhite,[aoFillPath,aoPie],texture);
1103end;
1104
1105{ Following functions are defined for convenience }
1106procedure TBGRACustomBitmap.RectangleWithin(x1, y1, x2, y2: single;
1107  ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel;
1108  APixelCenteredCoordinates: boolean);
1109begin
1110  if not APixelCenteredCoordinates then
1111  begin
1112    DecF(x1, 0.5);
1113    DecF(y1, 0.5);
1114    DecF(x2, 0.5);
1115    DecF(y2, 0.5);
1116  end;
1117  RectangleAntialias(x1+w*0.5,y1+w*0.5,x2-w*0.5,y2-w*0.5, ABorderColor, w, AFillColor);
1118end;
1119
1120procedure TBGRACustomBitmap.RectangleWithin(r: TRect; ABorderColor: TBGRAPixel;
1121  w: single; AFillColor: TBGRAPixel);
1122begin
1123  RectangleWithin(r.left,r.top,r.right,r.bottom,ABorderColor,w,AFillColor,false);
1124end;
1125
1126procedure TBGRACustomBitmap.FillRect(r: TRect; texture: IBGRAScanner;
1127  mode: TDrawMode; ditheringAlgorithm: TDitheringAlgorithm);
1128begin
1129  FillRect(r.Left,r.Top,r.Right,r.Bottom, texture, mode, ditheringAlgorithm);
1130end;
1131
1132procedure TBGRACustomBitmap.FillRect(r: TRect; texture: IBGRAScanner;
1133  mode: TDrawMode; AScanOffset: TPoint; ditheringAlgorithm: TDitheringAlgorithm);
1134begin
1135  FillRect(r.Left,r.Top,r.Right,r.Bottom, texture, mode, AScanOffset, ditheringAlgorithm);
1136end;
1137
1138procedure TBGRACustomBitmap.FillRect(x, y, x2, y2: integer;
1139  texture: IBGRAScanner; mode: TDrawMode;
1140  ditheringAlgorithm: TDitheringAlgorithm);
1141begin
1142  FillRect(x,y,x2,y2,texture,mode,Point(0,0),ditheringAlgorithm);
1143end;
1144
1145procedure TBGRACustomBitmap.TextOutCurved(APath: IBGRAPath; const sUTF8: string;
1146  AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single);
1147var cursor: TBGRACustomPathCursor;
1148begin
1149  cursor := APath.getCursor;
1150  if cursor = nil then exit;
1151  case AAlign of
1152    taCenter: cursor.Position := cursor.PathLength*0.5;
1153    taRightJustify: cursor.Position:= cursor.PathLength;
1154  end;
1155  TextOutCurved(cursor, sUTF8, AColor, AAlign, ALetterSpacing);
1156  cursor.free;
1157end;
1158
1159procedure TBGRACustomBitmap.TextOutCurved(APath: IBGRAPath; const sUTF8: string;
1160  ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single);
1161var cursor: TBGRACustomPathCursor;
1162begin
1163  cursor := APath.getCursor;
1164  if cursor = nil then exit;
1165  case AAlign of
1166    taCenter: cursor.Position := cursor.PathLength*0.5;
1167    taRightJustify: cursor.Position:= cursor.PathLength;
1168  end;
1169  TextOutCurved(cursor, sUTF8, ATexture, AAlign, ALetterSpacing);
1170  cursor.free;
1171end;
1172
1173procedure TBGRACustomBitmap.TextMultiline(x, y: single; const sUTF8: string;
1174  c: TBGRAPixel; AAlign: TBidiTextAlignment; AVertAlign: TTextLayout; AParagraphSpacing: single);
1175begin
1176  TextMultiline(x, y, EmptySingle, sUTF8, c, AAlign, AVertAlign, AParagraphSpacing);
1177end;
1178
1179procedure TBGRACustomBitmap.TextMultiline(x, y: single; const sUTF8: string;
1180  ATexture: IBGRAScanner; AAlign: TBidiTextAlignment; AVertAlign: TTextLayout; AParagraphSpacing: single);
1181begin
1182  TextMultiline(x, y, EmptySingle, sUTF8, ATexture, AAlign, AVertAlign, AParagraphSpacing);
1183end;
1184
1185procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel;
1186  align: TAlignment);
1187begin
1188  TextOut(x,y,sUTF8,c,align, GetFontRightToLeftFor(sUTF8));
1189end;
1190
1191procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string;
1192  texture: IBGRAScanner; align: TAlignment);
1193begin
1194  TextOut(x,y,sUTF8,texture,align, GetFontRightToLeftFor(sUTF8));
1195end;
1196
1197{ Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c is used to fill the text.
1198  The value of FontOrientation is taken into account, so that the text may be rotated. }
1199procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel);
1200begin
1201  TextOut(x, y, sUTF8, c, taLeftJustify);
1202end;
1203
1204procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel;
1205  ARightToLeft: boolean);
1206begin
1207  TextOut(x, y, sUTF8, c, taLeftJustify, ARightToLeft);
1208end;
1209
1210{ Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c is used to fill the text.
1211  The value of FontOrientation is taken into account, so that the text may be rotated. }
1212procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TColor);
1213begin
1214  TextOut(x, y, sUTF8, ColorToBGRA(c));
1215end;
1216
1217procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TColor;
1218  ARightToLeft: boolean);
1219begin
1220  TextOut(x, y, sUTF8, ColorToBGRA(c), ARightToLeft);
1221end;
1222
1223{ Draw the UTF8 encoded string, (x,y) being the top-left corner. The texture is used to fill the text.
1224  The value of FontOrientation is taken into account, so that the text may be rotated. }
1225procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string;
1226  texture: IBGRAScanner);
1227begin
1228  TextOut(x, y, sUTF8, texture, taLeftJustify);
1229end;
1230
1231procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string;
1232  texture: IBGRAScanner; ARightToLeft: boolean);
1233begin
1234  TextOut(x, y, sUTF8, texture, taLeftJustify, ARightToLeft);
1235end;
1236
1237procedure TBGRACustomBitmap.TextOutAngle(x, y: single;
1238  orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel);
1239begin
1240  TextOutAngle(x,y, orientationTenthDegCCW, sUTF8,c,taLeftJustify);
1241end;
1242
1243procedure TBGRACustomBitmap.TextOutAngle(x, y: single;
1244  orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel;
1245  align: TAlignment);
1246begin
1247  TextOutAngle(x,y, orientationTenthDegCCW, sUTF8,c,align, GetFontRightToLeftFor(sUTF8));
1248end;
1249
1250procedure TBGRACustomBitmap.TextOutAngle(x, y: single;
1251  orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner);
1252begin
1253  TextOutAngle(x,y, orientationTenthDegCCW, sUTF8,texture,taLeftJustify);
1254end;
1255
1256procedure TBGRACustomBitmap.TextOutAngle(x, y: single;
1257  orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner;
1258  align: TAlignment);
1259begin
1260  TextOutAngle(x,y, orientationTenthDegCCW, sUTF8,texture,align, GetFontRightToLeftFor(sUTF8));
1261end;
1262
1263{ Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary.
1264  The position depends on the specified horizontal alignment halign and vertical alignement valign.
1265  The color c is used to fill the text. No rotation is applied. }
1266procedure TBGRACustomBitmap.TextRect(ARect: TRect; const sUTF8: string;
1267  halign: TAlignment; valign: TTextLayout; c: TBGRAPixel);
1268var
1269  style: TTextStyle;
1270  sUTF8bidi: String;
1271begin
1272  {$hints off}
1273  FillChar(style,sizeof(style),0);
1274  {$hints on}
1275  style.Alignment := halign;
1276  style.Layout := valign;
1277  style.Wordbreak := true;
1278  style.ShowPrefix := false;
1279  style.Clipping := false;
1280  style.RightToLeft := GetFontRightToLeftFor(sUTF8);
1281  if FontBidiMode = fbmAuto then
1282    sUTF8bidi := AddParagraphBidiUTF8(sUTF8, style.RightToLeft)
1283    else sUTF8bidi := sUTF8;
1284  TextRect(ARect, ARect.Left, ARect.Top, sUTF8bidi, style, c);
1285end;
1286
1287{ Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary.
1288  The position depends on the specified horizontal alignment halign and vertical alignement valign.
1289  The texture is used to fill the text. No rotation is applied. }
1290procedure TBGRACustomBitmap.TextRect(ARect: TRect; const sUTF8: string;
1291  halign: TAlignment; valign: TTextLayout; texture: IBGRAScanner);
1292var
1293  style: TTextStyle;
1294  sUTF8bidi: String;
1295begin
1296  {$hints off}
1297  FillChar(style,sizeof(style),0);
1298  {$hints on}
1299  style.Alignment := halign;
1300  style.Layout := valign;
1301  style.Wordbreak := true;
1302  style.ShowPrefix := false;
1303  style.Clipping := false;
1304  style.RightToLeft := GetFontRightToLeftFor(sUTF8);
1305  if FontBidiMode = fbmAuto then
1306    sUTF8bidi := AddParagraphBidiUTF8(sUTF8, style.RightToLeft)
1307    else sUTF8bidi := sUTF8;
1308  TextRect(ARect,ARect.Left,ARect.Top,sUTF8bidi,style,texture);
1309end;
1310
1311function TBGRACustomBitmap.ComputeEllipse(x, y, rx, ry: single): ArrayOfTPointF;
1312begin
1313  result := ComputeEllipseContour(x,y,rx,ry);
1314end;
1315
1316function TBGRACustomBitmap.ComputeEllipse(x, y, rx, ry, w: single
1317  ): ArrayOfTPointF;
1318begin
1319  result := ComputeEllipseBorder(x,y,rx,ry,w);
1320end;
1321
1322procedure TBGRACustomBitmap.Fill(texture: IBGRAScanner);
1323begin
1324  FillRect(ClipRect, texture, dmSet);
1325end;
1326
1327procedure TBGRACustomBitmap.Fill(texture: IBGRAScanner; mode: TDrawMode);
1328begin
1329  FillRect(ClipRect, texture, mode);
1330end;
1331
1332procedure TBGRACustomBitmap.FloodFill(X, Y: integer; Color: TBGRAPixel;
1333  mode: TFloodfillMode; Tolerance: byte);
1334begin
1335  ParallelFloodFill(X,Y, Self, Color, mode, Tolerance);
1336end;
1337
1338procedure TBGRACustomBitmap.FloodFill(X, Y: integer;
1339  const Brush: TUniversalBrush; Progressive: boolean; ToleranceW: Word);
1340begin
1341  ParallelFloodFill(X,Y, Self, Brush, Progressive, ToleranceW);
1342end;
1343
1344procedure TBGRACustomBitmap.DrawPart(ARect: TRect; ACanvas: TCanvas; x,
1345  y: integer; Opaque: boolean);
1346var
1347  partial: TBGRACustomBitmap;
1348begin
1349  if (ARect.Left = 0) and (ARect.Top = 0) and (ARect.Right = Width) and (ARect.Bottom = Height) then
1350    Draw(ACanvas, x,y, Opaque)
1351  else
1352  begin
1353    partial := GetPart(ARect);
1354    if partial <> nil then
1355    begin
1356      partial.Draw(ACanvas, x, y, Opaque);
1357      partial.Free;
1358    end;
1359  end;
1360end;
1361
1362procedure TBGRACustomBitmap.DrawPart(ARect: TRect; ACanvas: TCanvas;
1363  ATargetRect: TRect; Opaque: boolean);
1364var
1365  partial: TBGRACustomBitmap;
1366begin
1367  if (ARect.Left = 0) and (ARect.Top = 0) and (ARect.Right = Width) and (ARect.Bottom = Height) then
1368    Draw(ACanvas, ATargetRect, Opaque)
1369  else
1370  begin
1371    partial := GetPart(ARect);
1372    if partial <> nil then
1373    begin
1374      partial.Draw(ACanvas, ATargetRect, Opaque);
1375      partial.Free;
1376    end;
1377  end;
1378end;
1379
1380procedure TBGRACustomBitmap.PutImage(x, y: integer; Source: TBitmap;
1381  mode: TDrawMode; AOpacity: byte);
1382var bgra: TBGRACustomBitmap;
1383begin
1384  bgra := BGRABitmapFactory.create(Source);
1385  PutImage(x,y, bgra, mode, AOpacity);
1386  bgra.free;
1387end;
1388
1389procedure TBGRACustomBitmap.StretchPutImage(ARect: TRect; Source: TBitmap;
1390  mode: TDrawMode; AOpacity: byte);
1391var bgra: TBGRACustomBitmap;
1392begin
1393  bgra := BGRABitmapFactory.create(Source);
1394  StretchPutImage(ARect, bgra, mode, AOpacity);
1395  bgra.free;
1396end;
1397
1398procedure TBGRACustomBitmap.StretchPutImageProportionally(ARect: TRect;
1399  AHorizAlign: TAlignment; AVertAlign: TTextLayout; Source: TBGRACustomBitmap;
1400  mode: TDrawMode; AOpacity: byte);
1401var
1402  ratio: single;
1403  imgRect: TRect;
1404begin
1405  if (Source.Width = 0) or (Source.Height = 0) then exit;
1406  if (ARect.Width <= 0) or (ARect.Height <= 0) then exit;
1407
1408  ratio := min(ARect.Width/Source.Width, ARect.Height/Source.Height);
1409  imgRect := RectWithSize(ARect.Left,ARect.Top, round(Source.Width*ratio), round(Source.Height*ratio));
1410  case AHorizAlign of
1411    taCenter: imgRect.Offset((ARect.Width-imgRect.Width) div 2, 0);
1412    taRightJustify: imgRect.Offset(ARect.Width-imgRect.Width, 0);
1413  end;
1414  case AVertAlign of
1415    tlCenter: imgRect.Offset(0,(ARect.Height-imgRect.Height) div 2);
1416    tlBottom: imgRect.Offset(0,ARect.Height-imgRect.Height);
1417  end;
1418  StretchPutImage(imgRect, Source, mode, AOpacity);
1419end;
1420
1421procedure TBGRACustomBitmap.PutImageSubpixel(x, y: single; Source: TBGRACustomBitmap; AOpacity: byte);
1422begin
1423  PutImageAngle(x,y,source,0,0,0,AOpacity);
1424end;
1425
1426procedure TBGRACustomBitmap.PutImagePart(x, y: integer;
1427  Source: TBGRACustomBitmap; SourceRect: TRect; mode: TDrawMode; AOpacity: byte);
1428var w,h,sourcex,sourcey,nx,ny,xb,yb,destx,desty: integer;
1429    oldClip,newClip: TRect;
1430begin
1431  if (Source = nil) or (AOpacity = 0) then exit;
1432  w := SourceRect.Right-SourceRect.Left;
1433  h := SourceRect.Bottom-SourceRect.Top;
1434  if (w <= 0) or (h <= 0) or (Source.Width = 0) or (Source.Height = 0) then exit;
1435  sourcex := PositiveMod(SourceRect.Left, Source.Width);
1436  sourcey := PositiveMod(SourceRect.Top, Source.Height);
1437  nx := (sourceX+w + Source.Width-1) div Source.Width;
1438  ny := (sourceY+h + Source.Height-1) div Source.Height;
1439
1440  oldClip := ClipRect;
1441  newClip := rect(x,y,x+w,y+h);
1442  newClip.Intersect(oldClip);
1443  if newClip.IsEmpty then exit;
1444
1445  ClipRect := newClip;
1446
1447  desty := y-sourcey;
1448  for yb := 0 to ny-1 do
1449  begin
1450    destx := x-sourcex;
1451    for xb := 0 to nx-1 do
1452    begin
1453      self.PutImage(destx,desty,Source,mode,AOpacity);
1454      inc(destx,Source.Width);
1455    end;
1456    inc(desty,Source.Height);
1457  end;
1458
1459  ClipRect := oldClip;
1460end;
1461
1462procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF;
1463  Source: TBGRACustomBitmap; AOpacity: Byte; ACorrectBlur: Boolean);
1464begin
1465  if ACorrectBlur then
1466    PutImageAffine(Origin,HAxis,VAxis,Source,rfCosine,AOpacity)
1467  else
1468    PutImageAffine(Origin,HAxis,VAxis,Source,rfLinear,AOpacity);
1469end;
1470
1471procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF;
1472  Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte);
1473begin
1474  if (Source = nil) or (Source.Width = 0) or (Source.Height = 0) or (AOpacity = 0) then exit;
1475  PutImageAffine(Origin,HAxis,VAxis,Source,GetImageAffineBounds(Origin,HAxis,VAxis,Source),AResampleFilter,dmDrawWithTransparency,AOpacity);
1476end;
1477
1478procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF;
1479  Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter;
1480  AMode: TDrawMode; AOpacity: Byte);
1481begin
1482  if (Source = nil) or (Source.Width = 0) or (Source.Height = 0) or (AOpacity = 0) then exit;
1483  PutImageAffine(Origin,HAxis,VAxis,Source,GetImageAffineBounds(Origin,HAxis,VAxis,Source),AResampleFilter,AMode,AOpacity);
1484end;
1485
1486procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF;
1487  Source: TBGRACustomBitmap; AOutputBounds: TRect;
1488  AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte);
1489var m: TAffineMatrix; w,h: integer;
1490begin
1491  if (Source = nil) or (Source.Width = 0) or (Source.Height = 0) or (AOpacity = 0) then exit;
1492  if Source.Width < 2 then w := 2 else w := Source.Width; //avoid actual size of zero
1493  if Source.Height < 2 then h := 2 else h := Source.Height;
1494  m[1,1] := (HAxis.x-Origin.x)/(w-1); m[1,2] := (VAxis.x-Origin.x)/(h-1); m[1,3] := Origin.x;
1495  m[2,1] := (HAxis.y-Origin.y)/(w-1); m[2,2] := (VAxis.y-Origin.y)/(h-1); m[2,3] := Origin.y;
1496  PutImageAffine(m,Source,AOutputBounds,AResampleFilter,AMode,AOpacity);
1497end;
1498
1499procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF;
1500  Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte;
1501  ACorrectBlur: Boolean);
1502begin
1503  if ACorrectBlur then
1504    PutImageAffine(Origin,HAxis,VAxis,Source,AOutputBounds,rfCosine,dmDrawWithTransparency,AOpacity)
1505  else
1506    PutImageAffine(Origin,HAxis,VAxis,Source,AOutputBounds,rfLinear,dmDrawWithTransparency,AOpacity);
1507end;
1508
1509procedure TBGRACustomBitmap.PutImageAffine(AMatrix: TAffineMatrix;
1510  Source: TBGRACustomBitmap; AOpacity: Byte; ACorrectBlur: Boolean; APixelCenteredCoords: boolean);
1511begin
1512  if ACorrectBlur then
1513    PutImageAffine(AMatrix,Source,rfCosine,AOpacity,APixelCenteredCoords)
1514  else
1515    PutImageAffine(AMatrix,Source,rfLinear,AOpacity,APixelCenteredCoords);
1516end;
1517
1518procedure TBGRACustomBitmap.PutImageAffine(AMatrix: TAffineMatrix;
1519  Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte; APixelCenteredCoords: boolean);
1520begin
1521  PutImageAffine(AMatrix, Source, AResampleFilter, dmDrawWithTransparency, AOpacity, APixelCenteredCoords);
1522end;
1523
1524procedure TBGRACustomBitmap.PutImageAffine(AMatrix: TAffineMatrix;
1525  Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter;
1526  AMode: TDrawMode; AOpacity: Byte; APixelCenteredCoords: boolean);
1527begin
1528  if (Source = nil) or (Source.Width = 0) or (Source.Height = 0) or (AOpacity = 0) then exit;
1529  PutImageAffine(AMatrix, Source, GetImageAffineBounds(AMatrix,Source),
1530                 AResampleFilter,AMode,AOpacity,APixelCenteredCoords);
1531end;
1532
1533procedure TBGRACustomBitmap.PutImageAffine(AMatrix: TAffineMatrix;
1534  Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte;
1535  ACorrectBlur: Boolean; APixelCenteredCoords: boolean);
1536begin
1537  if ACorrectBlur then
1538    PutImageAffine(AMatrix,Source,AOutputBounds,rfCosine,dmDrawWithTransparency,AOpacity,APixelCenteredCoords)
1539  else
1540    PutImageAffine(AMatrix,Source,AOutputBounds,rfLinear,dmDrawWithTransparency,AOpacity,APixelCenteredCoords);
1541end;
1542
1543{ Returns the area that contains the affine transformed image }
1544function TBGRACustomBitmap.GetImageAffineBounds(Origin, HAxis, VAxis: TPointF;
1545  Source: TBGRACustomBitmap): TRect;
1546begin
1547  if Source = nil then
1548    result := EmptyRect
1549  else
1550    result := GetImageAffineBounds(Origin,HAxis,VAxis,Source.Width,Source.Height,Source.GetImageBounds);
1551end;
1552
1553function TBGRACustomBitmap.GetImageAffineBounds(Origin, HAxis, VAxis: TPointF;
1554  ASourceWidth, ASourceHeight: integer; const ASourceBounds: TRect; AClipOutput: boolean): TRect;
1555var m: TAffineMatrix;
1556begin
1557  if (ASourceWidth = 0) or (ASourceHeight = 0) then
1558    result := EmptyRect
1559  else
1560  begin
1561    if ASourceWidth < 2 then ASourceWidth := 2;   //avoid division by zero by supposing a pixel size of 2
1562    if ASourceHeight < 2 then ASourceHeight := 2; //i.e. an actual size of 1 (cf pixel centered coordinates)
1563    m[1,1] := (HAxis.x-Origin.x)/(ASourceWidth-1); m[1,2] := (VAxis.x-Origin.x)/(ASourceHeight-1); m[1,3] := Origin.x;
1564    m[2,1] := (HAxis.y-Origin.y)/(ASourceWidth-1); m[2,2] := (VAxis.y-Origin.y)/(ASourceHeight-1); m[2,3] := Origin.y;
1565    result := GetImageAffineBounds(m, ASourceBounds, AClipOutput);
1566  end;
1567end;
1568
1569function TBGRACustomBitmap.GetImageAffineBounds(AMatrix: TAffineMatrix;
1570  Source: TBGRACustomBitmap; APixelCenteredCoords: boolean): TRect;
1571begin
1572  result := GetImageAffineBounds(AMatrix, Source.GetImageBounds, true, APixelCenteredCoords);
1573end;
1574
1575procedure TBGRACustomBitmap.PutImageAngle(x, y: single;
1576  Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect;
1577  imageCenterX: single; imageCenterY: single; AOpacity: Byte;
1578  ARestoreOffsetAfterRotation: boolean; ACorrectBlur: Boolean);
1579begin
1580  if ACorrectBlur then
1581    PutImageAngle(x,y,Source,angle,AOutputBounds,rfCosine,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation)
1582  else
1583    PutImageAngle(x,y,Source,angle,AOutputBounds,rfLinear,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation);
1584end;
1585
1586procedure TBGRACustomBitmap.PutImageAngle(x, y: single;
1587  Source: TBGRACustomBitmap; angle: single; imageCenterX: single;
1588  imageCenterY: single; AOpacity: Byte; ARestoreOffsetAfterRotation: boolean; ACorrectBlur: Boolean);
1589begin
1590  if ACorrectBlur then
1591    PutImageAngle(x,y,Source,angle,rfCosine,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation)
1592  else
1593    PutImageAngle(x,y,Source,angle,rfLinear,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation);
1594end;
1595
1596procedure TBGRACustomBitmap.PutImageAngle(x, y: single;
1597  Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect;
1598  AResampleFilter: TResampleFilter; imageCenterX: single; imageCenterY: single; AOpacity: Byte;
1599  ARestoreOffsetAfterRotation: boolean);
1600var
1601  Origin,HAxis,VAxis: TPointF;
1602begin
1603  if (source = nil) or (AOpacity=0) then exit;
1604  ComputeImageAngleAxes(x,y,source.Width,source.Height,angle,imageCenterX,imageCenterY,ARestoreOffsetAfterRotation,
1605     Origin,HAxis,VAxis);
1606  PutImageAffine(Origin,HAxis,VAxis,source,AOutputBounds,AResampleFilter,dmDrawWithTransparency,AOpacity);
1607end;
1608
1609procedure TBGRACustomBitmap.PutImageAngle(x, y: single;
1610  Source: TBGRACustomBitmap; angle: single; AResampleFilter: TResampleFilter;
1611  imageCenterX: single; imageCenterY: single; AOpacity: Byte;
1612  ARestoreOffsetAfterRotation: boolean);
1613var
1614  Origin,HAxis,VAxis: TPointF;
1615begin
1616  if (source = nil) or (AOpacity=0) then exit;
1617  ComputeImageAngleAxes(x,y,source.Width,source.Height,angle,imageCenterX,imageCenterY,ARestoreOffsetAfterRotation,
1618     Origin,HAxis,VAxis);
1619  PutImageAffine(Origin,HAxis,VAxis,source,AResampleFilter,AOpacity);
1620end;
1621
1622procedure TBGRACustomBitmap.ComputeImageAngleAxes(x, y, w, h,
1623  angle: single; imageCenterX, imageCenterY: single;
1624  ARestoreOffsetAfterRotation: boolean; out Origin, HAxis, VAxis: TPointF);
1625var
1626  cosa,sina: single;
1627
1628  { Compute rotated coordinates }
1629  function Coord(relX,relY: single): TPointF;
1630  begin
1631    DecF(relX, imageCenterX);
1632    DecF(relY, imageCenterY);
1633    result.x := relX*cosa - relY*sina+ x;
1634    result.y := relY*cosa + relX*sina+ y;
1635    if ARestoreOffsetAfterRotation then
1636      result.Offset(imageCenterX,imageCenterY);
1637  end;
1638
1639begin
1640  cosa := cos(-angle*Pi/180);
1641  sina := -sin(-angle*Pi/180);
1642  Origin := Coord(0,0);
1643  if w < 2 then w := 2; //when pixel size is 1, actual size is zero, so avoid that
1644  if h < 2 then h := 2;
1645  HAxis := Coord(w-1,0);
1646  VAxis := Coord(0,h-1);
1647end;
1648
1649function TBGRACustomBitmap.GetImageAngleBounds(x, y: single;
1650  Source: TBGRACustomBitmap; angle: single; imageCenterX: single;
1651  imageCenterY: single; ARestoreOffsetAfterRotation: boolean): TRect;
1652var
1653  cosa,sina: single;
1654
1655  { Compute rotated coordinates }
1656  function Coord(relX,relY: single): TPointF;
1657  begin
1658    DecF(relX, imageCenterX);
1659    DecF(relY, imageCenterY);
1660    result.x := relX*cosa - relY*sina + x;
1661    result.y := relY*cosa + relX*sina + y;
1662    if ARestoreOffsetAfterRotation then
1663      result.Offset(imageCenterX,imageCenterY);
1664  end;
1665
1666begin
1667  if (source = nil) then
1668  begin
1669    result := EmptyRect;
1670    exit;
1671  end;
1672  cosa := cos(-angle*Pi/180);
1673  sina := -sin(-angle*Pi/180);
1674  result := GetImageAffineBounds(Coord(0,0),Coord(source.Width,0),Coord(0,source.Height),source);
1675end;
1676
1677procedure TBGRACustomBitmap.Blend(AColor: TBGRAPixel;
1678  AOperation: TBlendOperation; AIgnoreDestAlpha: boolean);
1679begin
1680  BlendRect(ClipRect, AColor, AOperation, AIgnoreDestAlpha);
1681end;
1682
1683procedure TBGRACustomBitmap.BlendOver(AColor: TBGRAPixel;
1684  AOperation: TBlendOperation; AOpacity: byte; ALinearBlend: boolean; AIgnoreDestAlpha: boolean);
1685begin
1686  BlendRectOver(ClipRect, AColor, AOperation, AOpacity, ALinearBlend, AIgnoreDestAlpha);
1687end;
1688
1689procedure TBGRACustomBitmap.BlendRect(ADest: TRect; AColor: TBGRAPixel;
1690  AOperation: TBlendOperation; AIgnoreDestAlpha: boolean);
1691begin
1692  if AIgnoreDestAlpha then
1693    BlendRect(ADest, AColor, AOperation, [cAlpha])
1694    else BlendRect(ADest, AColor, AOperation, []);
1695end;
1696
1697procedure TBGRACustomBitmap.BlendRectOver(ADest: TRect; AColor: TBGRAPixel;
1698  AOperation: TBlendOperation; AOpacity: byte; ALinearBlend: boolean;
1699  AIgnoreDestAlpha: boolean);
1700begin
1701  if AIgnoreDestAlpha then
1702    BlendRectOver(ADest, AColor, AOperation, AOpacity, ALinearBlend,[cAlpha])
1703    else BlendRectOver(ADest, AColor, AOperation, AOpacity, ALinearBlend, []);
1704end;
1705
1706procedure TBGRACustomBitmap.FillMask(x, y: integer;
1707  AMask: TCustomUniversalBitmap; ATexture: IBGRAScanner; ADrawMode: TDrawMode);
1708begin
1709  FillMask(x, y, AMask, ATexture, ADrawMode, 255);
1710end;
1711
1712procedure TBGRACustomBitmap.VerticalFlip(ARect: TRect);
1713begin
1714  inherited VerticalFlip(ARect);
1715  if Assigned(XorMask) then XorMask.VerticalFlip(ARect);
1716end;
1717
1718procedure TBGRACustomBitmap.HorizontalFlip(ARect: TRect);
1719begin
1720  inherited HorizontalFlip(ARect);
1721  if Assigned(XorMask) then XorMask.HorizontalFlip(ARect);
1722end;
1723
1724procedure TBGRACustomBitmap.RotateUDInplace(ARect: TRect);
1725begin
1726  inherited RotateUDInplace(ARect);
1727  if Assigned(XorMask) then XorMask.RotateUDInplace(ARect);
1728end;
1729
1730function TBGRACustomBitmap.RotateCW: TBGRACustomBitmap;
1731begin
1732  result := TBGRACustomBitmap(Inherited RotateCW);
1733  if Assigned(XorMask) then result.FXorMask := self.XorMask.RotateCW;
1734end;
1735
1736function TBGRACustomBitmap.RotateCCW: TBGRACustomBitmap;
1737begin
1738  result := TBGRACustomBitmap(Inherited RotateCCW);
1739  if Assigned(XorMask) then result.FXorMask := self.XorMask.RotateCCW;
1740end;
1741
1742function TBGRACustomBitmap.RotateUD: TBGRACustomBitmap;
1743begin
1744  result := TBGRACustomBitmap(Inherited RotateUD);
1745  if Assigned(XorMask) then result.FXorMask := self.XorMask.RotateUD;
1746end;
1747
1748function TBGRACustomBitmap.FilterBlurRadial(radius: single;
1749  blurType: TRadialBlurType): TBGRACustomBitmap;
1750begin
1751  result := TBGRACustomBitmap(inherited FilterBlurRadial(radius, blurType));
1752end;
1753
1754function TBGRACustomBitmap.FilterBlurRadial(const ABounds: TRect; radius: single;
1755  blurType: TRadialBlurType): TBGRACustomBitmap;
1756begin
1757  result := TBGRACustomBitmap(inherited FilterBlurRadial(ABounds, radius, blurType));
1758end;
1759
1760function TBGRACustomBitmap.FilterBlurRadial(radiusX, radiusY: single;
1761  blurType: TRadialBlurType): TBGRACustomBitmap;
1762begin
1763  result := TBGRACustomBitmap(inherited FilterBlurRadial(radiusX,radiusY, blurType));
1764end;
1765
1766function TBGRACustomBitmap.FilterBlurRadial(const ABounds: TRect; radiusX,
1767  radiusY: single; blurType: TRadialBlurType): TBGRACustomBitmap;
1768begin
1769  result := TBGRACustomBitmap(inherited FilterBlurRadial(ABounds, radiusX,radiusY, blurType));
1770end;
1771
1772function TBGRACustomBitmap.FilterBlurMotion(distance: single; angle: single;
1773  oriented: boolean): TBGRACustomBitmap;
1774begin
1775  result := TBGRACustomBitmap(inherited FilterBlurMotion(distance, angle, oriented));
1776end;
1777
1778function TBGRACustomBitmap.FilterBlurMotion(const ABounds: TRect; distance: single;
1779  angle: single; oriented: boolean): TBGRACustomBitmap;
1780begin
1781  result := TBGRACustomBitmap(inherited FilterBlurMotion(ABounds, distance, angle, oriented));
1782end;
1783
1784function TBGRACustomBitmap.FilterCustomBlur(mask: TCustomUniversalBitmap
1785  ): TBGRACustomBitmap;
1786begin
1787  result := TBGRACustomBitmap(inherited FilterCustomBlur(mask));
1788end;
1789
1790function TBGRACustomBitmap.FilterCustomBlur(const ABounds: TRect;
1791  mask: TCustomUniversalBitmap): TBGRACustomBitmap;
1792begin
1793  result := TBGRACustomBitmap(inherited FilterCustomBlur(ABounds,mask));
1794end;
1795
1796function TBGRACustomBitmap.GetImageBoundsWithin(const ARect: TRect;
1797  Channel: TChannel; ANothingValue: Byte): TRect;
1798begin
1799  result := InternalGetImageBoundsWithin(self,nil,ARect,[Channel],ANothingValue);
1800end;
1801
1802function TBGRACustomBitmap.GetImageBoundsWithin(const ARect: TRect;
1803  Channels: TChannels; ANothingValue: Byte): TRect;
1804begin
1805  result := InternalGetImageBoundsWithin(self,nil,ARect,Channels,ANothingValue);
1806end;
1807
1808function TBGRACustomBitmap.ScanAtIntegerExpanded(X, Y: integer): TExpandedPixel;
1809begin
1810  result := GammaExpansion(ScanAtInteger(X,Y));
1811end;
1812
1813function TBGRACustomBitmap.ScanNextExpandedPixel: TExpandedPixel;
1814begin
1815  result := GammaExpansion(ScanNextPixel);
1816end;
1817
1818function TBGRACustomBitmap.ScanAtExpanded(X, Y: Single): TExpandedPixel;
1819begin
1820  result := GammaExpansion(ScanAt(X,Y));
1821end;
1822
1823function TBGRACustomBitmap.ProvidesScanline(ARect: TRect): boolean;
1824begin
1825  result := (ARect.Left+ScanOffset.x >= 0) and (ARect.Top+ScanOffset.y >= 0) and
1826      (ARect.Right+ScanOffset.x <= Width) and (ARect.Bottom+ScanOffset.y <= Height);
1827end;
1828
1829function TBGRACustomBitmap.GetScanlineAt(X, Y: integer): PBGRAPixel;
1830begin
1831  result := ScanLine[y+ScanOffset.y]+x+ScanOffset.x;
1832end;
1833
1834procedure TBGRACustomBitmap.ScanNextMaskChunk(var ACount: integer; out AMask: PByteMask; out AStride: integer);
1835var
1836  PPixels: Pointer;
1837begin
1838  ScanNextCustomChunk(ACount, PPixels);
1839  AMask := (PByteMask(PPixels)+TBGRAPixel_ChannelByteOffset[ScanMaskChannel]);
1840  AStride := sizeof(TBGRAPixel);
1841end;
1842
1843function TBGRACustomBitmap.ScanAtIntegerMask(X,Y: integer): TByteMask;
1844var
1845  c: TBGRAPixel;
1846begin
1847  c := ScanAtInteger(X,Y);
1848  result := (PByte(@c)+TBGRAPixel_ChannelByteOffset[ScanMaskChannel])^;
1849end;
1850
1851function TBGRACustomBitmap.ScanAtMask(X,Y: Single): TByteMask;
1852var
1853  c: TBGRAPixel;
1854begin
1855  c := ScanAt(X,Y);
1856  result := (PByte(@c)+TBGRAPixel_ChannelByteOffset[ScanMaskChannel])^;
1857end;
1858
1859{$ENDIF}
1860