Ignore:
Timestamp:
Dec 22, 2016, 8:49:19 PM (7 years ago)
Author:
chronos
Message:
  • Modified: Updated BGRABitmap package.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest/Packages/bgrabitmap/bgradefaultbitmap.pas

    r472 r494  
    3333
    3434uses
    35   Classes, SysUtils, Types, FPImage, Graphics, BGRABitmapTypes, GraphType, FPImgCanv,
    36   BGRACanvas, BGRACanvas2D, FPWritePng, BGRAArrow, BGRAPen;
     35  SysUtils, Classes, Types, FPImage, BGRAGraphics, BGRABitmapTypes, FPImgCanv,
     36  BGRACanvas, BGRACanvas2D, BGRAArrow, BGRAPen, BGRATransform;
    3737
    3838type
     39  TBGRAPtrBitmap = class;
     40  {=== TBGRABitmap reference ===}
    3941  { TBGRADefaultBitmap }
    40 
     42  {* This class is the base for all ''TBGRABitmap'' classes. It implements most
     43     function to the exception from implementations specific to the
     44     widgetset }{ in the doc, it is presented as
     45  TBGRABitmap = class(TBGRACustomBitmap)
     46  }
    4147  TBGRADefaultBitmap = class(TBGRACustomBitmap)
    4248  private
     
    4753    function CheckVertLineBounds(var x, y, y2: int32or64; out delta: int32or64): boolean; inline;
    4854    function CheckRectBounds(var x,y,x2,y2: integer; minsize: integer): boolean; inline;
    49     function CheckClippedRectBounds(var x,y,x2,y2: integer): boolean; inline;
    5055    function CheckAntialiasRectBounds(var x,y,x2,y2: single; w: single): boolean;
    5156    function GetCanvasBGRA: TBGRACanvas;
    5257    function GetCanvas2D: TBGRACanvas2D;
     58    procedure GradientFillDithered(x, y, x2, y2: integer; c1, c2: TBGRAPixel;
     59      gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode;
     60      gammaColorCorrection: boolean = True; Sinus: Boolean=False;
     61      ditherAlgo: TDitheringAlgorithm = daFloydSteinberg);
     62    procedure GradientFillDithered(x, y, x2, y2: integer; gradient: TBGRACustomGradient;
     63      gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode;
     64      Sinus: Boolean=False;
     65      ditherAlgo: TDitheringAlgorithm = daFloydSteinberg);
    5366  protected
    5467    FRefCount: integer; //reference counter (not related to interface reference counter)
     
    5770    FData:      PBGRAPixel;              //pointer to pixels
    5871    FWidth, FHeight, FNbPixels: integer; //dimensions
     72    FScanWidth, FScanHeight: integer;    //possibility to reduce the zone being scanned
    5973    FDataModified: boolean;              //if data image has changed so TBitmap should be updated
    6074    FLineOrder: TRawImageLineOrder;
     
    6579    FScanCurX,FScanCurY: integer;   //current scan coordinates
    6680
    67     //LCL bitmap object
     81    //GUI bitmap object
    6882    FBitmap:   TBitmap;
    6983    FBitmapModified: boolean;         //if TBitmap has changed so pixel data should be updated
     
    86100    FFontRenderer: TBGRACustomFontRenderer;
    87101
    88     { Pen style can be defined by PenStyle property of by CustomPenStyle property.
    89       When PenStyle property is assigned, CustomPenStyle property is assigned the actual
    90       pen pattern. }
    91     FCustomPenStyle:  TBGRAPenStyle;
    92     FPenStyle: TPenStyle;
    93     FArrow: TBGRAArrow;
    94     FLineCap: TPenEndCap;
     102    FPenStroker: TBGRAPenStroker;
    95103
    96104    //Pixel data
     
    98106    function GetScanLine(y: integer): PBGRAPixel; override; //don't forget to call InvalidateBitmap after modifications
    99107    function LoadFromRawImage(ARawImage: TRawImage; DefaultOpacity: byte;
    100       AlwaysReplaceAlpha: boolean = False; RaiseErrorOnInvalidPixelFormat: boolean = True): boolean;
     108      AlwaysReplaceAlpha: boolean = False; RaiseErrorOnInvalidPixelFormat: boolean = True): boolean; virtual; abstract;
    101109    function GetDataPtr: PBGRAPixel; override;
    102110    procedure ClearTransparentPixels; override;
    103111    function GetScanlineFast(y: integer): PBGRAPixel; inline;
    104112    function GetLineOrder: TRawImageLineOrder; override;
     113    procedure SetLineOrder(AValue: TRawImageLineOrder); virtual;
    105114    function GetNbPixels: integer; override;
    106115    function GetWidth: integer; override;
    107116    function GetHeight: integer; override;
    108117
    109     //LCL bitmap object
     118    //GUI bitmap object
    110119    function GetBitmap: TBitmap; override;
    111120    function GetCanvas: TCanvas; override;
     
    116125    function GetCanvasAlphaCorrection: boolean; override;
    117126    procedure SetCanvasAlphaCorrection(const AValue: boolean); override;
     127    procedure DoLoadFromBitmap; virtual;
    118128
    119129    //FreePascal drawing routines
     
    125135    procedure ReallocData; virtual;
    126136    procedure FreeData; virtual;
    127 
    128     procedure RebuildBitmap; virtual;
     137    function CreatePtrBitmap(AWidth,AHeight: integer; AData: PBGRAPixel): TBGRAPtrBitmap; virtual;
     138
     139    procedure RebuildBitmap; virtual; abstract;
    129140    procedure FreeBitmap; virtual;
    130141
     
    144155    function GetAverageColor: TColor; override;
    145156    function GetAveragePixel: TBGRAPixel; override;
    146     function CreateAdaptedPngWriter: TFPWriterPNG;
    147157
    148158    //drawing
     159    function GetPenJoinStyle: TPenJoinStyle; override;
     160    procedure SetPenJoinStyle(const AValue: TPenJoinStyle); override;
     161    function GetPenMiterLimit: single; override;
     162    procedure SetPenMiterLimit(const AValue: single); override;
    149163    function GetCustomPenStyle: TBGRAPenStyle; override;
    150164    procedure SetCustomPenStyle(const AValue: TBGRAPenStyle); override;
     
    153167    function GetLineCap: TPenEndCap; override;
    154168    procedure SetLineCap(AValue: TPenEndCap); override;
     169    function GetPenStroker: TBGRACustomPenStroker; override;
     170
    155171    function GetArrowEndSize: TPointF; override;
    156172    function GetArrowStartSize: TPointF; override;
     
    173189    function GetFontRenderer: TBGRACustomFontRenderer; override;
    174190    procedure SetFontRenderer(AValue: TBGRACustomFontRenderer); override;
     191    function CreateDefaultFontRenderer: TBGRACustomFontRenderer; virtual; abstract;
     192    function GetFontAnchorVerticalOffset: single;
     193    function GetFontAnchorRotatedOffset: TPointF;
     194    function GetFontAnchorRotatedOffset(ACustomOrientation: integer): TPointF;
    175195
    176196    function GetClipRect: TRect; override;
     
    179199    function InternalGetPixelCycle256(ix,iy: int32or64; iFactX,iFactY: int32or64): TBGRAPixel;
    180200    function InternalGetPixel256(ix,iy: int32or64; iFactX,iFactY: int32or64; smoothBorder: boolean): TBGRAPixel;
    181     function GetPolyLineOption: TBGRAPolyLineOptions;
    182201    function GetArrow: TBGRAArrow;
    183     procedure SetArrowStart(AStyle: TBGRAArrowStyle; ATipStyle: TPenJoinStyle = pjsMiter; ARelativePenWidth: single = 1; ATriangleBackOffset: single = 0); override;
    184     procedure SetArrowEnd(AStyle: TBGRAArrowStyle; ATipStyle: TPenJoinStyle = pjsMiter; ARelativePenWidth: single = 1; ATriangleBackOffset: single = 0); override;
     202    procedure InternalTextOutCurved(ACursor: TBGRACustomPathCursor; sUTF8: string; AColor: TBGRAPixel; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single);
     203
     204    function CheckClippedRectBounds(var x,y,x2,y2: integer): boolean;
     205    procedure InternalArc(cx,cy,rx,ry: single; StartAngleRad,EndAngleRad: Single; ABorderColor: TBGRAPixel; w: single;
     206      AFillColor: TBGRAPixel; AOptions: TArcOptions; ADrawChord: boolean = false; ATexture: IBGRAScanner = nil); override;
    185207
    186208  public
    187     {Reference counter functions}
     209    {** Provides a canvas with opacity and antialiasing }
     210    property CanvasBGRA: TBGRACanvas read GetCanvasBGRA;
     211    {** Provides a canvas with 2d transformation and similar to HTML5. }
     212    property Canvas2D: TBGRACanvas2D read GetCanvas2D;
     213    {** For more properties, see parent class [[TBGRACustomBitmap and IBGRAScanner#TBGRACustomBitmap|TBGRACustomBitmap]] }
     214
     215    {==== Reference counting ====}
     216
     217    {** Adds a reference (this reference count is not the same as
     218        the reference count of an interface, it changes only by
     219        explicit calls }
    188220    function NewReference: TBGRACustomBitmap;
     221    {** Free a reference. When the resulting reference count gets
     222        to zero, the image is freed. The initial reference count
     223        is equal to 1 }
    189224    procedure FreeReference;
     225    {** Returns an object with a reference count equal to 1. Duplicate
     226        this bitmap if necessary }
    190227    function GetUnique: TBGRACustomBitmap;
    191228
     229    {==== Constructors ====}
     230
    192231    {------------------------- Constructors from TFPCustomImage----------------}
    193     constructor Create(AWidth, AHeight: integer); override; //Creates a new bitmap, initialize properties and bitmap data
    194     procedure SetSize(AWidth, AHeight: integer); override;  //Can only be called with an existing instance of TBGRABitmap.
    195                                                             //Sets the dimensions of an existing TBGRABitmap instance.
     232    {** Creates a new bitmap, initialize properties and bitmap data }
     233    constructor Create(AWidth, AHeight: integer); override;
     234    {** Can only be called with an existing instance of ''TBGRABitmap''.
     235        Sets the dimensions of an existing ''TBGRABitmap'' instance. }
     236    procedure SetSize(AWidth, AHeight: integer); override;
    196237
    197238    {------------------------- Constructors from TBGRACustomBitmap-------------}
    198     constructor Create; override;                    //Creates an image of width and height equal to zero.
    199     constructor Create(ABitmap: TBitmap); override;  //Creates an image of dimensions AWidth and AHeight and filled with transparent pixels.
    200     constructor Create(AWidth, AHeight: integer; Color: TColor); override;      //Creates an image of dimensions AWidth and AHeight and fills it with the opaque color Color.
    201     constructor Create(AWidth, AHeight: integer; Color: TBGRAPixel); override;  //Creates an image of dimensions AWidth and AHeight and fills it with Color.
    202 
    203     constructor Create(AFilename: string); override; // Creates an image by loading its content from the file AFilename.
    204                                                      // The encoding of the string is the default one for the operating system.
    205                                                      // It is recommended to use the next constructor and UTF8 encoding.
    206 
    207     constructor Create(AFilename: string; AIsUtf8: boolean); override; //Creates an image by loading its content from the file AFilename.
    208                                                                        //The boolean AIsUtf8Filename specifies if UTF8 encoding is assumed for the filename.
    209 
    210     constructor Create(AStream: TStream); override;  // Creates an image by loading its content from the stream AStream.
    211     destructor Destroy; override;                    // Free the object and all its resources
     239    {** Creates an image of width and height equal to zero. In this case,
     240        ''Data'' = '''nil''' }
     241    constructor Create; override;
     242    {** Creates an image by copying the content of a ''TFPCustomImage'' }
     243    constructor Create(AFPImage: TFPCustomImage); override;
     244    {** Creates an image by copying the content of a ''TBitmap'' }
     245    constructor Create(ABitmap: TBitmap; AUseTransparent: boolean = true); override;
     246    {** Creates an image of dimensions ''AWidth'' and ''AHeight'' and fills it with the opaque color ''Color'' }
     247    constructor Create(AWidth, AHeight: integer; Color: TColor); override;
     248    {** Creates an image of dimensions ''AWidth'' and ''AHeight'' and fills it with ''Color'' }
     249    constructor Create(AWidth, AHeight: integer; Color: TBGRAPixel); override;
     250
     251    {** Creates an image by loading its content from the file ''AFilename''.
     252        The encoding of the string is the default one for the operating system.
     253        It is recommended to use the next constructor and UTF8 encoding }
     254    constructor Create(AFilename: string); override;
     255
     256    {** Creates an image by loading its content from the file ''AFilename''.
     257        The boolean ''AIsUtf8Filename'' specifies if UTF8 encoding is assumed
     258        for the filename }
     259    constructor Create(AFilename: string; AIsUtf8: boolean); override;
     260    constructor Create(AFilename: string; AIsUtf8: boolean; AOptions: TBGRALoadingOptions); override;
     261
     262    {** Creates an image by loading its content from the stream ''AStream'' }
     263    constructor Create(AStream: TStream); override;
     264    {** Free the object and all its resources }
     265    destructor Destroy; override;
    212266
    213267    {------------------------- Quasi-constructors -----------------------------}
    214     function NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap; override;  //Can only be called from an existing instance of TBGRABitmap.
    215                                                                                 //Creates a new instance with dimensions AWidth and AHeight,
    216                                                                                 //containing transparent pixels.
    217 
    218     function NewBitmap(AWidth, AHeight: integer; Color: TBGRAPixel): TBGRACustomBitmap; override;  //Can only be called from an existing instance of TBGRABitmap.
    219                                                                                 //Creates a new instance with dimensions AWidth and AHeight,
    220                                                                                 //and fills it with Color.
    221 
    222     function NewBitmap(Filename: string): TBGRACustomBitmap; override;          //Can only be called from an existing instance of TBGRABitmap.
    223                                                                                 //Creates a new instance with by loading its content
    224                                                                                 //from the file Filename. The encoding of the string
    225                                                                                 //is the default one for the operating system.
    226 
    227     function NewBitmap(Filename: string; AIsUtf8: boolean): TBGRACustomBitmap; override; //Can only be called from an existing instance of TBGRABitmap.
    228                                                                                 //Creates a new instance with by loading its content
    229                                                                                 //from the file Filename.
    230 
    231     procedure SaveToFile(const filename: string); override;
    232     procedure SaveToStreamAsPng(Str: TStream); override;
    233     procedure Assign(ARaster: TRasterImage); override; overload;
    234     procedure Assign(MemBitmap: TBGRACustomBitmap);override; overload;
     268    {** Can only be called from an existing instance of ''TBGRABitmap''.
     269        Creates a new instance with dimensions ''AWidth'' and ''AHeight'',
     270        containing transparent pixels. }
     271    function NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap; override;
     272
     273    {** Can only be called from an existing instance of ''TBGRABitmap''.
     274        Creates a new instance with dimensions ''AWidth'' and ''AHeight'',
     275        and fills it with Color }
     276    function NewBitmap(AWidth, AHeight: integer; Color: TBGRAPixel): TBGRACustomBitmap; override;
     277
     278    {** Can only be called from an existing instance of ''TBGRABitmap''.
     279        Creates a new instance with by loading its content
     280        from the file ''Filename''. The encoding of the string
     281        is the default one for the operating system }
     282    function NewBitmap(Filename: string): TBGRACustomBitmap; override;
     283
     284    {** Can only be called from an existing instance of ''TBGRABitmap''.
     285        Creates a new instance with by loading its content
     286        from the file ''Filename'' }
     287    function NewBitmap(Filename: string; AIsUtf8: boolean): TBGRACustomBitmap; override;
     288    function NewBitmap(Filename: string; AIsUtf8: boolean; AOptions: TBGRALoadingOptions): TBGRACustomBitmap; override;
     289
     290    {** Can only be called from an existing instance of ''TBGRABitmap''.
     291        Creates an image by copying the content of a ''TFPCustomImage'' }
     292    function NewBitmap(AFPImage: TFPCustomImage): TBGRACustomBitmap; override;
     293
     294    {** Load image from a stream. The specified image reader is used }
     295    procedure LoadFromStream(Str: TStream; Handler: TFPCustomImageReader; AOptions: TBGRALoadingOptions); override;
     296
     297    {** Assign the content of the specified ''Source''. It can be a ''TBGRACustomBitmap'' or
     298        a ''TFPCustomImage'' }
     299    procedure Assign(Source: TPersistent); override;
     300    procedure Assign(Source: TBitmap; AUseTransparent: boolean); overload;
     301    {** Stores the image in the stream without compression nor header }
    235302    procedure Serialize(AStream: TStream); override;
     303    {** Reads the image in a stream that was previously serialized }
    236304    procedure Deserialize(AStream: TStream); override;
     305    {** Stores an empty image (of size zero) }
    237306    class procedure SerializeEmpty(AStream: TStream);
    238307
    239     {Pixel functions}
     308    {* Example:
     309       <syntaxhighlight>
     310     * var bmp1, bmp2: TBGRABitmap;
     311     * begin
     312     *   bmp1 := TBGRABitmap.Create(100,100);
     313     *   bmp2 := bmp1.NewBitmap(100,100) as TBGRABitmap;
     314     *   ...
     315     * end;</syntaxhighlight>
     316       See tutorial 2 on [[BGRABitmap_tutorial_2|how to load and display an image]].
     317     * See reference on [[TBGRACustomBitmap_and_IBGRAScanner#Load_and_save_files|loading and saving files]] }
     318
     319    {==== Pixel functions ====}
     320    {** Checks if the specified point is in the clipping rectangle ''ClipRect'' }
    240321    function PtInClipRect(x, y: int32or64): boolean; inline;
     322    {** Sets the pixel by replacing the content at (''x'',''y'') with the specified color.
     323        Alpha value is set to 255 (opaque) }
    241324    procedure SetPixel(x, y: int32or64; c: TColor); override;
     325    {** Sets the pixel at (''x'',''y'') with the specified content }
    242326    procedure SetPixel(x, y: int32or64; c: TBGRAPixel); override;
     327    {** Applies a logical '''xor''' to the content of the pixel with the specified value.
     328        This includes the alpha channel, so if you want to preserve the opacity, provide
     329        a color ''c'' with alpha channel equal to zero }
    243330    procedure XorPixel(x, y: int32or64; c: TBGRAPixel); override;
     331    {** Draws a pixel with gamma correction at (''x'',''y''). Pixel is supplied
     332        in sRGB colorspace }
    244333    procedure DrawPixel(x, y: int32or64; c: TBGRAPixel); override;
     334    {** Draws a pixel with the specified ''ADrawMode'' at (''x'',''y'').
     335        Pixel is supplied in sRGB colorspace. Gamma correction may be applied
     336        depending on the draw mode }{inherited
     337    procedure DrawPixel(x, y: int32or64; c: TBGRAPixel; ADrawMode: TDrawMode); overload;
     338  }{** Draws a pixel with gamma correction at (''x'',''y''). Pixel is supplied
     339        in gamma expanded colorspace }
    245340    procedure DrawPixel(x, y: int32or64; ec: TExpandedPixel); override;
     341    {** Draws a pixel without gamma correction at (''x'',''y''). Pixel is supplied
     342        in sRGB colorspace }
    246343    procedure FastBlendPixel(x, y: int32or64; c: TBGRAPixel); override;
     344    {** Erase the content of the pixel by reducing the value of the
     345        alpha channel. ''alpha'' specifies how much to decrease.
     346        If the resulting alpha reaches zero, the content
     347        is replaced by ''BGRAPixelTransparent'' }
    247348    procedure ErasePixel(x, y: int32or64; alpha: byte); override;
     349    {** Sets the alpha value at (''x'',''y''). If ''alpha'' = 0, the
     350        pixel is replaced by ''BGRAPixelTransparent'' }
    248351    procedure AlphaPixel(x, y: int32or64; alpha: byte); override;
     352    {** Returns the content of the specified pixel. If it is out of the
     353        bounds of the picture, the result is ''BGRAPixelTransparent'' }
    249354    function GetPixel(x, y: int32or64): TBGRAPixel; override;
     355    {** Computes the value of the pixel at a floating point coordiante
     356        by interpolating the values of the pixels around it.
     357      * There is a one pixel wide margin around the pixel where the pixels are
     358        still considered inside. If ''smoothBorder'' is set to true, pixel fade
     359        to transparent.
     360      * If it is more out of the bounds, the result is ''BGRAPixelTransparent''.
     361      * ''AResampleFilter'' specifies how pixels must be interpolated. Accepted
     362        values are ''rfBox'', ''rfLinear'', ''rfHalfCosine'' and ''rfCosine'' }
     363    function GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; override;
     364    {** Similar to previous ''GetPixel'' function, but the fractional part of
     365        the coordinate is supplied with a number from 0 to 255. The actual
     366        coordinate is (''x'' + ''fracX256''/256, ''y'' + ''fracY256''/256) }
    250367    function GetPixel256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; override;
    251     function GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; override;
     368    {** Computes the value of the pixel at a floating point coordiante
     369        by interpolating the values of the pixels around it. If the pixel
     370        is out of bounds, the image is repeated.
     371      * ''AResampleFilter'' specifies how pixels must be interpolated. Accepted
     372        values are ''rfBox'', ''rfLinear'', ''rfHalfCosine'' and ''rfCosine'' }
    252373    function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; override;
     374    {** Similar to previous ''GetPixel'' function, but the fractional part of
     375        the coordinate is supplied with a number from 0 to 255. The actual
     376        coordinate is (''x'' + ''fracX256''/256, ''y'' + ''fracY256''/256) }
     377    function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; override;
     378    {** Computes the value of the pixel at a floating point coordiante
     379        by interpolating the values of the pixels around it. ''repeatX'' and
     380        ''repeatY'' specifies if the image is to be repeated or not.
     381      * ''AResampleFilter'' specifies how pixels must be interpolated. Accepted
     382        values are ''rfBox'', ''rfLinear'', ''rfHalfCosine'' and ''rfCosine'' }
    253383    function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; override;
    254     function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; override;
     384    {** Similar to previous ''GetPixel'' function, but the fractional part of
     385        the coordinate is supplied with a number from 0 to 255. The actual
     386        coordinate is (''x'' + ''fracX256''/256, ''y'' + ''fracY256''/256) }
    255387    function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; override;
    256388
    257     {Line primitives}
     389    {==== Drawing lines and polylines (integer coordinates) ====}
     390    {* These functions do not take into account current pen style/cap/join.
     391       See [[BGRABitmap tutorial 13|coordinate system]]. }
     392
     393    {** Replaces the content of the pixels at line ''y'' and
     394        at columns ''x'' to ''x2'' included, using specified color }
    258395    procedure SetHorizLine(x, y, x2: int32or64; c: TBGRAPixel); override;
     396    {** Applies xor to the pixels at line ''y'' and
     397        at columns ''x'' to ''x2'' included, using specified color.
     398        This includes the alpha channel, so if you want to preserve the
     399        opacity, provide a color ''c'' with alpha channel equal to zero }
    259400    procedure XorHorizLine(x, y, x2: int32or64; c: TBGRAPixel); override;
     401    {** Draws an horizontal line with gamma correction at line ''y'' and
     402        at columns ''x'' to ''x2'' included, using specified color }
    260403    procedure DrawHorizLine(x, y, x2: int32or64; c: TBGRAPixel); override;
     404    {** Draws an horizontal line with gamma correction at line ''y'' and
     405        at columns ''x'' to ''x2'' included, using specified color }
    261406    procedure DrawHorizLine(x, y, x2: int32or64; ec: TExpandedPixel); override;
     407    {** Draws an horizontal line with gamma correction at line ''y'' and
     408        at columns ''x'' to ''x2'' included, using specified scanner
     409        to get the source colors }{inherited
     410    procedure DrawHorizLine(x, y, x2: int32or64; texture: IBGRAScanner); overload;
     411   }{** Draws an horizontal line without gamma correction at line ''y'' and
     412        at columns ''x'' to ''x2'' included, using specified color }
     413    procedure FastBlendHorizLine(x, y, x2: int32or64; c: TBGRAPixel); override;
     414    {** Draws an horizontal line at line ''y'' and
     415        at columns ''x'' to ''x2'' included, using specified scanner
     416        and the specified ''ADrawMode'' }
    262417    procedure HorizLine(x, y, x2: int32or64; texture: IBGRAScanner; ADrawMode : TDrawMode); override;
    263 
    264     procedure FastBlendHorizLine(x, y, x2: int32or64; c: TBGRAPixel); override;
     418    {** Draws an horizontal line at line ''y'' and
     419        at columns ''x'' to ''x2'' included, using specified color
     420        and the specified ''ADrawMode'' }{inherited
     421    procedure HorizLine(x,y,x2: Int32or64; c: TBGRAPixel; ADrawMode: TDrawMode); overload;
     422    }
     423    {** Replaces the alpha value of the pixels at line ''y'' and
     424        at columns ''x'' to ''x2'' included }
    265425    procedure AlphaHorizLine(x, y, x2: int32or64; alpha: byte); override;
    266     procedure SetVertLine(x, y, y2: int32or64; c: TBGRAPixel); override;
    267     procedure XorVertLine(x, y, y2: int32or64; c: TBGRAPixel); override;
    268     procedure DrawVertLine(x, y, y2: int32or64; c: TBGRAPixel); override;
    269     procedure AlphaVertLine(x, y, y2: int32or64; alpha: byte); override;
    270     procedure FastBlendVertLine(x, y, y2: int32or64; c: TBGRAPixel); override;
     426    {** Draws an horizontal line with gamma correction at line ''y'' and
     427        at columns ''x'' to ''x2'' included, using specified color,
     428        and with a transparency that increases with the color difference
     429        with ''compare''. If the difference is greater than ''maxDiff'',
     430        pixels are not changed }
    271431    procedure DrawHorizLineDiff(x, y, x2: int32or64; c, compare: TBGRAPixel;
    272432      maxDiff: byte); override;
    273433
    274     {Shapes}
    275     procedure DrawPath(APath: IBGRAPath; c: TBGRAPixel; w: single); override;
    276     procedure DrawPath(APath: IBGRAPath; texture: IBGRAScanner; w: single); override;
    277 
     434    {** Replaces a vertical line at column ''x'' and at row ''y'' to ''y2'' }
     435    procedure SetVertLine(x, y, y2: int32or64; c: TBGRAPixel); override;
     436    {** Xors a vertical line at column ''x'' and at row ''y'' to ''y2'' }
     437    procedure XorVertLine(x, y, y2: int32or64; c: TBGRAPixel); override;
     438    {** Draws a vertical line with gamma correction at column ''x'' and at row ''y'' to ''y2'' }
     439    procedure DrawVertLine(x, y, y2: int32or64; c: TBGRAPixel); override;
     440    {** Draws a vertical line without gamma correction at column ''x'' and at row ''y'' to ''y2'' }
     441    procedure FastBlendVertLine(x, y, y2: int32or64; c: TBGRAPixel); override;
     442    {** Replace alpha values in a vertical line at column ''x'' and at row ''y'' to ''y2'' }
     443    procedure AlphaVertLine(x, y, y2: int32or64; alpha: byte); override;
     444    {** Draws a vertical line with the specified draw mode at column ''x'' and at row ''y'' to ''y2'' }{inherited
     445    procedure VertLine(x,y,y2: Int32or64; c: TBGRAPixel; ADrawMode: TDrawMode);
     446    }
     447
     448    {** Draws an aliased line from (x1,y1) to (x2,y2) using Bresenham's algorithm
     449        ''c'' specifies the color. ''DrawLastPixel'' specifies if (x2,y2) must be drawn.
     450        ''ADrawMode'' specifies the mode to use when drawing the pixels }
    278451    procedure DrawLine(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode = dmDrawWithTransparency); override;
     452    {** Draws an antialiased line from (x1,y1) to (x2,y2) using an improved version of Bresenham's algorithm
     453        ''c'' specifies the color. ''DrawLastPixel'' specifies if (x2,y2) must be drawn }
    279454    procedure DrawLineAntialias(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean); override;
     455    {** Draws an antialiased line with two colors ''c1'' and ''c2'' as dashes of lenght ''dashLen'' }
    280456    procedure DrawLineAntialias(x1, y1, x2, y2: integer; c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean); override;
     457    {** Draws an antialiased line with two colors ''c1'' and ''c2'' as dashes of lenght ''dashLen''.
     458        ''DashPos'' can be used to specify the start dash position and to retrieve the dash position at the end
     459        of the line, in order to draw a polyline with consistent dashes }
    281460    procedure DrawLineAntialias(x1, y1, x2, y2: integer; c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean; var DashPos: integer); override;
     461
     462    {** Erases the line from (x1,y1) to (x2,y2) using Bresenham's algorithm.
     463        ''alpha'' specifies how much to decrease. If ''alpha'' = 0, nothing
     464        is changed and if ''alpha'' = 255, all pixels become transparent.
     465        ''DrawListPixel'' specifies if (x2,y2) must be changed }
     466    procedure EraseLine(x1, y1, x2, y2: integer; alpha: byte; DrawLastPixel: boolean); override;
     467    {** Erases the line from (x1,y1) to (x2,y2) width antialiasing.
     468        ''alpha'' specifies how much to decrease. If ''alpha'' = 0, nothing
     469        is changed and if ''alpha'' = 255, all pixels become transparent.
     470        ''DrawListPixel'' specifies if (x2,y2) must be changed }
     471    procedure EraseLineAntialias(x1, y1, x2, y2: integer; alpha: byte; DrawLastPixel: boolean); override;
     472
     473    {==== Drawing lines and polylines (floating point coordinates) ====}
     474    {* These functions use the current pen style/cap/join. The parameter ''w''
     475       specifies the width of the line and the base unit for dashes.
     476       See [[BGRABitmap tutorial 13|coordinate system]]. }
     477
     478    {** Draws a line from (x1,y1) to (x2,y2) using current pen style/cap/join }
    282479    procedure DrawLineAntialias(x1, y1, x2, y2: single; c: TBGRAPixel; w: single); override;
     480    {** Draws a line from (x1,y1) to (x2,y2) using current pen style/cap/join.
     481        ''texture'' specifies the source color to use when filling the line }
    283482    procedure DrawLineAntialias(x1, y1, x2, y2: single; texture: IBGRAScanner; w: single); override;
    284     procedure DrawLineAntialias(x1, y1, x2, y2: single; c: TBGRAPixel; w: single; Closed: boolean); override;
    285     procedure DrawLineAntialias(x1, y1, x2, y2: single; texture: IBGRAScanner; w: single; Closed: boolean); override;
    286 
     483    {** Draws a line from (x1,y1) to (x2,y2) using current pen style/cap/join.
     484        ''Closed'' specifies if the end of the line is closed. If it is not closed,
     485        a space is left so that the next line can fit }
     486    procedure DrawLineAntialias(x1, y1, x2, y2: single; c: TBGRAPixel; w: single; ClosedCap: boolean); override;
     487    {** Same as above with ''texture'' specifying the source color to use when filling the line }
     488    procedure DrawLineAntialias(x1, y1, x2, y2: single; texture: IBGRAScanner; w: single; ClosedCap: boolean); override;
     489
     490    {** Draws a polyline using current pen style/cap/join }
    287491    procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single); override;
     492    {** Draws a polyline using current pen style/cap/join.
     493        ''texture'' specifies the source color to use when filling the line }
    288494    procedure DrawPolyLineAntialias(const points: array of TPointF; texture: IBGRAScanner; w: single); override;
    289     procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; Closed: boolean); override;
     495    {** Draws a polyline using current pen style/cap/join.
     496        ''Closed'' specifies if the end of the line is closed. If it is not closed,
     497        a space is left so that the next line can fit }
     498    procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; ClosedCap: boolean); override;
     499    procedure DrawPolyLineAntialias(const points: array of TPointF; texture: IBGRAScanner; w: single; ClosedCap: boolean); override;
     500    {** Draws a polyline using current pen style/cap/join.
     501        ''fillcolor'' specifies a color to fill the polygon formed by the points }
    290502    procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); override;
     503    {** Draws a polyline using current pen style/cap/join.
     504        The last point considered as a join with the first point if it has
     505        the same coordinate }
     506    procedure DrawPolyLineAntialiasAutocycle(const points: array of TPointF; c: TBGRAPixel; w: single); override;
     507    procedure DrawPolyLineAntialiasAutocycle(const points: array of TPointF; texture: IBGRAScanner; w: single); override;
     508    {** Draws a polygon using current pen style/cap/join.
     509        The polygon is always closed. You don't need to set the last point
     510        to be the same as the first point }
    291511    procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single); override;
     512    {** Draws a polygon using current pen style/cap/join.
     513        The polygon is always closed. You don't need to set the last point
     514        to be the same as the first point }
    292515    procedure DrawPolygonAntialias(const points: array of TPointF; texture: IBGRAScanner; w: single); override;
     516    {** Draws a filled polygon using current pen style/cap/join.
     517        The polygon is always closed. You don't need to set the last point
     518        to be the same as the first point. }
    293519    procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); override;
    294520
    295     procedure EraseLine(x1, y1, x2, y2: integer; alpha: byte; DrawLastPixel: boolean); override;
    296     procedure EraseLineAntialias(x1, y1, x2, y2: integer; alpha: byte; DrawLastPixel: boolean); override;
     521    {** Erases a line from (x1,y1) to (x2,y2) using current pen style/cap/join }
    297522    procedure EraseLineAntialias(x1, y1, x2, y2: single; alpha: byte; w: single); override;
     523    {** Erases a line from (x1,y1) to (x2,y2) using current pen style/cap/join.
     524        ''Closed'' specifies if the end of the line is closed. If it is not closed,
     525        a space is left so that the next line can fit }
    298526    procedure EraseLineAntialias(x1, y1, x2, y2: single; alpha: byte; w: single; Closed: boolean); override;
     527    {** Erases a polyline using current pen style/cap/join }
    299528    procedure ErasePolyLineAntialias(const points: array of TPointF; alpha: byte; w: single); override;
    300529
    301     procedure FillPath(APath: IBGRAPath; c: TBGRAPixel); override;
    302     procedure FillPath(APath: IBGRAPath; texture: IBGRAScanner); override;
    303 
    304     procedure FillTriangleLinearColor(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); override;
    305     procedure FillTriangleLinearColorAntialias(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); override;
    306     procedure FillTriangleLinearMapping(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; TextureInterpolation: Boolean= True); override;
    307     procedure FillTriangleLinearMappingLightness(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; light1,light2,light3: word; TextureInterpolation: Boolean= True); override;
    308     procedure FillTriangleLinearMappingAntialias(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF); override;
    309 
    310     procedure FillQuadLinearColor(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); override;
    311     procedure FillQuadLinearColorAntialias(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); override;
    312     procedure FillQuadLinearMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; TextureInterpolation: Boolean= True); override;
    313     procedure FillQuadLinearMappingLightness(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; light1,light2,light3,light4: word; TextureInterpolation: Boolean= True); override;
    314     procedure FillQuadLinearMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); override;
    315     procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); override;
    316     procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); override;
    317     procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); override;
    318     procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); override;
    319 
    320     procedure FillPolyLinearMapping(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean); override;
    321     procedure FillPolyLinearMappingLightness(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; lightnesses: array of word; TextureInterpolation: Boolean); override;
    322     procedure FillPolyLinearColor(const points: array of TPointF; AColors: array of TBGRAPixel); override;
    323     procedure FillPolyPerspectiveMapping(const points: array of TPointF; const pointsZ: array of single; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean; zbuffer: psingle = nil); override;
    324     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); override;
    325 
     530    {==== Rectangles (integer coordinates) ====}
     531    {* The integer coordinates of rectangles interpreted such that
     532       that the bottom/right pixels are not drawn. The width is equal
     533       to x2-x, and pixels are drawn from x to x2-1. If x = x2, then nothing
     534       is drawn. See [[BGRABitmap tutorial 13|coordinate system]].
     535     * These functions do not take into account current pen style/cap/join.
     536       They draw a continuous 1-pixel width border }
     537
     538    {** Draw a size border of a rectangle,
     539        using the specified ''mode'' }
     540    procedure Rectangle(x, y, x2, y2: integer; c: TBGRAPixel; mode: TDrawMode); override;
     541    {** Draw a filled rectangle with a border of color ''BorderColor'',
     542        using the specified ''mode'' }
     543    procedure Rectangle(x, y, x2, y2: integer; BorderColor, FillColor: TBGRAPixel; mode: TDrawMode); override;
     544    {** Fills completely a rectangle, without any border, with the specified ''mode'' }
     545    procedure FillRect(x, y, x2, y2: integer; c: TBGRAPixel; mode: TDrawMode); override; overload;
     546    {** Fills completely a rectangle, without any border, with the specified ''texture'' and
     547        with the specified ''mode'' }
     548    procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode; AScanOffset: TPoint); override; overload;
     549    procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode; AScanOffset: TPoint; ditheringAlgorithm: TDitheringAlgorithm); override; overload;
     550    {** Sets the alpha value within the specified rectangle }
     551    procedure AlphaFillRect(x, y, x2, y2: integer; alpha: byte); override;
     552    {** Draws a filled round rectangle, with corners having an elliptical diameter of ''DX'' and ''DY'' }
     553    procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; BorderColor, FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); override;
     554    {** Draws a round rectangle, with corners having an elliptical diameter of ''DX'' and ''DY'' }
     555    procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; BorderColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); override;
     556
     557    {==== Rectangles and ellipses (floating point coordinates) ====}
     558    {* These functions use the current pen style/cap/join. The parameter ''w''
     559       specifies the width of the line and the base unit for dashes
     560     * The coordinates are pixel-centered, so that when filling a rectangle,
     561       if the supplied values are integers, the border will be half transparent.
     562       If you want the border to be completely filled, you can subtract/add
     563       0.5 to the coordinates to include the remaining thin border.
     564       See [[BGRABitmap tutorial 13|coordinate system]]. }
     565
     566    {** Draws a rectangle with antialiasing and fills it with color ''back''.
     567        Note that the pixel (x2,y2) is included contrary to integer coordinates }
     568    procedure RectangleAntialias(x, y, x2, y2: single; c: TBGRAPixel; w: single; back: TBGRAPixel); override;
     569    {** Draws a rectangle with antialiasing. Note that the pixel (x2,y2) is
     570        included contrary to integer coordinates }
     571    procedure RectangleAntialias(x, y, x2, y2: single; texture: IBGRAScanner; w: single); override;
     572    {** Fills a rectangle with antialiasing. For example (-0.5,-0.5,0.5,0.5)
     573        fills one pixel }
     574    procedure FillRectAntialias(x, y, x2, y2: single; c: TBGRAPixel; pixelCenteredCoordinates: boolean = true); override;
     575    {** Fills a rectangle with a texture }
     576    procedure FillRectAntialias(x, y, x2, y2: single; texture: IBGRAScanner; pixelCenteredCoordinates: boolean = true); override;
     577    {** Erases the content of a rectangle with antialiasing }
     578    procedure EraseRectAntialias(x, y, x2, y2: single; alpha: byte; pixelCenteredCoordinates: boolean = true); override;
     579
     580    {** Draws a rounded rectangle border with antialiasing. The corners have an
     581        elliptical radius of ''rx'' and ''ry''. ''options'' specifies how to
     582        draw the corners. See [[BGRABitmap Geometry types|geometry types]] }
     583    procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; w: single; options: TRoundRectangleOptions = []); override;
     584    {** Draws a rounded rectangle border with the specified texture.
     585        The corners have an elliptical radius of ''rx'' and ''ry''.
     586        ''options'' specifies how to draw the corners.
     587        See [[BGRABitmap Geometry types|geometry types]] }
     588    procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; w: single; options: TRoundRectangleOptions = []); override;
     589    {** Draws and fills a round rectangle }
     590    procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; pencolor: TBGRAPixel; w: single; fillcolor: TBGRAPixel; options: TRoundRectangleOptions = []); override;
     591    {** Draws and fills a round rectangle with textures }
     592    procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; penTexture: IBGRAScanner; w: single; fillTexture: IBGRAScanner; options: TRoundRectangleOptions = []); override;
     593
     594    {** Fills a rounded rectangle with antialiasing. The corners have an
     595        elliptical radius of ''rx'' and ''ry''. ''options'' specifies how to
     596        draw the corners. See [[BGRABitmap Geometry types|geometry types]] }
     597    procedure FillRoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; options: TRoundRectangleOptions = []; pixelCenteredCoordinates: boolean = true); override;
     598    {** Fills a rounded rectangle with a texture }
     599    procedure FillRoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; options: TRoundRectangleOptions = []; pixelCenteredCoordinates: boolean = true); override;
     600    {** Erases the content of a rounded rectangle with a texture }
     601    procedure EraseRoundRectAntialias(x,y,x2,y2,rx,ry: single; alpha: byte; options: TRoundRectangleOptions = []; pixelCenteredCoordinates: boolean = true); override;
     602
     603    {** Draws an ellipse with antialising. ''rx'' is the horizontal radius and
     604        ''ry'' the vertical radius }
     605    procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single); override;
     606    {** Draws an ellipse border with a ''texture'' }
     607    procedure EllipseAntialias(x, y, rx, ry: single; texture: IBGRAScanner; w: single); override;
     608    {** Draws and fills an ellipse }
     609    procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single; back: TBGRAPixel); override;
     610    {** Fills an ellipse }
     611    procedure FillEllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel); override;
     612    {** Fills an ellipse with a ''texture'' }
     613    procedure FillEllipseAntialias(x, y, rx, ry: single; texture: IBGRAScanner); override;
     614    {** Fills an ellipse with a gradient of color. ''outercolor'' specifies
     615        the end color of the gradient on the border of the ellipse and
     616        ''innercolor'' the end color of the gradient at the center of the
     617        ellipse }
     618    procedure FillEllipseLinearColorAntialias(x, y, rx, ry: single; outercolor, innercolor: TBGRAPixel); override;
     619    {** Erases the content of an ellipse }
     620    procedure EraseEllipseAntialias(x, y, rx, ry: single; alpha: byte); override;
     621
     622    {==== Polygons and path ====}
    326623    procedure FillPoly(const points: array of TPointF; c: TBGRAPixel; drawmode: TDrawMode); override;
    327624    procedure FillPoly(const points: array of TPointF; texture: IBGRAScanner; drawmode: TDrawMode); override;
     
    331628    procedure ErasePolyAntialias(const points: array of TPointF; alpha: byte); override;
    332629
     630    procedure FillTriangleLinearColor(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); override;
     631    procedure FillTriangleLinearColorAntialias(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); override;
     632    procedure FillTriangleLinearMapping(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; TextureInterpolation: Boolean= True); override;
     633    procedure FillTriangleLinearMappingLightness(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; light1,light2,light3: word; TextureInterpolation: Boolean= True); override;
     634    procedure FillTriangleLinearMappingAntialias(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF); override;
     635
     636    procedure FillQuadLinearColor(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); override;
     637    procedure FillQuadLinearColorAntialias(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); override;
     638    procedure FillQuadLinearMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; TextureInterpolation: Boolean= True; ACulling: TFaceCulling = fcNone); override;
     639    procedure FillQuadLinearMappingLightness(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; light1,light2,light3,light4: word; TextureInterpolation: Boolean= True); override;
     640    procedure FillQuadLinearMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACulling: TFaceCulling = fcNone); override;
     641    procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ADrawMode: TDrawMode = dmDrawWithTransparency); override;
     642    procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect; ADrawMode: TDrawMode = dmDrawWithTransparency); override;
     643    procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); override;
     644    procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); override;
     645    procedure FillQuadAffineMapping(Orig,HAxis,VAxis: TPointF; AImage: TBGRACustomBitmap; APixelCenteredCoordinates: boolean = true; ADrawMode: TDrawMode = dmDrawWithTransparency; AOpacity: byte = 255); override;
     646    procedure FillQuadAffineMappingAntialias(Orig,HAxis,VAxis: TPointF; AImage: TBGRACustomBitmap; APixelCenteredCoordinates: boolean = true; AOpacity: byte = 255); override;
     647
     648    procedure FillPolyLinearMapping(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean); override;
     649    procedure FillPolyLinearMappingLightness(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; lightnesses: array of word; TextureInterpolation: Boolean); override;
     650    procedure FillPolyLinearColor(const points: array of TPointF; AColors: array of TBGRAPixel); override;
     651    procedure FillPolyPerspectiveMapping(const points: array of TPointF; const pointsZ: array of single; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean; zbuffer: psingle = nil); override;
     652    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); override;
     653
    333654    procedure FillShape(shape: TBGRACustomFillInfo; c: TBGRAPixel; drawmode: TDrawMode); override;
    334655    procedure FillShape(shape: TBGRACustomFillInfo; texture: IBGRAScanner; drawmode: TDrawMode); override;
     
    338659    procedure EraseShapeAntialias(shape: TBGRACustomFillInfo; alpha: byte); override;
    339660
    340     procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single); override;
    341     procedure EllipseAntialias(x, y, rx, ry: single; texture: IBGRAScanner; w: single); override;
    342     procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single; back: TBGRAPixel); override;
    343     procedure FillEllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel); override;
    344     procedure FillEllipseAntialias(x, y, rx, ry: single; texture: IBGRAScanner); override;
    345     procedure FillEllipseLinearColorAntialias(x, y, rx, ry: single; outercolor, innercolor: TBGRAPixel); override;
    346     procedure EraseEllipseAntialias(x, y, rx, ry: single; alpha: byte); override;
    347 
    348     procedure Rectangle(x, y, x2, y2: integer; c: TBGRAPixel; mode: TDrawMode); override;
    349     procedure Rectangle(x, y, x2, y2: integer; BorderColor, FillColor: TBGRAPixel; mode: TDrawMode); override;
    350     procedure RectangleAntialias(x, y, x2, y2: single; c: TBGRAPixel; w: single; back: TBGRAPixel); override;
    351     procedure RectangleAntialias(x, y, x2, y2: single; texture: IBGRAScanner; w: single); override;
    352 
    353     procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; w: single; options: TRoundRectangleOptions = []); override;
    354     procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; w: single; options: TRoundRectangleOptions = []); override;
    355     procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; pencolor: TBGRAPixel; w: single; fillcolor: TBGRAPixel; options: TRoundRectangleOptions = []); override;
    356     procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; penTexture: IBGRAScanner; w: single; fillTexture: IBGRAScanner; options: TRoundRectangleOptions = []); override;
    357 
    358     procedure FillRect(x, y, x2, y2: integer; c: TBGRAPixel; mode: TDrawMode); override; overload;
    359     procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode); override; overload;
    360     procedure FillRectAntialias(x, y, x2, y2: single; c: TBGRAPixel); override;
    361     procedure EraseRectAntialias(x, y, x2, y2: single; alpha: byte); override;
    362     procedure FillRectAntialias(x, y, x2, y2: single; texture: IBGRAScanner); override;
    363     procedure FillRoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; options: TRoundRectangleOptions = []); override;
    364     procedure FillRoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; options: TRoundRectangleOptions = []); override;
    365     procedure EraseRoundRectAntialias(x,y,x2,y2,rx,ry: single; alpha: byte; options: TRoundRectangleOptions = []); override;
    366     procedure AlphaFillRect(x, y, x2, y2: integer; alpha: byte); override;
    367     procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer;
    368       BorderColor, FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); override;
    369     procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer;
    370       BorderColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); override;
     661    procedure DrawPath(APath: IBGRAPath; AStrokeColor: TBGRAPixel; AWidth: single; AFillColor: TBGRAPixel); override;
     662    procedure DrawPath(APath: IBGRAPath; AStrokeTexture: IBGRAScanner; AWidth: single; AFillColor: TBGRAPixel); override;
     663    procedure DrawPath(APath: IBGRAPath; AStrokeColor: TBGRAPixel; AWidth: single; AFillTexture: IBGRAScanner); override;
     664    procedure DrawPath(APath: IBGRAPath; AStrokeTexture: IBGRAScanner; AWidth: single; AFillTexture: IBGRAScanner); override;
     665    procedure DrawPath(APath: IBGRAPath; AStrokeColor: TBGRAPixel; AWidth: single); override;
     666    procedure DrawPath(APath: IBGRAPath; AStrokeTexture: IBGRAScanner; AWidth: single); override;
     667    procedure FillPath(APath: IBGRAPath; AFillColor: TBGRAPixel); override;
     668    procedure FillPath(APath: IBGRAPath; AFillTexture: IBGRAScanner); override;
     669    procedure ErasePath(APath: IBGRAPath; alpha: byte); override;
     670
     671    procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeColor: TBGRAPixel; AWidth: single; AFillColor: TBGRAPixel); override;
     672    procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeTexture: IBGRAScanner; AWidth: single; AFillColor: TBGRAPixel); override;
     673    procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeColor: TBGRAPixel; AWidth: single; AFillTexture: IBGRAScanner); override;
     674    procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeTexture: IBGRAScanner; AWidth: single; AFillTexture: IBGRAScanner); override;
     675    procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeColor: TBGRAPixel; AWidth: single); override;
     676    procedure DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AStrokeTexture: IBGRAScanner; AWidth: single); override;
     677    procedure FillPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AFillColor: TBGRAPixel); override;
     678    procedure FillPath(APath: IBGRAPath; AMatrix: TAffineMatrix; AFillTexture: IBGRAScanner); override;
     679    procedure ErasePath(APath: IBGRAPath; AMatrix: TAffineMatrix; alpha: byte); override;
     680
     681    procedure ArrowStartAsNone; override;
     682    procedure ArrowStartAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); override;
     683    procedure ArrowStartAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); override;
     684    procedure ArrowStartAsTail; override;
     685
     686    procedure ArrowEndAsNone; override;
     687    procedure ArrowEndAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); override;
     688    procedure ArrowEndAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); override;
     689    procedure ArrowEndAsTail; override;
    371690
    372691    { Draws the UTF8 encoded string, with color c.
     
    385704    procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); override; overload;
    386705
     706    procedure TextOutCurved(ACursor: TBGRACustomPathCursor; sUTF8: string; AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single); override; overload;
     707    procedure TextOutCurved(ACursor: TBGRACustomPathCursor; sUTF8: string; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single); override; overload;
     708
    387709    { Draw the UTF8 encoded string at the coordinate (x,y), clipped inside the rectangle ARect.
    388710      Additional style information is provided by the style parameter.
     
    405727
    406728    function ComputeWidePolyline(const points: array of TPointF; w: single): ArrayOfTPointF; override;
    407     function ComputeWidePolyline(const points: array of TPointF; w: single; Closed: boolean): ArrayOfTPointF; override;
     729    function ComputeWidePolyline(const points: array of TPointF; w: single; ClosedCap: boolean): ArrayOfTPointF; override;
    408730    function ComputeWidePolygon(const points: array of TPointF; w: single): ArrayOfTPointF; override;
    409731
     
    425747    procedure AlphaFill(alpha: byte; start, Count: integer); override;
    426748    procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ADrawMode: TDrawMode); override;
    427     procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ADrawMode: TDrawMode); override;
     749    procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ADrawMode: TDrawMode; AOpacity: byte = 255); override;
    428750    procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ARGBOrder: boolean = true); override;
    429751    procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ARGBOrder: boolean = true); override;
    430752    procedure ReplaceColor(before, after: TColor); override;
    431753    procedure ReplaceColor(before, after: TBGRAPixel); override;
     754    procedure ReplaceColor(ABounds: TRect; before, after: TColor); override;
     755    procedure ReplaceColor(ABounds: TRect; before, after: TBGRAPixel); override;
    432756    procedure ReplaceTransparent(after: TBGRAPixel); override;
     757    procedure ReplaceTransparent(ABounds: TRect; after: TBGRAPixel); override;
    433758    procedure ParallelFloodFill(X, Y: integer; Dest: TBGRACustomBitmap; Color: TBGRAPixel;
    434759      mode: TFloodfillMode; Tolerance: byte = 0); override;
    435760    procedure GradientFill(x, y, x2, y2: integer; c1, c2: TBGRAPixel;
    436761      gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode;
    437       gammaColorCorrection: boolean = True; Sinus: Boolean=False); override;
     762      gammaColorCorrection: boolean = True; Sinus: Boolean=False;
     763      ditherAlgo: TDitheringAlgorithm = daNearestNeighbor); override;
    438764    procedure GradientFill(x, y, x2, y2: integer; gradient: TBGRACustomGradient;
    439765      gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode;
    440       Sinus: Boolean=False); override;
     766      Sinus: Boolean=False; ditherAlgo: TDitheringAlgorithm = daNearestNeighbor); override;
    441767    function CreateBrushTexture(ABrushStyle: TBrushStyle; APatternColor, ABackgroundColor: TBGRAPixel;
    442768                AWidth: integer = 8; AHeight: integer = 8; APenWidth: single = 1): TBGRACustomBitmap; override;
     
    449775
    450776    {Canvas drawing functions}
    451     procedure DataDrawTransparent(ACanvas: TCanvas; Rect: TRect;
    452       AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer); override;
    453     procedure DataDrawOpaque(ACanvas: TCanvas; Rect: TRect; AData: Pointer;
    454       ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer); override;
    455     procedure GetImageFromCanvas(CanvasSource: TCanvas; x, y: integer); override;
    456777    procedure Draw(ACanvas: TCanvas; x, y: integer; Opaque: boolean = True); override;
    457778    procedure Draw(ACanvas: TCanvas; Rect: TRect; Opaque: boolean = True); override;
     
    463784    procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadeMask: IBGRAScanner; mode: TDrawMode = dmDrawWithTransparency); override;
    464785    procedure PutImage(x, y: integer; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); override;
    465     procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); override;
     786    procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); override; overload;
     787    function GetImageAffineBounds(AMatrix: TAffineMatrix; ASourceBounds: TRect; AClipOutput: boolean = true): TRect; override; overload;
     788    function IsAffineRoughlyTranslation(AMatrix: TAffineMatrix; ASourceBounds: TRect): boolean; override;
     789
    466790    procedure StretchPutImage(ARect: TRect; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); override;
    467791
     
    476800    function Equals(comp: TBGRACustomBitmap): boolean; override;
    477801    function Equals(comp: TBGRAPixel): boolean; override;
    478     function GetImageBounds(Channel: TChannel = cAlpha; ANothingValue: Byte = 0): TRect; override;
    479     function GetImageBounds(Channels: TChannels; ANothingValue: Byte = 0): TRect; override;
    480802    function GetDifferenceBounds(ABitmap: TBGRACustomBitmap): TRect; override;
    481803    function MakeBitmapCopy(BackgroundColor: TColor): TBitmap; override;
     
    483805    function Resample(newWidth, newHeight: integer;
    484806      mode: TResampleMode = rmFineResample): TBGRACustomBitmap; override;
    485     procedure VerticalFlip(ARect: TRect); override;
    486     procedure HorizontalFlip(ARect: TRect); override;
     807    procedure VerticalFlip(ARect: TRect); override; overload;
     808    procedure HorizontalFlip(ARect: TRect); override; overload;
    487809    function RotateCW: TBGRACustomBitmap; override;
    488810    function RotateCCW: TBGRACustomBitmap; override;
     
    491813    procedure LinearNegative; override;
    492814    procedure LinearNegativeRect(ABounds: TRect); override;
    493     procedure InplaceGrayscale; override;
    494     procedure InplaceGrayscale(ABounds: TRect); override;
     815    procedure InplaceGrayscale(AGammaCorrection: boolean = true); override;
     816    procedure InplaceGrayscale(ABounds: TRect; AGammaCorrection: boolean = true); override;
     817    procedure InplaceNormalize(AEachChannel: boolean = True); override;
     818    procedure InplaceNormalize(ABounds: TRect; AEachChannel: boolean = True); override;
    495819    procedure SwapRedBlue; override;
     820    procedure SwapRedBlue(ARect: TRect); override;
    496821    procedure GrayscaleToAlpha; override;
    497822    procedure AlphaToGrayscale; override;
    498     procedure ApplyMask(mask: TBGRACustomBitmap; ARect: TRect; AMaskRectTopLeft: TPoint); override;
     823    procedure ApplyMask(mask: TBGRACustomBitmap; ARect: TRect; AMaskRectTopLeft: TPoint); override; overload;
    499824    procedure ApplyGlobalOpacity(alpha: byte); override;
     825    procedure ApplyGlobalOpacity(ABounds: TRect; alpha: byte); override;
    500826    procedure ConvertToLinearRGB; override;
    501827    procedure ConvertFromLinearRGB; override;
     
    510836    function FilterContour: TBGRACustomBitmap; override;
    511837    function FilterPixelate(pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear): TBGRACustomBitmap; override;
    512     function FilterBlurRadial(radius: integer;
    513       blurType: TRadialBlurType): TBGRACustomBitmap; override;
    514     function FilterBlurRadial(ABounds: TRect; radius: integer;
    515       blurType: TRadialBlurType): TBGRACustomBitmap; override;
    516     function FilterBlurMotion(distance: integer; angle: single;
    517       oriented: boolean): TBGRACustomBitmap; override;
    518     function FilterBlurMotion(ABounds: TRect; distance: integer; angle: single;
    519       oriented: boolean): TBGRACustomBitmap; override;
     838    function FilterBlurRadial(radius: single; blurType: TRadialBlurType): TBGRACustomBitmap; override;
     839    function FilterBlurRadial(ABounds: TRect; radius: single; blurType: TRadialBlurType): TBGRACustomBitmap; override;
     840    function FilterBlurRadial(radiusX, radiusY: single; blurType: TRadialBlurType): TBGRACustomBitmap; override;
     841    function FilterBlurRadial(ABounds: TRect; radiusX, radiusY: single; blurType: TRadialBlurType): TBGRACustomBitmap; override;
     842    function FilterBlurMotion(distance: single; angle: single; oriented: boolean): TBGRACustomBitmap; override;
     843    function FilterBlurMotion(ABounds: TRect; distance: single; angle: single; oriented: boolean): TBGRACustomBitmap; override;
    520844    function FilterCustomBlur(mask: TBGRACustomBitmap): TBGRACustomBitmap; override;
    521845    function FilterCustomBlur(ABounds: TRect; mask: TBGRACustomBitmap): TBGRACustomBitmap; override;
    522     function FilterEmboss(angle: single): TBGRACustomBitmap; override;
    523     function FilterEmboss(angle: single; ABounds: TRect): TBGRACustomBitmap; override;
     846    function FilterEmboss(angle: single; AStrength: integer= 64; AOptions: TEmbossOptions = []): TBGRACustomBitmap; override;
     847    function FilterEmboss(angle: single; ABounds: TRect; AStrength: integer= 64; AOptions: TEmbossOptions = []): TBGRACustomBitmap; override;
    524848    function FilterEmbossHighlight(FillSelection: boolean): TBGRACustomBitmap; override;
    525849    function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel): TBGRACustomBitmap; override;
     
    530854    function FilterNormalize(ABounds: TRect; eachChannel: boolean = True): TBGRACustomBitmap; override;
    531855    function FilterRotate(origin: TPointF; angle: single; correctBlur: boolean = false): TBGRACustomBitmap; override;
     856    function FilterAffine(AMatrix: TAffineMatrix; correctBlur: boolean = false): TBGRACustomBitmap; override;
    532857    function FilterSphere: TBGRACustomBitmap; override;
    533858    function FilterTwirl(ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; override;
     
    535860    function FilterCylinder: TBGRACustomBitmap; override;
    536861    function FilterPlane: TBGRACustomBitmap; override;
    537 
    538     property CanvasBGRA: TBGRACanvas read GetCanvasBGRA;
    539     property Canvas2D: TBGRACanvas2D read GetCanvas2D;
    540862  end;
    541863
     
    544866  TBGRAPtrBitmap = class(TBGRADefaultBitmap)
    545867  protected
     868    function GetLineOrder: TRawImageLineOrder; override;
     869    procedure SetLineOrder(AValue: TRawImageLineOrder); override;
    546870    procedure ReallocData; override;
    547871    procedure FreeData; override;
     872    procedure CannotResize;
     873    procedure NotImplemented;
     874    procedure RebuildBitmap; override;
     875
     876    function CreateDefaultFontRenderer: TBGRACustomFontRenderer; override; //to override
     877    function LoadFromRawImage({%H-}ARawImage: TRawImage; {%H-}DefaultOpacity: byte;
     878      {%H-}AlwaysReplaceAlpha: boolean=False; {%H-}RaiseErrorOnInvalidPixelFormat: boolean
     879      =True): boolean; override; //to override
    548880  public
    549881    constructor Create(AWidth, AHeight: integer; AData: Pointer); overload;
    550882    function Duplicate(DuplicateProperties: Boolean = False): TBGRACustomBitmap; override;
    551883    procedure SetDataPtr(AData: Pointer);
    552     property LineOrder: TRawImageLineOrder Read FLineOrder Write FLineOrder;
     884    property LineOrder: TRawImageLineOrder Read GetLineOrder Write SetLineOrder;
     885
     886    procedure DataDrawTransparent({%H-}ACanvas: TCanvas; {%H-}Rect: TRect; {%H-}AData: Pointer;
     887      {%H-}ALineOrder: TRawImageLineOrder; {%H-}AWidth, {%H-}AHeight: integer); override; //to override
     888    procedure DataDrawOpaque({%H-}ACanvas: TCanvas; {%H-}Rect: TRect; {%H-}AData: Pointer;
     889      {%H-}ALineOrder: TRawImageLineOrder; {%H-}AWidth, {%H-}AHeight: integer); override; //to override
     890    procedure GetImageFromCanvas({%H-}CanvasSource: TCanvas; {%H-}x, {%H-}y: integer); override; //to override
     891
     892    procedure Assign({%H-}Source: TPersistent); override;
     893    procedure TakeScreenshot({%H-}ARect: TRect); override;
     894    procedure TakeScreenshotOfPrimaryMonitor; override;
     895    procedure LoadFromDevice({%H-}DC: System.THandle); override;
     896    procedure LoadFromDevice({%H-}DC: System.THandle; {%H-}ARect: TRect); override;
    553897  end;
    554898
     
    560904  gammaColorCorrection: boolean = True; Sinus: Boolean=False);
    561905
    562 implementation
    563 
    564 uses Math, LCLIntf, LCLType,
    565   BGRABlend, BGRAFilters, BGRAText, BGRATextFX, BGRAGradientScanner,
    566   BGRAResample, BGRATransform, BGRAPolygon, BGRAPolygonAliased,
    567   BGRAPath, FPReadPcx, FPWritePcx, FPReadXPM, FPWriteXPM;
    568 
    569906type
     907
     908  { TBitmapTracker }
     909
    570910  TBitmapTracker = class(TBitmap)
    571911  protected
     
    576916  end;
    577917
     918implementation
     919
     920uses Math, BGRAUTF8, BGRABlend, BGRAFilters, BGRAGradientScanner,
     921  BGRAResample, BGRAPolygon, BGRAPolygonAliased,
     922  BGRAPath, FPReadPcx, FPWritePcx, FPReadXPM, FPWriteXPM,
     923  BGRAReadBMP, BGRAReadJpeg,
     924  BGRADithering, BGRAFilterScanner;
     925
     926{ TBitmapTracker }
     927
    578928constructor TBitmapTracker.Create(AUser: TBGRADefaultBitmap);
    579929begin
     
    592942
    593943function TBGRADefaultBitmap.CheckEmpty: boolean;
     944const
     945  alphaMask = $ff shl TBGRAPixel_AlphaShift;
    594946var
    595947  i: integer;
     
    597949begin
    598950  p := Data;
    599   for i := NbPixels - 1 downto 0 do
    600   begin
    601     if p^.alpha <> 0 then
     951  for i := (NbPixels shr 1) - 1 downto 0 do
     952  begin
     953    if PInt64(p)^ and (alphaMask or (alphaMask shl 32)) <> 0 then
    602954    begin
    603955      Result := False;
    604956      exit;
    605957    end;
    606     Inc(p);
     958    Inc(p,2);
     959  end;
     960  if Odd(NbPixels) and (p^.alpha <> 0) then
     961  begin
     962    Result := false;
     963    exit;
    607964  end;
    608965  Result := True;
     
    616973function TBGRADefaultBitmap.GetCustomPenStyle: TBGRAPenStyle;
    617974begin
    618   result := DuplicatePenStyle(FCustomPenStyle);
     975  result := DuplicatePenStyle(FPenStroker.CustomPenStyle);
    619976end;
    620977
     
    628985  else
    629986    FCanvasOpacity := 0;
     987end;
     988
     989procedure TBGRADefaultBitmap.DoLoadFromBitmap;
     990begin
     991  //nothing
    630992end;
    631993
     
    6481010procedure TBGRADefaultBitmap.SetCustomPenStyle(const AValue: TBGRAPenStyle);
    6491011begin
    650   FCustomPenStyle := DuplicatePenStyle(AValue);
     1012  FPenStroker.CustomPenStyle := DuplicatePenStyle(AValue);
    6511013end;
    6521014
    6531015procedure TBGRADefaultBitmap.SetPenStyle(const AValue: TPenStyle);
    6541016begin
    655   Case AValue of
    656   psSolid: CustomPenStyle := SolidPenStyle;
    657   psDash: CustomPenStyle := DashPenStyle;
    658   psDot: CustomPenStyle := DotPenStyle;
    659   psDashDot: CustomPenStyle := DashDotPenStyle;
    660   psDashDotDot: CustomPenStyle := DashDotDotPenStyle;
    661   else CustomPenStyle := ClearPenStyle;
    662   end;
    663   FPenStyle := AValue;
     1017  FPenStroker.Style := AValue;
    6641018end;
    6651019
    6661020function TBGRADefaultBitmap.GetPenStyle: TPenStyle;
    6671021begin
    668   Result:= FPenStyle;
     1022  Result:= FPenStroker.Style;
    6691023end;
    6701024
    6711025function TBGRADefaultBitmap.GetLineCap: TPenEndCap;
    6721026begin
    673   result := FLineCap;
     1027  result := FPenStroker.LineCap;
    6741028end;
    6751029
    6761030procedure TBGRADefaultBitmap.SetLineCap(AValue: TPenEndCap);
    6771031begin
    678   if AValue <> FLineCap then
    679   begin
    680     FLineCap:= AValue;
    681     if Assigned(FArrow) then FArrow.LineCap := AValue;
    682   end;
     1032  if AValue <> FPenStroker.LineCap then
     1033  begin
     1034    FPenStroker.LineCap := AValue;
     1035    if Assigned(FPenStroker.Arrow) then
     1036      FPenStroker.Arrow.LineCap := AValue;
     1037  end;
     1038end;
     1039
     1040function TBGRADefaultBitmap.GetPenStroker: TBGRACustomPenStroker;
     1041begin
     1042  result := FPenStroker;
    6831043end;
    6841044
     
    7711131function TBGRADefaultBitmap.GetFontRenderer: TBGRACustomFontRenderer;
    7721132begin
    773   if FFontRenderer = nil then FFontRenderer := TLCLFontRenderer.Create;
     1133  if FFontRenderer = nil then FFontRenderer := CreateDefaultFontRenderer;
     1134  if FFontRenderer = nil then raise exception.Create('No font renderer');
    7741135  result := FFontRenderer;
    7751136  result.FontName := FontName;
     
    7871148end;
    7881149
     1150function TBGRADefaultBitmap.GetFontAnchorVerticalOffset: single;
     1151begin
     1152  case FontVerticalAnchor of
     1153  fvaTop: result := 0;
     1154  fvaCenter: result := FontFullHeight*0.5;
     1155  fvaCapLine: result := FontPixelMetric.CapLine;
     1156  fvaCapCenter: result := (FontPixelMetric.CapLine+FontPixelMetric.Baseline)*0.5;
     1157  fvaXLine: result := FontPixelMetric.xLine;
     1158  fvaXCenter: result := (FontPixelMetric.xLine+FontPixelMetric.Baseline)*0.5;
     1159  fvaBaseline: result := FontPixelMetric.Baseline;
     1160  fvaDescentLine: result := FontPixelMetric.DescentLine;
     1161  fvaBottom: result := FontFullHeight;
     1162  else
     1163    result := 0;
     1164  end;
     1165end;
     1166
     1167function TBGRADefaultBitmap.GetFontAnchorRotatedOffset: TPointF;
     1168begin
     1169  result := GetFontAnchorRotatedOffset(FontOrientation);
     1170end;
     1171
     1172function TBGRADefaultBitmap.GetFontAnchorRotatedOffset(
     1173  ACustomOrientation: integer): TPointF;
     1174begin
     1175  result := PointF(0, GetFontAnchorVerticalOffset);
     1176  if ACustomOrientation <> 0 then
     1177    result := AffineMatrixRotationDeg(-ACustomOrientation*0.1)*result;
     1178end;
     1179
    7891180{ Get scanline without checking bounds nor updated from TBitmap }
    7901181function TBGRADefaultBitmap.GetScanlineFast(y: integer): PBGRAPixel; inline;
     
    8941285  BGRAClass := TBGRABitmapAny(self.ClassType);
    8951286  Result    := BGRAClass.Create(Filename,AIsUtf8);
     1287end;
     1288
     1289function TBGRADefaultBitmap.NewBitmap(Filename: string; AIsUtf8: boolean;
     1290  AOptions: TBGRALoadingOptions): TBGRACustomBitmap;
     1291var
     1292  BGRAClass: TBGRABitmapAny;
     1293begin
     1294  BGRAClass := TBGRABitmapAny(self.ClassType);
     1295  Result    := BGRAClass.Create(Filename,AIsUtf8,AOptions);
     1296end;
     1297
     1298function TBGRADefaultBitmap.NewBitmap(AFPImage: TFPCustomImage): TBGRACustomBitmap;
     1299var
     1300  BGRAClass: TBGRABitmapAny;
     1301begin
     1302  BGRAClass := TBGRABitmapAny(self.ClassType);
     1303  Result    := BGRAClass.Create(AFPImage);
     1304end;
     1305
     1306procedure TBGRADefaultBitmap.LoadFromStream(Str: TStream;
     1307  Handler: TFPCustomImageReader; AOptions: TBGRALoadingOptions);
     1308var OldBmpOption: TBMPTransparencyOption;
     1309  OldJpegPerf: TJPEGReadPerformance;
     1310begin
     1311  if (loBmpAutoOpaque in AOptions) and (Handler is TBGRAReaderBMP) then
     1312  begin
     1313    OldBmpOption := TBGRAReaderBMP(Handler).TransparencyOption;
     1314    TBGRAReaderBMP(Handler).TransparencyOption := toAuto;
     1315    inherited LoadFromStream(Str, Handler, AOptions);
     1316    TBGRAReaderBMP(Handler).TransparencyOption := OldBmpOption;
     1317  end else
     1318  if (loJpegQuick in AOptions) and (Handler is TBGRAReaderJpeg) then
     1319  begin
     1320    OldJpegPerf := TBGRAReaderJpeg(Handler).Performance;
     1321    TBGRAReaderJpeg(Handler).Performance := jpBestSpeed;
     1322    inherited LoadFromStream(Str, Handler, AOptions);
     1323    TBGRAReaderJpeg(Handler).Performance := OldJpegPerf;
     1324  end else
     1325    inherited LoadFromStream(Str, Handler, AOptions);
    8961326end;
    8971327
     
    9191349  FWidth    := AWidth;
    9201350  FHeight   := AHeight;
     1351  FScanWidth := FWidth;
     1352  FScanHeight:= FHeight;
    9211353  FNbPixels := AWidth * AHeight;
    9221354  if FNbPixels < 0 then // 2 Go limit
     
    9361368end;
    9371369
     1370constructor TBGRADefaultBitmap.Create(AFPImage: TFPCustomImage);
     1371begin
     1372  Init;
     1373  inherited Create(AFPImage.Width, AFPImage.Height);
     1374  Assign(AFPImage);
     1375end;
     1376
    9381377{ Creates an image of dimensions AWidth and AHeight and filled with transparent pixels. }
    939 constructor TBGRADefaultBitmap.Create(ABitmap: TBitmap);
     1378constructor TBGRADefaultBitmap.Create(ABitmap: TBitmap; AUseTransparent: boolean);
    9401379begin
    9411380  Init;
    9421381  inherited Create(ABitmap.Width, ABitmap.Height);
    943   Assign(ABitmap);
     1382  Assign(ABitmap, AUseTransparent);
    9441383end;
    9451384
     
    9731412destructor TBGRADefaultBitmap.Destroy;
    9741413begin
    975   FreeData;
     1414  FPenStroker.Free;
    9761415  FFontRenderer.Free;
    977   FBitmap.Free;
    9781416  FCanvasFP.Free;
    9791417  FCanvasBGRA.Free;
    9801418  FCanvas2D.Free;
    981   FArrow.Free;
     1419  FreeData;
     1420  FreeBitmap;
    9821421  inherited Destroy;
    9831422end;
     
    9971436end;
    9981437
     1438constructor TBGRADefaultBitmap.Create(AFilename: string; AIsUtf8: boolean;
     1439  AOptions: TBGRALoadingOptions);
     1440begin
     1441  Init;
     1442  inherited Create(0, 0);
     1443  if AIsUtf8 then
     1444    LoadFromFileUTF8(Afilename, AOptions)
     1445  else
     1446    LoadFromFile(Afilename, AOptions);
     1447end;
     1448
    9991449{ Creates an image by loading its content from the stream AStream. }
    10001450constructor TBGRADefaultBitmap.Create(AStream: TStream);
     
    10031453  inherited Create(0, 0); 
    10041454  LoadFromStream(AStream);
    1005 end;
    1006 
    1007 procedure TBGRADefaultBitmap.Assign(ARaster: TRasterImage);
    1008 var TempBmp: TBitmap;
    1009     ConvertOk: boolean;
    1010 begin
    1011   DiscardBitmapChange;
    1012   SetSize(ARaster.Width, ARaster.Height);
    1013   if not LoadFromRawImage(ARaster.RawImage,0,False,False) then
    1014   if ARaster is TBitmap then
    1015   begin //try to convert
    1016     TempBmp := TBitmap.Create;
    1017     TempBmp.Width := ARaster.Width;
    1018     TempBmp.Height := ARaster.Height;
    1019     TempBmp.Canvas.Draw(0,0,ARaster);
    1020     ConvertOk := LoadFromRawImage(TempBmp.RawImage,0,False,False);
    1021     TempBmp.Free;
    1022     if not ConvertOk then
    1023       raise Exception.Create('Unable to convert image to 24 bit');
    1024   end else
    1025     raise Exception.Create('Unable to convert image to 24 bit');
    1026   If Empty then AlphaFill(255); // if bitmap seems to be empty, assume
    1027                                 // it is an opaque bitmap without alpha channel
    1028 end;
    1029 
    1030 procedure TBGRADefaultBitmap.Assign(MemBitmap: TBGRACustomBitmap);
    1031 begin
    1032   DiscardBitmapChange;
    1033   SetSize(MemBitmap.Width, MemBitmap.Height);
    1034   PutImage(0, 0, MemBitmap, dmSet);
    10351455end;
    10361456
     
    10421462  AStream.Write(lWidth,sizeof(lWidth));
    10431463  AStream.Write(lHeight,sizeof(lHeight));
     1464  If TBGRAPixel_RGBAOrder then TBGRAFilterScannerSwapRedBlue.ComputeFilterAt(FData,FData,FNbPixels,False);
    10441465  for y := 0 to Height-1 do
    10451466    AStream.Write(ScanLine[y]^, Width*sizeof(TBGRAPixel));
    1046 end;
    1047 
    1048 {$hints off}
     1467  If TBGRAPixel_RGBAOrder then TBGRAFilterScannerSwapRedBlue.ComputeFilterAt(FData,FData,FNbPixels,False);
     1468end;
     1469
    10491470procedure TBGRADefaultBitmap.Deserialize(AStream: TStream);
    10501471var lWidth,lHeight,y: integer;
    10511472begin
    1052   AStream.Read(lWidth,sizeof(lWidth));
    1053   AStream.Read(lHeight,sizeof(lHeight));
     1473  AStream.Read({%H-}lWidth,sizeof(lWidth));
     1474  AStream.Read({%H-}lHeight,sizeof(lHeight));
    10541475  lWidth := LEtoN(lWidth);
    10551476  lHeight := LEtoN(lHeight);
     
    10571478  for y := 0 to Height-1 do
    10581479    AStream.Read(ScanLine[y]^, Width*sizeof(TBGRAPixel));
    1059 end;
    1060 {$hints on}
     1480  If TBGRAPixel_RGBAOrder then TBGRAFilterScannerSwapRedBlue.ComputeFilterAt(FData,FData,FNbPixels,False);
     1481  InvalidateBitmap;
     1482end;
    10611483
    10621484class procedure TBGRADefaultBitmap.SerializeEmpty(AStream: TStream);
     
    10681490end;
    10691491
    1070 procedure TBGRADefaultBitmap.SaveToFile(const filename: string);
    1071 var
    1072   ext:    string;
    1073   writer: TFPCustomImageWriter;
    1074 begin
    1075   ext := AnsiLowerCase(ExtractFileExt(filename));
    1076 
    1077   { When saving to PNG, define some parameters so that the
    1078     image be readable by most programs }
    1079   if ext = '.png' then
    1080     writer := CreateAdaptedPngWriter
    1081   else
    1082   if (ext='.xpm') and (Width*Height > 32768) then //xpm is slow so avoid big images
    1083     raise exception.Create('Image is too big to be saved as XPM') else
    1084       writer := nil;
    1085 
    1086   if writer <> nil then //use custom writer if defined
    1087   begin
    1088     inherited SaveToFile(Filename, writer);
    1089     writer.Free;
    1090   end
    1091   else
    1092     inherited SaveToFile(Filename);
    1093 end;
    1094 
    1095 procedure TBGRADefaultBitmap.SaveToStreamAsPng(Str: TStream);
    1096 var writer: TFPWriterPNG;
    1097 begin
    1098   writer := CreateAdaptedPngWriter;
    1099   SaveToStream(Str,writer);
    1100   writer.Free;
     1492procedure TBGRADefaultBitmap.Assign(Source: TPersistent);
     1493var pdest: PBGRAPixel;
     1494  x,y: NativeInt;
     1495begin
     1496  if Source is TBGRACustomBitmap then
     1497  begin
     1498    DiscardBitmapChange;
     1499    SetSize(TBGRACustomBitmap(Source).Width, TBGRACustomBitmap(Source).Height);
     1500    PutImage(0, 0, TBGRACustomBitmap(Source), dmSet);
     1501  end else
     1502  if Source is TFPCustomImage then
     1503  begin
     1504    DiscardBitmapChange;
     1505    SetSize(TFPCustomImage(Source).Width, TFPCustomImage(Source).Height);
     1506    for y := 0 to TFPCustomImage(Source).Height-1 do
     1507    begin
     1508      pdest := ScanLine[y];
     1509      for x := 0 to TFPCustomImage(Source).Width-1 do
     1510      begin
     1511        pdest^ := FPColorToBGRA(TFPCustomImage(Source).Colors[x,y]);
     1512        inc(pdest);
     1513      end;
     1514    end;
     1515  end else
     1516    inherited Assign(Source);
     1517end;
     1518
     1519procedure TBGRADefaultBitmap.Assign(Source: TBitmap; AUseTransparent: boolean);
     1520var
     1521  transpColor: TBGRAPixel;
     1522begin
     1523  Assign(Source);
     1524  if AUseTransparent and TBitmap(Source).Transparent then
     1525  begin
     1526    if TBitmap(Source).TransparentMode = tmFixed then
     1527      transpColor := ColorToBGRA(TBitmap(Source).TransparentColor)
     1528    else
     1529      transpColor := GetPixel(0,Height-1);
     1530    ReplaceColor(transpColor, BGRAPixelTransparent);
     1531  end;
    11011532end;
    11021533
     
    11321563  iFactY: int32or64): TBGRAPixel;
    11331564var
    1134   ixMod1,ixMod2: int32or64;
    1135   w1,w2,w3,w4,alphaW: UInt32or64;
    1136   bSum, gSum, rSum: UInt32or64;
    1137   aSum: UInt32or64;
    1138 
    1139   c:    TBGRAPixel;
     1565  ixMod2: int32or64;
     1566  pUpLeft, pUpRight, pDownLeft, pDownRight: PBGRAPixel;
    11401567  scan: PBGRAPixel;
    11411568begin
    1142   w4 := (iFactX*iFactY+127) shr 8;
    1143   w3 := iFactY-w4;
    1144   w1 := cardinal(256-iFactX)-w3;
    1145   w2 := iFactX-w4;
    1146 
    1147   rSum   := 0;
    1148   gSum   := 0;
    1149   bSum   := 0;
    1150   aSum   := 0;
    1151 
    11521569  scan := GetScanlineFast(iy);
    11531570
    1154   ixMod1 := ix;
    1155   c      := (scan + ix)^;
    1156   alphaW := c.alpha * w1;
    1157   aSum   += alphaW;
    1158 
    1159   rSum   += c.red * alphaW;
    1160   gSum   += c.green * alphaW;
    1161   bSum   += c.blue * alphaW;
    1162 
     1571  pUpLeft := (scan + ix);
    11631572  ixMod2 := ix+1;
    11641573  if ixMod2=Width then ixMod2 := 0;
    1165   c      := (scan + ixMod2)^;
    1166   alphaW := c.alpha * w2;
    1167   aSum   += alphaW;
    1168 
    1169   rSum   += c.red * alphaW;
    1170   gSum   += c.green * alphaW;
    1171   bSum   += c.blue * alphaW;
     1574  pUpRight := (scan + ixMod2);
    11721575
    11731576  Inc(iy);
    11741577  if iy = Height then iy := 0;
    11751578  scan := GetScanlineFast(iy);
    1176 
    1177   c      := (scan + ixMod2)^;
    1178   alphaW := c.alpha * w4;
    1179   aSum   += alphaW;
    1180 
    1181   rSum   += c.red * alphaW;
    1182   gSum   += c.green * alphaW;
    1183   bSum   += c.blue * alphaW;
    1184 
    1185   c      := (scan + ixMod1)^;
    1186   alphaW := c.alpha * w3;
    1187   aSum   += alphaW;
    1188 
    1189   rSum   += c.red * alphaW;
    1190   gSum   += c.green * alphaW;
    1191   bSum   += c.blue * alphaW;
    1192 
    1193   if (aSum < 128) then
    1194     Result := BGRAPixelTransparent
    1195   else
    1196   begin
    1197     Result.red   := (rSum + aSum shr 1) div aSum;
    1198     Result.green := (gSum + aSum shr 1) div aSum;
    1199     Result.blue  := (bSum + aSum shr 1) div aSum;
    1200     Result.alpha := (aSum + 128) shr 8;
    1201   end;
     1579  pDownLeft := (scan + ix);
     1580  pDownRight := (scan + ixMod2);
     1581
     1582  InterpolateBilinear(pUpLeft, pUpRight, pDownLeft,
     1583          pDownRight, iFactX, iFactY, @result);
    12021584end;
    12031585
     
    12051587  iFactY: int32or64; smoothBorder: boolean): TBGRAPixel;
    12061588var
    1207   w1,w2,w3,w4,alphaW: cardinal;
    1208   rSum, gSum, bSum: cardinal; //rgbDiv = aSum
    1209   aSum, aDiv: cardinal;
    1210   c:    TBGRAPixel;
     1589  pUpLeft, pUpRight, pDownLeft, pDownRight: PBGRAPixel;
    12111590  scan: PBGRAPixel;
    12121591begin
    1213   rSum   := 0;
    1214   gSum   := 0;
    1215   bSum   := 0;
    1216   aSum   := 0;
    1217   aDiv   := 0;
    1218 
    1219   w4 := (iFactX*iFactY+127) shr 8;
    1220   w3 := iFactY-w4;
    1221   {$PUSH}{$HINTS OFF}
    1222   w1 := (256-iFactX)-w3;
    1223   {$POP}
    1224   w2 := iFactX-w4;
    1225 
    1226   { For each pixel around the coordinate, compute
    1227     the weight for it and multiply values by it before
    1228     adding to the sum }
    12291592  if (iy >= 0) and (iy < Height) then
    12301593  begin
     
    12321595
    12331596    if (ix >= 0) and (ix < Width) then
    1234     begin
    1235       c      := (scan + ix)^;
    1236       alphaW := c.alpha * w1;
    1237       aDiv   += w1;
    1238       aSum   += alphaW;
    1239       rSum   += c.red * alphaW;
    1240       gSum   += c.green * alphaW;
    1241       bSum   += c.blue * alphaW;
    1242     end;
    1243 
    1244     Inc(ix);
     1597      pUpLeft := scan+ix
     1598    else if smoothBorder then
     1599      pUpLeft := @BGRAPixelTransparent
     1600    else
     1601      pUpLeft := nil;
     1602
     1603    if (ix+1 >= 0) and (ix+1 < Width) then
     1604      pUpRight := scan+(ix+1)
     1605    else if smoothBorder then
     1606      pUpRight := @BGRAPixelTransparent
     1607    else
     1608      pUpRight := nil;
     1609  end else
     1610  if smoothBorder then
     1611  begin
     1612    pUpLeft := @BGRAPixelTransparent;
     1613    pUpRight := @BGRAPixelTransparent;
     1614  end else
     1615  begin
     1616    pUpLeft := nil;
     1617    pUpRight := nil;
     1618  end;
     1619
     1620  if (iy+1 >= 0) and (iy+1 < Height) then
     1621  begin
     1622    scan := GetScanlineFast(iy+1);
     1623
    12451624    if (ix >= 0) and (ix < Width) then
    1246     begin
    1247       c      := (scan + ix)^;
    1248       alphaW := c.alpha * w2;
    1249       aDiv   += w2;
    1250       aSum   += alphaW;
    1251       rSum   += c.red * alphaW;
    1252       gSum   += c.green * alphaW;
    1253       bSum   += c.blue * alphaW;
    1254     end;
    1255   end
    1256   else
    1257   begin
    1258     Inc(ix);
    1259   end;
    1260 
    1261   Inc(iy);
    1262   if (iy >= 0) and (iy < Height) then
    1263   begin
    1264     scan := GetScanlineFast(iy);
    1265 
    1266     if (ix >= 0) and (ix < Width) then
    1267     begin
    1268       c      := (scan + ix)^;
    1269       alphaW := c.alpha * w4;
    1270       aDiv   += w4;
    1271       aSum   += alphaW;
    1272       rSum   += c.red * alphaW;
    1273       gSum   += c.green * alphaW;
    1274       bSum   += c.blue * alphaW;
    1275     end;
    1276 
    1277     Dec(ix);
    1278     if (ix >= 0) and (ix < Width) then
    1279     begin
    1280       c      := (scan + ix)^;
    1281       alphaW := c.alpha * w3;
    1282       aDiv   += w3;
    1283       aSum   += alphaW;
    1284       rSum   += c.red * alphaW;
    1285       gSum   += c.green * alphaW;
    1286       bSum   += c.blue * alphaW;
    1287     end;
    1288   end;
    1289 
    1290   if aSum < 128 then //if there is no alpha
    1291     Result := BGRAPixelTransparent
    1292   else
    1293   begin
    1294     Result.red   := (rSum + aSum shr 1) div aSum;
    1295     Result.green := (gSum + aSum shr 1) div aSum;
    1296     Result.blue  := (bSum + aSum shr 1) div aSum;
    1297     if smoothBorder or (aDiv = 256) then
    1298       Result.alpha := (aSum + 128) shr 8
     1625      pDownLeft := scan+ix
     1626    else if smoothBorder then
     1627      pDownLeft := @BGRAPixelTransparent
    12991628    else
    1300       Result.alpha := (aSum + aDiv shr 1) div aDiv;
    1301   end;
    1302 end;
    1303 
    1304 function TBGRADefaultBitmap.GetPolyLineOption: TBGRAPolyLineOptions;
    1305 begin
    1306   result := [];
    1307   if Assigned(FArrow) and FArrow.IsStartDefined then result += [plNoStartCap];
    1308   if Assigned(FArrow) and FArrow.IsEndDefined then result += [plNoEndCap];
     1629      pDownLeft := nil;
     1630
     1631    if (ix+1 >= 0) and (ix+1 < Width) then
     1632      pDownRight := scan+(ix+1)
     1633    else if smoothBorder then
     1634      pDownRight := @BGRAPixelTransparent
     1635    else
     1636      pDownRight := nil;
     1637  end else
     1638  if smoothBorder then
     1639  begin
     1640    pDownLeft := @BGRAPixelTransparent;
     1641    pDownRight := @BGRAPixelTransparent;
     1642  end else
     1643  begin
     1644    pDownLeft := nil;
     1645    pDownRight := nil;
     1646  end;
     1647
     1648  InterpolateBilinear(pUpLeft, pUpRight, pDownLeft,
     1649          pDownRight, iFactX, iFactY, @result);
    13091650end;
    13101651
    13111652function TBGRADefaultBitmap.GetArrow: TBGRAArrow;
    13121653begin
    1313   if FArrow = nil then
    1314   begin
    1315     FArrow := TBGRAArrow.Create;
    1316     FArrow.LineCap := LineCap;
    1317   end;
    1318   result := FArrow;
     1654  if FPenStroker.Arrow = nil then
     1655  begin
     1656    FPenStroker.Arrow := TBGRAArrow.Create;
     1657    FPenStroker.Arrow.LineCap := LineCap;
     1658    FPenStroker.ArrowOwned := true;
     1659  end;
     1660  result := FPenStroker.Arrow as TBGRAArrow;
    13191661end;
    13201662
     
    13421684procedure TBGRADefaultBitmap.SetPixel(x, y: int32or64; c: TColor);
    13431685var
    1344   p: PByte;
     1686  p: PBGRAPixel;
    13451687begin
    13461688  if not PtInClipRect(x,y) then exit;
    13471689  LoadFromBitmapIfNeeded;
    1348   p  := PByte(GetScanlineFast(y) + x);
    1349   p^ := c shr 16;
    1350   Inc(p);
    1351   p^ := c shr 8;
    1352   Inc(p);
    1353   p^ := c;
    1354   Inc(p);
    1355   p^ := 255;
     1690  p  := GetScanlineFast(y) + x;
     1691  RedGreenBlue(c, p^.red,p^.green,p^.blue);
     1692  p^.alpha := 255;
    13561693  InvalidateBitmap;
    13571694end;
     
    16391976end;
    16401977
    1641 { Load raw image data. It must be 32bit or 24 bits per pixel}
    1642 function TBGRADefaultBitmap.LoadFromRawImage(ARawImage: TRawImage;
    1643   DefaultOpacity: byte; AlwaysReplaceAlpha: boolean; RaiseErrorOnInvalidPixelFormat: boolean): boolean;
    1644 var
    1645   psource_byte, pdest_byte,
    1646   psource_first, pdest_first: PByte;
    1647   psource_delta, pdest_delta: integer;
    1648 
    1649   n: integer;
    1650   mustSwapRedBlue, mustReverse32: boolean;
    1651 
    1652   procedure CopyAndSwapIfNecessary(psrc: PBGRAPixel; pdest: PBGRAPixel; count: integer);
    1653   begin
    1654     if mustReverse32 then
    1655     begin
    1656       while count > 0 do
    1657       begin
    1658         pdest^.blue := psrc^.alpha;
    1659         pdest^.green := psrc^.red;
    1660         pdest^.red := psrc^.green;
    1661         pdest^.alpha := psrc^.blue;
    1662         dec(count);
    1663         inc(pdest);
    1664         inc(psrc);
    1665       end;
    1666     end else
    1667     if mustSwapRedBlue then
    1668     begin
    1669       while count > 0 do
    1670       begin
    1671         pdest^.red := psrc^.blue;
    1672         pdest^.green := psrc^.green;
    1673         pdest^.blue := psrc^.red;
    1674         pdest^.alpha := psrc^.alpha;
    1675         dec(count);
    1676         inc(pdest);
    1677         inc(psrc);
    1678       end;
    1679     end else
    1680       move(psrc^,pdest^,count*sizeof(TBGRAPixel));
    1681   end;
    1682 
    1683   procedure CopyRGBAndSwapIfNecessary(psrc: PByte; pdest: PBGRAPixel; count: integer);
    1684   begin
    1685     if mustSwapRedBlue then
    1686     begin
    1687       while count > 0 do
    1688       begin
    1689         pdest^.blue := (psrc+2)^;
    1690         pdest^.green := (psrc+1)^;
    1691         pdest^.red := psrc^;
    1692         pdest^.alpha := DefaultOpacity;
    1693         inc(psrc,3);
    1694         inc(pdest);
    1695         dec(count);
    1696       end;
    1697     end else
    1698     begin
    1699       while count > 0 do
    1700       begin
    1701         PWord(pdest)^ := PWord(psrc)^;
    1702         pdest^.red := (psrc+2)^;
    1703         pdest^.alpha := DefaultOpacity;
    1704         inc(psrc,3);
    1705         inc(pdest);
    1706         dec(count);
    1707       end;
    1708     end;
    1709   end;     
    1710 
    1711   procedure CopyAndSwapIfNecessaryAndSetAlpha(psrc: PBGRAPixel; pdest: PBGRAPixel; count: integer);
    1712   begin
    1713     if mustReverse32 then
    1714     begin
    1715       while count > 0 do
    1716       begin
    1717         pdest^.blue := psrc^.alpha;
    1718         pdest^.green := psrc^.red;
    1719         pdest^.red := psrc^.green;
    1720         pdest^.alpha := DefaultOpacity; //use default opacity
    1721         inc(psrc);
    1722         inc(pdest);
    1723         dec(count);
    1724       end;
    1725     end else
    1726     if mustSwapRedBlue then
    1727     begin
    1728       while count > 0 do
    1729       begin
    1730         pdest^.red := psrc^.blue;
    1731         pdest^.green := psrc^.green;
    1732         pdest^.blue := psrc^.red;
    1733         pdest^.alpha := DefaultOpacity; //use default opacity
    1734         inc(psrc);
    1735         inc(pdest);
    1736         dec(count);
    1737       end;
    1738     end else
    1739     begin
    1740       while count > 0 do
    1741       begin
    1742         PWord(pdest)^ := PWord(psrc)^;
    1743         pdest^.red := psrc^.red;
    1744         pdest^.alpha := DefaultOpacity; //use default opacity
    1745         inc(psrc);
    1746         inc(pdest);
    1747         dec(count);
    1748       end;
    1749     end;
    1750   end;
    1751 
    1752   procedure CopyAndSwapIfNecessaryAndReplaceAlpha(psrc: PBGRAPixel; pdest: PBGRAPixel; count: integer);
    1753   var OpacityOrMask, OpacityAndMask, sourceval: Longword;
    1754   begin
    1755     OpacityOrMask := NtoLE(longword(DefaultOpacity) shl 24);
    1756     OpacityAndMask := NtoLE($FFFFFF);
    1757     if mustReverse32 then
    1758     begin
    1759       OpacityAndMask := NtoBE($FFFFFF);
    1760       while count > 0 do
    1761       begin
    1762         sourceval := plongword(psrc)^ and OpacityAndMask;
    1763         if (sourceval <> 0) and (psrc^.blue{=alpha} = 0) then //if not black but transparent
    1764         begin
    1765           pdest^.blue := psrc^.alpha;
    1766           pdest^.green := psrc^.red;
    1767           pdest^.red := psrc^.green;
    1768           pdest^.alpha := DefaultOpacity; //use default opacity
    1769         end
    1770         else
    1771         begin
    1772           pdest^.blue := psrc^.alpha;
    1773           pdest^.green := psrc^.red;
    1774           pdest^.red := psrc^.green;
    1775           pdest^.alpha := psrc^.blue;
    1776         end;
    1777         dec(count);
    1778         inc(pdest);
    1779         inc(psrc);
    1780       end;
    1781     end else
    1782     if mustSwapRedBlue then
    1783     begin
    1784       while count > 0 do
    1785       begin
    1786         sourceval := plongword(psrc)^ and OpacityAndMask;
    1787         if (sourceval <> 0) and (psrc^.alpha = 0) then //if not black but transparent
    1788         begin
    1789           pdest^.red := psrc^.blue;
    1790           pdest^.green := psrc^.green;
    1791           pdest^.blue := psrc^.red;
    1792           pdest^.alpha := DefaultOpacity; //use default opacity
    1793         end
    1794         else
    1795         begin
    1796           pdest^.red := psrc^.blue;
    1797           pdest^.green := psrc^.green;
    1798           pdest^.blue := psrc^.red;
    1799           pdest^.alpha := psrc^.alpha;
    1800         end;
    1801         dec(count);
    1802         inc(pdest);
    1803         inc(psrc);
    1804       end;
    1805     end else
    1806     begin
    1807       while count > 0 do
    1808       begin
    1809         sourceval := plongword(psrc)^ and OpacityAndMask;
    1810         if (sourceval <> 0) and (psrc^.alpha = 0) then //if not black but transparent
    1811           plongword(pdest)^ := sourceval or OpacityOrMask //use default opacity
    1812         else
    1813           pdest^ := psrc^;
    1814         dec(count);
    1815         inc(pdest);
    1816         inc(psrc);
    1817       end;
    1818     end;
    1819   end;
    1820 
    1821 begin
    1822   if (ARawImage.Description.Width <> cardinal(Width)) or
    1823     (ARawImage.Description.Height <> cardinal(Height)) then
    1824     raise Exception.Create('Bitmap size is inconsistant');
    1825 
    1826   DiscardBitmapChange;
    1827   if (Height=0) or (Width=0) then
    1828   begin
    1829     result := true;
    1830     exit;
    1831   end;
    1832 
    1833   if ARawImage.Description.LineOrder = riloTopToBottom then
    1834   begin
    1835     psource_first := ARawImage.Data;
    1836     psource_delta := ARawImage.Description.BytesPerLine;
    1837   end else
    1838   begin
    1839     psource_first := ARawImage.Data + (ARawImage.Description.Height-1) * ARawImage.Description.BytesPerLine;
    1840     psource_delta := -ARawImage.Description.BytesPerLine;
    1841   end;
    1842 
    1843   if ((ARawImage.Description.RedShift = 0) and
    1844     (ARawImage.Description.BlueShift = 16) and
    1845     (ARawImage.Description.ByteOrder = riboLSBFirst)) or
    1846     ((ARawImage.Description.RedShift = 24) and
    1847     (ARawImage.Description.BlueShift = 8) and
    1848     (ARawImage.Description.ByteOrder = riboMSBFirst)) then
    1849   begin
    1850     mustSwapRedBlue:= true;
    1851     mustReverse32 := false;
    1852   end
    1853   else
    1854   begin
    1855     mustSwapRedBlue:= false;
    1856     if ((ARawImage.Description.RedShift = 8) and
    1857       (ARawImage.Description.GreenShift = 16) and
    1858       (ARawImage.Description.BlueShift = 24) and
    1859       (ARawImage.Description.ByteOrder = riboLSBFirst)) or
    1860       ((ARawImage.Description.RedShift = 16) and
    1861       (ARawImage.Description.GreenShift = 8) and
    1862       (ARawImage.Description.BlueShift = 0) and
    1863       (ARawImage.Description.ByteOrder = riboMSBFirst)) then
    1864         mustReverse32 := true
    1865       else
    1866         mustReverse32 := false;
    1867   end;
    1868 
    1869   if self.LineOrder = riloTopToBottom then
    1870   begin
    1871     pdest_first := PByte(self.Data);
    1872     pdest_delta := self.Width*sizeof(TBGRAPixel);
    1873   end else
    1874   begin
    1875     pdest_first := PByte(self.Data) + (self.Height-1)*self.Width*sizeof(TBGRAPixel);
    1876     pdest_delta := -self.Width*sizeof(TBGRAPixel);
    1877   end;
    1878 
    1879   { 32 bits per pixel }
    1880   if (ARawImage.Description.BitsPerPixel = 32) and
    1881     (ARawImage.DataSize >= longword(NbPixels) * 4) then
    1882   begin
    1883     { If there is an alpha channel }
    1884     if (ARawImage.Description.AlphaPrec = 8) and not AlwaysReplaceAlpha then
    1885     begin
    1886       if DefaultOpacity = 0 then
    1887       begin
    1888         if ARawImage.Description.LineOrder = FLineOrder then
    1889           CopyAndSwapIfNecessary(PBGRAPixel(ARawImage.Data), FData, NbPixels) else
    1890         begin
    1891           psource_byte := psource_first;
    1892           pdest_byte := pdest_first;
    1893           for n := FHeight-1 downto 0 do
    1894           begin
    1895             CopyAndSwapIfNecessary(PBGRAPixel(psource_byte), PBGRAPixel(pdest_byte), FWidth);
    1896             inc(psource_byte, psource_delta);
    1897             inc(pdest_byte, pdest_delta);
    1898           end;
    1899         end;
    1900       end
    1901       else
    1902       begin
    1903         psource_byte := psource_first;
    1904         pdest_byte := pdest_first;
    1905         for n := FHeight-1 downto 0 do
    1906         begin
    1907           CopyAndSwapIfNecessaryAndReplaceAlpha(PBGRAPixel(psource_byte), PBGRAPixel(pdest_byte), FWidth);
    1908           inc(psource_byte, psource_delta);
    1909           inc(pdest_byte, pdest_delta);
    1910         end;
    1911       end;
    1912     end
    1913     else
    1914     begin { If there isn't any alpha channel }
    1915       psource_byte := psource_first;
    1916       pdest_byte := pdest_first;
    1917       for n := FHeight-1 downto 0 do
    1918       begin
    1919         CopyAndSwapIfNecessaryAndSetAlpha(PBGRAPixel(psource_byte), PBGRAPixel(pdest_byte), FWidth);
    1920         inc(psource_byte, psource_delta);
    1921         inc(pdest_byte, pdest_delta);
    1922       end;
    1923     end;
    1924   end
    1925   else
    1926   { 24 bit per pixel }
    1927   if (ARawImage.Description.BitsPerPixel = 24) then
    1928   begin
    1929     psource_byte := psource_first;
    1930     pdest_byte := pdest_first;
    1931     for n := FHeight-1 downto 0 do
    1932     begin
    1933       CopyRGBAndSwapIfNecessary(psource_byte, PBGRAPixel(pdest_byte), FWidth);
    1934       inc(psource_byte, psource_delta);
    1935       inc(pdest_byte, pdest_delta);
    1936     end;
    1937   end
    1938   else
    1939   begin
    1940     if RaiseErrorOnInvalidPixelFormat then
    1941       raise Exception.Create('Invalid raw image format (' + IntToStr(
    1942         ARawImage.Description.Depth) + ' found)') else
    1943     begin
    1944       result := false;
    1945       exit;
    1946     end;
    1947   end;
    1948 
    1949   InvalidateBitmap;
    1950   result := true;
    1951 end;
    1952 
    19531978procedure TBGRADefaultBitmap.LoadFromBitmapIfNeeded;
    19541979begin
    19551980  if FBitmapModified then
    19561981  begin
    1957     if FBitmap <> nil then
    1958       LoadFromRawImage(FBitmap.RawImage, FCanvasOpacity);
     1982    DoLoadFromBitmap;
    19591983    DiscardBitmapChange;
    19601984  end;
     
    20242048  FWidth     := 0;
    20252049  FHeight    := 0;
     2050  FScanWidth := FWidth;
     2051  FScanHeight:= FHeight;
    20262052  FLineOrder := riloTopToBottom;
    20272053  FCanvasOpacity := 255;
     
    20332059  FontStyle := [];
    20342060  FontAntialias := False;
     2061  FontVerticalAnchor:= fvaTop;
    20352062  FFontHeight := 20;
    20362063
    2037   PenStyle := psSolid;
    2038   LineCap := pecRound;
    2039   JoinStyle := pjsBevel;
    2040   JoinMiterLimit := 2;
    20412064  ResampleFilter := rfHalfCosine;
    20422065  ScanInterpolationFilter := rfLinear;
    20432066  ScanOffset := Point(0,0);
     2067
     2068  FPenStroker := TBGRAPenStroker.Create;
     2069  FPenStroker.Arrow := TBGRAArrow.Create;
     2070  FPenStroker.Arrow.LineCap := LineCap;
     2071  FPenStroker.ArrowOwned := true;
    20442072end;
    20452073
     
    20512079function TBGRADefaultBitmap.GetInternalColor(x, y: integer): TFPColor;
    20522080begin
    2053   if (x < 0) or (y < 0) or (x >= Width) or (y >= Height) then exit;
    2054   result := BGRAToFPColor((Scanline[y] + x)^);
     2081  if (x < 0) or (y < 0) or (x >= Width) or (y >= Height) then
     2082    result := colTransparent
     2083  else
     2084    result := BGRAToFPColor((Scanline[y] + x)^);
    20552085end;
    20562086
     
    20692099  c: TFPColor;
    20702100begin
    2071   if (x < 0) or (y < 0) or (x >= Width) or (y >= Height) then exit;
    2072   c := BGRAToFPColor((Scanline[y] + x)^);
    2073   Result := palette.IndexOf(c);
     2101  if (x < 0) or (y < 0) or (x >= Width) or (y >= Height) then
     2102    result := 0
     2103  else
     2104  begin
     2105    c := BGRAToFPColor((Scanline[y] + x)^);
     2106    Result := palette.IndexOf(c);
     2107  end;
    20742108end;
    20752109
    20762110procedure TBGRADefaultBitmap.Draw(ACanvas: TCanvas; x, y: integer; Opaque: boolean);
    20772111begin
    2078   if self = nil then
    2079     exit;
     2112  if (self = nil) or (Width = 0) or (Height = 0) then exit;
    20802113  if Opaque then
    20812114    DataDrawOpaque(ACanvas, Rect(X, Y, X + Width, Y + Height), Data,
     
    20922125procedure TBGRADefaultBitmap.Draw(ACanvas: TCanvas; Rect: TRect; Opaque: boolean);
    20932126begin
    2094   if self = nil then
    2095     exit;
     2127  if (self = nil) or (Width = 0) or (Height = 0) then exit;
    20962128  if Opaque then
    20972129    DataDrawOpaque(ACanvas, Rect, Data, FLineOrder, FWidth, FHeight)
     
    20992131  begin
    21002132    LoadFromBitmapIfNeeded;
    2101     if Empty then
    2102       exit;
    21032133    ACanvas.StretchDraw(Rect, Bitmap);
    21042134  end;
     
    23092339end;
    23102340
    2311 procedure TBGRADefaultBitmap.SetArrowStart(AStyle: TBGRAArrowStyle;
    2312   ATipStyle: TPenJoinStyle; ARelativePenWidth: single; ATriangleBackOffset: single);
    2313 begin
    2314   GetArrow.SetStart(AStyle,ATipStyle,ARelativePenWidth,ATriangleBackOffset);
    2315 end;
    2316 
    2317 procedure TBGRADefaultBitmap.SetArrowEnd(AStyle: TBGRAArrowStyle;
    2318   ATipStyle: TPenJoinStyle; ARelativePenWidth: single; ATriangleBackOffset: single);
    2319 begin
    2320   GetArrow.SetEnd(AStyle,ATipStyle,ARelativePenWidth,ATriangleBackOffset);
    2321 end;
    2322 
    2323 procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; c: TBGRAPixel; w: single);
    2324 var tempCanvas: TBGRACanvas2D;
    2325 begin
    2326   tempCanvas:= TBGRACanvas2D.Create(self);
    2327   tempCanvas.strokeStyle(c);
    2328   tempCanvas.lineWidth := w;
    2329   tempCanvas.lineStyle(CustomPenStyle);
    2330   tempCanvas.lineCapLCL := LineCap;
    2331   tempCanvas.lineJoinLCL := JoinStyle;
    2332   tempCanvas.path(APath);
    2333   tempCanvas.stroke;
    2334   tempCanvas.Free;
    2335 end;
    2336 
    2337 procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; texture: IBGRAScanner; w: single);
    2338 var tempCanvas: TBGRACanvas2D;
    2339 begin
    2340   tempCanvas:= TBGRACanvas2D.Create(self);
    2341   tempCanvas.strokeStyle(texture);
    2342   tempCanvas.lineWidth := w;
    2343   tempCanvas.lineStyle(CustomPenStyle);
    2344   tempCanvas.lineCapLCL := LineCap;
    2345   tempCanvas.lineJoinLCL := JoinStyle;
    2346   tempCanvas.path(APath);
    2347   tempCanvas.stroke;
    2348   tempCanvas.Free;
     2341procedure TBGRADefaultBitmap.InternalTextOutCurved(
     2342  ACursor: TBGRACustomPathCursor; sUTF8: string; AColor: TBGRAPixel;
     2343  ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single);
     2344var
     2345  pstr: pchar;
     2346  left,charlen: integer;
     2347  nextchar: string;
     2348  charwidth, angle, textlen: single;
     2349begin
     2350  if (ATexture = nil) and (AColor.alpha = 0) then exit;
     2351  sUTF8 := CleanTextOutString(sUTF8);
     2352  if sUTF8 = '' then exit;
     2353  pstr := @sUTF8[1];
     2354  left := length(sUTF8);
     2355  if AALign<> taLeftJustify then
     2356  begin
     2357    textlen := TextSize(sUTF8).cx + (UTF8Length(sUTF8)-1)*ALetterSpacing;
     2358    case AAlign of
     2359      taCenter: ACursor.MoveBackward(textlen*0.5);
     2360      taRightJustify: ACursor.MoveBackward(textlen);
     2361    end;
     2362  end;
     2363  while left > 0 do
     2364  begin
     2365    charlen := UTF8CharacterLength(pstr);
     2366    setlength(nextchar, charlen);
     2367    move(pstr^, nextchar[1], charlen);
     2368    inc(pstr,charlen);
     2369    dec(left,charlen);
     2370    charwidth := TextSize(nextchar).cx;
     2371    ACursor.MoveForward(charwidth);
     2372    ACursor.MoveBackward(charwidth, false);
     2373    ACursor.MoveForward(charwidth*0.5);
     2374    with ACursor.CurrentTangent do angle := arctan2(y,x);
     2375    with ACursor.CurrentCoordinate do
     2376    begin
     2377      if ATexture = nil then
     2378        TextOutAngle(x,y, system.round(-angle*1800/Pi), nextchar, AColor, taCenter)
     2379      else
     2380        TextOutAngle(x,y, system.round(-angle*1800/Pi), nextchar, ATexture, taCenter);
     2381    end;
     2382    ACursor.MoveForward(charwidth*0.5 + ALetterSpacing);
     2383  end;
     2384end;
     2385
     2386procedure TBGRADefaultBitmap.InternalArc(cx, cy, rx, ry: single; StartAngleRad,
     2387  EndAngleRad: Single; ABorderColor: TBGRAPixel; w: single; AFillColor: TBGRAPixel; AOptions: TArcOptions;
     2388  ADrawChord: boolean; ATexture: IBGRAScanner);
     2389var
     2390  pts, ptsFill: array of TPointF;
     2391  temp: single;
     2392  multi: TBGRAMultishapeFiller;
     2393begin
     2394  if (rx = 0) or (ry = 0) then exit;
     2395  if ADrawChord then AOptions := AOptions+[aoClosePath];
     2396  if not (aoFillPath in AOptions) then
     2397    AFillColor := BGRAPixelTransparent;
     2398
     2399  if (ABorderColor.alpha = 0) and (AFillColor.alpha = 0) then exit;
     2400
     2401  if abs(StartAngleRad-EndAngleRad) >= 2*PI - 1e-6 then
     2402  begin
     2403    if aoPie in AOptions then
     2404      EndAngleRad:= StartAngleRad+2*PI
     2405    else
     2406      EllipseAntialias(cx,cy,rx,ry,ABorderColor,w,AFillColor);
     2407    exit;
     2408  end;
     2409
     2410  if EndAngleRad < StartAngleRad then
     2411  begin
     2412    temp := StartAngleRad;
     2413    StartAngleRad:= EndAngleRad;
     2414    EndAngleRad:= temp;
     2415  end;
     2416
     2417  pts := ComputeArcRad(cx,cy,rx,ry,StartAngleRad,EndAngleRad);
     2418  if aoPie in AOptions then pts := ConcatPointsF([PointsF([PointF(cx,cy)]),pts]);
     2419
     2420  multi := TBGRAMultishapeFiller.Create;
     2421  multi.PolygonOrder := poLastOnTop;
     2422  if AFillColor.alpha <> 0 then
     2423  begin
     2424    if not (aoPie in AOptions) and (length(pts)>=2) then ptsFill := ConcatPointsF([PointsF([(pts[0]+pts[high(pts)])*0.5]),pts])
     2425     else ptsFill := pts;
     2426    if ATexture <> nil then
     2427      multi.AddPolygon(ptsFill, ATexture)
     2428    else
     2429      multi.AddPolygon(ptsFill, AFillColor);
     2430  end;
     2431  if ABorderColor.alpha <> 0 then
     2432  begin
     2433    if [aoPie,aoClosePath]*AOptions <> [] then
     2434      multi.AddPolygon(ComputeWidePolygon(pts,w), ABorderColor)
     2435    else
     2436      multi.AddPolygon(ComputeWidePolyline(pts,w), ABorderColor);
     2437  end;
     2438  multi.Antialiasing := true;
     2439  multi.Draw(self);
     2440  multi.Free;
     2441end;
     2442
     2443function TBGRADefaultBitmap.IsAffineRoughlyTranslation(AMatrix: TAffineMatrix; ASourceBounds: TRect): boolean;
     2444const oneOver512 = 1/512;
     2445var Orig,HAxis,VAxis: TPointF;
     2446begin
     2447  Orig := AMatrix*PointF(ASourceBounds.Left,ASourceBounds.Top);
     2448  if (abs(Orig.x-round(Orig.x)) > oneOver512) or
     2449     (abs(Orig.y-round(Orig.y)) > oneOver512) then
     2450  begin
     2451    result := false;
     2452    exit;
     2453  end;
     2454  HAxis := AMatrix*PointF(ASourceBounds.Right-1,ASourceBounds.Top);
     2455  if (abs(HAxis.x - (round(Orig.x)+ASourceBounds.Right-1 - ASourceBounds.Left)) > oneOver512) or
     2456     (abs(HAxis.y - round(Orig.y)) > oneOver512) then
     2457  begin
     2458    result := false;
     2459    exit;
     2460  end;
     2461  VAxis := AMatrix*PointF(ASourceBounds.Left,ASourceBounds.Bottom-1);
     2462  if (abs(VAxis.y - (round(Orig.y)+ASourceBounds.Bottom-1 - ASourceBounds.Top)) > oneOver512) or
     2463     (abs(VAxis.x - round(Orig.x)) > oneOver512) then
     2464  begin
     2465    result := false;
     2466    exit;
     2467  end;
     2468  result := true;
    23492469end;
    23502470
     
    23812501  c: TBGRAPixel; w: single);
    23822502begin
    2383   if Assigned(FArrow) then
    2384     BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,nil,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX)
    2385   else
    2386     BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,nil,JoinMiterLimit);
     2503  FillPolyAntialias( FPenStroker.ComputePolyline([PointF(x1,y1),PointF(x2,y2)],w,c), c);
    23872504end;
    23882505
     
    23902507  texture: IBGRAScanner; w: single);
    23912508begin
    2392   if Assigned(FArrow) then
    2393     BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,texture,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX)
    2394   else
    2395     BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,texture,JoinMiterLimit);
     2509  FillPolyAntialias( FPenStroker.ComputePolyline([PointF(x1,y1),PointF(x2,y2)],w), texture);
    23962510end;
    23972511
    23982512procedure TBGRADefaultBitmap.DrawLineAntialias(x1, y1, x2, y2: single;
    2399   c: TBGRAPixel; w: single; Closed: boolean);
    2400 var
    2401   options: TBGRAPolyLineOptions;
    2402 begin
    2403   if not closed then options := [plRoundCapOpen] else options := [];
    2404   options += GetPolyLineOption;
    2405   if Assigned(FArrow) then
    2406     BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,nil,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX)
    2407   else
    2408     BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,nil,JoinMiterLimit)
     2513  c: TBGRAPixel; w: single; ClosedCap: boolean);
     2514begin
     2515  FillPolyAntialias( FPenStroker.ComputePolyline([PointF(x1,y1),PointF(x2,y2)],w,c,ClosedCap), c);
    24092516end;
    24102517
    24112518procedure TBGRADefaultBitmap.DrawLineAntialias(x1, y1, x2, y2: single;
    2412   texture: IBGRAScanner; w: single; Closed: boolean);
    2413 var
    2414   options: TBGRAPolyLineOptions;
    2415   c: TBGRAPixel;
    2416 begin
    2417   if not closed then
    2418   begin
    2419     options := [plRoundCapOpen];
    2420     c := BGRAWhite; //needed for alpha junction
    2421   end else
    2422   begin
    2423     options := [];
    2424     c := BGRAPixelTransparent;
    2425   end;
    2426   options += GetPolyLineOption;
    2427   if Assigned(FArrow) then
    2428     BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,texture,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX)
    2429   else
    2430     BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,texture,JoinMiterLimit);
     2519  texture: IBGRAScanner; w: single; ClosedCap: boolean);
     2520begin
     2521  FillPolyAntialias( FPenStroker.ComputePolyline([PointF(x1,y1),PointF(x2,y2)],w,ClosedCap), texture);
    24312522end;
    24322523
     
    24342525  c: TBGRAPixel; w: single);
    24352526begin
    2436   if Assigned(FArrow) then
    2437     BGRAPen.BGRAPolyLine(self,points,w,c,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,nil,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX)
    2438   else
    2439     BGRAPen.BGRAPolyLine(self,points,w,c,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,nil,JoinMiterLimit)
     2527  FillPolyAntialias( FPenStroker.ComputePolyline(points,w,c), c);
    24402528end;
    24412529
     
    24432531  const points: array of TPointF; texture: IBGRAScanner; w: single);
    24442532begin
    2445   if Assigned(FArrow) then
    2446     BGRAPen.BGRAPolyLine(self,points,w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,texture,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX)
    2447   else
    2448     BGRAPen.BGRAPolyLine(self,points,w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,texture,JoinMiterLimit);
     2533  FillPolyAntialias( FPenStroker.ComputePolyline(points,w), texture);
    24492534end;
    24502535
    24512536procedure TBGRADefaultBitmap.DrawPolyLineAntialias(const points: array of TPointF;
    2452   c: TBGRAPixel; w: single; Closed: boolean);
    2453 var
    2454   options: TBGRAPolyLineOptions;
    2455 begin
    2456   if not closed then options := [plRoundCapOpen] else options := [];
    2457   options += GetPolyLineOption;
    2458   if Assigned(FArrow) then
    2459     BGRAPen.BGRAPolyLine(self,points,w,c,pecRound,JoinStyle,FCustomPenStyle,options,nil,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX)
    2460   else
    2461     BGRAPen.BGRAPolyLine(self,points,w,c,pecRound,JoinStyle,FCustomPenStyle,options,nil,JoinMiterLimit);
     2537  c: TBGRAPixel; w: single; ClosedCap: boolean);
     2538begin
     2539  FillPolyAntialias( FPenStroker.ComputePolyline(points,w,c,ClosedCap), c);
     2540end;
     2541
     2542procedure TBGRADefaultBitmap.DrawPolyLineAntialias(
     2543  const points: array of TPointF; texture: IBGRAScanner; w: single;
     2544  ClosedCap: boolean);
     2545begin
     2546  FillPolyAntialias( FPenStroker.ComputePolyline(points,w,ClosedCap), texture);
    24622547end;
    24632548
     
    24782563end;
    24792564
     2565procedure TBGRADefaultBitmap.DrawPolyLineAntialiasAutocycle(
     2566  const points: array of TPointF; c: TBGRAPixel; w: single);
     2567begin
     2568  FillPolyAntialias( FPenStroker.ComputePolylineAutocycle(points,w), c);
     2569end;
     2570
     2571procedure TBGRADefaultBitmap.DrawPolyLineAntialiasAutocycle(
     2572  const points: array of TPointF; texture: IBGRAScanner; w: single);
     2573begin
     2574  FillPolyAntialias( FPenStroker.ComputePolylineAutocycle(points,w), texture);
     2575end;
     2576
    24802577procedure TBGRADefaultBitmap.DrawPolygonAntialias(const points: array of TPointF;
    24812578  c: TBGRAPixel; w: single);
    24822579begin
    2483   BGRAPolyLine(self,points,w,c,LineCap,JoinStyle,FCustomPenStyle,[plCycle],nil,JoinMiterLimit);
     2580  FillPolyAntialias( FPenStroker.ComputePolygon(points,w), c);
    24842581end;
    24852582
     
    24872584  const points: array of TPointF; texture: IBGRAScanner; w: single);
    24882585begin
    2489   BGRAPolyLine(self,points,w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,[plCycle],texture,JoinMiterLimit);
     2586  FillPolyAntialias( FPenStroker.ComputePolygon(points,w), texture);
    24902587end;
    24912588
     
    25342631end;
    25352632
    2536 procedure TBGRADefaultBitmap.FillPath(APath: IBGRAPath; c: TBGRAPixel);
    2537 var tempCanvas: TBGRACanvas2D;
    2538 begin
    2539   tempCanvas:= TBGRACanvas2D.Create(self);
    2540   tempCanvas.fillStyle(c);
    2541   tempCanvas.path(APath);
    2542   tempCanvas.fill;
    2543   tempCanvas.Free;
    2544 end;
    2545 
    2546 procedure TBGRADefaultBitmap.FillPath(APath: IBGRAPath; texture: IBGRAScanner);
    2547 var tempCanvas: TBGRACanvas2D;
    2548 begin
    2549   tempCanvas:= TBGRACanvas2D.Create(self);
    2550   tempCanvas.fillStyle(texture);
    2551   tempCanvas.path(APath);
    2552   tempCanvas.fill;
    2553   tempCanvas.Free;
     2633procedure TBGRADefaultBitmap.FillPath(APath: IBGRAPath; AFillColor: TBGRAPixel);
     2634begin
     2635  FillPolyAntialias(APath.getPoints,AFillColor);
     2636end;
     2637
     2638procedure TBGRADefaultBitmap.FillPath(APath: IBGRAPath; AFillTexture: IBGRAScanner);
     2639begin
     2640  FillPolyAntialias(APath.getPoints,AFillTexture);
     2641end;
     2642
     2643procedure TBGRADefaultBitmap.ErasePath(APath: IBGRAPath; alpha: byte);
     2644begin
     2645  ErasePolyAntialias(APath.getPoints,alpha);
     2646end;
     2647
     2648procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix;
     2649  AStrokeColor: TBGRAPixel; AWidth: single; AFillColor: TBGRAPixel);
     2650var tempPath: TBGRAPath;
     2651  multi: TBGRAMultishapeFiller;
     2652begin
     2653  tempPath := TBGRAPath.Create(APath);
     2654  multi := TBGRAMultishapeFiller.Create;
     2655  multi.PolygonOrder := poLastOnTop;
     2656  multi.AddPathFill(tempPath,AMatrix,AFillColor);
     2657  multi.AddPathStroke(tempPath,AMatrix,AStrokeColor,AWidth,FPenStroker);
     2658  multi.Draw(self);
     2659  multi.Free;
     2660  tempPath.Free;
     2661end;
     2662
     2663procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix;
     2664  AStrokeTexture: IBGRAScanner; AWidth: single; AFillColor: TBGRAPixel);
     2665var tempPath: TBGRAPath;
     2666  multi: TBGRAMultishapeFiller;
     2667begin
     2668  tempPath := TBGRAPath.Create(APath);
     2669  multi := TBGRAMultishapeFiller.Create;
     2670  multi.PolygonOrder := poLastOnTop;
     2671  multi.AddPathFill(tempPath,AMatrix,AFillColor);
     2672  multi.AddPathStroke(tempPath,AMatrix,AStrokeTexture,AWidth,FPenStroker);
     2673  multi.Draw(self);
     2674  multi.Free;
     2675  tempPath.Free;
     2676end;
     2677
     2678procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix;
     2679  AStrokeColor: TBGRAPixel; AWidth: single; AFillTexture: IBGRAScanner);
     2680var tempPath: TBGRAPath;
     2681  multi: TBGRAMultishapeFiller;
     2682begin
     2683  tempPath := TBGRAPath.Create(APath);
     2684  multi := TBGRAMultishapeFiller.Create;
     2685  multi.PolygonOrder := poLastOnTop;
     2686  multi.AddPathFill(tempPath,AMatrix,AFillTexture);
     2687  multi.AddPathStroke(tempPath,AMatrix,AStrokeColor,AWidth,FPenStroker);
     2688  multi.Draw(self);
     2689  multi.Free;
     2690  tempPath.Free;
     2691end;
     2692
     2693procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix;
     2694  AStrokeTexture: IBGRAScanner; AWidth: single; AFillTexture: IBGRAScanner);
     2695var
     2696  tempPath: TBGRAPath;
     2697  multi: TBGRAMultishapeFiller;
     2698begin
     2699  tempPath := TBGRAPath.Create(APath);
     2700  multi := TBGRAMultishapeFiller.Create;
     2701  multi.PolygonOrder := poLastOnTop;
     2702  multi.AddPathFill(tempPath,AMatrix,AFillTexture);
     2703  multi.AddPathStroke(tempPath,AMatrix,AStrokeTexture,AWidth,FPenStroker);
     2704  multi.Draw(self);
     2705  multi.Free;
     2706  tempPath.Free;
     2707end;
     2708
     2709procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix;
     2710  AStrokeColor: TBGRAPixel; AWidth: single);
     2711var tempPath: TBGRAPath;
     2712begin
     2713  tempPath := TBGRAPath.Create(APath);
     2714  tempPath.stroke(self, AMatrix, AStrokeColor, AWidth);
     2715  tempPath.Free;
     2716end;
     2717
     2718procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; AMatrix: TAffineMatrix;
     2719  AStrokeTexture: IBGRAScanner; AWidth: single);
     2720var tempPath: TBGRAPath;
     2721begin
     2722  tempPath := TBGRAPath.Create(APath);
     2723  tempPath.stroke(self, AMatrix, AStrokeTexture, AWidth);
     2724  tempPath.Free;
     2725end;
     2726
     2727procedure TBGRADefaultBitmap.FillPath(APath: IBGRAPath; AMatrix: TAffineMatrix;
     2728  AFillColor: TBGRAPixel);
     2729begin
     2730  FillPolyAntialias(APath.getPoints(AMatrix),AFillColor);
     2731end;
     2732
     2733procedure TBGRADefaultBitmap.FillPath(APath: IBGRAPath; AMatrix: TAffineMatrix;
     2734  AFillTexture: IBGRAScanner);
     2735begin
     2736  FillPolyAntialias(APath.getPoints(AMatrix),AFillTexture);
     2737end;
     2738
     2739procedure TBGRADefaultBitmap.ErasePath(APath: IBGRAPath;
     2740  AMatrix: TAffineMatrix; alpha: byte);
     2741begin
     2742  ErasePolyAntialias(APath.getPoints(AMatrix),alpha);
     2743end;
     2744
     2745procedure TBGRADefaultBitmap.ArrowStartAsNone;
     2746begin
     2747  GetArrow.StartAsNone;
     2748end;
     2749
     2750procedure TBGRADefaultBitmap.ArrowStartAsClassic(AFlipped: boolean;
     2751  ACut: boolean; ARelativePenWidth: single);
     2752begin
     2753  GetArrow.StartAsClassic(AFlipped,ACut,ARelativePenWidth);
     2754end;
     2755
     2756procedure TBGRADefaultBitmap.ArrowStartAsTriangle(ABackOffset: single;
     2757  ARounded: boolean; AHollow: boolean; AHollowPenWidth: single);
     2758begin
     2759  GetArrow.StartAsTriangle(ABackOffset,ARounded,AHollow,AHollowPenWidth);
     2760end;
     2761
     2762procedure TBGRADefaultBitmap.ArrowStartAsTail;
     2763begin
     2764  GetArrow.StartAsTail;
     2765end;
     2766
     2767procedure TBGRADefaultBitmap.ArrowEndAsNone;
     2768begin
     2769  GetArrow.EndAsNone;
     2770end;
     2771
     2772procedure TBGRADefaultBitmap.ArrowEndAsClassic(AFlipped: boolean;
     2773  ACut: boolean; ARelativePenWidth: single);
     2774begin
     2775  GetArrow.EndAsClassic(AFlipped,ACut,ARelativePenWidth);
     2776end;
     2777
     2778procedure TBGRADefaultBitmap.ArrowEndAsTriangle(ABackOffset: single;
     2779  ARounded: boolean; AHollow: boolean; AHollowPenWidth: single);
     2780begin
     2781  GetArrow.EndAsTriangle(ABackOffset,ARounded,AHollow,AHollowPenWidth);
     2782end;
     2783
     2784procedure TBGRADefaultBitmap.ArrowEndAsTail;
     2785begin
     2786  GetArrow.EndAsTail;
    25542787end;
    25552788
     
    26322865
    26332866procedure TBGRADefaultBitmap.FillQuadLinearMapping(pt1, pt2, pt3, pt4: TPointF;
    2634   texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; TextureInterpolation: Boolean= True);
    2635 var
    2636   center: TPointF;
    2637   centerTex: TPointF;
    2638 begin
    2639   center := (pt1+pt2+pt3+pt4)*(1/4);
    2640   centerTex := (tex1+tex2+tex3+tex4)*(1/4);
    2641   FillTriangleLinearMapping(pt1,pt2,center, texture,tex1,tex2,centerTex, TextureInterpolation);
    2642   FillTriangleLinearMapping(pt2,pt3,center, texture,tex2,tex3,centerTex, TextureInterpolation);
    2643   FillTriangleLinearMapping(pt3,pt4,center, texture,tex3,tex4,centerTex, TextureInterpolation);
    2644   FillTriangleLinearMapping(pt4,pt1,center, texture,tex4,tex1,centerTex, TextureInterpolation);
     2867  texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF;
     2868  TextureInterpolation: Boolean; ACulling: TFaceCulling);
     2869var
     2870  scan: TBGRAQuadLinearScanner;
     2871begin
     2872  if ((abs(pt1.y-pt2.y)<1e-6) and (abs(pt3.y-pt4.y)<1e-6)) or
     2873     ((abs(pt3.y-pt2.y)<1e-6) and (abs(pt1.y-pt4.y)<1e-6)) then
     2874     FillPolyLinearMapping([pt1,pt2,pt3,pt4], texture,
     2875            [tex1,tex2,tex3,tex4], TextureInterpolation)
     2876  else
     2877  begin
     2878    scan := TBGRAQuadLinearScanner.Create(texture,
     2879         [tex1,tex2,tex3,tex4],
     2880         [pt1,pt2,pt3,pt4],TextureInterpolation);
     2881    scan.Culling := ACulling;
     2882    FillPoly([pt1,pt2,pt3,pt4],scan,dmDrawWithTransparency);
     2883    scan.Free;
     2884  end;
    26452885end;
    26462886
     
    26632903
    26642904procedure TBGRADefaultBitmap.FillQuadLinearMappingAntialias(pt1, pt2, pt3,
    2665   pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF);
     2905  pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF;
     2906  ACulling: TFaceCulling);
    26662907var multi : TBGRAMultishapeFiller;
    26672908begin
    26682909  multi := TBGRAMultishapeFiller.Create;
    2669   multi.AddQuadLinearMapping(pt1, pt2, pt3, pt4, texture, tex1,tex2,tex3,tex4);
     2910  multi.AddQuadLinearMapping(pt1, pt2, pt3, pt4, texture, tex1,tex2,tex3,tex4, ACulling);
    26702911  multi.Draw(self);
    26712912  multi.free;
     
    26732914
    26742915procedure TBGRADefaultBitmap.FillQuadPerspectiveMapping(pt1, pt2, pt3,
    2675   pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF);
     2916  pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF;
     2917  ADrawMode: TDrawMode);
    26762918var
    26772919  persp: TBGRAPerspectiveScannerTransform;
    26782920begin
    26792921  persp := TBGRAPerspectiveScannerTransform.Create(texture,[tex1,tex2,tex3,tex4],[pt1,pt2,pt3,pt4]);
    2680   FillPoly([pt1,pt2,pt3,pt4],persp,dmDrawWithTransparency);
     2922  FillPoly([pt1,pt2,pt3,pt4],persp,ADrawMode);
    26812923  persp.Free;
    26822924end;
     
    26842926procedure TBGRADefaultBitmap.FillQuadPerspectiveMapping(pt1, pt2, pt3,
    26852927  pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF;
    2686   ACleanBorders: TRect);
     2928  ACleanBorders: TRect; ADrawMode: TDrawMode);
    26872929var
    26882930  persp: TBGRAPerspectiveScannerTransform;
     
    26912933  clean := TBGRAExtendedBorderScanner.Create(texture,ACleanBorders);
    26922934  persp := TBGRAPerspectiveScannerTransform.Create(clean,[tex1,tex2,tex3,tex4],[pt1,pt2,pt3,pt4]);
    2693   FillPoly([pt1,pt2,pt3,pt4],persp,dmDrawWithTransparency);
     2935  FillPoly([pt1,pt2,pt3,pt4],persp,ADrawMode);
    26942936  persp.Free;
    26952937  clean.Free;
     
    27202962end;
    27212963
     2964procedure TBGRADefaultBitmap.FillQuadAffineMapping(Orig, HAxis, VAxis: TPointF;
     2965  AImage: TBGRACustomBitmap; APixelCenteredCoordinates: boolean; ADrawMode: TDrawMode; AOpacity: byte);
     2966var pts3: TPointF;
     2967  affine: TBGRAAffineBitmapTransform;
     2968begin
     2969  if not APixelCenteredCoordinates then
     2970  begin
     2971    Orig -= PointF(0.5,0.5);
     2972    HAxis -= PointF(0.5,0.5);
     2973    VAxis -= PointF(0.5,0.5);
     2974  end;
     2975  pts3 := HAxis+(VAxis-Orig);
     2976  affine := TBGRAAffineBitmapTransform.Create(AImage,False,AImage.ScanInterpolationFilter,not APixelCenteredCoordinates);
     2977  affine.GlobalOpacity:= AOpacity;
     2978  affine.Fit(Orig,HAxis,VAxis);
     2979  FillPoly([Orig,HAxis,pts3,VAxis],affine,ADrawMode);
     2980  affine.Free;
     2981end;
     2982
     2983procedure TBGRADefaultBitmap.FillQuadAffineMappingAntialias(Orig, HAxis,
     2984  VAxis: TPointF; AImage: TBGRACustomBitmap; APixelCenteredCoordinates: boolean; AOpacity: byte);
     2985var pts3: TPointF;
     2986  affine: TBGRAAffineBitmapTransform;
     2987begin
     2988  if not APixelCenteredCoordinates then
     2989  begin
     2990    Orig -= PointF(0.5,0.5);
     2991    HAxis -= PointF(0.5,0.5);
     2992    VAxis -= PointF(0.5,0.5);
     2993  end;
     2994  pts3 := HAxis+(VAxis-Orig);
     2995  affine := TBGRAAffineBitmapTransform.Create(AImage,False,AImage.ScanInterpolationFilter,not APixelCenteredCoordinates);
     2996  affine.GlobalOpacity:= AOpacity;
     2997  affine.Fit(Orig,HAxis,VAxis);
     2998  FillPolyAntialias([Orig,HAxis,pts3,VAxis],affine);
     2999  affine.Free;
     3000end;
     3001
    27223002procedure TBGRADefaultBitmap.FillPolyLinearMapping(const points: array of TPointF;
    27233003  texture: IBGRAScanner; texCoords: array of TPointF;
     
    28383118end;
    28393119
     3120procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath;
     3121  AStrokeColor: TBGRAPixel; AWidth: single; AFillColor: TBGRAPixel);
     3122begin
     3123  DrawPath(APath,AffineMatrixIdentity,AStrokeColor,AWidth,AFillColor);
     3124end;
     3125
     3126procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath;
     3127  AStrokeTexture: IBGRAScanner; AWidth: single; AFillColor: TBGRAPixel);
     3128begin
     3129  DrawPath(APath,AffineMatrixIdentity,AStrokeTexture,AWidth,AFillColor);
     3130end;
     3131
     3132procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath;
     3133  AStrokeColor: TBGRAPixel; AWidth: single; AFillTexture: IBGRAScanner);
     3134begin
     3135  DrawPath(APath,AffineMatrixIdentity,AStrokeColor,AWidth,AFillTexture);
     3136end;
     3137
     3138procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath;
     3139  AStrokeTexture: IBGRAScanner; AWidth: single; AFillTexture: IBGRAScanner);
     3140begin
     3141  DrawPath(APath,AffineMatrixIdentity,AStrokeTexture,AWidth,AFillTexture);
     3142end;
     3143
     3144procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; AStrokeColor: TBGRAPixel; AWidth: single);
     3145begin
     3146  DrawPath(APath, AffineMatrixIdentity, AStrokeColor, AWidth);
     3147end;
     3148
     3149procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; AStrokeTexture: IBGRAScanner; AWidth: single);
     3150begin
     3151  DrawPath(APath, AffineMatrixIdentity, AStrokeTexture, AWidth);
     3152end;
     3153
    28403154procedure TBGRADefaultBitmap.EllipseAntialias(x, y, rx, ry: single;
    28413155  c: TBGRAPixel; w: single);
    28423156begin
    2843   if IsClearPenStyle(FCustomPenStyle) or (c.alpha = 0) then exit;
    2844   if IsSolidPenStyle(FCustomPenStyle) then
     3157  if (PenStyle = psClear) or (c.alpha = 0) then exit;
     3158  if (PenStyle = psSolid) then
    28453159    BGRAPolygon.BorderEllipseAntialias(self, x, y, rx, ry, w, c, FEraseMode, LinearAntialiasing)
    28463160  else
     
    28513165  texture: IBGRAScanner; w: single);
    28523166begin
    2853   if IsClearPenStyle(FCustomPenStyle) then exit;
    2854   if IsSolidPenStyle(FCustomPenStyle) then
     3167  if (PenStyle = psClear) then exit;
     3168  if (PenStyle = psSolid) then
    28553169    BGRAPolygon.BorderEllipseAntialiasWithTexture(self, x, y, rx, ry, w, texture, LinearAntialiasing)
    28563170  else
     
    28743188  { use multishape filler for fine junction between polygons }
    28753189  multi := TBGRAMultishapeFiller.Create;
    2876   if not IsClearPenStyle(FCustomPenStyle) and (c.alpha <> 0) then
    2877   begin
    2878     if IsSolidPenStyle(FCustomPenStyle) then
     3190  if not (PenStyle = psClear) and (c.alpha <> 0) then
     3191  begin
     3192    if (PenStyle = psSolid) then
    28793193    begin
    28803194      multi.AddEllipse(x,y,rx-hw,ry-hw,back);
     
    29413255  hw: single;
    29423256begin
    2943   if IsClearPenStyle(FCustomPenStyle) or (c.alpha=0) or (w=0) then
     3257  if (PenStyle = psClear) or (c.alpha=0) or (w=0) then
    29443258  begin
    29453259    if back <> BGRAPixelTransparent then
     
    29663280  multi := TBGRAMultishapeFiller.Create;
    29673281  multi.FillMode := FillMode;
    2968   if (JoinStyle = pjsMiter) and IsSolidPenStyle(FCustomPenStyle) then
     3282  if (JoinStyle = pjsMiter) and (PenStyle = psSolid) then
    29693283    multi.AddRectangleBorder(x,y,x2,y2,w,c)
    29703284  else
     
    29853299  multi: TBGRAMultishapeFiller;
    29863300begin
    2987   if IsClearPenStyle(FCustomPenStyle) or (w=0) then exit;
     3301  if (PenStyle = psClear) or (w=0) then exit;
    29883302
    29893303  hw := w/2;
     
    30053319  multi := TBGRAMultishapeFiller.Create;
    30063320  multi.FillMode := FillMode;
    3007   if (JoinStyle = pjsMiter) and IsSolidPenStyle(FCustomPenStyle) then
     3321  if (JoinStyle = pjsMiter) and (PenStyle = psSolid) then
    30083322    multi.AddRectangleBorder(x,y,x2,y2,w, texture)
    30093323  else
     
    30163330   c: TBGRAPixel; w: single; options: TRoundRectangleOptions);
    30173331begin
    3018   if IsClearPenStyle(FCustomPenStyle) or (c.alpha = 0) then exit;
    3019   if IsSolidPenStyle(FCustomPenStyle) then
     3332  if (PenStyle = psClear) or (c.alpha = 0) then exit;
     3333  if (PenStyle = psSolid) then
    30203334    BGRAPolygon.BorderRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,w,options,c,False, LinearAntialiasing)
    30213335  else
     
    30293343  multi: TBGRAMultishapeFiller;
    30303344begin
    3031   if IsClearPenStyle(FCustomPenStyle) or (pencolor.alpha = 0) then
     3345  if (PenStyle = psClear) or (pencolor.alpha = 0) then
    30323346  begin
    30333347    FillRoundRectAntialias(x,y,x2,y2,rx,ry,fillColor,options);
    30343348    exit;
    30353349  end;
    3036   if IsSolidPenStyle(FCustomPenStyle) then
     3350  if (PenStyle = psSolid) then
    30373351    BGRAPolygon.BorderAndFillRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,w,options,pencolor,fillcolor,nil,nil,False)
    30383352  else
     
    30533367  multi: TBGRAMultishapeFiller;
    30543368begin
    3055   if IsClearPenStyle(FCustomPenStyle) then
     3369  if (PenStyle = psClear) then
    30563370  begin
    30573371    FillRoundRectAntialias(x,y,x2,y2,rx,ry,fillTexture,options);
    30583372    exit;
    30593373  end else
    3060   if IsSolidPenStyle(FCustomPenStyle) then
     3374  if (PenStyle = psSolid) then
    30613375    BGRAPolygon.BorderAndFillRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,w,options,BGRAPixelTransparent,BGRAPixelTransparent,pentexture,filltexture,False)
    30623376  else
     
    30743388  texture: IBGRAScanner; w: single; options: TRoundRectangleOptions);
    30753389begin
    3076   if IsClearPenStyle(FCustomPenStyle) then exit;
    3077   if IsSolidPenStyle(FCustomPenStyle) then
     3390  if (PenStyle = psClear) then exit;
     3391  if (PenStyle = psSolid) then
    30783392    BGRAPolygon.BorderRoundRectangleAntialiasWithTexture(self,x,y,x2,y2,rx,ry,w,options,texture, LinearAntialiasing)
    30793393  else
     
    32603574
    32613575procedure TBGRADefaultBitmap.FillRect(x, y, x2, y2: integer;
    3262   texture: IBGRAScanner; mode: TDrawMode);
     3576  texture: IBGRAScanner; mode: TDrawMode; AScanOffset: TPoint);
    32633577var
    32643578  yb, tx, delta: integer;
     
    32783592  for yb := y to y2 do
    32793593  begin
    3280     texture.ScanMoveTo(x,yb);
     3594    texture.ScanMoveTo(x+AScanOffset.X,yb+AScanOffset.Y);
    32813595    ScannerPutPixels(texture, p, tx, mode);
    32823596    Inc(p, delta);
     
    32843598
    32853599  InvalidateBitmap;
     3600end;
     3601
     3602procedure TBGRADefaultBitmap.FillRect(x, y, x2, y2: integer;
     3603  texture: IBGRAScanner; mode: TDrawMode; AScanOffset: TPoint; ditheringAlgorithm: TDitheringAlgorithm);
     3604var dither: TDitheringTask;
     3605begin
     3606  if not CheckClippedRectBounds(x,y,x2,y2) then exit;
     3607  dither := CreateDitheringTask(ditheringAlgorithm, texture, self, rect(x,y,x2,y2));
     3608  dither.ScanOffset := AScanOffset;
     3609  dither.DrawMode := mode;
     3610  dither.Execute;
     3611  dither.Free;
    32863612end;
    32873613
     
    33153641end;
    33163642
    3317 procedure TBGRADefaultBitmap.FillRectAntialias(x, y, x2, y2: single; c: TBGRAPixel);
     3643procedure TBGRADefaultBitmap.FillRectAntialias(x, y, x2, y2: single; c: TBGRAPixel; pixelCenteredCoordinates: boolean);
    33183644var tx,ty: single;
    33193645begin
     3646  if not pixelCenteredCoordinates then
     3647  begin
     3648    x -= 0.5;
     3649    y -= 0.5;
     3650    x2 -= 0.5;
     3651    y2 -= 0.5;
     3652  end;
     3653
    33203654  tx := x2-x;
    33213655  ty := y2-y;
    3322   if (tx=0) or (ty=0) then exit;
     3656  if (abs(tx)<1e-3) or (abs(ty)<1e-3) then exit;
    33233657  if (abs(tx) > 2) and (abs(ty) > 2) then
    33243658  begin
     
    33453679
    33463680procedure TBGRADefaultBitmap.EraseRectAntialias(x, y, x2, y2: single;
    3347   alpha: byte);
    3348 begin
     3681  alpha: byte; pixelCenteredCoordinates: boolean);
     3682begin
     3683  if not pixelCenteredCoordinates then
     3684  begin
     3685    x -= 0.5;
     3686    y -= 0.5;
     3687    x2 -= 0.5;
     3688    y2 -= 0.5;
     3689  end;
    33493690  ErasePolyAntialias([pointf(x, y), pointf(x2, y), pointf(x2, y2), pointf(x, y2)], alpha);
    33503691end;
    33513692
    33523693procedure TBGRADefaultBitmap.FillRectAntialias(x, y, x2, y2: single;
    3353   texture: IBGRAScanner);
    3354 begin
     3694  texture: IBGRAScanner; pixelCenteredCoordinates: boolean);
     3695begin
     3696  if not pixelCenteredCoordinates then
     3697  begin
     3698    x -= 0.5;
     3699    y -= 0.5;
     3700    x2 -= 0.5;
     3701    y2 -= 0.5;
     3702  end;
    33553703  FillPolyAntialias([pointf(x, y), pointf(x2, y), pointf(x2, y2), pointf(x, y2)], texture);
    33563704end;
    33573705
    33583706procedure TBGRADefaultBitmap.FillRoundRectAntialias(x, y, x2, y2, rx,ry: single;
    3359   c: TBGRAPixel; options: TRoundRectangleOptions);
    3360 begin
     3707  c: TBGRAPixel; options: TRoundRectangleOptions; pixelCenteredCoordinates: boolean);
     3708begin
     3709  if not pixelCenteredCoordinates then
     3710  begin
     3711    x -= 0.5;
     3712    y -= 0.5;
     3713    x2 -= 0.5;
     3714    y2 -= 0.5;
     3715  end;
    33613716  BGRAPolygon.FillRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,options,c,False, LinearAntialiasing);
    33623717end;
    33633718
    33643719procedure TBGRADefaultBitmap.FillRoundRectAntialias(x, y, x2, y2, rx,
    3365   ry: single; texture: IBGRAScanner; options: TRoundRectangleOptions);
    3366 begin
     3720  ry: single; texture: IBGRAScanner; options: TRoundRectangleOptions; pixelCenteredCoordinates: boolean);
     3721begin
     3722  if not pixelCenteredCoordinates then
     3723  begin
     3724    x -= 0.5;
     3725    y -= 0.5;
     3726    x2 -= 0.5;
     3727    y2 -= 0.5;
     3728  end;
    33673729  BGRAPolygon.FillRoundRectangleAntialiasWithTexture(self,x,y,x2,y2,rx,ry,options,texture, LinearAntialiasing);
    33683730end;
    33693731
    33703732procedure TBGRADefaultBitmap.EraseRoundRectAntialias(x, y, x2, y2, rx,
    3371   ry: single; alpha: byte; options: TRoundRectangleOptions);
    3372 begin
     3733  ry: single; alpha: byte; options: TRoundRectangleOptions; pixelCenteredCoordinates: boolean);
     3734begin
     3735  if not pixelCenteredCoordinates then
     3736  begin
     3737    x -= 0.5;
     3738    y -= 0.5;
     3739    x2 -= 0.5;
     3740    y2 -= 0.5;
     3741  end;
    33733742  BGRAPolygon.FillRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,options,BGRA(0,0,0,alpha),True, LinearAntialiasing);
    33743743end;
     
    33913760  sUTF8: string; c: TBGRAPixel; align: TAlignment);
    33923761begin
    3393   FontRenderer.TextOutAngle(self,x,y,orientationTenthDegCCW,CleanTextOutString(sUTF8),c,align);
     3762  with (PointF(x,y)-GetFontAnchorRotatedOffset(orientationTenthDegCCW)) do
     3763    FontRenderer.TextOutAngle(self,x,y,orientationTenthDegCCW,CleanTextOutString(sUTF8),c,align);
    33943764end;
    33953765
     
    33973767  sUTF8: string; texture: IBGRAScanner; align: TAlignment);
    33983768begin
    3399   FontRenderer.TextOutAngle(self,x,y,orientationTenthDegCCW,CleanTextOutString(sUTF8),texture,align);
     3769  with (PointF(x,y)-GetFontAnchorRotatedOffset(orientationTenthDegCCW)) do
     3770    FontRenderer.TextOutAngle(self,x,y,orientationTenthDegCCW,CleanTextOutString(sUTF8),texture,align);
     3771end;
     3772
     3773procedure TBGRADefaultBitmap.TextOutCurved(ACursor: TBGRACustomPathCursor; sUTF8: string; AColor: TBGRAPixel; AAlign: TAlignment; ALetterSpacing: single);
     3774begin
     3775  InternalTextOutCurved(ACursor, sUTF8, AColor, nil, AAlign, ALetterSpacing);
     3776end;
     3777
     3778procedure TBGRADefaultBitmap.TextOutCurved(ACursor: TBGRACustomPathCursor; sUTF8: string; ATexture: IBGRAScanner; AAlign: TAlignment; ALetterSpacing: single);
     3779begin
     3780  InternalTextOutCurved(ACursor, sUTF8, BGRAPixelTransparent, ATexture, AAlign, ALetterSpacing);
    34003781end;
    34013782
     
    34093790  c: TBGRAPixel; align: TAlignment);
    34103791begin
    3411   FontRenderer.TextOut(self,x,y,CleanTextOutString(sUTF8),c,align);
     3792  with (PointF(x,y)-GetFontAnchorRotatedOffset) do
     3793    FontRenderer.TextOut(self,x,y,CleanTextOutString(sUTF8),c,align);
    34123794end;
    34133795
     
    34153797  sUTF8: string; style: TTextStyle; c: TBGRAPixel);
    34163798begin
    3417   FontRenderer.TextRect(self,ARect,x,y,sUTF8,style,c);
     3799  with (PointF(x,y)-GetFontAnchorRotatedOffset(0)) do
     3800    FontRenderer.TextRect(self,ARect,system.round(x),system.round(y),sUTF8,style,c);
    34183801end;
    34193802
     
    34213804  style: TTextStyle; texture: IBGRAScanner);
    34223805begin
    3423   FontRenderer.TextRect(self,ARect,x,y,sUTF8,style,texture);
     3806  with (PointF(x,y)-GetFontAnchorRotatedOffset(0)) do
     3807    FontRenderer.TextRect(self,ARect,system.round(x),system.round(y),sUTF8,style,texture);
    34243808end;
    34253809
     
    34703854  w: single): ArrayOfTPointF;
    34713855begin
    3472   if Assigned(FArrow) then
    3473     Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX)
    3474   else
    3475     Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,JoinMiterLimit)
     3856  result := FPenStroker.ComputePolyline(points,w);
    34763857end;
    34773858
    34783859function TBGRADefaultBitmap.ComputeWidePolyline(const points: array of TPointF;
    3479   w: single; Closed: boolean): ArrayOfTPointF;
    3480 var
    3481   options: TBGRAPolyLineOptions;
    3482 begin
    3483   if not closed then options := [plRoundCapOpen] else options := [];
    3484   options += GetPolyLineOption;
    3485   if Assigned(FArrow) then
    3486     Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,pecRound,pjsRound,FCustomPenStyle,options,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX)
    3487   else
    3488     Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,pecRound,pjsRound,FCustomPenStyle,options,JoinMiterLimit);
     3860  w: single; ClosedCap: boolean): ArrayOfTPointF;
     3861begin
     3862  result := FPenStroker.ComputePolyline(points,w,ClosedCap);
    34893863end;
    34903864
     
    34923866  w: single): ArrayOfTPointF;
    34933867begin
    3494   Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption+[plCycle],JoinMiterLimit);
     3868  result := FPenStroker.ComputePolygon(points,w);
    34953869end;
    34963870
     
    35983972
    35993973procedure TBGRADefaultBitmap.FillMask(x, y: integer; AMask: TBGRACustomBitmap;
    3600   texture: IBGRAScanner; ADrawMode: TDrawMode);
     3974  texture: IBGRAScanner; ADrawMode: TDrawMode; AOpacity: byte);
    36013975var
    36023976  scan: TBGRACustomScanner;
    36033977begin
    36043978  if AMask = nil then exit;
    3605   scan := TBGRATextureMaskScanner.Create(AMask,Point(-X,-Y),texture);
     3979  scan := TBGRATextureMaskScanner.Create(AMask,Point(-X,-Y),texture, AOpacity);
    36063980  self.FillRect(X,Y,X+AMask.Width,Y+AMask.Height,scan,ADrawMode);
    36073981  scan.Free;
     
    36264000  n: integer;
    36274001  colorMask,beforeBGR, afterBGR: longword;
    3628 begin
    3629   colorMask := NtoLE($00FFFFFF);
    3630   beforeBGR := NtoLE((before and $FF shl 16) + (before and $FF00) + (before shr 16 and $FF));
    3631   afterBGR  := NtoLE((after and $FF shl 16) + (after and $FF00) + (after shr 16 and $FF));
     4002  rAfter,gAfter,bAfter,rBefore,gBefore,bBefore: byte;
     4003begin
     4004  colorMask := LongWord(BGRA(255,255,255,0));
     4005  RedGreenBlue(before, rBefore,gBefore,bBefore);
     4006  RedGreenBlue(after, rAfter,gAfter,bAfter);
     4007  beforeBGR := LongWord(BGRA(rBefore,gBefore,bBefore,0));
     4008  afterBGR  := LongWord(BGRA(rAfter,gAfter,bAfter,0));
    36324009
    36334010  p := PLongWord(Data);
     
    36544031  for n := NbPixels - 1 downto 0 do
    36554032  begin
    3656     if p^ = before then
     4033    if PDWord(p)^ = DWord(before) then
    36574034      p^ := after;
    36584035    Inc(p);
     4036  end;
     4037  InvalidateBitmap;
     4038end;
     4039
     4040procedure TBGRADefaultBitmap.ReplaceColor(ABounds: TRect; before, after: TColor);
     4041var p: PLongWord;
     4042  xb,yb,xcount: integer;
     4043
     4044  colorMask,beforeBGR, afterBGR: longword;
     4045  rAfter,gAfter,bAfter,rBefore,gBefore,bBefore: byte;
     4046begin
     4047  colorMask := LongWord(BGRA(255,255,255,0));
     4048  RedGreenBlue(before, rBefore,gBefore,bBefore);
     4049  RedGreenBlue(after, rAfter,gAfter,bAfter);
     4050  beforeBGR := LongWord(BGRA(rBefore,gBefore,bBefore,0));
     4051  afterBGR  := LongWord(BGRA(rAfter,gAfter,bAfter,0));
     4052
     4053  if not IntersectRect(ABounds,ABounds,ClipRect) then exit;
     4054  xcount := ABounds.Right-ABounds.Left;
     4055  for yb := ABounds.Top to ABounds.Bottom-1 do
     4056  begin
     4057    p := PLongWord(ScanLine[yb]+ABounds.Left);
     4058    for xb := xcount-1 downto 0 do
     4059    begin
     4060      if p^ and colorMask = beforeBGR then
     4061        p^ := (p^ and not ColorMask) or afterBGR;
     4062      Inc(p);
     4063    end;
     4064  end;
     4065  InvalidateBitmap;
     4066end;
     4067
     4068procedure TBGRADefaultBitmap.ReplaceColor(ABounds: TRect; before,
     4069  after: TBGRAPixel);
     4070var p: PBGRAPixel;
     4071  xb,yb,xcount: integer;
     4072begin
     4073  if before.alpha = 0 then
     4074  begin
     4075    ReplaceTransparent(ABounds,after);
     4076    exit;
     4077  end;
     4078  if not IntersectRect(ABounds,ABounds,ClipRect) then exit;
     4079  xcount := ABounds.Right-ABounds.Left;
     4080  for yb := ABounds.Top to ABounds.Bottom-1 do
     4081  begin
     4082    p := ScanLine[yb]+ABounds.Left;
     4083    for xb := xcount-1 downto 0 do
     4084    begin
     4085      if PDWord(p)^ = DWord(before) then
     4086        p^ := after;
     4087      Inc(p);
     4088    end;
    36594089  end;
    36604090  InvalidateBitmap;
     
    36734103      p^ := after;
    36744104    Inc(p);
     4105  end;
     4106  InvalidateBitmap;
     4107end;
     4108
     4109procedure TBGRADefaultBitmap.ReplaceTransparent(ABounds: TRect;
     4110  after: TBGRAPixel);
     4111var p: PBGRAPixel;
     4112  xb,yb,xcount: integer;
     4113begin
     4114  if not IntersectRect(ABounds,ABounds,ClipRect) then exit;
     4115  xcount := ABounds.Right-ABounds.Left;
     4116  for yb := ABounds.Top to ABounds.Bottom-1 do
     4117  begin
     4118    p := ScanLine[yb]+ABounds.Left;
     4119    for xb := xcount-1 downto 0 do
     4120    begin
     4121      if p^.alpha = 0 then
     4122        p^ := after;
     4123      Inc(p);
     4124    end;
    36754125  end;
    36764126  InvalidateBitmap;
     
    38264276procedure TBGRADefaultBitmap.GradientFill(x, y, x2, y2: integer;
    38274277  c1, c2: TBGRAPixel; gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode;
    3828   gammaColorCorrection: boolean = True; Sinus: Boolean=False);
    3829 begin
    3830   BGRAGradientFill(self, x, y, x2, y2, c1, c2, gtype, o1, o2, mode, gammaColorCorrection, Sinus);
     4278  gammaColorCorrection: boolean; Sinus: Boolean; ditherAlgo: TDitheringAlgorithm);
     4279var
     4280  scanner: TBGRAGradientScanner;
     4281begin
     4282  if (c1.alpha = 0) and (c2.alpha = 0) then
     4283    FillRect(x, y, x2, y2, BGRAPixelTransparent, mode)
     4284  else
     4285  if ditherAlgo <> daNearestNeighbor then
     4286    GradientFillDithered(x,y,x2,y2,c1,c2,gtype,o1,o2,mode,gammaColorCorrection,sinus,ditherAlgo)
     4287  else
     4288  begin
     4289    scanner := TBGRAGradientScanner.Create(c1,c2,gtype,o1,o2,gammaColorCorrection,Sinus);
     4290    FillRect(x,y,x2,y2,scanner,mode);
     4291    scanner.Free;
     4292  end;
    38314293end;
    38324294
    38334295procedure TBGRADefaultBitmap.GradientFill(x, y, x2, y2: integer;
    38344296  gradient: TBGRACustomGradient; gtype: TGradientType; o1, o2: TPointF;
    3835   mode: TDrawMode; Sinus: Boolean);
     4297  mode: TDrawMode; Sinus: Boolean; ditherAlgo: TDitheringAlgorithm);
    38364298var
    38374299  scanner: TBGRAGradientScanner;
    38384300begin
     4301  if ditherAlgo <> daNearestNeighbor then
     4302    GradientFillDithered(x,y,x2,y2,gradient,gtype,o1,o2,mode,sinus,ditherAlgo)
     4303  else
     4304  begin
     4305    scanner := TBGRAGradientScanner.Create(gradient,gtype,o1,o2,sinus);
     4306    FillRect(x,y,x2,y2,scanner,mode);
     4307    scanner.Free;
     4308  end;
     4309end;
     4310
     4311procedure TBGRADefaultBitmap.GradientFillDithered(x, y, x2, y2: integer; c1,
     4312  c2: TBGRAPixel; gtype: TGradientType; o1, o2: TPointF;
     4313  mode: TDrawMode; gammaColorCorrection: boolean; Sinus: Boolean;
     4314  ditherAlgo: TDitheringAlgorithm);
     4315var
     4316  scanner: TBGRAGradientScanner;
     4317begin
     4318  if (c1.alpha = 0) and (c2.alpha = 0) then
     4319    FillRect(x, y, x2, y2, BGRAPixelTransparent, dmSet)
     4320  else
     4321  begin
     4322    scanner := TBGRAGradientScanner.Create(c1,c2,gtype,o1,o2,gammaColorCorrection,Sinus);
     4323    FillRect(x,y,x2,y2,scanner,mode,ditherAlgo);
     4324    scanner.Free;
     4325  end;
     4326end;
     4327
     4328procedure TBGRADefaultBitmap.GradientFillDithered(x, y, x2, y2: integer;
     4329  gradient: TBGRACustomGradient; gtype: TGradientType; o1, o2: TPointF;
     4330  mode: TDrawMode; Sinus: Boolean; ditherAlgo: TDitheringAlgorithm);
     4331var
     4332  scanner: TBGRAGradientScanner;
     4333begin
    38394334  scanner := TBGRAGradientScanner.Create(gradient,gtype,o1,o2,sinus);
    3840   FillRect(x,y,x2,y2,scanner,mode);
     4335  FillRect(x,y,x2,y2,scanner,mode,ditherAlgo);
    38414336  scanner.Free;
    38424337end;
     
    38504345function TBGRADefaultBitmap.ScanAtInteger(X, Y: integer): TBGRAPixel;
    38514346begin
    3852   if FData <> nil then
    3853     result := (GetScanlineFast(PositiveMod(Y+ScanOffset.Y, FHeight))+PositiveMod(X+ScanOffset.X, FWidth))^
     4347  if (FScanWidth <> 0) and (FScanHeight <> 0) then
     4348    result := (GetScanlineFast(PositiveMod(Y+ScanOffset.Y, FScanHeight))+PositiveMod(X+ScanOffset.X, FScanWidth))^
    38544349  else
    38554350    result := BGRAPixelTransparent;
     
    38594354procedure TBGRADefaultBitmap.ScanMoveTo(X, Y: Integer);
    38604355begin
    3861   if FData = nil then exit;
     4356  if (FScanWidth = 0) or (FScanHeight = 0) then exit;
    38624357  LoadFromBitmapIfNeeded;
    3863   FScanCurX := PositiveMod(X+ScanOffset.X, FWidth);
    3864   FScanCurY := PositiveMod(Y+ScanOffset.Y, FHeight);
     4358  FScanCurX := PositiveMod(X+ScanOffset.X, FScanWidth);
     4359  FScanCurY := PositiveMod(Y+ScanOffset.Y, FScanHeight);
    38654360  FScanPtr := ScanLine[FScanCurY];
    38664361end;
     
    38684363function TBGRADefaultBitmap.ScanNextPixel: TBGRAPixel;
    38694364begin
    3870   if FData <> nil then
     4365  if (FScanWidth <> 0) and (FScanHeight <> 0) then
    38714366  begin
    38724367    result := (FScanPtr+FScanCurX)^;
    38734368    inc(FScanCurX);
    3874     if FScanCurX = FWidth then //cycle
     4369    if FScanCurX = FScanWidth then //cycle
    38754370      FScanCurX := 0;
    38764371  end
     
    38844379  iFactX,iFactY: Int32or64;
    38854380begin
    3886   if FData = nil then
     4381  if (FScanWidth = 0) or (FScanHeight = 0) then
    38874382  begin
    38884383    result := BGRAPixelTransparent;
     
    38924387  ix := round(x*256);
    38934388  iy := round(y*256);
     4389  if ScanInterpolationFilter = rfBox then
     4390  begin
     4391    ix := PositiveMod((ix+128)+(ScanOffset.X shl 8), FScanWidth shl 8) shr 8;
     4392    iy := PositiveMod((iy+128)+(ScanOffset.Y shl 8), FScanHeight shl 8) shr 8;
     4393    result := (GetScanlineFast(iy)+ix)^;
     4394    exit;
     4395  end;
    38944396  iFactX := ix and 255;
    38954397  iFactY := iy and 255;
    3896   ix := PositiveMod(ix+(ScanOffset.X shl 8), FWidth shl 8) shr 8;
    3897   iy := PositiveMod(iy+(ScanOffset.Y shl 8), FHeight shl 8) shr 8;
     4398  ix := PositiveMod(ix+(ScanOffset.X shl 8), FScanWidth shl 8) shr 8;
     4399  iy := PositiveMod(iy+(ScanOffset.Y shl 8), FScanHeight shl 8) shr 8;
    38984400  if (iFactX = 0) and (iFactY = 0) then
    38994401  begin
     
    39204422  c: TBGRAPixel;
    39214423begin
     4424  if (FScanWidth <= 0) or (FScanHeight <= 0) then
     4425  begin
     4426    if mode = dmSet then
     4427      FillDWord(pdest^, count, DWord(BGRAPixelTransparent));
     4428    exit;
     4429  end;
    39224430  case mode of
    39234431    dmLinearBlend:
     
    39364444      while count > 0 do
    39374445      begin
    3938         nbCopy := FWidth-FScanCurX;
     4446        nbCopy := FScanWidth-FScanCurX;
    39394447        if count < nbCopy then nbCopy := count;
    39404448        move((FScanPtr+FScanCurX)^,pdest^,nbCopy*sizeof(TBGRAPixel));
    39414449        inc(pdest,nbCopy);
    39424450        inc(FScanCurX,nbCopy);
    3943         if FScanCurX = FWidth then FScanCurX := 0;
     4451        if FScanCurX = FScanWidth then FScanCurX := 0;
    39444452        dec(count,nbCopy);
    39454453      end;
     
    39944502  p: PBGRAPixel;
    39954503  n: integer;
     4504  colormask: longword;
    39964505begin
    39974506  if CanvasAlphaCorrection then
    39984507  begin
    39994508    p := FData;
     4509    colormask := longword(BGRA(255,255,255,0));
    40004510    for n := NbPixels - 1 downto 0 do
    40014511    begin
    4002       if (longword(p^) and $FFFFFF <> 0) and (p^.alpha = 0) then
     4512      if (longword(p^) and colormask <> 0) and (p^.alpha = 0) then
    40034513        p^.alpha := FCanvasOpacity;
    40044514      Inc(p);
     
    42994809  Parameters are the bitmap origin, the end of the horizontal axis and the end of the vertical axis.
    43004810  The output bounds correspond to the pixels that will be affected in the destination. }
    4301 procedure TBGRADefaultBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF;
    4302   Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte);
     4811procedure TBGRADefaultBitmap.PutImageAffine(AMatrix: TAffineMatrix;
     4812  Source: TBGRACustomBitmap; AOutputBounds: TRect;
     4813  AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte);
    43034814var affine: TBGRAAffineBitmapTransform;
    4304     SourceBounds: TRect;
    4305 begin
    4306   if (Source = nil) or (AOpacity = 0) then exit;
     4815    sourceBounds: TRect;
     4816begin
     4817  if (Source = nil) or (Source.Width = 0) or (Source.Height = 0) or (AOpacity = 0) then exit;
    43074818  IntersectRect(AOutputBounds,AOutputBounds,ClipRect);
    43084819  if IsRectEmpty(AOutputBounds) then exit;
    43094820
    4310   if (abs(Origin.x-round(Origin.x))<1e-6) and (abs(Origin.y-round(Origin.Y))<1e-6) and
    4311      (abs(HAxis.x-(Origin.x+Source.Width))<1e-6) and (abs(HAxis.y-origin.y)<1e-6) and
    4312      (abs(VAxis.x-Origin.x)<1e-6) and (abs(VAxis.y-(Origin.y+Source.Height))<1e-6) then
    4313   begin
    4314     SourceBounds := AOutputBounds;
    4315     OffsetRect(SourceBounds, -round(origin.x),-round(origin.y));
    4316     IntersectRect(SourceBounds,SourceBounds,rect(0,0,Source.Width,Source.Height));
    4317     PutImagePart(round(origin.x)+SourceBounds.Left,round(origin.y)+SourceBounds.Top,Source,SourceBounds,AMode,AOpacity);
    4318     exit;
    4319   end;
    4320 
    4321   { Create affine transformation }
    4322   affine := TBGRAAffineBitmapTransform.Create(Source, false, AResampleFilter);
    4323   affine.GlobalOpacity := AOpacity;
    4324   affine.Fit(Origin,HAxis,VAxis);
    4325   FillRect(AOutputBounds,affine,AMode);
    4326   affine.Free;
     4821  if IsAffineRoughlyTranslation(AMatrix, rect(0,0,Source.Width,Source.Height)) then
     4822  begin
     4823    sourceBounds := AOutputBounds;
     4824    OffsetRect(sourceBounds, -round(AMatrix[1,3]),-round(AMatrix[2,3]));
     4825    IntersectRect(sourceBounds,sourceBounds,rect(0,0,Source.Width,Source.Height));
     4826    PutImagePart(round(AMatrix[1,3])+sourceBounds.Left,round(AMatrix[2,3])+sourceBounds.Top,Source,sourceBounds,AMode,AOpacity);
     4827  end else
     4828  begin
     4829    affine := TBGRAAffineBitmapTransform.Create(Source, false, AResampleFilter);
     4830    affine.GlobalOpacity := AOpacity;
     4831    affine.ViewMatrix := AMatrix;
     4832    FillRect(AOutputBounds,affine,AMode);
     4833    affine.Free;
     4834  end;
     4835end;
     4836
     4837function TBGRADefaultBitmap.GetImageAffineBounds(AMatrix: TAffineMatrix;
     4838  ASourceBounds: TRect; AClipOutput: boolean): TRect;
     4839const pointMargin = 0.5 - 1/512;
     4840
     4841  procedure FirstPoint(pt: TPointF);
     4842  begin
     4843    result.Left := round(pt.X);
     4844    result.Top := round(pt.Y);
     4845    result.Right := round(pt.X)+1;
     4846    result.Bottom := round(pt.Y)+1;
     4847  end;
     4848
     4849  //include specified point in the bounds
     4850  procedure IncludePoint(pt: TPointF);
     4851  begin
     4852    if round(pt.X) < result.Left then result.Left := round(pt.X);
     4853    if round(pt.Y) < result.Top then result.Top := round(pt.Y);
     4854    if round(pt.X)+1 > result.Right then result.Right := round(pt.X)+1;
     4855    if round(pt.Y)+1 > result.Bottom then result.Bottom := round(pt.Y)+1;
     4856  end;
     4857
     4858begin
     4859  result := EmptyRect;
     4860  if IsRectEmpty(ASourceBounds) then exit;
     4861  if IsAffineRoughlyTranslation(AMatrix,ASourceBounds) then
     4862  begin
     4863    result := ASourceBounds;
     4864    OffsetRect(result,round(AMatrix[1,3]),round(AMatrix[2,3]));
     4865  end else
     4866  begin
     4867    FirstPoint(AMatrix*PointF(ASourceBounds.Left-pointMargin,ASourceBounds.Top-pointMargin));
     4868    IncludePoint(AMatrix*PointF(ASourceBounds.Right-1+pointMargin,ASourceBounds.Top-pointMargin));
     4869    IncludePoint(AMatrix*PointF(ASourceBounds.Left-pointMargin,ASourceBounds.Bottom-1+pointMargin));
     4870    IncludePoint(AMatrix*PointF(ASourceBounds.Right-1+pointMargin,ASourceBounds.Bottom-1+pointMargin));
     4871  end;
     4872  if AClipOutput then IntersectRect(result,result,ClipRect);
    43274873end;
    43284874
     
    44344980function TBGRADefaultBitmap.FilterSmooth: TBGRACustomBitmap;
    44354981begin
    4436   Result := BGRAFilters.FilterBlurRadialPrecise(self, 0.3);
     4982  Result := BGRAFilters.FilterBlurRadial(self, 3, rbPrecise);
    44374983end;
    44384984
     
    44795025end;
    44805026
    4481 function TBGRADefaultBitmap.FilterBlurRadial(radius: integer;
     5027function TBGRADefaultBitmap.FilterBlurRadial(radius: single;
    44825028  blurType: TRadialBlurType): TBGRACustomBitmap;
    44835029begin
     
    44855031end;
    44865032
    4487 function TBGRADefaultBitmap.FilterBlurRadial(ABounds: TRect; radius: integer;
     5033function TBGRADefaultBitmap.FilterBlurRadial(ABounds: TRect; radius: single;
    44885034  blurType: TRadialBlurType): TBGRACustomBitmap;
    44895035var task: TFilterTask;
     
    44975043end;
    44985044
     5045function TBGRADefaultBitmap.FilterBlurRadial(radiusX, radiusY: single;
     5046  blurType: TRadialBlurType): TBGRACustomBitmap;
     5047begin
     5048  Result := BGRAFilters.FilterBlurRadial(self, radiusX,radiusY, blurType);
     5049end;
     5050
     5051function TBGRADefaultBitmap.FilterBlurRadial(ABounds: TRect; radiusX,
     5052  radiusY: single; blurType: TRadialBlurType): TBGRACustomBitmap;
     5053var task: TFilterTask;
     5054begin
     5055  task := BGRAFilters.CreateRadialBlurTask(self, ABounds, radiusX,radiusY, blurType);
     5056  try
     5057    result := task.Execute;
     5058  finally
     5059    task.Free;
     5060  end;
     5061end;
     5062
    44995063function TBGRADefaultBitmap.FilterPixelate(pixelSize: integer;
    45005064  useResample: boolean; filter: TResampleFilter): TBGRACustomBitmap;
     
    45035067end;
    45045068
    4505 function TBGRADefaultBitmap.FilterBlurMotion(distance: integer;
     5069function TBGRADefaultBitmap.FilterBlurMotion(distance: single;
    45065070  angle: single; oriented: boolean): TBGRACustomBitmap;
    45075071begin
     
    45095073end;
    45105074
    4511 function TBGRADefaultBitmap.FilterBlurMotion(ABounds: TRect; distance: integer;
     5075function TBGRADefaultBitmap.FilterBlurMotion(ABounds: TRect; distance: single;
    45125076  angle: single; oriented: boolean): TBGRACustomBitmap;
    45135077var task: TFilterTask;
     
    45395103end;
    45405104
    4541 function TBGRADefaultBitmap.FilterEmboss(angle: single): TBGRACustomBitmap;
    4542 begin
    4543   Result := BGRAFilters.FilterEmboss(self, angle);
    4544 end;
    4545 
    4546 function TBGRADefaultBitmap.FilterEmboss(angle: single; ABounds: TRect): TBGRACustomBitmap;
    4547 begin
    4548   Result := BGRAFilters.FilterEmboss(self, angle, ABounds);
     5105function TBGRADefaultBitmap.FilterEmboss(angle: single;
     5106  AStrength: integer; AOptions: TEmbossOptions): TBGRACustomBitmap;
     5107begin
     5108  Result := BGRAFilters.FilterEmboss(self, angle, AStrength, AOptions);
     5109end;
     5110
     5111function TBGRADefaultBitmap.FilterEmboss(angle: single; ABounds: TRect;
     5112  AStrength: integer; AOptions: TEmbossOptions): TBGRACustomBitmap;
     5113begin
     5114  Result := BGRAFilters.FilterEmboss(self, angle, ABounds, AStrength, AOptions);
    45495115end;
    45505116
     
    45925158begin
    45935159  Result := BGRAFilters.FilterRotate(self, origin, angle, correctBlur);
     5160end;
     5161
     5162function TBGRADefaultBitmap.FilterAffine(AMatrix: TAffineMatrix;
     5163  correctBlur: boolean): TBGRACustomBitmap;
     5164begin
     5165  Result := NewBitmap(Width,Height);
     5166  Result.PutImageAffine(AMatrix,self,255,correctBlur);
    45945167end;
    45955168
     
    46205193  if pix.alpha = 0 then
    46215194    result := clNone else
    4622      result := pix.red + pix.green shl 8 + pix.blue shl 16;
     5195     result := RGBToColor(pix.red,pix.green,pix.blue);
    46235196  {$hints on}
    46245197end;
     
    46515224end;
    46525225
    4653 function TBGRADefaultBitmap.CreateAdaptedPngWriter: TFPWriterPNG;
    4654 begin
    4655   result := TFPWriterPNG.Create;
    4656   result.Indexed := False;
    4657   result.UseAlpha := HasTransparentPixels;
    4658   result.WordSized := false;
     5226function TBGRADefaultBitmap.GetPenJoinStyle: TPenJoinStyle;
     5227begin
     5228  result := FPenStroker.JoinStyle;
     5229end;
     5230
     5231procedure TBGRADefaultBitmap.SetPenJoinStyle(const AValue: TPenJoinStyle);
     5232begin
     5233  FPenStroker.JoinStyle := AValue;
     5234end;
     5235
     5236function TBGRADefaultBitmap.GetPenMiterLimit: single;
     5237begin
     5238  result := FPenStroker.MiterLimit;
     5239end;
     5240
     5241procedure TBGRADefaultBitmap.SetPenMiterLimit(const AValue: single);
     5242begin
     5243  FPenStroker.MiterLimit := AValue;
    46595244end;
    46605245
     
    48255410  It is NOT EXACTLY an involution, when applied twice, some color information is lost }
    48265411procedure TBGRADefaultBitmap.Negative;
    4827 var
    4828   p: PBGRAPixel;
    4829   n: integer;
    4830 begin
    4831   LoadFromBitmapIfNeeded;
    4832   p := Data;
    4833   for n := NbPixels - 1 downto 0 do
    4834   begin
    4835     if p^.alpha <> 0 then
    4836     begin
    4837       p^.red   := GammaCompressionTab[not GammaExpansionTab[p^.red]];
    4838       p^.green := GammaCompressionTab[not GammaExpansionTab[p^.green]];
    4839       p^.blue  := GammaCompressionTab[not GammaExpansionTab[p^.blue]];
    4840     end;
    4841     Inc(p);
    4842   end;
    4843   InvalidateBitmap;
     5412begin
     5413  TBGRAFilterScannerNegative.ComputeFilterInplace(self, rect(0,0,FWidth,FHeight), True);
    48445414end;
    48455415
    48465416procedure TBGRADefaultBitmap.NegativeRect(ABounds: TRect);
    4847 var p: PBGRAPixel;
    4848   xb,yb,xcount: integer;
    48495417begin
    48505418  if not IntersectRect(ABounds,ABounds,ClipRect) then exit;
    4851   xcount := ABounds.Right-ABounds.Left;
    4852   for yb := ABounds.Top to ABounds.Bottom-1 do
    4853   begin
    4854     p := ScanLine[yb]+ABounds.Left;
    4855     for xb := xcount-1 downto 0 do
    4856     begin
    4857       if p^.alpha <> 0 then
    4858       begin
    4859         p^.red   := GammaCompressionTab[not GammaExpansionTab[p^.red]];
    4860         p^.green := GammaCompressionTab[not GammaExpansionTab[p^.green]];
    4861         p^.blue  := GammaCompressionTab[not GammaExpansionTab[p^.blue]];
    4862       end;
    4863       Inc(p);
    4864     end;
    4865   end;
     5419  TBGRAFilterScannerNegative.ComputeFilterInplace(self, ABounds, True);
    48665420end;
    48675421
     
    48705424  It is an involution, i.e it does nothing when applied twice }
    48715425procedure TBGRADefaultBitmap.LinearNegative;
    4872 var
    4873   p: PBGRAPixel;
    4874   n: integer;
    4875 begin
    4876   LoadFromBitmapIfNeeded;
    4877   p := Data;
    4878   for n := NbPixels - 1 downto 0 do
    4879   begin
    4880     if p^.alpha <> 0 then
    4881     begin
    4882       p^.red   := not p^.red;
    4883       p^.green := not p^.green;
    4884       p^.blue  := not p^.blue;
    4885     end;
    4886     Inc(p);
    4887   end;
    4888   InvalidateBitmap;
     5426begin
     5427  TBGRAFilterScannerNegative.ComputeFilterInplace(self, rect(0,0,FWidth,FHeight), False);
    48895428end;
    48905429
    48915430procedure TBGRADefaultBitmap.LinearNegativeRect(ABounds: TRect);
    4892 var p: PBGRAPixel;
    4893   xb,yb,xcount: integer;
    48945431begin
    48955432  if not IntersectRect(ABounds,ABounds,ClipRect) then exit;
    4896   xcount := ABounds.Right-ABounds.Left;
    4897   for yb := ABounds.Top to ABounds.Bottom-1 do
    4898   begin
    4899     p := ScanLine[yb]+ABounds.Left;
    4900     for xb := xcount-1 downto 0 do
    4901     begin
    4902       if p^.alpha <> 0 then
    4903       begin
    4904         p^.red   := not p^.red;
    4905         p^.green := not p^.green;
    4906         p^.blue  := not p^.blue;
    4907       end;
    4908       Inc(p);
    4909     end;
    4910   end;
    4911 end;
    4912 
    4913 procedure TBGRADefaultBitmap.InplaceGrayscale;
    4914 begin
    4915   InplaceGrayscale(rect(0,0,Width,Height));
    4916 end;
    4917 
    4918 procedure TBGRADefaultBitmap.InplaceGrayscale(ABounds: TRect);
    4919 var
    4920   task: TFilterTask;
    4921 begin
    4922   task := CreateGrayscaleTask(self, ABounds);
    4923   task.Destination := self;
    4924   task.Execute;
    4925   task.Free;
     5433  TBGRAFilterScannerNegative.ComputeFilterInplace(self, ABounds, False);
     5434end;
     5435
     5436procedure TBGRADefaultBitmap.InplaceGrayscale(AGammaCorrection: boolean = true);
     5437begin
     5438  TBGRAFilterScannerGrayscale.ComputeFilterInplace(self, rect(0,0,FWidth,FHeight), AGammaCorrection);
     5439end;
     5440
     5441procedure TBGRADefaultBitmap.InplaceGrayscale(ABounds: TRect; AGammaCorrection: boolean = true);
     5442begin
     5443  if not IntersectRect(ABounds,ABounds,ClipRect) then exit;
     5444  TBGRAFilterScannerGrayscale.ComputeFilterInplace(self, ABounds, AGammaCorrection);
     5445end;
     5446
     5447procedure TBGRADefaultBitmap.InplaceNormalize(AEachChannel: boolean);
     5448begin
     5449  InplaceNormalize(rect(0,0,Width,Height),AEachChannel);
     5450end;
     5451
     5452procedure TBGRADefaultBitmap.InplaceNormalize(ABounds: TRect;
     5453  AEachChannel: boolean);
     5454var scanner: TBGRAFilterScannerNormalize;
     5455begin
     5456  if not IntersectRect(ABounds,ABounds,ClipRect) then exit;
     5457  scanner := TBGRAFilterScannerNormalize.Create(self,Point(0,0),ABounds,AEachChannel);
     5458  FillRect(ABounds,scanner,dmSet);
     5459  scanner.Free;
    49265460end;
    49275461
     
    49305464  It is an involution, i.e it does nothing when applied twice }
    49315465procedure TBGRADefaultBitmap.SwapRedBlue;
     5466begin
     5467  TBGRAFilterScannerSwapRedBlue.ComputeFilterInplace(self, rect(0,0,FWidth,FHeight), False);
     5468end;
     5469
     5470procedure TBGRADefaultBitmap.SwapRedBlue(ARect: TRect);
     5471begin
     5472  if not CheckClippedRectBounds(ARect.Left,ARect.Top,ARect.Right,ARect.Bottom) then exit;
     5473  TBGRAFilterScannerSwapRedBlue.ComputeFilterInplace(self, ARect, False);
     5474end;
     5475
     5476{ Convert a grayscale image into a black image with alpha value }
     5477procedure TBGRADefaultBitmap.GrayscaleToAlpha;
    49325478var
    49335479  n:    integer;
    4934   temp: longword;
    49355480  p:    PLongword;
    49365481begin
     
    49415486    exit;
    49425487  repeat
    4943     temp := LEtoN(p^);
    4944     p^   := NtoLE(((temp and $FF) shl 16) or ((temp and $FF0000) shr 16) or
    4945       temp and $FF00FF00);
     5488    p^   := (p^ shr TBGRAPixel_RedShift and $FF) shl TBGRAPixel_AlphaShift;
    49465489    Inc(p);
    49475490    Dec(n);
     
    49505493end;
    49515494
    4952 { Convert a grayscale image into a black image with alpha value }
    4953 procedure TBGRADefaultBitmap.GrayscaleToAlpha;
     5495procedure TBGRADefaultBitmap.AlphaToGrayscale;
    49545496var
    49555497  n:    integer;
     
    49635505    exit;
    49645506  repeat
    4965     temp := LEtoN(p^);
    4966     p^   := NtoLE((temp and $FF) shl 24);
    4967     Inc(p);
    4968     Dec(n);
    4969   until n = 0;
    4970   InvalidateBitmap;
    4971 end;
    4972 
    4973 procedure TBGRADefaultBitmap.AlphaToGrayscale;
    4974 var
    4975   n:    integer;
    4976   temp: longword;
    4977   p:    PLongword;
    4978 begin
    4979   LoadFromBitmapIfNeeded;
    4980   p := PLongword(Data);
    4981   n := NbPixels;
    4982   if n = 0 then
    4983     exit;
    4984   repeat
    4985     temp := LEtoN(p^ shr 24);
    4986     p^   := NtoLE(temp or (temp shl 8) or (temp shl 16) or $FF000000);
     5507    temp := (p^ shr TBGRAPixel_AlphaShift) and $ff;
     5508    p^   := (temp shl TBGRAPixel_RedShift) or (temp shl TBGRAPixel_GreenShift)
     5509         or (temp shl TBGRAPixel_BlueShift) or ($ff shl TBGRAPixel_AlphaShift);
    49875510    Inc(p);
    49885511    Dec(n);
     
    50455568    end;
    50465569  end;
     5570end;
     5571
     5572procedure TBGRADefaultBitmap.ApplyGlobalOpacity(ABounds: TRect; alpha: byte);
     5573var p: PBGRAPixel;
     5574  xb,yb,xcount: integer;
     5575begin
     5576  if not IntersectRect(ABounds,ABounds,ClipRect) then exit;
     5577  xcount := ABounds.Right-ABounds.Left;
     5578  for yb := ABounds.Top to ABounds.Bottom-1 do
     5579  begin
     5580    p := ScanLine[yb]+ABounds.Left;
     5581    for xb := xcount-1 downto 0 do
     5582    begin
     5583      p^.alpha := ApplyOpacity(p^.alpha, alpha);
     5584      Inc(p);
     5585    end;
     5586  end;
     5587  InvalidateBitmap;
    50475588end;
    50485589
     
    51275668end;
    51285669
    5129 { Get bounds of non zero values of specified channel }
    5130 function TBGRADefaultBitmap.GetImageBounds(Channel: TChannel = cAlpha; ANothingValue: Byte = 0): TRect;
    5131 begin
    5132   result := GetImageBounds([Channel], ANothingValue);
    5133 end;
    5134 
    5135 function TBGRADefaultBitmap.GetImageBounds(Channels: TChannels; ANothingValue: Byte = 0): TRect;
    5136 var
    5137   minx, miny, maxx, maxy: integer;
    5138   xb, xb2, yb: integer;
    5139   p:      PDWord;
    5140   colorMask, colorZeros: DWord;
    5141 begin
    5142   maxx := -1;
    5143   maxy := -1;
    5144   minx := self.Width;
    5145   miny := self.Height;
    5146   colorMask := 0;
    5147   colorZeros := 0;
    5148   if cBlue in Channels then
    5149   begin
    5150     colorMask := colorMask or $ff;
    5151     colorZeros:= colorZeros or ANothingValue;
    5152   end;
    5153   if cGreen in Channels then
    5154   begin
    5155     colorMask := colorMask or $ff00;
    5156     colorZeros:= colorZeros or (ANothingValue shl 8);
    5157   end;
    5158   if cRed in Channels then
    5159   begin
    5160     colorMask := colorMask or $ff0000;
    5161     colorZeros:= colorZeros or (ANothingValue shl 16);
    5162   end;
    5163   if cAlpha in Channels then
    5164   begin
    5165     colorMask := colorMask or $ff000000;
    5166     colorZeros:= colorZeros or (ANothingValue shl 24);
    5167   end;
    5168   colorMask := NtoLE(colorMask);
    5169   colorZeros := NtoLE(colorZeros);
    5170   for yb := 0 to self.Height - 1 do
    5171   begin
    5172     p := PDWord(self.ScanLine[yb]);
    5173     for xb := 0 to self.Width - 1 do
    5174     begin
    5175       if (p^ and colorMask) <> colorZeros then
    5176       begin
    5177         if xb < minx then
    5178           minx := xb;
    5179         if yb < miny then
    5180           miny := yb;
    5181         if xb > maxx then
    5182           maxx := xb;
    5183         if yb > maxy then
    5184           maxy := yb;
    5185 
    5186         inc(p, self.width-1-xb);
    5187         for xb2 := self.Width-1 downto xb+1 do
    5188         begin
    5189           if (p^ and colorMask) <> colorZeros then
    5190           begin
    5191             if xb2 > maxx then
    5192               maxx := xb2;
    5193             break;
    5194           end;
    5195           dec(p);
    5196         end;
    5197         break;
    5198       end;
    5199       Inc(p);
    5200     end;
    5201   end;
    5202   if minx > maxx then
    5203   begin
    5204     Result.left   := 0;
    5205     Result.top    := 0;
    5206     Result.right  := 0;
    5207     Result.bottom := 0;
    5208   end
    5209   else
    5210   begin
    5211     Result.left   := minx;
    5212     Result.top    := miny;
    5213     Result.right  := maxx + 1;
    5214     Result.bottom := maxy + 1;
    5215   end;
    5216 end;
    5217 
    52185670function TBGRADefaultBitmap.GetDifferenceBounds(ABitmap: TBGRACustomBitmap): TRect;
    52195671var
     
    53785830  begin
    53795831    if LineOrder = riloTopToBottom then
    5380       ptrbmp := TBGRAPtrBitmap.Create(Width,Bottom-Top,ScanLine[Top]) else
    5381       ptrbmp := TBGRAPtrBitmap.Create(Width,Bottom-Top,ScanLine[Bottom-1]);
     5832      ptrbmp := CreatePtrBitmap(Width,Bottom-Top,ScanLine[Top]) else
     5833      ptrbmp := CreatePtrBitmap(Width,Bottom-Top,ScanLine[Bottom-1]);
    53825834    ptrbmp.LineOrder := LineOrder;
    53835835    result := ptrbmp;
    53845836  end;
    5385 end;
    5386 
    5387 { Draw BGRA data to a canvas with transparency }
    5388 procedure TBGRADefaultBitmap.DataDrawTransparent(ACanvas: TCanvas;
    5389   Rect: TRect; AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer);
    5390 var
    5391   Temp:     TBitmap;
    5392   RawImage: TRawImage;
    5393   BitmapHandle, MaskHandle: HBitmap;
    5394 begin
    5395   RawImage.Init;
    5396   RawImage.Description.Init_BPP32_B8G8R8A8_BIO_TTB(AWidth, AHeight);
    5397   RawImage.Description.LineOrder := ALineOrder;
    5398   RawImage.Data     := PByte(AData);
    5399   RawImage.DataSize := AWidth * AHeight * sizeof(TBGRAPixel);
    5400   if not RawImage_CreateBitmaps(RawImage, BitmapHandle, MaskHandle, False) then
    5401     raise FPImageException.Create('Failed to create bitmap handle');
    5402   Temp := TBitmap.Create;
    5403   Temp.Handle := BitmapHandle;
    5404   Temp.MaskHandle := MaskHandle;
    5405   ACanvas.StretchDraw(Rect, Temp);
    5406   Temp.Free;
    5407 end;
    5408 
    5409 { Draw BGRA data to a canvas without transparency }
    5410 procedure TBGRADefaultBitmap.DataDrawOpaque(ACanvas: TCanvas;
    5411   Rect: TRect; AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer);
    5412 var
    5413   Temp:      TBitmap;
    5414   RawImage:  TRawImage;
    5415   BitmapHandle, MaskHandle: HBitmap;
    5416   TempData:  Pointer;
    5417   x, y:      integer;
    5418   PTempData: PByte;
    5419   PSource:   PByte;
    5420   ADataSize: integer;
    5421   ALineEndMargin: integer;
    5422   CreateResult: boolean;
    5423   {$IFDEF DARWIN}
    5424   TempShift: Byte;
    5425   {$ENDIF}
    5426 begin
    5427   if (AHeight = 0) or (AWidth = 0) then
    5428     exit;
    5429 
    5430   ALineEndMargin := (4 - ((AWidth * 3) and 3)) and 3;
    5431   ADataSize      := (AWidth * 3 + ALineEndMargin) * AHeight;
    5432 
    5433      {$HINTS OFF}
    5434   GetMem(TempData, ADataSize);
    5435      {$HINTS ON}
    5436   PTempData := TempData;
    5437   PSource   := AData;
    5438 
    5439 {$IFDEF DARWIN} //swap red and blue values
    5440   for y := 0 to AHeight - 1 do
    5441   begin
    5442     for x := 0 to AWidth - 1 do
    5443     begin
    5444       PTempData^ := (PSource+2)^;
    5445       (PTempData+1)^ := (PSource+1)^;
    5446       (PTempData+2)^ := PSource^;
    5447       inc(PTempData,3);
    5448       inc(PSource,4);
    5449     end;
    5450     Inc(PTempData, ALineEndMargin);
    5451   end;
    5452 {$ELSE}
    5453   for y := 0 to AHeight - 1 do
    5454   begin
    5455     for x := 0 to AWidth - 1 do
    5456     begin
    5457       PWord(PTempData)^ := PWord(PSource)^;
    5458       (PTempData+2)^ := (PSource+2)^;
    5459       Inc(PTempData,3);
    5460       Inc(PSource, 4);
    5461     end;
    5462     Inc(PTempData, ALineEndMargin);
    5463   end;
    5464 {$ENDIF}
    5465 
    5466   RawImage.Init;
    5467   RawImage.Description.Init_BPP24_B8G8R8_BIO_TTB(AWidth, AHeight);
    5468 {$IFDEF DARWIN}
    5469   TempShift := RawImage.Description.RedShift;
    5470   RawImage.Description.RedShift := RawImage.Description.BlueShift;
    5471   RawImage.Description.BlueShift := TempShift;
    5472 {$ENDIF}
    5473 
    5474   RawImage.Description.LineOrder := ALineOrder;
    5475   RawImage.Description.LineEnd := rileDWordBoundary;
    5476 
    5477   if integer(RawImage.Description.BytesPerLine) <> AWidth * 3 + ALineEndMargin then
    5478   begin
    5479     FreeMem(TempData);
    5480     raise FPImageException.Create('Line size is inconsistant');
    5481   end;
    5482   RawImage.Data     := PByte(TempData);
    5483   RawImage.DataSize := ADataSize;
    5484 
    5485   CreateResult := RawImage_CreateBitmaps(RawImage, BitmapHandle, MaskHandle, False);
    5486   FreeMem(TempData);
    5487 
    5488   if not CreateResult then
    5489     raise FPImageException.Create('Failed to create bitmap handle');
    5490 
    5491   Temp := TBitmap.Create;
    5492   Temp.Handle := BitmapHandle;
    5493   Temp.MaskHandle := MaskHandle;
    5494   ACanvas.StretchDraw(Rect, Temp);
    5495   Temp.Free;
    54965837end;
    54975838
     
    55145855end;
    55155856
    5516 procedure TBGRADefaultBitmap.RebuildBitmap;
    5517 var
    5518   RawImage: TRawImage;
    5519   BitmapHandle, MaskHandle: HBitmap;
    5520 begin
    5521   if FBitmap <> nil then
    5522     FBitmap.Free;
    5523 
    5524   FBitmap := TBitmapTracker.Create(self);
    5525 
    5526   if (FWidth > 0) and (FHeight > 0) then
    5527   begin
    5528     RawImage.Init;
    5529     RawImage.Description.Init_BPP32_B8G8R8A8_BIO_TTB(FWidth, FHeight);
    5530     RawImage.Description.LineOrder := FLineOrder;
    5531     RawImage.Data     := PByte(FData);
    5532     RawImage.DataSize := FWidth * FHeight * sizeof(TBGRAPixel);
    5533     if not RawImage_CreateBitmaps(RawImage, BitmapHandle, MaskHandle, False) then
    5534       raise FPImageException.Create('Failed to create bitmap handle');
    5535     FBitmap.Handle     := BitmapHandle;
    5536     FBitmap.MaskHandle := MaskHandle;
    5537   end;
    5538 
    5539   FBitmap.Canvas.AntialiasingMode := amOff;
    5540   FBitmapModified := False;
     5857function TBGRADefaultBitmap.CreatePtrBitmap(AWidth, AHeight: integer;
     5858  AData: PBGRAPixel): TBGRAPtrBitmap;
     5859begin
     5860  result := TBGRAPtrBitmap.Create(AWidth,AHeight,AData);
    55415861end;
    55425862
     
    55465866end;
    55475867
    5548 procedure TBGRADefaultBitmap.GetImageFromCanvas(CanvasSource: TCanvas; x, y: integer);
    5549 var
    5550   bmp: TBitmap;
    5551   subBmp: TBGRACustomBitmap;
    5552   subRect: TRect;
    5553   cw,ch: integer;
    5554 begin
    5555   DiscardBitmapChange;
    5556   cw := CanvasSource.Width;
    5557   ch := CanvasSource.Height;
    5558   if (x < 0) or (y < 0) or (x+Width > cw) or
    5559     (y+Height > ch) then
    5560   begin
    5561     FillTransparent;
    5562     if (x+Width <= 0) or (y+Height <= 0) or
    5563       (x >= cw) or (y >= ch) then
    5564       exit;
    5565 
    5566     if (x > 0) then subRect.Left := x else subRect.Left := 0;
    5567     if (y > 0) then subRect.Top := y else subRect.Top := 0;
    5568     if (x+Width > cw) then subRect.Right := cw else
    5569       subRect.Right := x+Width;
    5570     if (y+Height > ch) then subRect.Bottom := ch else
    5571       subRect.Bottom := y+Height;
    5572 
    5573     subBmp := NewBitmap(subRect.Right-subRect.Left,subRect.Bottom-subRect.Top);
    5574     subBmp.GetImageFromCanvas(CanvasSource,subRect.Left,subRect.Top);
    5575     PutImage(subRect.Left-x,subRect.Top-y,subBmp,dmSet);
    5576     subBmp.Free;
    5577     exit;
    5578   end;
    5579   bmp := TBitmap.Create;
    5580   bmp.PixelFormat := pf24bit;
    5581   bmp.Width := Width;
    5582   bmp.Height := Height;
    5583   bmp.Canvas.CopyRect(Classes.rect(0, 0, Width, Height), CanvasSource,
    5584     Classes.rect(x, y, x + Width, y + Height));
    5585   LoadFromRawImage(bmp.RawImage, 255, True);
    5586   bmp.Free;
    5587   InvalidateBitmap;
    5588 end;
    5589 
    55905868function TBGRADefaultBitmap.GetNbPixels: integer;
    55915869begin
     
    56135891end;
    56145892
     5893procedure TBGRADefaultBitmap.SetLineOrder(AValue: TRawImageLineOrder);
     5894begin
     5895  FLineOrder := AValue;
     5896end;
     5897
    56155898function TBGRADefaultBitmap.GetCanvasOpacity: byte;
    56165899begin
     
    56255908{ TBGRAPtrBitmap }
    56265909
     5910function TBGRAPtrBitmap.GetLineOrder: TRawImageLineOrder;
     5911begin
     5912  result := inherited GetLineOrder;
     5913end;
     5914
     5915procedure TBGRAPtrBitmap.SetLineOrder(AValue: TRawImageLineOrder);
     5916begin
     5917  inherited SetLineOrder(AValue);
     5918end;
     5919
    56275920procedure TBGRAPtrBitmap.ReallocData;
    56285921begin
     
    56335926begin
    56345927  FData := nil;
     5928end;
     5929
     5930procedure TBGRAPtrBitmap.CannotResize;
     5931begin
     5932  raise exception.Create('A pointer bitmap cannot be resized');
     5933end;
     5934
     5935procedure TBGRAPtrBitmap.NotImplemented;
     5936begin
     5937  raise exception.Create('Not implemented');
     5938end;
     5939
     5940procedure TBGRAPtrBitmap.RebuildBitmap;
     5941begin
     5942  NotImplemented;
     5943end;
     5944
     5945function TBGRAPtrBitmap.CreateDefaultFontRenderer: TBGRACustomFontRenderer;
     5946begin
     5947  result := nil;
     5948  NotImplemented;
     5949end;
     5950
     5951function TBGRAPtrBitmap.LoadFromRawImage(ARawImage: TRawImage;
     5952  DefaultOpacity: byte; AlwaysReplaceAlpha: boolean;
     5953  RaiseErrorOnInvalidPixelFormat: boolean): boolean;
     5954begin
     5955  result := false;
     5956  NotImplemented;
    56355957end;
    56365958
     
    56505972begin
    56515973  FData := AData;
     5974end;
     5975
     5976procedure TBGRAPtrBitmap.DataDrawTransparent(ACanvas: TCanvas; Rect: TRect;
     5977  AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer);
     5978begin
     5979  NotImplemented;
     5980end;
     5981
     5982procedure TBGRAPtrBitmap.DataDrawOpaque(ACanvas: TCanvas; Rect: TRect;
     5983  AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer);
     5984begin
     5985  NotImplemented;
     5986end;
     5987
     5988procedure TBGRAPtrBitmap.GetImageFromCanvas(CanvasSource: TCanvas; x, y: integer
     5989  );
     5990begin
     5991  NotImplemented;
     5992end;
     5993
     5994procedure TBGRAPtrBitmap.Assign(Source: TPersistent);
     5995begin
     5996  CannotResize;
     5997end;
     5998
     5999procedure TBGRAPtrBitmap.TakeScreenshot(ARect: TRect);
     6000begin
     6001  CannotResize;
     6002end;
     6003
     6004procedure TBGRAPtrBitmap.TakeScreenshotOfPrimaryMonitor;
     6005begin
     6006  CannotResize;
     6007end;
     6008
     6009procedure TBGRAPtrBitmap.LoadFromDevice(DC: System.THandle);
     6010begin
     6011  CannotResize;
     6012end;
     6013
     6014procedure TBGRAPtrBitmap.LoadFromDevice(DC: System.THandle; ARect: TRect);
     6015begin
     6016  CannotResize;
    56526017end;
    56536018
     
    56556020  c1, c2: TBGRAPixel; gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode;
    56566021  gammaColorCorrection: boolean = True; Sinus: Boolean=False);
    5657 var
    5658   gradScan : TBGRAGradientScanner;
    5659 begin
    5660   //handles transparency
    5661   if (c1.alpha = 0) and (c2.alpha = 0) then
    5662   begin
    5663     bmp.FillRect(x, y, x2, y2, BGRAPixelTransparent, mode);
    5664     exit;
    5665   end;
    5666 
    5667   gradScan := TBGRAGradientScanner.Create(c1,c2,gtype,o1,o2,gammaColorCorrection,Sinus);
    5668   bmp.FillRect(x,y,x2,y2,gradScan,mode);
    5669   gradScan.Free;
     6022begin
     6023  bmp.GradientFill(x,y,x2,y2,c1,c2,gtype,o1,o2,mode,gammaColorCorrection,sinus);
    56706024end;
    56716025
     
    56836037  end;
    56846038
    5685   ImageHandlers.RegisterImageWriter ('Personal Computer eXchange', 'pcx', TFPWriterPcx);
    5686   ImageHandlers.RegisterImageReader ('Personal Computer eXchange', 'pcx', TFPReaderPcx);
    5687 
    5688   ImageHandlers.RegisterImageWriter ('X Pixmap', 'xpm', TFPWriterXPM);
    5689   ImageHandlers.RegisterImageReader ('X Pixmap', 'xpm', TFPReaderXPM);
    5690 
    56916039end.
    56926040
Note: See TracChangeset for help on using the changeset viewer.