// SPDX-License-Identifier: LGPL-3.0-linking-exception {$IFDEF INCLUDE_INTERFACE} {$UNDEF INCLUDE_INTERFACE} type {=== TBGRACustomBitmap ===} { TBGRACustomBitmap } {* @abstract(Base class for TBGRABitmap.) It is the direct parent of TBGRADefaultBitmap class, which is the parent of the diverse implementations. A bitmap can be used as a scanner using the IBGRAScanner interface. } TBGRACustomBitmap = class(specialize TGenericUniversalBitmap,IBGRAScanner) protected FXorMask: TBGRACustomBitmap; { accessors to properies } procedure SetXorMask(AValue: TBGRACustomBitmap); function GetAverageColor: TColor; virtual; abstract; function GetAveragePixel: TBGRAPixel; virtual; abstract; //FreePascal drawing routines {$IFDEF BGRABITMAP_USE_FPCANVAS}function GetCanvasFP: TFPImageCanvas; virtual; abstract;{$ENDIF} function GetCanvasDrawModeFP: TDrawMode; virtual; abstract; procedure SetCanvasDrawModeFP(const AValue: TDrawMode); virtual; abstract; //GUI bitmap object function GetBitmap: TBitmap; virtual; abstract; function GetCanvas: TCanvas; virtual; abstract; function GetCanvasOpacity: byte; virtual; abstract; procedure SetCanvasOpacity(AValue: byte); virtual; abstract; function GetCanvasAlphaCorrection: boolean; virtual; abstract; procedure SetCanvasAlphaCorrection(const AValue: boolean); virtual; abstract; procedure Init; override; function InternalNew: TBGRACustomBitmap; override; 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; 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; procedure InternalArcInRect(r: TRect; StartAngleRad,EndAngleRad: Single; ABorderColor : TBGRAPixel; w: single; AFillColor: TBGRAPixel; AOptions: TArcOptions; ADrawChord: boolean = false; ATexture: IBGRAScanner = nil); procedure InternalFillArcInRect(r: TRect; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel; AOptions: TArcOptions; ATexture: IBGRAScanner = nil); public {** Resample filter is used when resizing the bitmap. See [[BGRABitmap Miscellaneous types#Images and resampling|resampling types]] } ResampleFilter : TResampleFilter; {** Scan interpolation filter is used when the bitmap is used as a scanner (interface ''IBGRAScanner'') } ScanInterpolationFilter: TResampleFilter; ScanMaskChannel: TChannel; {** Cursor position for mouse pointer } HotSpot: TPoint; { ** Free reference to xor mask } procedure DiscardXorMask; virtual; { ** Allocate xor mask } procedure NeedXorMask; virtual; {** Xor mask to be applied when image is drawn } property XorMask: TBGRACustomBitmap read FXorMask write SetXorMask; {** Average color of the image } property AverageColor: TColor Read GetAverageColor; {** Average color (including alpha) of the image } property AveragePixel: TBGRAPixel Read GetAveragePixel; {** Canvas compatible with FreePascal } {$IFDEF BGRABITMAP_USE_FPCANVAS}property CanvasFP: TFPImageCanvas read GetCanvasFP;{$ENDIF} {** Draw mode to used when image is access using FreePascal functions and ''Colors'' property } property CanvasDrawModeFP: TDrawMode read GetCanvasDrawModeFP write SetCanvasDrawModeFP; {** Bitmap in a format compatible with the current GUI. Don't forget to call ''InvalidateBitmap'' before using it if you changed something with direct pixel access (''Scanline'' and ''Data'') } property Bitmap: TBitmap Read GetBitmap; {** Canvas provided by the GUI } property Canvas: TCanvas Read GetCanvas; {** Opacity to apply to changes made using GUI functions, provided ''CanvasAlphaCorrection'' is set to ''True'' } property CanvasOpacity: byte Read GetCanvasOpacity Write SetCanvasOpacity; {** Specifies if the alpha values must be corrected after GUI access to the bitmap } property CanvasAlphaCorrection: boolean Read GetCanvasAlphaCorrection Write SetCanvasAlphaCorrection; protected {----------- pen style accessors ----------------} function GetPenJoinStyle: TPenJoinStyle; virtual; abstract; procedure SetPenJoinStyle(const AValue: TPenJoinStyle); virtual; abstract; function GetPenMiterLimit: single; virtual; abstract; procedure SetPenMiterLimit(const AValue: single); virtual; abstract; function GetPenStyle: TPenStyle; virtual; abstract; procedure SetPenStyle(const AValue: TPenStyle); virtual; abstract; function GetCustomPenStyle: TBGRAPenStyle; virtual; abstract; procedure SetCustomPenStyle(const AValue: TBGRAPenStyle); virtual; abstract; function GetArrowEndRepeat: integer; virtual; abstract; function GetArrowStartRepeat: integer; virtual; abstract; procedure SetArrowEndRepeat(AValue: integer); virtual; abstract; procedure SetArrowStartRepeat(AValue: integer); virtual; abstract; function GetArrowEndOffset: single; virtual; abstract; function GetArrowStartOffset: single; virtual; abstract; procedure SetArrowEndOffset(AValue: single); virtual; abstract; procedure SetArrowStartOffset(AValue: single); virtual; abstract; function GetArrowEndSize: TPointF; virtual; abstract; function GetArrowStartSize: TPointF; virtual; abstract; procedure SetArrowEndSize(AValue: TPointF); virtual; abstract; procedure SetArrowStartSize(AValue: TPointF); virtual; abstract; public {----------- pen style ----------------} {** How to join segments. See [[BGRABitmap Types imported from Graphics|BGRAGraphics]] } property JoinStyle: TPenJoinStyle read GetPenJoinStyle Write SetPenJoinStyle; {** Limit for the extension of the segments when joining them with ''pjsMiter'' join style, expressed in multiples of the width of the pen } property JoinMiterLimit: single read GetPenMiterLimit Write SetPenMiterLimit; {** Pen style. See [[BGRABitmap Types imported from Graphics|BGRAGraphics]] } property PenStyle: TPenStyle read GetPenStyle Write SetPenStyle; {** Custom pen style. See [[BGRABitmap Geometry types|geometric types]] } property CustomPenStyle: TBGRAPenStyle read GetCustomPenStyle write SetCustomPenStyle; {** Size of arrows at the start of the line } property ArrowStartSize: TPointF read GetArrowStartSize write SetArrowStartSize; {** Size of arrows at the end of the line } property ArrowEndSize: TPointF read GetArrowEndSize write SetArrowEndSize; {** Offset of the arrow from the start of the line } property ArrowStartOffset: single read GetArrowStartOffset write SetArrowStartOffset; {** Offset of the arrow from the end of the line } property ArrowEndOffset: single read GetArrowEndOffset write SetArrowEndOffset; {** Number of times to repeat the starting arrow } property ArrowStartRepeat: integer read GetArrowStartRepeat write SetArrowStartRepeat; {** Number of times to repeat the ending arrow } property ArrowEndRepeat: integer read GetArrowEndRepeat write SetArrowEndRepeat; procedure ArrowStartAsNone; virtual; abstract; procedure ArrowStartAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); virtual; abstract; procedure ArrowStartAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); virtual; abstract; procedure ArrowStartAsTail; virtual; abstract; procedure ArrowEndAsNone; virtual; abstract; procedure ArrowEndAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); virtual; abstract; procedure ArrowEndAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); virtual; abstract; procedure ArrowEndAsTail; virtual; abstract; protected {-------------------font style accessors------------------------} function GetFontAntialias: Boolean; procedure SetFontAntialias(const AValue: Boolean); function GetFontRenderer: TBGRACustomFontRenderer; virtual; abstract; procedure SetFontRenderer(AValue: TBGRACustomFontRenderer); virtual; abstract; function GetFontHeight: integer; virtual; abstract; procedure SetFontHeight(AHeight: integer); virtual; abstract; function GetFontFullHeight: integer; virtual; abstract; procedure SetFontFullHeight(AHeight: integer); virtual; abstract; function GetFontVerticalAnchorOffset: single; virtual; abstract; function GetFontPixelMetric: TFontPixelMetric; virtual; abstract; function GetFontRightToLeftFor(AText: string): boolean; public {-------------------font style------------------------} {** Specifies the font to use. Unless the font renderer accept otherwise, the name is in human readable form, like 'Arial', 'Times New Roman', ... } FontName: string; {** Specifies the set of styles to be applied to the font. These can be ''fsBold'', ''fsItalic'', ''fsStrikeOut'', ''fsUnderline''. So the value [''fsBold'',''fsItalic''] means that the font must be bold and italic. See [[BGRABitmap Miscellaneous types|miscellaneous types]] } FontStyle: TFontStyles; {** Specifies the quality of rendering. Default value is ''fqSystem''. See [[BGRABitmap Miscellaneous types|miscellaneous types]] } FontQuality : TBGRAFontQuality; {** Specifies the rotation of the text, for functions that support text rotation. It is expressed in tenth of degrees, positive values going counter-clockwise. } FontOrientation: integer; {** Specifies how the font is vertically aligned relative to the start coordinate. See [[BGRABitmap Miscellaneous types|miscellaneous types]]} FontVerticalAnchor: TFontVerticalAnchor; {** Specifies the base direction of the text (cf Unicode). By default, it is automatically determined by the first strongly oriented character. You can specify another base direction here however it is not taken into account by the LCL on Linux. } FontBidiMode: TFontBidiMode; {** Specifies the height of the font in pixels without taking into account additional line spacing. A negative value means that it is the full height instead (see below) } property FontHeight: integer Read GetFontHeight Write SetFontHeight; {** Specifies the height of the font in pixels, taking into account the additional line spacing defined for the font } property FontFullHeight: integer read GetFontFullHeight write SetFontFullHeight; {** Simplified property to specify the quality (see ''FontQuality'') } property FontAntialias: Boolean read GetFontAntialias write SetFontAntialias; property FontVerticalAnchorOffset: single read GetFontVerticalAnchorOffset; {** Returns measurement for the current font in pixels } property FontPixelMetric: TFontPixelMetric read GetFontPixelMetric; {** Specifies the font renderer. When working with the LCL, by default it is an instance of ''TLCLFontRenderer'' of unit ''BGRAText''. Other renderers are provided in ''BGRATextFX'' unit and ''BGRAVectorize'' unit. Additionally, ''BGRAFreeType'' provides a renderer independent from the LCL. * * Once you assign a renderer, it will automatically be freed when the bitmap is freed. The renderers may provide additional styling for the font, not accessible with the properties in this class * * See [[BGRABitmap tutorial Font rendering|font rendering]]} property FontRenderer: TBGRACustomFontRenderer read GetFontRenderer write SetFontRenderer; public constructor Create(AFPImage: TFPCustomImage; ACopyProperties: Boolean=False); overload; virtual; abstract; constructor Create(ABitmap: TBitmap); overload; virtual; abstract; constructor Create(ABitmap: TBitmap; AUseTransparent: boolean); overload; virtual; abstract; constructor Create(AFilename: string); overload; virtual; abstract; constructor Create(AFilename: string; AIsUtf8Filename: boolean); overload; virtual; abstract; constructor Create(AFilename: string; AIsUtf8Filename: boolean; AOptions: TBGRALoadingOptions); overload; virtual; abstract; constructor Create(AStream: TStream); overload; virtual; abstract; function NewBitmap: TBGRACustomBitmap; overload; override; function NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap; overload; override; function NewBitmap(AWidth, AHeight: integer; const Color: TBGRAPixel): TBGRACustomBitmap; overload; override; function NewBitmap(AWidth, AHeight: integer; AColor: Pointer): TBGRACustomBitmap; overload; override; function NewBitmap(Filename: string): TBGRACustomBitmap; overload; virtual; abstract; function NewBitmap(Filename: string; AIsUtf8: boolean): TBGRACustomBitmap; overload; virtual; abstract; function NewBitmap(Filename: string; AIsUtf8: boolean; AOptions: TBGRALoadingOptions): TBGRACustomBitmap; overload; virtual; abstract; function NewBitmap(AFPImage: TFPCustomImage): TBGRACustomBitmap; overload; virtual; abstract; procedure LoadFromStream(AStream: TStream; AHandler: TFPCustomImageReader; AOptions: TBGRALoadingOptions); override; {==== Reference counting ====} {** Adds a reference (this reference count is not the same as the reference count of an interface, it changes only by explicit calls) } function NewReference: TBGRACustomBitmap; override; {** Returns an object with a reference count equal to 1. Duplicate this bitmap if necessary } function GetUnique: TBGRACustomBitmap; override; function Duplicate(DuplicateProperties: Boolean = False): TBGRACustomBitmap; overload; override; function Duplicate(DuplicateProperties, DuplicateXorMask: Boolean): TBGRACustomBitmap; overload; virtual; procedure CopyPropertiesTo(ABitmap: TCustomUniversalBitmap); override; function GetPart(const ARect: TRect; ACopyProperties: Boolean=False): TBGRACustomBitmap; override; function CreateBrushTexture(ABrushStyle: TBrushStyle; APatternColor, ABackgroundColor: TBGRAPixel; AWidth: integer = 8; AHeight: integer = 8; APenWidth: single = 1): TBGRACustomBitmap; override; {** Can only be called with an existing instance of ''TBGRACustomBitmap''. Sets the dimensions of an existing ''TBGRACustomBitmap'' instance. } procedure SetSize(AWidth, AHeight: integer); override; {==== Retrieve image from system ====} {** Gets the content of the specified device context } procedure LoadFromDevice(DC: HDC); overload; virtual; abstract; {** Gets the content from the specified rectangular area of a device context } procedure LoadFromDevice(DC: HDC; ARect: TRect); overload; virtual; abstract; {** Fills the content with a screenshot of the primary monitor } procedure TakeScreenshotOfPrimaryMonitor; virtual; abstract; {** Fills the content with a screenshot of the specified rectangular area of the desktop (it can be from any screen) } procedure TakeScreenshot(ARect: TRect); virtual; abstract; {** For more methods, see derived class [[TBGRABitmap class|TBGRABitmap]] } {==== Drawing functions ====} {Pixel functions} procedure SetPixel(x, y: int32or64; c: TColor); overload; virtual; abstract; procedure XorPixel(x, y: int32or64; const c: TBGRAPixel); overload; virtual; abstract; procedure DrawPixel(x, y: int32or64; const c: TBGRAPixel; ADrawMode: TDrawMode); overload; override; procedure FastBlendPixel(x, y: int32or64; const c: TBGRAPixel); virtual; abstract; function GetPixel256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; virtual; abstract; function GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; overload; virtual; abstract; function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; overload; virtual; abstract; function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; overload; virtual; abstract; function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; overload; virtual; abstract; function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; overload; virtual; abstract; {Line primitives} procedure XorHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; procedure DrawHorizLine(x, y, x2: int32or64; ec: TExpandedPixel); overload; virtual; abstract; procedure DrawHorizLine(x, y, x2: int32or64; texture: IBGRAScanner); overload; procedure FastBlendHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; procedure DrawHorizLineDiff(x, y, x2: int32or64; c, compare: TBGRAPixel; maxDiff: byte); virtual; abstract; procedure HorizLineDiff(x, y, x2: int32or64; const ABrush: TUniversalBrush; ACompare: TBGRAPixel; AMaxDiffW: word); virtual; abstract; procedure XorVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; procedure DrawVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; procedure FastBlendVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; {==== Rectangles, ellipses and path (floating point coordinates) ====} {* These functions use the current pen style/cap/join. The parameter ''w'' specifies the width of the line and the base unit for dashes * The coordinates are pixel-centered, so that when filling a rectangle, if the supplied values are integers, the border will be half transparent. If you want the border to be completely filled, you can subtract/add 0.5 to the coordinates to include the remaining thin border. See [[BGRABitmap tutorial 13|coordinate system]]. } {==== Multi-shape fill ====} {** Draws and fill a polyline using current pen style/cap/join in one go. The stroke is stricly over the fill even if partially transparent. ''fillcolor'' specifies a color to fill the polygon formed by the points } procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); overload; virtual; abstract; {** Draws a filled polygon using current pen style/cap/join in one go. The stroke is stricly over the fill even if partially transparent. The polygon is always closed. You don't need to set the last point to be the same as the first point. } procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); overload; virtual; abstract; procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single; back: TBGRAPixel); overload; virtual; abstract; procedure EllipseAntialias(AOrigin, AXAxis, AYAxis: TPointF; c: TBGRAPixel; w: single; back: TBGRAPixel); overload; virtual; abstract; procedure DrawPath(APath: IBGRAPath; AStrokeColor: TBGRAPixel; AWidth: single; AFillColor: TBGRAPixel); overload; virtual; abstract; procedure DrawPath(APath: IBGRAPath; AStrokeTexture: IBGRAScanner; AWidth: single; AFillColor: TBGRAPixel); overload; virtual; abstract; procedure DrawPath(APath: IBGRAPath; AStrokeColor: TBGRAPixel; AWidth: single; AFillTexture: IBGRAScanner); overload; virtual; abstract; procedure DrawPath(APath: IBGRAPath; AStrokeTexture: IBGRAScanner; AWidth: single; AFillTexture: IBGRAScanner); overload; virtual; abstract; procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeColor: TBGRAPixel; AWidth: single; AFillColor: TBGRAPixel); overload; virtual; abstract; procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeTexture: IBGRAScanner; AWidth: single; AFillColor: TBGRAPixel); overload; virtual; abstract; procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeColor: TBGRAPixel; AWidth: single; AFillTexture: IBGRAScanner); overload; virtual; abstract; procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeTexture: IBGRAScanner; AWidth: single; AFillTexture: IBGRAScanner); overload; virtual; abstract; {==== Gradient/textured polygons ====} procedure FillTriangleLinearColor(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); overload; virtual; abstract; procedure FillTriangleLinearColorAntialias(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); overload; virtual; abstract; procedure FillTriangleLinearMapping(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; TextureInterpolation: Boolean= True); overload; virtual; abstract; {$IFNDEF BGRABITMAP_CORE}{ Fills a triangle with linear mapping of a texture and lightness } procedure FillTriangleLinearMappingLightness(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; light1,light2,light3: word; TextureInterpolation: Boolean= True); overload; virtual; abstract; {$ENDIF} procedure FillTriangleLinearMappingAntialias(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF); overload; virtual; abstract; procedure FillQuadLinearColor(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); overload; virtual; abstract; procedure FillQuadLinearColorAntialias(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); overload; virtual; abstract; 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; {$IFNDEF BGRABITMAP_CORE}{ Fills a quadrilateral with linear mapping and lightness } 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;{$ENDIF} procedure FillQuadLinearMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACulling: TFaceCulling = fcNone); overload; virtual; abstract; procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ADrawMode: TDrawMode = dmDrawWithTransparency); overload; virtual; abstract; procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect; ADrawMode: TDrawMode = dmDrawWithTransparency); overload; virtual; abstract; procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); overload; virtual; abstract; procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); overload; virtual; abstract; procedure FillQuadAffineMapping(Orig,HAxis,VAxis: TPointF; AImage: TBGRACustomBitmap; APixelCenteredCoordinates: boolean = true; ADrawMode: TDrawMode = dmDrawWithTransparency; AOpacity: byte = 255); virtual; abstract; procedure FillQuadAffineMappingAntialias(Orig,HAxis,VAxis: TPointF; AImage: TBGRACustomBitmap; APixelCenteredCoordinates: boolean = true; AOpacity: byte = 255); virtual; abstract; procedure FillEllipseLinearColorAntialias(x, y, rx, ry: single; outercolor, innercolor: TBGRAPixel); overload; virtual; abstract; procedure FillEllipseLinearColorAntialias(AOrigin, AXAxis, AYAxis: TPointF; outercolor, innercolor: TBGRAPixel); overload; virtual; abstract; {$IFNDEF BGRABITMAP_CORE} procedure FillPolyLinearColor(const points: array of TPointF; AColors: array of TBGRAPixel); overload; virtual; abstract; procedure FillPolyLinearMapping(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean); overload; virtual; abstract; procedure FillPolyLinearMappingLightness(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; lightnesses: array of word; TextureInterpolation: Boolean); overload; virtual; abstract; 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; 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; {$ENDIF} procedure Arc(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; AColor: TBGRAPixel; w: single; ADrawChord: boolean; AFillColor: TBGRAPixel); overload; procedure Arc(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; AColor: TBGRAPixel; w: single; ADrawChord: boolean; AFillColor: TBGRAPixel); overload; procedure FillChord(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; AFillColor: TBGRAPixel); overload; procedure FillChord(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel); overload; procedure FillChord(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; texture: IBGRAScanner); overload; procedure FillChord(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; texture: IBGRAScanner); overload; procedure FillChordInRect(const ARect: TRect; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel); overload; procedure FillChordInRect(const ARect: TRect; StartAngleRad,EndAngleRad: Single; texture: IBGRAScanner); overload; procedure Pie(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; AColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel); overload; procedure Pie(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; AColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel); overload; procedure FillPie(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; AFillColor: TBGRAPixel); overload; procedure FillPie(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel); overload; procedure FillPie(cx,cy,rx,ry: single; const StartPoint,EndPoint: TPointF; texture: IBGRAScanner); overload; procedure FillPie(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; texture: IBGRAScanner); overload; procedure FillPieInRect(const ARect: TRect; StartAngleRad,EndAngleRad: Single; AFillColor: TBGRAPixel); overload; procedure FillPieInRect(const ARect: TRect; StartAngleRad,EndAngleRad: Single; texture: IBGRAScanner); overload; procedure RectangleAntialias(x, y, x2, y2: single; c: TBGRAPixel; w: single; back: TBGRAPixel); overload; virtual; abstract; procedure RectangleWithin(x1,y1,x2,y2: single; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; APixelCenteredCoordinates: boolean = true); overload; procedure RectangleWithin(r: TRect; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel); overload; procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; w: single; options: TRoundRectangleOptions = []); overload; virtual; abstract; procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; pencolor: TBGRAPixel; w: single; fillcolor: TBGRAPixel; options: TRoundRectangleOptions = []); overload; virtual; abstract; procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; penTexture: IBGRAScanner; w: single; fillTexture: IBGRAScanner; options: TRoundRectangleOptions = []); overload; virtual; abstract; procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; w: single; options: TRoundRectangleOptions = []); overload; virtual; abstract; {** Fills completely a rectangle, without any border, with the specified ''texture'' and with the specified ''mode'' and optional dithering algorithm } procedure FillRect(r: TRect; texture: IBGRAScanner; mode: TDrawMode; ditheringAlgorithm: TDitheringAlgorithm); overload; virtual; procedure FillRect(r: TRect; texture: IBGRAScanner; mode: TDrawMode; AScanOffset: TPoint; ditheringAlgorithm: TDitheringAlgorithm); overload; virtual; procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode; ditheringAlgorithm: TDitheringAlgorithm); overload; virtual; procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode; AScanOffset: TPoint; ditheringAlgorithm: TDitheringAlgorithm); overload; virtual; abstract; procedure TextOutCurved(ACursor: TBGRACustomPathCursor; const sUTF8: string; AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; abstract; procedure TextOutCurved(ACursor: TBGRACustomPathCursor; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; abstract; procedure TextOutCurved(APath: IBGRAPath; const sUTF8: string; AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; procedure TextOutCurved(APath: IBGRAPath; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; procedure TextRect(ARect: TRect; x, y: integer; const sUTF8: string; style: TTextStyle; c: TBGRAPixel); overload; virtual; abstract; procedure TextRect(ARect: TRect; x, y: integer; const sUTF8: string; style: TTextStyle; texture: IBGRAScanner); overload; virtual; abstract; {$IFNDEF BGRABITMAP_CORE} { Draw text taking into account line endings, filling it with a solid color } procedure TextMultiline(x,y: single; const sUTF8: string; c: TBGRAPixel; AAlign: TBidiTextAlignment = btaLeftJustify; AVertAlign: TTextLayout = tlTop; AParagraphSpacing: single = 0); overload; { Draw text taking into account line endings, filling it with a texture } procedure TextMultiline(x,y: single; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TBidiTextAlignment = btaLeftJustify; AVertAlign: TTextLayout = tlTop; AParagraphSpacing: single = 0); overload; { Draw text with line breaks, filling it with a solid color } procedure TextMultiline(ALeft,ATop,AWidth: single; const sUTF8: string; c: TBGRAPixel; AAlign: TBidiTextAlignment = btaNatural; AVertAlign: TTextLayout = tlTop; AParagraphSpacing: single = 0); overload; virtual; abstract; { Draw text with line breaks, filling it with a texture } procedure TextMultiline(ALeft,ATop,AWidth: single; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TBidiTextAlignment = btaNatural; AVertAlign: TTextLayout = tlTop; AParagraphSpacing: single = 0); overload; virtual; abstract; {$ENDIF} function TextSize(const sUTF8: string): TSize; overload; virtual; abstract; function TextAffineBox(const sUTF8: string): TAffineBox; virtual; abstract; function TextSize(const sUTF8: string; AMaxWidth: integer): TSize; overload; virtual; abstract; function TextSize(const sUTF8: string; AMaxWidth: integer; ARightToLeft: boolean): TSize; overload; virtual; abstract; function TextFitInfo(const sUTF8: string; AMaxWidth: integer): integer; virtual; abstract; {$IFNDEF BGRABITMAP_CORE}{ Returns the total size of the string provided using the current font and taking into account line breaks. } function TextSizeMultiline(const sUTF8: string; AMaxWidth: single = EmptySingle; AParagraphSpacing: single = 0): TSize; virtual; abstract;{$ENDIF} { 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. The value of FontOrientation is taken into account, so that the text may be rotated. } procedure TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel; align: TAlignment); overload; virtual; procedure TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner; align: TAlignment); overload; virtual; procedure TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel); overload; virtual; procedure TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel; ARightToLeft: boolean); overload; virtual; procedure TextOut(x, y: single; const sUTF8: string; c: TColor); overload; virtual; procedure TextOut(x, y: single; const sUTF8: string; c: TColor; ARightToLeft: boolean); overload; virtual; procedure TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner); overload; virtual; procedure TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner; ARightToLeft: boolean); overload; virtual; procedure TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel; align: TAlignment; ARightToLeft: boolean); overload; virtual; abstract; procedure TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner; align: TAlignment; ARightToLeft: boolean); overload; virtual; abstract; procedure TextOut(x, y: single; const sUTF8: string; AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; abstract; procedure TextOut(x, y: single; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single); overload; virtual; abstract; { Overrides the font orientation with the parameter orientationTenthDegCCW } procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel); overload; virtual; procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel; align: TAlignment); overload; virtual; procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel; align: TAlignment; ARightToLeft: boolean); overload; virtual; abstract; procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner); overload; virtual; procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner; align: TAlignment); overload; virtual; procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner; align: TAlignment; ARightToLeft: boolean); overload; virtual; abstract; { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary. The position depends on the specified horizontal alignment halign and vertical alignement valign. The color c or texture is used to fill the text. No rotation is applied. } procedure TextRect(ARect: TRect; const sUTF8: string; halign: TAlignment; valign: TTextLayout; c: TBGRAPixel); overload; virtual; procedure TextRect(ARect: TRect; const sUTF8: string; halign: TAlignment; valign: TTextLayout; texture: IBGRAScanner); overload; virtual; //-------------------------- computing path ------------------------------------ {Spline} function ComputeClosedSpline(const APoints: array of TPointF; AStyle: TSplineStyle): ArrayOfTPointF; virtual; abstract; function ComputeOpenedSpline(const APoints: array of TPointF; AStyle: TSplineStyle): ArrayOfTPointF; virtual; abstract; function ComputeBezierCurve(const curve: TCubicBezierCurve): ArrayOfTPointF; overload; virtual; abstract; function ComputeBezierCurve(const curve: TQuadraticBezierCurve): ArrayOfTPointF; overload; virtual; abstract; function ComputeBezierSpline(const spline: array of TCubicBezierCurve): ArrayOfTPointF; overload; virtual; abstract; function ComputeBezierSpline(const spline: array of TQuadraticBezierCurve): ArrayOfTPointF; overload; virtual; abstract; {can be accessed via Pen property} function ComputeWidePolyline(const points: array of TPointF; w: single): ArrayOfTPointF; overload; virtual; abstract; function ComputeWidePolyline(const points: array of TPointF; w: single; ClosedCap: boolean): ArrayOfTPointF; overload; virtual; abstract; function ComputeWidePolygon(const points: array of TPointF; w: single): ArrayOfTPointF; virtual; abstract; function ComputeEllipse(x,y,rx,ry: single): ArrayOfTPointF; overload; deprecated; function ComputeEllipse(x,y,rx,ry,w: single): ArrayOfTPointF; overload; deprecated; function ComputeEllipseContour(x,y,rx,ry: single; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract; function ComputeEllipseContour(AOrigin, AXAxis, AYAxis: TPointF; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract; function ComputeEllipseBorder(x,y,rx,ry,w: single; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract; function ComputeEllipseBorder(AOrigin, AXAxis, AYAxis: TPointF; w: single; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract; function ComputeArc65536(x,y,rx,ry: single; start65536,end65536: word; quality: single = 1): ArrayOfTPointF; virtual; abstract; function ComputeArcRad(x,y,rx,ry: single; startRad,endRad: single; quality: single = 1): ArrayOfTPointF; virtual; abstract; function ComputeRoundRect(x1,y1,x2,y2,rx,ry: single; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract; function ComputeRoundRect(x1,y1,x2,y2,rx,ry: single; options: TRoundRectangleOptions; quality: single = 1): ArrayOfTPointF; overload; virtual; abstract; function ComputePie65536(x,y,rx,ry: single; start65536,end65536: word; quality: single = 1): ArrayOfTPointF; virtual; abstract; function ComputePieRad(x,y,rx,ry: single; startRad,endRad: single; quality: single = 1): ArrayOfTPointF; virtual; abstract; {Filling} // compatibility: take into account ClipRect procedure Fill(texture: IBGRAScanner); overload; virtual; procedure Fill(texture: IBGRAScanner; mode: TDrawMode); overload; override; procedure Fill(c: TBGRAPixel; start, Count: integer); overload; virtual; abstract; procedure DrawPixels(c: TBGRAPixel; start, Count: integer); virtual; abstract; procedure AlphaFill(alpha: byte; start, Count: integer); overload; virtual; abstract; procedure ReplaceColor(before, after: TColor); overload; virtual; abstract; procedure ReplaceColor(ARect: TRect; before, after: TColor); overload; virtual; abstract; procedure FloodFill(X, Y: integer; Color: TBGRAPixel; mode: TFloodfillMode; Tolerance: byte = 0); overload; virtual; procedure FloodFill(X, Y: integer; const Brush: TUniversalBrush; Progressive: boolean; ToleranceW: Word = $00ff); overload; virtual; procedure ParallelFloodFill(X, Y: integer; Dest: TCustomUniversalBitmap; Color: TBGRAPixel; mode: TFloodfillMode; Tolerance: byte = 0; DestOfsX: integer = 0; DestOfsY: integer = 0); overload; virtual; abstract; procedure ParallelFloodFill(X, Y: integer; Dest: TCustomUniversalBitmap; const Brush: TUniversalBrush; Progressive: boolean; ToleranceW: Word = $00ff; DestOfsX: integer = 0; DestOfsY: integer = 0); overload; virtual; abstract; procedure GradientFill(x, y, x2, y2: integer; c1, c2: TBGRAPixel; gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode; gammaColorCorrection: boolean = True; Sinus: Boolean=False; ditherAlgo: TDitheringAlgorithm = daNearestNeighbor); overload; virtual; abstract; procedure GradientFill(x, y, x2, y2: integer; gradient: TBGRACustomGradient; gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode; Sinus: Boolean=False; ditherAlgo: TDitheringAlgorithm = daNearestNeighbor); overload; virtual; abstract; {Canvas drawing functions} procedure DataDrawTransparent(ACanvas: TCanvas; Rect: TRect; AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer); virtual; abstract; procedure DataDrawOpaque(ACanvas: TCanvas; ARect: TRect; AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer); virtual; abstract; procedure GetImageFromCanvas(CanvasSource: TCanvas; x, y: integer); virtual; abstract; procedure Draw(ACanvas: TCanvas; x, y: integer; Opaque: boolean = True); overload; virtual; abstract; procedure Draw(ACanvas: TCanvas; Rect: TRect; Opaque: boolean = True); overload; virtual; abstract; procedure DrawPart(ARect: TRect; ACanvas: TCanvas; x, y: integer; Opaque: boolean); overload; virtual; procedure DrawPart(ARect: TRect; ACanvas: TCanvas; ATargetRect: TRect; Opaque: boolean); overload; virtual; function GetPtrBitmap(Top,Bottom: Integer): TBGRACustomBitmap; virtual; abstract; function MakeBitmapCopy(BackgroundColor: TColor; AMasked: boolean = False): TBitmap; virtual; abstract; {BGRA bitmap functions} procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadePosition: byte; mode: TDrawMode = dmDrawWithTransparency); overload; virtual; abstract; procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadeMask: IBGRAScanner; mode: TDrawMode = dmDrawWithTransparency); overload; virtual; abstract; procedure PutImage(x, y: integer; Source: TBitmap; mode: TDrawMode; AOpacity: byte = 255); overload; procedure StretchPutImage(ARect: TRect; Source: TBitmap; mode: TDrawMode; AOpacity: byte = 255); overload; procedure StretchPutImage(ARect: TRect; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); overload; virtual; abstract; procedure StretchPutImageProportionally(ARect: TRect; AHorizAlign: TAlignment; AVertAlign: TTextLayout; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255; ACover: boolean = false); procedure PutImageSubpixel(x, y: single; Source: TBGRACustomBitmap; AOpacity: byte = 255); procedure PutImagePart(x,y: integer; Source: TBGRACustomBitmap; SourceRect: TRect; mode: TDrawMode; AOpacity: byte = 255); procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload; procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte=255); overload; procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); overload; procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); overload; procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload; procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOpacity: Byte=255; ACorrectBlur: Boolean = false; APixelCenteredCoords: boolean = true); overload; procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte=255; APixelCenteredCoords: boolean = true); overload; procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255; APixelCenteredCoords: boolean = true); overload; procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255; APixelCenteredCoords: boolean = true); overload; virtual; abstract; procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte=255; ACorrectBlur: Boolean = false; APixelCenteredCoords: boolean = true); overload; function GetImageAffineBounds(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap): TRect; overload; function GetImageAffineBounds(Origin,HAxis,VAxis: TPointF; ASourceWidth, ASourceHeight: integer; const ASourceBounds: TRect; AClipOutput: boolean = true): TRect; overload; function GetImageAffineBounds(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; APixelCenteredCoords: boolean = true): TRect; overload; function GetImageAffineBounds(AMatrix: TAffineMatrix; ASourceBounds: TRect; AClipOutput: boolean = true; APixelCenteredCoords: boolean = true): TRect; overload; virtual; abstract; class function IsAffineRoughlyTranslation(AMatrix: TAffineMatrix; ASourceBounds: TRect): boolean; virtual; abstract; 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; 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; 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; procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AResampleFilter: TResampleFilter; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false); overload; procedure ComputeImageAngleAxes(x,y,w,h,angle: single; imageCenterX,imageCenterY: single; ARestoreOffsetAfterRotation: boolean; out Origin,HAxis,VAxis: TPointF); function GetImageAngleBounds(x,y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single = 0; imageCenterY: single = 0; ARestoreOffsetAfterRotation: boolean = false): TRect; procedure Blend(AColor: TBGRAPixel; AOperation: TBlendOperation; AIgnoreDestAlpha: boolean = false); virtual; procedure BlendOver(AColor: TBGRAPixel; AOperation: TBlendOperation; AOpacity: byte = 255; ALinearBlend: boolean = false; AIgnoreDestAlpha: boolean = false); virtual; procedure BlendRect(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AIgnoreDestAlpha: boolean = false); overload; procedure BlendRect(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AExcludeChannels: TChannels); overload; virtual; abstract; procedure BlendRectOver(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AOpacity: byte = 255; ALinearBlend: boolean = false; AIgnoreDestAlpha: boolean = false); overload; procedure BlendRectOver(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AOpacity: byte; ALinearBlend: boolean; AExcludeChannels: TChannels); overload; virtual; abstract; procedure BlendImage(x, y: integer; ASource: TBGRACustomBitmap; AOperation: TBlendOperation); overload; virtual; abstract; procedure BlendImage(ADest: TRect; ASource: IBGRAScanner; AOffsetX, AOffsetY: integer; AOperation: TBlendOperation); overload; virtual; abstract; procedure BlendImageOver(x, y: integer; ASource: TBGRACustomBitmap; AOperation: TBlendOperation; AOpacity: byte = 255; ALinearBlend: boolean = false); overload; virtual; abstract; procedure BlendImageOver(ADest: TRect; ASource: IBGRAScanner; AOffsetX, AOffsetY: integer; AOperation: TBlendOperation; AOpacity: byte = 255; ALinearBlend: boolean = false); overload; virtual; abstract; function Resample(newWidth, newHeight: integer; mode: TResampleMode = rmFineResample; ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; //masks procedure FillMask(x,y: integer; AMask: TCustomUniversalBitmap; ATexture: IBGRAScanner; ADrawMode: TDrawMode); overload; override; procedure FillMask(x,y: integer; AMask: TCustomUniversalBitmap; ATexture: IBGRAScanner; ADrawMode: TDrawMode; AOpacity: byte); overload; virtual; abstract; procedure EraseMask(x,y: integer; AMask: TBGRACustomBitmap; alpha: byte=255); virtual; abstract; procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ARGBOrder: boolean = true); overload; virtual; abstract; procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ARGBOrder: boolean = true); overload; virtual; abstract; function GetMaskFromAlpha: TBGRACustomBitmap; virtual; abstract; function GetImageBoundsWithin(const ARect: TRect; Channel: TChannel = cAlpha; ANothingValue: Byte = 0): TRect; overload; override; function GetImageBoundsWithin(const ARect: TRect; Channels: TChannels; ANothingValue: Byte = 0): TRect; overload; override; {inplace filters} procedure Negative; virtual; abstract; procedure NegativeRect(ABounds: TRect); virtual; abstract; procedure LinearNegative; virtual; abstract; procedure LinearNegativeRect(ABounds: TRect); virtual; abstract; procedure InplaceGrayscale(AGammaCorrection: boolean = true); overload; virtual; abstract; procedure InplaceGrayscale(ABounds: TRect; AGammaCorrection: boolean = true); overload; virtual; abstract; procedure InplaceNormalize(AEachChannel: boolean = True); overload; virtual; abstract; procedure InplaceNormalize(ABounds: TRect; AEachChannel: boolean = True); overload; virtual; abstract; procedure ConvertToLinearRGB; virtual; abstract; procedure ConvertFromLinearRGB; virtual; abstract; procedure SwapRedBlue; overload; virtual; abstract; procedure SwapRedBlue(ARect: TRect); overload; virtual; abstract; procedure GrayscaleToAlpha; virtual; abstract; procedure AlphaToGrayscale; virtual; abstract; procedure VerticalFlip(ARect: TRect); overload; override; procedure HorizontalFlip(ARect: TRect); overload; override; procedure RotateUDInplace(ARect: TRect); overload; override; {Filters} function RotateCW(ACopyProperties: Boolean=False): TBGRACustomBitmap; override; function RotateCCW(ACopyProperties: Boolean=False): TBGRACustomBitmap; override; function RotateUD(ACopyProperties: Boolean=False): TBGRACustomBitmap; override; {$IFNDEF BGRABITMAP_CORE} function FilterSmartZoom3(Option: TMedianOption; ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; function FilterMedian(Option: TMedianOption; ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; function FilterSmooth(ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; function FilterSharpen(Amount: single = 1; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterSharpen(ABounds: TRect; Amount: single = 1; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterContour(AGammaCorrection: boolean = false; ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; function FilterPixelate(pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear; ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; function FilterBlurRadial(radius: single; blurType: TRadialBlurType; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; override; function FilterBlurRadial(const ABounds: TRect; radius: single; blurType: TRadialBlurType; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; override; function FilterBlurRadial(radiusX, radiusY: single; blurType: TRadialBlurType; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; override; function FilterBlurRadial(const ABounds: TRect; radiusX, radiusY: single; blurType: TRadialBlurType; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; override; function FilterBlurMotion(distance: single; angle: single; oriented: boolean; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; override; function FilterBlurMotion(const ABounds: TRect; distance: single; angle: single; oriented: boolean; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; override; function FilterCustomBlur(mask: TCustomUniversalBitmap; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; override; function FilterCustomBlur(const ABounds: TRect; mask: TCustomUniversalBitmap; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; override; function FilterEmboss(angle: single; AStrength: integer= 64; AOptions: TEmbossOptions = []; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterEmboss(angle: single; ABounds: TRect; AStrength: integer= 64; AOptions: TEmbossOptions = []; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterEmbossHighlight(FillSelection: boolean; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel; var Offset: TPoint; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterGrayscale(ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterGrayscale(ABounds: TRect; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterNormalize(eachChannel: boolean = True; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterNormalize(ABounds: TRect; eachChannel: boolean = True; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterRotate(origin: TPointF; angle: single; correctBlur: boolean = false; ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; function FilterAffine(AMatrix: TAffineMatrix; correctBlur: boolean = false; ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; function FilterSphere(ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; function FilterTwirl(ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterTwirl(ABounds: TRect; ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3; ACopyProperties: Boolean=False): TBGRACustomBitmap; overload; virtual; abstract; function FilterCylinder(ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; function FilterPlane(ACopyProperties: Boolean=False): TBGRACustomBitmap; virtual; abstract; {$ENDIF} //IBGRAScanner function ScanAtIntegerExpanded(X,Y: integer): TExpandedPixel; override; function ScanNextExpandedPixel: TExpandedPixel; override; function ScanAtExpanded(X,Y: Single): TExpandedPixel; override; function ProvidesScanline(ARect: TRect): boolean; override; function GetScanlineAt(X, Y: integer): PBGRAPixel; override; procedure ScanNextMaskChunk(var ACount: integer; out AMask: PByteMask; out AStride: integer); override; function ScanAtIntegerMask(X,Y: integer): TByteMask; override; function ScanAtMask(X,Y: Single): TByteMask; override; end; type TBGRABitmapAny = class of TBGRACustomBitmap; //used to create instances of the same type (see NewBitmap) var BGRABitmapFactory : TBGRABitmapAny; {$ENDIF} {$IFDEF INCLUDE_IMPLEMENTATION} {$UNDEF INCLUDE_IMPLEMENTATION} function InternalGetImageBoundsWithin(ASourceBitmap: TBGRACustomBitmap; ASourceTexture: IBGRAScanner; const ARect: TRect; Channels: TChannels; ANothingValue: Byte): TRect; var minx, miny, maxx, maxy: integer; xb, xb2, yb: integer; p: PLongWord; colorMask, colorZeros: LongWord; actualRect: TRect; pixelBuffer: TBGRAPixelBuffer; begin pixelBuffer := nil; if ASourceBitmap <> nil then begin actualRect := TRect.Intersect(ARect, rect(0,0,ASourceBitmap.Width,ASourceBitmap.Height)); end else if ASourceTexture <> nil then begin actualRect := ARect; AllocateBGRAPixelBuffer(pixelBuffer, ARect.Right-ARect.Left) end else begin result := EmptyRect; exit; end; maxx := actualRect.Left-1; maxy := actualRect.Top-1; minx := actualRect.Right; miny := actualRect.Bottom; colorMask := 0; colorZeros := 0; if cBlue in Channels then begin colorMask := colorMask or LongWord(BGRA(0,0,255,0)); colorZeros:= colorZeros or LongWord(BGRA(0,0,ANothingValue,0)); end; if cGreen in Channels then begin colorMask := colorMask or LongWord(BGRA(0,255,0,0)); colorZeros:= colorZeros or LongWord(BGRA(0,ANothingValue,0,0)); end; if cRed in Channels then begin colorMask := colorMask or LongWord(BGRA(255,0,0,0)); colorZeros:= colorZeros or LongWord(BGRA(ANothingValue,0,0,0)); end; if cAlpha in Channels then begin colorMask := colorMask or LongWord(BGRA(0,0,0,255)); colorZeros:= colorZeros or LongWord(BGRA(0,0,0,ANothingValue)); end; colorMask := NtoLE(colorMask); colorZeros := NtoLE(colorZeros); for yb := actualRect.Top to actualRect.Bottom-1 do begin if ASourceBitmap <> nil then p := PLongWord(ASourceBitmap.ScanLine[yb])+actualRect.Left else begin p := @pixelBuffer[0]; ASourceTexture.ScanMoveTo(actualRect.Left,actualRect.Top); ASourceTexture.ScanPutPixels(PBGRAPixel(p),ARect.Right-ARect.Left, dmSet); end; for xb := actualRect.Left to actualRect.Right - 1 do begin if (p^ and colorMask) <> colorZeros then begin if xb < minx then minx := xb; if yb < miny then miny := yb; if xb > maxx then maxx := xb; if yb > maxy then maxy := yb; inc(p, actualRect.Right-1-xb); for xb2 := actualRect.Right-1 downto xb+1 do begin if (p^ and colorMask) <> colorZeros then begin if xb2 > maxx then maxx := xb2; break; end; dec(p); end; break; end; Inc(p); end; end; if minx > maxx then begin Result.left := 0; Result.top := 0; Result.right := 0; Result.bottom := 0; end else begin Result.left := minx; Result.top := miny; Result.right := maxx + 1; Result.bottom := maxy + 1; end; end; { TBGRACustomBitmap } function TBGRACustomBitmap.GetFontAntialias: Boolean; begin result := FontQuality <> fqSystem; end; procedure TBGRACustomBitmap.SetFontAntialias(const AValue: Boolean); begin if AValue and not FontAntialias then FontQuality := fqFineAntialiasing else if not AValue and (FontQuality <> fqSystem) then FontQuality := fqSystem; end; procedure TBGRACustomBitmap.SetXorMask(AValue: TBGRACustomBitmap); begin if FXorMask=AValue then Exit; if (AValue.Width <> Width) or (AValue.Height <> Height) then raise exception.Create('Dimension mismatch'); DiscardXorMask; FXorMask:=AValue; end; procedure TBGRACustomBitmap.Init; begin inherited Init; ScanMaskChannel:= cGreen; end; function TBGRACustomBitmap.GetFontRightToLeftFor(AText: string): boolean; begin case FontBidiMode of fbmAuto: result := IsRightToLeftUTF8(AText); fbmRightToLeft: result := true; else {fbmLeftToRight} result := false; end; end; function TBGRACustomBitmap.NewBitmap: TBGRACustomBitmap; begin Result:=inherited NewBitmap as TBGRACustomBitmap; end; function TBGRACustomBitmap.NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap; begin Result:=inherited NewBitmap(AWidth, AHeight) as TBGRACustomBitmap; end; function TBGRACustomBitmap.NewBitmap(AWidth, AHeight: integer; const Color: TBGRAPixel): TBGRACustomBitmap; begin Result:=inherited NewBitmap(AWidth, AHeight, Color) as TBGRACustomBitmap; end; function TBGRACustomBitmap.NewBitmap(AWidth, AHeight: integer; AColor: Pointer ): TBGRACustomBitmap; begin Result:=inherited NewBitmap(AWidth, AHeight, AColor) as TBGRACustomBitmap; end; function TBGRACustomBitmap.InternalNew: TBGRACustomBitmap; begin Result:= BGRABitmapFactory.Create; end; procedure TBGRACustomBitmap.DiscardXorMask; begin if Assigned(FXorMask) then begin if FXorMask is TBGRACustomBitmap then begin TBGRACustomBitmap(FXorMask).FreeReference; FXorMask := nil; end else FreeAndNil(FXorMask); end; end; procedure TBGRACustomBitmap.NeedXorMask; begin if FXorMask = nil then FXorMask := BGRABitmapFactory.Create(Width,Height); end; function TBGRACustomBitmap.NewReference: TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited NewReference); end; function TBGRACustomBitmap.GetUnique: TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited GetUnique); end; function TBGRACustomBitmap.Duplicate(DuplicateProperties: Boolean): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited Duplicate(DuplicateProperties)); end; function TBGRACustomBitmap.Duplicate(DuplicateProperties, DuplicateXorMask: Boolean): TBGRACustomBitmap; begin result := Duplicate(DuplicateProperties); if DuplicateXorMask and Assigned(XorMask) then result.XorMask := FXorMask.Duplicate(True); end; procedure TBGRACustomBitmap.CopyPropertiesTo(ABitmap: TCustomUniversalBitmap); var other: TBGRACustomBitmap; begin inherited CopyPropertiesTo(ABitmap); if ABitmap is TBGRACustomBitmap then begin other := TBGRACustomBitmap(ABitmap); other.CanvasOpacity := CanvasOpacity; other.CanvasDrawModeFP := CanvasDrawModeFP; other.PenStyle := PenStyle; other.CustomPenStyle := CustomPenStyle; other.FontName := FontName; other.FontHeight := FontHeight; other.FontStyle := FontStyle; other.FontQuality := FontQuality; other.FontOrientation := FontOrientation; other.FontVerticalAnchor:= FontVerticalAnchor; other.FontBidiMode:= FontBidiMode; other.LineCap := LineCap; other.JoinStyle := JoinStyle; other.ResampleFilter := ResampleFilter; other.ScanInterpolationFilter:= ScanInterpolationFilter; other.HotSpot := HotSpot; end; end; function TBGRACustomBitmap.GetPart(const ARect: TRect; ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited GetPart(ARect, ACopyProperties)); end; function TBGRACustomBitmap.CreateBrushTexture(ABrushStyle: TBrushStyle; APatternColor, ABackgroundColor: TBGRAPixel; AWidth: integer; AHeight: integer; APenWidth: single): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited CreateBrushTexture(ABrushStyle, APatternColor, ABackgroundColor, AWidth,AHeight,APenWidth)); end; procedure TBGRACustomBitmap.SetSize(AWidth, AHeight: integer); begin if (AWidth <> Width) or (AHeight <> Height) then begin inherited SetSize(AWidth, AHeight); DiscardXorMask; end; end; procedure TBGRACustomBitmap.InternalArc(cx, cy, rx, ry: single; const StartPoint, EndPoint: TPointF; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; AOptions: TArcOptions; ADrawChord: boolean; ATexture: IBGRAScanner); var angle1,angle2: single; begin if (rx = 0) or (ry = 0) then exit; angle1 := arctan2(-(StartPoint.y-cy)/ry,(StartPoint.x-cx)/rx); angle2 := arctan2(-(EndPoint.y-cy)/ry,(EndPoint.x-cx)/rx); if angle1 = angle2 then angle2 := angle1+2*Pi; InternalArc(cx,cy,rx,ry, angle1,angle2, ABorderColor,w,AFillColor, AOptions, ADrawChord, ATexture); end; procedure TBGRACustomBitmap.InternalArcInRect(r: TRect; StartAngleRad, EndAngleRad: Single; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; AOptions: TArcOptions; ADrawChord: boolean; ATexture: IBGRAScanner); var temp: LongInt; begin if r.right = r.left then exit; if r.bottom = r.top then exit; if r.right < r.left then begin temp := r.left; r.left := r.right; r.right := temp; end; if r.Bottom < r.Top then begin temp := r.Top; r.Top := r.Bottom; r.Bottom := temp; end; InternalArc((r.left+r.right-1)/2,(r.top+r.bottom-1)/2, (r.right-r.left-1)/2,(r.bottom-r.top-1)/2, StartAngleRad,EndAngleRad, ABorderColor,w,AFillColor, AOptions, ADrawChord, ATexture); end; procedure TBGRACustomBitmap.InternalFillArcInRect(r: TRect; StartAngleRad, EndAngleRad: Single; AFillColor: TBGRAPixel; AOptions: TArcOptions; ATexture: IBGRAScanner); var temp: LongInt; begin if r.right = r.left then exit; if r.bottom = r.top then exit; if r.right < r.left then begin temp := r.left; r.left := r.right; r.right := temp; end; if r.Bottom < r.Top then begin temp := r.Top; r.Top := r.Bottom; r.Bottom := temp; end; InternalArc((r.left+r.right-1)/2,(r.top+r.bottom-1)/2, (r.right-r.left)/2,(r.bottom-r.top)/2, StartAngleRad,EndAngleRad, BGRAPixelTransparent,0,AFillColor, AOptions, False, ATexture); end; procedure TBGRACustomBitmap.DrawPixel(x, y: int32or64; const c: TBGRAPixel; ADrawMode: TDrawMode); begin case ADrawMode of dmSet: SetPixel(x,y,c); dmSetExceptTransparent: if c.alpha = 255 then SetPixel(x,y,c); dmLinearBlend: FastBlendPixel(x,y,c); dmDrawWithTransparency: DrawPixel(x,y,c); dmXor: XorPixel(x,y,c); end; end; procedure TBGRACustomBitmap.LoadFromStream(AStream: TStream; AHandler: TFPCustomImageReader; AOptions: TBGRALoadingOptions); var OldDrawMode: TDrawMode; begin { LoadFromStream uses TFPCustomImage routine, which uses Colors property to access pixels. That's why the FP drawing mode is temporarily changed to load bitmaps properly } OldDrawMode := CanvasDrawModeFP; CanvasDrawModeFP := dmSet; DiscardXorMask; try inherited LoadFromStream(AStream, AHandler, AOptions); finally CanvasDrawModeFP := OldDrawMode; end; end; { Look for a pixel considering the bitmap is repeated in both directions } procedure TBGRACustomBitmap.DrawHorizLine(x, y, x2: int32or64; texture: IBGRAScanner); begin HorizLine(x,y,x2,texture,dmDrawWithTransparency); end; procedure TBGRACustomBitmap.Arc(cx, cy, rx, ry: single; const StartPoint, EndPoint: TPointF; AColor: TBGRAPixel; w: single; ADrawChord: boolean; AFillColor: TBGRAPixel); begin InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,AColor,w,AFillColor,[aoFillPath],ADrawChord); end; procedure TBGRACustomBitmap.Arc(cx, cy, rx, ry: single; StartAngleRad, EndAngleRad: Single; AColor: TBGRAPixel; w: single; ADrawChord: boolean; AFillColor: TBGRAPixel); begin InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,AColor,w,AFillColor,[aoFillPath],ADrawChord); end; procedure TBGRACustomBitmap.FillChord(cx, cy, rx, ry: single; const StartPoint, EndPoint: TPointF; AFillColor: TBGRAPixel); begin InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,BGRAPixelTransparent,0,AFillColor,[aoFillPath]); end; procedure TBGRACustomBitmap.FillChord(cx, cy, rx, ry: single; StartAngleRad, EndAngleRad: Single; AFillColor: TBGRAPixel); begin InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,BGRAPixelTransparent,0,AFillColor,[aoFillPath]); end; procedure TBGRACustomBitmap.FillChord(cx, cy, rx, ry: single; const StartPoint, EndPoint: TPointF; texture: IBGRAScanner); begin InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,BGRAPixelTransparent,0,BGRAWhite,[aoFillPath],False,texture); end; procedure TBGRACustomBitmap.FillChord(cx, cy, rx, ry: single; StartAngleRad, EndAngleRad: Single; texture: IBGRAScanner); begin InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,BGRAPixelTransparent,0,BGRAWhite,[aoFillPath],False,texture); end; procedure TBGRACustomBitmap.FillChordInRect(const ARect: TRect; StartAngleRad, EndAngleRad: Single; AFillColor: TBGRAPixel); begin InternalFillArcInRect(ARect,StartAngleRad,EndAngleRad,AFillColor,[aoFillPath]); end; procedure TBGRACustomBitmap.FillChordInRect(const ARect: TRect; StartAngleRad, EndAngleRad: Single; texture: IBGRAScanner); begin InternalFillArcInRect(ARect,StartAngleRad,EndAngleRad,BGRAWhite,[aoFillPath],texture); end; procedure TBGRACustomBitmap.Pie(cx, cy, rx, ry: single; const StartPoint, EndPoint: TPointF; AColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel); begin InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,AColor,w,AFillColor,[aoFillPath,aoPie]); end; procedure TBGRACustomBitmap.Pie(cx, cy, rx, ry: single; StartAngleRad, EndAngleRad: Single; AColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel); begin InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,AColor,w,AFillColor,[aoFillPath,aoPie]); end; procedure TBGRACustomBitmap.FillPie(cx, cy, rx, ry: single; const StartPoint, EndPoint: TPointF; AFillColor: TBGRAPixel); begin InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,BGRAPixelTransparent,0,AFillColor,[aoFillPath,aoPie]); end; procedure TBGRACustomBitmap.FillPie(cx, cy, rx, ry: single; StartAngleRad, EndAngleRad: Single; AFillColor: TBGRAPixel); begin InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,BGRAPixelTransparent,0,AFillColor,[aoFillPath,aoPie]); end; procedure TBGRACustomBitmap.FillPie(cx, cy, rx, ry: single; const StartPoint, EndPoint: TPointF; texture: IBGRAScanner); begin InternalArc(cx,cy,rx,ry,StartPoint,EndPoint,BGRAPixelTransparent,0,BGRAWhite,[aoFillPath,aoPie],False,texture); end; procedure TBGRACustomBitmap.FillPie(cx, cy, rx, ry: single; StartAngleRad, EndAngleRad: Single; texture: IBGRAScanner); begin InternalArc(cx,cy,rx,ry,StartAngleRad,EndAngleRad,BGRAPixelTransparent,0,BGRAWhite,[aoFillPath,aoPie],False,texture); end; procedure TBGRACustomBitmap.FillPieInRect(const ARect: TRect; StartAngleRad, EndAngleRad: Single; AFillColor: TBGRAPixel); begin InternalFillArcInRect(ARect,StartAngleRad,EndAngleRad,AFillColor,[aoFillPath,aoPie]); end; procedure TBGRACustomBitmap.FillPieInRect(const ARect: TRect; StartAngleRad, EndAngleRad: Single; texture: IBGRAScanner); begin InternalFillArcInRect(ARect,StartAngleRad,EndAngleRad,BGRAWhite,[aoFillPath,aoPie],texture); end; { Following functions are defined for convenience } procedure TBGRACustomBitmap.RectangleWithin(x1, y1, x2, y2: single; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; APixelCenteredCoordinates: boolean); begin if not APixelCenteredCoordinates then begin DecF(x1, 0.5); DecF(y1, 0.5); DecF(x2, 0.5); DecF(y2, 0.5); end; RectangleAntialias(x1+w*0.5,y1+w*0.5,x2-w*0.5,y2-w*0.5, ABorderColor, w, AFillColor); end; procedure TBGRACustomBitmap.RectangleWithin(r: TRect; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel); begin RectangleWithin(r.left,r.top,r.right,r.bottom,ABorderColor,w,AFillColor,false); end; procedure TBGRACustomBitmap.FillRect(r: TRect; texture: IBGRAScanner; mode: TDrawMode; ditheringAlgorithm: TDitheringAlgorithm); begin FillRect(r.Left,r.Top,r.Right,r.Bottom, texture, mode, ditheringAlgorithm); end; procedure TBGRACustomBitmap.FillRect(r: TRect; texture: IBGRAScanner; mode: TDrawMode; AScanOffset: TPoint; ditheringAlgorithm: TDitheringAlgorithm); begin FillRect(r.Left,r.Top,r.Right,r.Bottom, texture, mode, AScanOffset, ditheringAlgorithm); end; procedure TBGRACustomBitmap.FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode; ditheringAlgorithm: TDitheringAlgorithm); begin FillRect(x,y,x2,y2,texture,mode,Point(0,0),ditheringAlgorithm); end; procedure TBGRACustomBitmap.TextOutCurved(APath: IBGRAPath; const sUTF8: string; AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single); var cursor: TBGRACustomPathCursor; begin cursor := APath.getCursor; if cursor = nil then exit; case AAlign of taCenter: cursor.Position := cursor.PathLength*0.5; taRightJustify: cursor.Position:= cursor.PathLength; end; TextOutCurved(cursor, sUTF8, AColor, AAlign, ALetterSpacing); cursor.free; end; procedure TBGRACustomBitmap.TextOutCurved(APath: IBGRAPath; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single); var cursor: TBGRACustomPathCursor; begin cursor := APath.getCursor; if cursor = nil then exit; case AAlign of taCenter: cursor.Position := cursor.PathLength*0.5; taRightJustify: cursor.Position:= cursor.PathLength; end; TextOutCurved(cursor, sUTF8, ATexture, AAlign, ALetterSpacing); cursor.free; end; {$IFNDEF BGRABITMAP_CORE}procedure TBGRACustomBitmap.TextMultiline(x, y: single; const sUTF8: string; c: TBGRAPixel; AAlign: TBidiTextAlignment; AVertAlign: TTextLayout; AParagraphSpacing: single); begin TextMultiline(x, y, EmptySingle, sUTF8, c, AAlign, AVertAlign, AParagraphSpacing); end;{$ENDIF} {$IFNDEF BGRABITMAP_CORE}procedure TBGRACustomBitmap.TextMultiline(x, y: single; const sUTF8: string; ATexture: IBGRAScanner; AAlign: TBidiTextAlignment; AVertAlign: TTextLayout; AParagraphSpacing: single); begin TextMultiline(x, y, EmptySingle, sUTF8, ATexture, AAlign, AVertAlign, AParagraphSpacing); end;{$ENDIF} procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel; align: TAlignment); begin TextOut(x,y,sUTF8,c,align, GetFontRightToLeftFor(sUTF8)); end; procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner; align: TAlignment); begin TextOut(x,y,sUTF8,texture,align, GetFontRightToLeftFor(sUTF8)); end; { Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c is used to fill the text. The value of FontOrientation is taken into account, so that the text may be rotated. } procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel); begin TextOut(x, y, sUTF8, c, taLeftJustify); end; procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TBGRAPixel; ARightToLeft: boolean); begin TextOut(x, y, sUTF8, c, taLeftJustify, ARightToLeft); end; { Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c is used to fill the text. The value of FontOrientation is taken into account, so that the text may be rotated. } procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TColor); begin TextOut(x, y, sUTF8, ColorToBGRA(c)); end; procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; c: TColor; ARightToLeft: boolean); begin TextOut(x, y, sUTF8, ColorToBGRA(c), ARightToLeft); end; { Draw the UTF8 encoded string, (x,y) being the top-left corner. The texture is used to fill the text. The value of FontOrientation is taken into account, so that the text may be rotated. } procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner); begin TextOut(x, y, sUTF8, texture, taLeftJustify); end; procedure TBGRACustomBitmap.TextOut(x, y: single; const sUTF8: string; texture: IBGRAScanner; ARightToLeft: boolean); begin TextOut(x, y, sUTF8, texture, taLeftJustify, ARightToLeft); end; procedure TBGRACustomBitmap.TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel); begin TextOutAngle(x,y, orientationTenthDegCCW, sUTF8,c,taLeftJustify); end; procedure TBGRACustomBitmap.TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; c: TBGRAPixel; align: TAlignment); begin TextOutAngle(x,y, orientationTenthDegCCW, sUTF8,c,align, GetFontRightToLeftFor(sUTF8)); end; procedure TBGRACustomBitmap.TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner); begin TextOutAngle(x,y, orientationTenthDegCCW, sUTF8,texture,taLeftJustify); end; procedure TBGRACustomBitmap.TextOutAngle(x, y: single; orientationTenthDegCCW: integer; const sUTF8: string; texture: IBGRAScanner; align: TAlignment); begin TextOutAngle(x,y, orientationTenthDegCCW, sUTF8,texture,align, GetFontRightToLeftFor(sUTF8)); end; { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary. The position depends on the specified horizontal alignment halign and vertical alignement valign. The color c is used to fill the text. No rotation is applied. } procedure TBGRACustomBitmap.TextRect(ARect: TRect; const sUTF8: string; halign: TAlignment; valign: TTextLayout; c: TBGRAPixel); var style: TTextStyle; sUTF8bidi: String; begin {$hints off} FillChar(style,sizeof(style),0); {$hints on} style.Alignment := halign; style.Layout := valign; style.Wordbreak := true; style.ShowPrefix := false; style.Clipping := false; style.RightToLeft := GetFontRightToLeftFor(sUTF8); if FontBidiMode = fbmAuto then sUTF8bidi := AddParagraphBidiUTF8(sUTF8, style.RightToLeft) else sUTF8bidi := sUTF8; TextRect(ARect, ARect.Left, ARect.Top, sUTF8bidi, style, c); end; { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary. The position depends on the specified horizontal alignment halign and vertical alignement valign. The texture is used to fill the text. No rotation is applied. } procedure TBGRACustomBitmap.TextRect(ARect: TRect; const sUTF8: string; halign: TAlignment; valign: TTextLayout; texture: IBGRAScanner); var style: TTextStyle; sUTF8bidi: String; begin {$hints off} FillChar(style,sizeof(style),0); {$hints on} style.Alignment := halign; style.Layout := valign; style.Wordbreak := true; style.ShowPrefix := false; style.Clipping := false; style.RightToLeft := GetFontRightToLeftFor(sUTF8); if FontBidiMode = fbmAuto then sUTF8bidi := AddParagraphBidiUTF8(sUTF8, style.RightToLeft) else sUTF8bidi := sUTF8; TextRect(ARect,ARect.Left,ARect.Top,sUTF8bidi,style,texture); end; function TBGRACustomBitmap.ComputeEllipse(x, y, rx, ry: single): ArrayOfTPointF; begin result := ComputeEllipseContour(x,y,rx,ry); end; function TBGRACustomBitmap.ComputeEllipse(x, y, rx, ry, w: single ): ArrayOfTPointF; begin result := ComputeEllipseBorder(x,y,rx,ry,w); end; procedure TBGRACustomBitmap.Fill(texture: IBGRAScanner); begin FillRect(ClipRect, texture, dmSet); end; procedure TBGRACustomBitmap.Fill(texture: IBGRAScanner; mode: TDrawMode); begin FillRect(ClipRect, texture, mode); end; procedure TBGRACustomBitmap.FloodFill(X, Y: integer; Color: TBGRAPixel; mode: TFloodfillMode; Tolerance: byte); begin ParallelFloodFill(X,Y, Self, Color, mode, Tolerance); end; procedure TBGRACustomBitmap.FloodFill(X, Y: integer; const Brush: TUniversalBrush; Progressive: boolean; ToleranceW: Word); begin ParallelFloodFill(X,Y, Self, Brush, Progressive, ToleranceW); end; procedure TBGRACustomBitmap.DrawPart(ARect: TRect; ACanvas: TCanvas; x, y: integer; Opaque: boolean); var partial: TBGRACustomBitmap; begin if (ARect.Left = 0) and (ARect.Top = 0) and (ARect.Right = Width) and (ARect.Bottom = Height) then Draw(ACanvas, x,y, Opaque) else begin partial := GetPart(ARect); if partial <> nil then begin partial.Draw(ACanvas, x, y, Opaque); partial.Free; end; end; end; procedure TBGRACustomBitmap.DrawPart(ARect: TRect; ACanvas: TCanvas; ATargetRect: TRect; Opaque: boolean); var partial: TBGRACustomBitmap; begin if (ARect.Left = 0) and (ARect.Top = 0) and (ARect.Right = Width) and (ARect.Bottom = Height) then Draw(ACanvas, ATargetRect, Opaque) else begin partial := GetPart(ARect); if partial <> nil then begin partial.Draw(ACanvas, ATargetRect, Opaque); partial.Free; end; end; end; procedure TBGRACustomBitmap.PutImage(x, y: integer; Source: TBitmap; mode: TDrawMode; AOpacity: byte); var bgra: TBGRACustomBitmap; begin bgra := BGRABitmapFactory.create(Source); PutImage(x,y, bgra, mode, AOpacity); bgra.free; end; procedure TBGRACustomBitmap.StretchPutImage(ARect: TRect; Source: TBitmap; mode: TDrawMode; AOpacity: byte); var bgra: TBGRACustomBitmap; begin bgra := BGRABitmapFactory.create(Source); StretchPutImage(ARect, bgra, mode, AOpacity); bgra.free; end; procedure TBGRACustomBitmap.StretchPutImageProportionally(ARect: TRect; AHorizAlign: TAlignment; AVertAlign: TTextLayout; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte; ACover: boolean); var ratio: single; imgRect: TRect; begin if (Source.Width = 0) or (Source.Height = 0) then exit; if (ARect.Width <= 0) or (ARect.Height <= 0) then exit; if ACover then ratio := max(ARect.Width/Source.Width, ARect.Height/Source.Height) else ratio := min(ARect.Width/Source.Width, ARect.Height/Source.Height); imgRect := RectWithSize(ARect.Left,ARect.Top, round(Source.Width*ratio), round(Source.Height*ratio)); case AHorizAlign of taCenter: imgRect.Offset((ARect.Width-imgRect.Width) div 2, 0); taRightJustify: imgRect.Offset(ARect.Width-imgRect.Width, 0); end; case AVertAlign of tlCenter: imgRect.Offset(0,(ARect.Height-imgRect.Height) div 2); tlBottom: imgRect.Offset(0,ARect.Height-imgRect.Height); end; StretchPutImage(imgRect, Source, mode, AOpacity); end; procedure TBGRACustomBitmap.PutImageSubpixel(x, y: single; Source: TBGRACustomBitmap; AOpacity: byte); begin PutImageAngle(x,y,source,0,0,0,AOpacity); end; procedure TBGRACustomBitmap.PutImagePart(x, y: integer; Source: TBGRACustomBitmap; SourceRect: TRect; mode: TDrawMode; AOpacity: byte); var w,h,sourcex,sourcey,nx,ny,xb,yb,destx,desty: integer; oldClip,newClip: TRect; begin if (Source = nil) or (AOpacity = 0) then exit; w := SourceRect.Right-SourceRect.Left; h := SourceRect.Bottom-SourceRect.Top; if (w <= 0) or (h <= 0) or (Source.Width = 0) or (Source.Height = 0) then exit; sourcex := PositiveMod(SourceRect.Left, Source.Width); sourcey := PositiveMod(SourceRect.Top, Source.Height); nx := (sourceX+w + Source.Width-1) div Source.Width; ny := (sourceY+h + Source.Height-1) div Source.Height; oldClip := ClipRect; newClip := rect(x,y,x+w,y+h); newClip.Intersect(oldClip); if newClip.IsEmpty then exit; ClipRect := newClip; desty := y-sourcey; for yb := 0 to ny-1 do begin destx := x-sourcex; for xb := 0 to nx-1 do begin self.PutImage(destx,desty,Source,mode,AOpacity); inc(destx,Source.Width); end; inc(desty,Source.Height); end; ClipRect := oldClip; end; procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; Source: TBGRACustomBitmap; AOpacity: Byte; ACorrectBlur: Boolean); begin if ACorrectBlur then PutImageAffine(Origin,HAxis,VAxis,Source,rfCosine,AOpacity) else PutImageAffine(Origin,HAxis,VAxis,Source,rfLinear,AOpacity); end; procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte); begin if (Source = nil) or (Source.Width = 0) or (Source.Height = 0) or (AOpacity = 0) then exit; PutImageAffine(Origin,HAxis,VAxis,Source,GetImageAffineBounds(Origin,HAxis,VAxis,Source),AResampleFilter,dmDrawWithTransparency,AOpacity); end; procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte); begin if (Source = nil) or (Source.Width = 0) or (Source.Height = 0) or (AOpacity = 0) then exit; PutImageAffine(Origin,HAxis,VAxis,Source,GetImageAffineBounds(Origin,HAxis,VAxis,Source),AResampleFilter,AMode,AOpacity); end; procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte); var m: TAffineMatrix; w,h: integer; begin if (Source = nil) or (Source.Width = 0) or (Source.Height = 0) or (AOpacity = 0) then exit; if Source.Width < 2 then w := 2 else w := Source.Width; //avoid actual size of zero if Source.Height < 2 then h := 2 else h := Source.Height; m[1,1] := (HAxis.x-Origin.x)/(w-1); m[1,2] := (VAxis.x-Origin.x)/(h-1); m[1,3] := Origin.x; m[2,1] := (HAxis.y-Origin.y)/(w-1); m[2,2] := (VAxis.y-Origin.y)/(h-1); m[2,3] := Origin.y; PutImageAffine(m,Source,AOutputBounds,AResampleFilter,AMode,AOpacity); end; procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte; ACorrectBlur: Boolean); begin if ACorrectBlur then PutImageAffine(Origin,HAxis,VAxis,Source,AOutputBounds,rfCosine,dmDrawWithTransparency,AOpacity) else PutImageAffine(Origin,HAxis,VAxis,Source,AOutputBounds,rfLinear,dmDrawWithTransparency,AOpacity); end; procedure TBGRACustomBitmap.PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOpacity: Byte; ACorrectBlur: Boolean; APixelCenteredCoords: boolean); begin if ACorrectBlur then PutImageAffine(AMatrix,Source,rfCosine,AOpacity,APixelCenteredCoords) else PutImageAffine(AMatrix,Source,rfLinear,AOpacity,APixelCenteredCoords); end; procedure TBGRACustomBitmap.PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte; APixelCenteredCoords: boolean); begin PutImageAffine(AMatrix, Source, AResampleFilter, dmDrawWithTransparency, AOpacity, APixelCenteredCoords); end; procedure TBGRACustomBitmap.PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte; APixelCenteredCoords: boolean); begin if (Source = nil) or (Source.Width = 0) or (Source.Height = 0) or (AOpacity = 0) then exit; PutImageAffine(AMatrix, Source, GetImageAffineBounds(AMatrix,Source), AResampleFilter,AMode,AOpacity,APixelCenteredCoords); end; procedure TBGRACustomBitmap.PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte; ACorrectBlur: Boolean; APixelCenteredCoords: boolean); begin if ACorrectBlur then PutImageAffine(AMatrix,Source,AOutputBounds,rfCosine,dmDrawWithTransparency,AOpacity,APixelCenteredCoords) else PutImageAffine(AMatrix,Source,AOutputBounds,rfLinear,dmDrawWithTransparency,AOpacity,APixelCenteredCoords); end; { Returns the area that contains the affine transformed image } function TBGRACustomBitmap.GetImageAffineBounds(Origin, HAxis, VAxis: TPointF; Source: TBGRACustomBitmap): TRect; begin if Source = nil then result := EmptyRect else result := GetImageAffineBounds(Origin,HAxis,VAxis,Source.Width,Source.Height,Source.GetImageBounds); end; function TBGRACustomBitmap.GetImageAffineBounds(Origin, HAxis, VAxis: TPointF; ASourceWidth, ASourceHeight: integer; const ASourceBounds: TRect; AClipOutput: boolean): TRect; var m: TAffineMatrix; begin if (ASourceWidth = 0) or (ASourceHeight = 0) then result := EmptyRect else begin if ASourceWidth < 2 then ASourceWidth := 2; //avoid division by zero by supposing a pixel size of 2 if ASourceHeight < 2 then ASourceHeight := 2; //i.e. an actual size of 1 (cf pixel centered coordinates) m[1,1] := (HAxis.x-Origin.x)/(ASourceWidth-1); m[1,2] := (VAxis.x-Origin.x)/(ASourceHeight-1); m[1,3] := Origin.x; m[2,1] := (HAxis.y-Origin.y)/(ASourceWidth-1); m[2,2] := (VAxis.y-Origin.y)/(ASourceHeight-1); m[2,3] := Origin.y; result := GetImageAffineBounds(m, ASourceBounds, AClipOutput); end; end; function TBGRACustomBitmap.GetImageAffineBounds(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; APixelCenteredCoords: boolean): TRect; begin result := GetImageAffineBounds(AMatrix, Source.GetImageBounds, true, APixelCenteredCoords); end; procedure TBGRACustomBitmap.PutImageAngle(x, y: single; Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; imageCenterX: single; imageCenterY: single; AOpacity: Byte; ARestoreOffsetAfterRotation: boolean; ACorrectBlur: Boolean); begin if ACorrectBlur then PutImageAngle(x,y,Source,angle,AOutputBounds,rfCosine,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation) else PutImageAngle(x,y,Source,angle,AOutputBounds,rfLinear,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation); end; procedure TBGRACustomBitmap.PutImageAngle(x, y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single; imageCenterY: single; AOpacity: Byte; ARestoreOffsetAfterRotation: boolean; ACorrectBlur: Boolean); begin if ACorrectBlur then PutImageAngle(x,y,Source,angle,rfCosine,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation) else PutImageAngle(x,y,Source,angle,rfLinear,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation); end; procedure TBGRACustomBitmap.PutImageAngle(x, y: single; Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; AResampleFilter: TResampleFilter; imageCenterX: single; imageCenterY: single; AOpacity: Byte; ARestoreOffsetAfterRotation: boolean); var Origin,HAxis,VAxis: TPointF; begin if (source = nil) or (AOpacity=0) then exit; ComputeImageAngleAxes(x,y,source.Width,source.Height,angle,imageCenterX,imageCenterY,ARestoreOffsetAfterRotation, Origin,HAxis,VAxis); PutImageAffine(Origin,HAxis,VAxis,source,AOutputBounds,AResampleFilter,dmDrawWithTransparency,AOpacity); end; procedure TBGRACustomBitmap.PutImageAngle(x, y: single; Source: TBGRACustomBitmap; angle: single; AResampleFilter: TResampleFilter; imageCenterX: single; imageCenterY: single; AOpacity: Byte; ARestoreOffsetAfterRotation: boolean); var Origin,HAxis,VAxis: TPointF; begin if (source = nil) or (AOpacity=0) then exit; ComputeImageAngleAxes(x,y,source.Width,source.Height,angle,imageCenterX,imageCenterY,ARestoreOffsetAfterRotation, Origin,HAxis,VAxis); PutImageAffine(Origin,HAxis,VAxis,source,AResampleFilter,AOpacity); end; procedure TBGRACustomBitmap.ComputeImageAngleAxes(x, y, w, h, angle: single; imageCenterX, imageCenterY: single; ARestoreOffsetAfterRotation: boolean; out Origin, HAxis, VAxis: TPointF); var cosa,sina: single; { Compute rotated coordinates } function Coord(relX,relY: single): TPointF; begin DecF(relX, imageCenterX); DecF(relY, imageCenterY); result.x := relX*cosa - relY*sina+ x; result.y := relY*cosa + relX*sina+ y; if ARestoreOffsetAfterRotation then result.Offset(imageCenterX,imageCenterY); end; begin cosa := cos(-angle*Pi/180); sina := -sin(-angle*Pi/180); Origin := Coord(0,0); if w < 2 then w := 2; //when pixel size is 1, actual size is zero, so avoid that if h < 2 then h := 2; HAxis := Coord(w-1,0); VAxis := Coord(0,h-1); end; function TBGRACustomBitmap.GetImageAngleBounds(x, y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single; imageCenterY: single; ARestoreOffsetAfterRotation: boolean): TRect; var cosa,sina: single; { Compute rotated coordinates } function Coord(relX,relY: single): TPointF; begin DecF(relX, imageCenterX); DecF(relY, imageCenterY); result.x := relX*cosa - relY*sina + x; result.y := relY*cosa + relX*sina + y; if ARestoreOffsetAfterRotation then result.Offset(imageCenterX,imageCenterY); end; begin if (source = nil) then begin result := EmptyRect; exit; end; cosa := cos(-angle*Pi/180); sina := -sin(-angle*Pi/180); result := GetImageAffineBounds(Coord(0,0),Coord(source.Width,0),Coord(0,source.Height),source); end; procedure TBGRACustomBitmap.Blend(AColor: TBGRAPixel; AOperation: TBlendOperation; AIgnoreDestAlpha: boolean); begin BlendRect(ClipRect, AColor, AOperation, AIgnoreDestAlpha); end; procedure TBGRACustomBitmap.BlendOver(AColor: TBGRAPixel; AOperation: TBlendOperation; AOpacity: byte; ALinearBlend: boolean; AIgnoreDestAlpha: boolean); begin BlendRectOver(ClipRect, AColor, AOperation, AOpacity, ALinearBlend, AIgnoreDestAlpha); end; procedure TBGRACustomBitmap.BlendRect(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AIgnoreDestAlpha: boolean); begin if AIgnoreDestAlpha then BlendRect(ADest, AColor, AOperation, [cAlpha]) else BlendRect(ADest, AColor, AOperation, []); end; procedure TBGRACustomBitmap.BlendRectOver(ADest: TRect; AColor: TBGRAPixel; AOperation: TBlendOperation; AOpacity: byte; ALinearBlend: boolean; AIgnoreDestAlpha: boolean); begin if AIgnoreDestAlpha then BlendRectOver(ADest, AColor, AOperation, AOpacity, ALinearBlend,[cAlpha]) else BlendRectOver(ADest, AColor, AOperation, AOpacity, ALinearBlend, []); end; procedure TBGRACustomBitmap.FillMask(x, y: integer; AMask: TCustomUniversalBitmap; ATexture: IBGRAScanner; ADrawMode: TDrawMode); begin FillMask(x, y, AMask, ATexture, ADrawMode, 255); end; procedure TBGRACustomBitmap.VerticalFlip(ARect: TRect); begin inherited VerticalFlip(ARect); if Assigned(XorMask) then XorMask.VerticalFlip(ARect); end; procedure TBGRACustomBitmap.HorizontalFlip(ARect: TRect); begin inherited HorizontalFlip(ARect); if Assigned(XorMask) then XorMask.HorizontalFlip(ARect); end; procedure TBGRACustomBitmap.RotateUDInplace(ARect: TRect); begin inherited RotateUDInplace(ARect); if Assigned(XorMask) then XorMask.RotateUDInplace(ARect); end; function TBGRACustomBitmap.RotateCW(ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(Inherited RotateCW(ACopyProperties)); if Assigned(XorMask) then result.FXorMask := self.XorMask.RotateCW(ACopyProperties); end; function TBGRACustomBitmap.RotateCCW(ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(Inherited RotateCCW(ACopyProperties)); if Assigned(XorMask) then result.FXorMask := self.XorMask.RotateCCW(ACopyProperties); end; function TBGRACustomBitmap.RotateUD(ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(Inherited RotateUD(ACopyProperties)); if Assigned(XorMask) then result.FXorMask := self.XorMask.RotateUD(ACopyProperties); end; {$IFNDEF BGRABITMAP_CORE}function TBGRACustomBitmap.FilterBlurRadial(radius: single; blurType: TRadialBlurType; ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited FilterBlurRadial(radius, blurType, ACopyProperties)); end;{$ENDIF} {$IFNDEF BGRABITMAP_CORE}function TBGRACustomBitmap.FilterBlurRadial(const ABounds: TRect; radius: single; blurType: TRadialBlurType; ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited FilterBlurRadial(ABounds, radius, blurType, ACopyProperties)); end;{$ENDIF} {$IFNDEF BGRABITMAP_CORE}function TBGRACustomBitmap.FilterBlurRadial(radiusX, radiusY: single; blurType: TRadialBlurType; ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited FilterBlurRadial(radiusX,radiusY, blurType, ACopyProperties)); end;{$ENDIF} {$IFNDEF BGRABITMAP_CORE}function TBGRACustomBitmap.FilterBlurRadial(const ABounds: TRect; radiusX, radiusY: single; blurType: TRadialBlurType; ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited FilterBlurRadial(ABounds, radiusX,radiusY, blurType, ACopyProperties)); end;{$ENDIF} {$IFNDEF BGRABITMAP_CORE}function TBGRACustomBitmap.FilterBlurMotion(distance: single; angle: single; oriented: boolean; ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited FilterBlurMotion(distance, angle, oriented, ACopyProperties)); end;{$ENDIF} {$IFNDEF BGRABITMAP_CORE}function TBGRACustomBitmap.FilterBlurMotion(const ABounds: TRect; distance: single; angle: single; oriented: boolean; ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited FilterBlurMotion(ABounds, distance, angle, oriented, ACopyProperties)); end;{$ENDIF} {$IFNDEF BGRABITMAP_CORE}function TBGRACustomBitmap.FilterCustomBlur(mask: TCustomUniversalBitmap; ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited FilterCustomBlur(mask, ACopyProperties)); end;{$ENDIF} {$IFNDEF BGRABITMAP_CORE}function TBGRACustomBitmap.FilterCustomBlur(const ABounds: TRect; mask: TCustomUniversalBitmap; ACopyProperties: Boolean=False): TBGRACustomBitmap; begin result := TBGRACustomBitmap(inherited FilterCustomBlur(ABounds,mask, ACopyProperties)); end;{$ENDIF} function TBGRACustomBitmap.GetImageBoundsWithin(const ARect: TRect; Channel: TChannel; ANothingValue: Byte): TRect; begin result := InternalGetImageBoundsWithin(self,nil,ARect,[Channel],ANothingValue); end; function TBGRACustomBitmap.GetImageBoundsWithin(const ARect: TRect; Channels: TChannels; ANothingValue: Byte): TRect; begin result := InternalGetImageBoundsWithin(self,nil,ARect,Channels,ANothingValue); end; function TBGRACustomBitmap.ScanAtIntegerExpanded(X, Y: integer): TExpandedPixel; begin result := GammaExpansion(ScanAtInteger(X,Y)); end; function TBGRACustomBitmap.ScanNextExpandedPixel: TExpandedPixel; begin result := GammaExpansion(ScanNextPixel); end; function TBGRACustomBitmap.ScanAtExpanded(X, Y: Single): TExpandedPixel; begin result := GammaExpansion(ScanAt(X,Y)); end; function TBGRACustomBitmap.ProvidesScanline(ARect: TRect): boolean; begin result := (ARect.Left+ScanOffset.x >= 0) and (ARect.Top+ScanOffset.y >= 0) and (ARect.Right+ScanOffset.x <= Width) and (ARect.Bottom+ScanOffset.y <= Height); end; function TBGRACustomBitmap.GetScanlineAt(X, Y: integer): PBGRAPixel; begin result := ScanLine[y+ScanOffset.y]+x+ScanOffset.x; end; procedure TBGRACustomBitmap.ScanNextMaskChunk(var ACount: integer; out AMask: PByteMask; out AStride: integer); var PPixels: Pointer; begin ScanNextCustomChunk(ACount, PPixels); AMask := (PByteMask(PPixels)+TBGRAPixel_ChannelByteOffset[ScanMaskChannel]); AStride := sizeof(TBGRAPixel); end; function TBGRACustomBitmap.ScanAtIntegerMask(X,Y: integer): TByteMask; var c: TBGRAPixel; begin c := ScanAtInteger(X,Y); Byte(result) := (PByte(@c)+TBGRAPixel_ChannelByteOffset[ScanMaskChannel])^; end; function TBGRACustomBitmap.ScanAtMask(X,Y: Single): TByteMask; var c: TBGRAPixel; begin c := ScanAt(X,Y); Byte(result) := (PByte(@c)+TBGRAPixel_ChannelByteOffset[ScanMaskChannel])^; end; {$ENDIF}