      {******************************************************************}
      { GDI+ Class                                                       }
      {                                                                  }
      { home page : http://www.progdigy.com                              }
      { email     : hgourvest@progdigy.com                               }
      {                                                                  }
      { date      : 15-02-2002                                           }
      {                                                                  }
      { The contents of this file are used with permission, subject to   }
      { the Mozilla Public License Version 1.1 (the "License"); you may  }
      { not use this file except in compliance with the License. You may }
      { obtain a copy of the License at                                  }
      { http://www.mozilla.org/MPL/MPL-1.1.html                          }
      {                                                                  }
      { Software distributed under the License is distributed on an      }
      { "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or   }
      { implied. See the License for the specific language governing     }
      { rights and limitations under the License.                        }
      {                                                                  }
      { *****************************************************************}

unit TeeGDIPOBJ;

interface
uses
  Windows,
  ActiveX,
//  DirectDraw,
  TeeGDIPAPI;

(**************************************************************************\
*
*   GDI+ Codec Image APIs
*
\**************************************************************************)

//--------------------------------------------------------------------------
// Codec Management APIs
//--------------------------------------------------------------------------

  function GetImageDecodersSize(out numDecoders, size: UINT): TStatus;
  function GetImageDecoders(numDecoders, size: UINT;
    decoders: PImageCodecInfo): TStatus;
  function GetImageEncodersSize(out numEncoders, size: UINT): TStatus;
  function GetImageEncoders(numEncoders, size: UINT;
    encoders: PImageCodecInfo): TStatus;

(**************************************************************************\
*
*   Private GDI+ header file.
*
\**************************************************************************)

//---------------------------------------------------------------------------
// GDI+ classes for forward reference
//---------------------------------------------------------------------------

type
  TGPGraphics = class;
  TGPPen = class;
  TGPBrush = class;
  TGPMatrix = class;
  TGPBitmap = class;
  TGPMetafile = class;
  TGPFontFamily = class;
  TGPGraphicsPath = class;
  TGPRegion = class;
  TGPImage = class;
  TGPHatchBrush = class;
  TGPSolidBrush = class;
  TGPLinearGradientBrush = class;
  TGPPathGradientBrush = class;
  TGPFont = class;
  TGPFontCollection = class;
  TGPInstalledFontCollection = class;
  TGPPrivateFontCollection = class;
  TGPImageAttributes = class;
  TGPCachedBitmap = class;

(**************************************************************************\
*
*   GDI+ Region, Font, Image, CustomLineCap class definitions.
*
\**************************************************************************)

  TGPRegion = class(TGdiplusBase)
  protected
    nativeRegion: GpRegion;
    lastResult: TStatus;
    function SetStatus(status: TStatus): TStatus;
    procedure SetNativeRegion(nativeRegion: GpRegion);
    constructor Create(nativeRegion: GpRegion); reintroduce; overload;
  public
    constructor Create; reintroduce; overload;
    constructor Create(const rect: TGPRectF); reintroduce; overload;
    constructor Create(const rect: TGPRect); reintroduce; overload;
    constructor Create(path: TGPGraphicsPath); reintroduce; overload;
    constructor Create(regionData: PBYTE; size: Integer); reintroduce; overload;
    constructor Create(hRgn: HRGN); reintroduce; overload;
    function FromHRGN(hRgn: HRGN): TGPRegion;
    destructor Destroy; override;
    function Clone: TGPRegion;
    function MakeInfinite: TStatus;
    function MakeEmpty: TStatus;
    function GetDataSize: UINT;
    // buffer     - where to put the data
    // bufferSize - how big the buffer is (should be at least as big as GetDataSize())
    // sizeFilled - if not NULL, this is an OUT param that says how many bytes
    //              of data were written to the buffer.
    function GetData(buffer: PBYTE; bufferSize: UINT;
       sizeFilled: PUINT = nil): TStatus;
    function Intersect(const rect: TGPRect): TStatus; overload;
    function Intersect(const rect: TGPRectF): TStatus; overload;
    function Intersect(path: TGPGraphicsPath): TStatus; overload;
    function Intersect(region: TGPRegion): TStatus; overload;
    function Union(const rect: TGPRect): TStatus; overload;
    function Union(const rect: TGPRectF): TStatus; overload;
    function Union(path: TGPGraphicsPath): TStatus; overload;
    function Union(region: TGPRegion): TStatus; overload;
    function Xor_(const rect: TGPRect): TStatus; overload;
    function Xor_(const rect: TGPRectF): TStatus; overload;
    function Xor_(path: TGPGraphicsPath): TStatus; overload;
    function Xor_(region: TGPRegion): TStatus; overload;
    function Exclude(const rect: TGPRect): TStatus; overload;
    function Exclude(const rect: TGPRectF): TStatus; overload;
    function Exclude(path: TGPGraphicsPath): TStatus; overload;
    function Exclude(region: TGPRegion): TStatus; overload;
    function Complement(const rect: TGPRect): TStatus; overload;
    function Complement(const rect: TGPRectF): TStatus; overload;
    function Complement(path: TGPGraphicsPath): TStatus; overload;
    function Complement(region: TGPRegion): TStatus; overload;
    function Translate(const dx, dy: Single): TStatus; overload;
    function Translate(dx, dy: Integer): TStatus; overload;
    function Transform(matrix: TGPMatrix): TStatus;
    function GetBounds(out rect: TGPRect; g: TGPGraphics): TStatus; overload;
    function GetBounds(out rect: TGPRectF; g: TGPGraphics): TStatus; overload;
    function GetHRGN(g: TGPGraphics): HRGN;
    function IsEmpty(g: TGPGraphics): BOOL;
    function IsInfinite(g: TGPGraphics): BOOL ;
    function IsVisible(x, y: Integer; g: TGPGraphics = nil): BOOL; overload;
    function IsVisible(const point: TGPPoint; g: TGPGraphics = nil): BOOL; overload;
    function IsVisible(const x, y: Single; g: TGPGraphics = nil): BOOL; overload;
    function IsVisible(const point: TGPPointF; g: TGPGraphics = nil): BOOL; overload;
    function IsVisible(x, y, width, height: Integer; g: TGPGraphics): BOOL; overload;
    function IsVisible(const rect: TGPRect; g: TGPGraphics = nil): BOOL; overload;
    function IsVisible(const x, y, width, height: Single; g: TGPGraphics = nil): BOOL; overload;
    function IsVisible(const rect: TGPRectF; g: TGPGraphics = nil): BOOL; overload;
    function EqualsRegion(region: TGPRegion; g: TGPGraphics): BOOL;  // "Equals" name conflict in D2009 and up
    function GetRegionScansCount(matrix: TGPMatrix): UINT;
    function GetRegionScans(matrix: TGPMatrix ;rects: PGPRectF; out count: Integer): TStatus; overload;
    function GetRegionScans(matrix: TGPMatrix; rects: PGPRect; out count: Integer): TStatus; overload;
    function GetLastStatus: TStatus;
  end;

//--------------------------------------------------------------------------
// FontFamily
//--------------------------------------------------------------------------

  TGPFontFamily = class(TGdiplusBase)
  protected
    nativeFamily: GpFontFamily;
    lastResult: TStatus;
    function SetStatus(status: TStatus): TStatus;
    constructor Create(nativeOrig: GpFontFamily;
      status: TStatus); reintroduce; overload;
  public
    constructor Create; reintroduce; overload;
    constructor Create(name: WideString; fontCollection: TGPFontCollection = nil); reintroduce; overload;
    destructor Destroy; override;
    class function GenericSansSerif: TGPFontFamily;
    class function GenericSerif: TGPFontFamily;
    class function GenericMonospace: TGPFontFamily;
    function GetFamilyName(out name: String; language: LANGID = 0): TStatus;
    function Clone: TGPFontFamily;
    function IsAvailable: BOOL;
    function IsStyleAvailable(style: Integer): BOOL;
    function GetEmHeight(style: Integer): UINT16;
    function GetCellAscent(style: Integer): UINT16;
    function GetCellDescent(style: Integer): UINT16;
    function GetLineSpacing(style: Integer): UINT16;
    function GetLastStatus: TStatus;
  end;

//--------------------------------------------------------------------------
// Font Collection
//--------------------------------------------------------------------------

  TGPFontCollection = class(TGdiplusBase)
  protected
    nativeFontCollection: GpFontCollection;
    lastResult: TStatus;
    function SetStatus(status: TStatus): TStatus;
  public
    constructor Create;
    destructor Destroy; override;
    function GetFamilyCount: Integer;
    function GetFamilies(numSought: Integer; out gpfamilies: array of TGPFontFamily;
      out numFound: Integer): TStatus;
    function GetLastStatus: TStatus;
  end;

  TGPInstalledFontCollection = class(TGPFontCollection)
  public
    constructor Create; reintroduce;
    destructor Destroy; override;
  end;

  TGPPrivateFontCollection = class(TGPFontCollection)
  public
    constructor Create; reintroduce;
    destructor Destroy; override;
    function AddFontFile(filename: WideString): TStatus;
    function AddMemoryFont(memory: Pointer; length: Integer): TStatus;
  end;

//--------------------------------------------------------------------------
// TFont
//--------------------------------------------------------------------------

  TGPFont = class(TGdiplusBase)
  protected
    nativeFont: GpFont;
    lastResult: TStatus;
    procedure SetNativeFont(Font: GpFont);
    function SetStatus(status: TStatus): TStatus;
    constructor Create(font: GpFont; status: TStatus); overload;
  public
    constructor Create(hdc: HDC); reintroduce; overload;
    constructor Create(hdc: HDC; logfont: PLogFontA); reintroduce; overload;
    constructor Create(hdc: HDC; logfont: PLogFontW); reintroduce; overload;
    constructor Create(hdc: HDC; hfont: HFONT); reintroduce; overload;
    constructor Create(family: TGPFontFamily; const emSize: Single;
      style: TFontStyle = FontStyleRegular;
      unit_: TUnit = UnitPoint); reintroduce; overload;
    constructor Create(familyName: WideString; const emSize: Single;
      style: TFontStyle = FontStyleRegular; unit_: TUnit = UnitPoint;
      fontCollection: TGPFontCollection = nil); reintroduce; overload;
    function GetLogFontA(g: TGPGraphics; out logfontA: TLogFontA): TStatus;
    function GetLogFontW(g: TGPGraphics; out logfontW: TLogFontW): TStatus;
    function Clone: TGPFont;
    destructor Destroy; override;
    function IsAvailable: BOOL;
    function GetStyle: Integer;
    function GetSize: Single;
    function GetUnit: TUnit;
    function GetLastStatus: TStatus;
    function GetHeight(graphics: TGPGraphics): Single; overload;
    function GetHeight(const dpi: Single): Single; overload;
    function GetFamily(family: TGPFontFamily): TStatus;
  end;

//--------------------------------------------------------------------------
// Abstract base class for Image and Metafile
//--------------------------------------------------------------------------

  TGPImage = class(TGdiplusBase)
  protected
    nativeImage: GpImage;
    lastResult: TStatus;
    loadStatus: TStatus;
    procedure SetNativeImage(nativeImage: GpImage);
    function SetStatus(status: TStatus): TStatus;
    constructor Create(nativeImage: GpImage; status: TStatus); reintroduce; overload;
  public
    constructor Create(filename: WideString; useEmbeddedColorManagement: BOOL = FALSE); reintroduce; overload;
    constructor Create(stream: IStream; useEmbeddedColorManagement: BOOL  = FALSE); reintroduce; overload;
    function FromFile(filename: WideString; useEmbeddedColorManagement: BOOL = FALSE): TGPImage;
    function FromStream(stream: IStream; useEmbeddedColorManagement: BOOL = FALSE): TGPImage;
    destructor Destroy; override;
    function Clone: TGPImage;
    function Save(filename: WideString; const clsidEncoder: TGUID;
      encoderParams: PEncoderParameters = nil): TStatus; overload;
    function Save(stream: IStream; const clsidEncoder: TGUID;
      encoderParams: PEncoderParameters  = nil): TStatus; overload;
    function SaveAdd(encoderParams: PEncoderParameters): TStatus; overload;
    function SaveAdd(newImage: TGPImage; encoderParams: PEncoderParameters): TStatus; overload;
    function GetType: TImageType;
    function GetPhysicalDimension(out size: TGPSizeF): TStatus;
    function GetBounds(out srcRect: TGPRectF; out srcUnit: TUnit): TStatus;
    function GetWidth: UINT;
    function GetHeight: UINT;
    function GetHorizontalResolution: Single;
    function GetVerticalResolution: Single;
    function GetFlags: UINT;
    function GetRawFormat(out format: TGUID): TStatus;
    function GetPixelFormat: TPixelFormat;
    function GetPaletteSize: Integer;
    function GetPalette(palette: PColorPalette; size: Integer): TStatus;
    function SetPalette(palette: PColorPalette): TStatus;
    function GetThumbnailImage(thumbWidth, thumbHeight: UINT;
      callback: GetThumbnailImageAbort = nil; callbackData: pointer = nil): TGPImage;
    function GetFrameDimensionsCount: UINT;
    function GetFrameDimensionsList(dimensionIDs: PGUID; count: UINT): TStatus;
    function GetFrameCount(const dimensionID: TGUID): UINT;
    function SelectActiveFrame(const dimensionID: TGUID; frameIndex: UINT): TStatus;
    function RotateFlip(rotateFlipType: TRotateFlipType): TStatus;
    function GetPropertyCount: UINT;
    function GetPropertyIdList(numOfProperty: UINT; list: PPropID): TStatus;
    function GetPropertyItemSize(propId: PROPID): UINT;
    function GetPropertyItem(propId: PROPID; propSize: UINT; buffer: PPropertyItem): TStatus;
    function GetPropertySize(out totalBufferSize, numProperties : UINT): TStatus;
    function GetAllPropertyItems(totalBufferSize, numProperties: UINT;
      allItems: PPROPERTYITEM): TStatus;
    function RemovePropertyItem(propId: TPROPID): TStatus;
    function SetPropertyItem(const item: TPropertyItem): TStatus;
    function GetEncoderParameterListSize(const clsidEncoder: TGUID): UINT;
    function GetEncoderParameterList(const clsidEncoder: TGUID; size: UINT;
      buffer: PEncoderParameters): TStatus;
    function GetLastStatus: TStatus;
  end;

  TGPBitmap = class(TGPImage)
  protected
    constructor Create(nativeBitmap: GpBitmap);  reintroduce; overload;
  public
    constructor Create(filename: WideString; useEmbeddedColorManagement: BOOL = FALSE); reintroduce; overload;
    constructor Create(stream: IStream; useEmbeddedColorManagement: BOOL = FALSE); reintroduce; overload;
    function FromFile(filename: WideString; useEmbeddedColorManagement: BOOL = FALSE): TGPBitmap;
    function FromStream(stream: IStream; useEmbeddedColorManagement: BOOL = FALSE): TGPBitmap;
    constructor Create(width, height, stride: Integer; format: TPixelFormat; scan0: PBYTE); reintroduce; overload;
    constructor Create(width, height: Integer; format: TPixelFormat = PixelFormat32bppARGB); reintroduce; overload;
    constructor Create(width, height: Integer; target: TGPGraphics); reintroduce; overload;
    function Clone(const rect: TGPRect; format: TPixelFormat): TGPBitmap; overload;
    function Clone(x, y, width, height: Integer; format: TPixelFormat): TGPBitmap; overload;
    function Clone(const rect: TGPRectF; format: TPixelFormat): TGPBitmap; overload;
    function Clone(const x, y, width, height: Single; format: TPixelFormat): TGPBitmap; overload;
    function LockBits(const rect: TGPRect; flags: UINT; format: TPixelFormat; out lockedBitmapData: TBitmapData): TStatus;
    function UnlockBits(var lockedBitmapData: TBitmapData): TStatus;
    function GetPixel(x, y: Integer; out color: TGPColor): TStatus;
    function SetPixel(x, y: Integer; color: TGPColor): TStatus;
    function SetResolution(const xdpi, ydpi: Single): TStatus;
//    constructor Create(surface: IDirectDrawSurface7); reintroduce; overload;
    constructor Create(var gdiBitmapInfo: TBITMAPINFO; gdiBitmapData: Pointer); reintroduce; overload;
    constructor Create(hbm: HBITMAP; hpal: HPALETTE); reintroduce; overload;
    constructor Create(hicon: HICON); reintroduce; overload;
    constructor Create(hInstance: HMODULE; bitmapName: WideString); reintroduce; overload;
//    function FromDirectDrawSurface7(surface: IDirectDrawSurface7): TGPBitmap;
    function FromBITMAPINFO(var gdiBitmapInfo: TBITMAPINFO; gdiBitmapData: Pointer): TGPBitmap;
    function FromHBITMAP(hbm: HBITMAP; hpal: HPALETTE): TGPBitmap;
    function FromHICON(hicon: HICON): TGPBitmap;
    function FromResource(hInstance: HMODULE; bitmapName: WideString): TGPBitmap;
    function GetHBITMAP(colorBackground: TGPColor; out hbmReturn: HBITMAP): TStatus;
    function GetHICON(out hicon: HICON): TStatus;
  end;

  TGPCustomLineCap = class(TGdiplusBase)
  protected
    nativeCap: GpCustomLineCap;
    lastResult: TStatus;
    procedure SetNativeCap(nativeCap: GpCustomLineCap);
    function SetStatus(status: TStatus): TStatus;
    constructor Create(nativeCap: GpCustomLineCap;
      status: TStatus); reintroduce; overload;
  public
    constructor Create; reintroduce; overload;
    constructor Create(fillPath, strokePath: TGPGraphicsPath;
      baseCap: TLineCap = LineCapFlat;
      const baseInset: Single = 0); reintroduce; overload;
    destructor Destroy; override;
    function Clone: TGPCustomLineCap;
    function SetStrokeCap(strokeCap: TLineCap): TStatus;
    function SetStrokeCaps(startCap, endCap: TLineCap): TStatus;
    function GetStrokeCaps(out startCap, endCap: TLineCap): TStatus;
    function SetStrokeJoin(lineJoin: TLineJoin): TStatus;
    function GetStrokeJoin: TLineJoin;
    function SetBaseCap(baseCap: TLineCap): TStatus;
    function GetBaseCap: TLineCap;
    function SetBaseInset(const inset: Single): TStatus;
    function GetBaseInset: Single;
    function SetWidthScale(const widthScale: Single): TStatus;
    function GetWidthScale: Single;                                
    function GetLastStatus: TStatus;
  end;

  TGPCachedBitmap = class(TGdiplusBase)
  protected
    nativeCachedBitmap: GpCachedBitmap;
    lastResult: TStatus;
  public
    constructor Create(bitmap: TGPBitmap; graphics: TGPGraphics); reintroduce;
    destructor Destroy; override;
    function GetLastStatus: TStatus;
  end;

(**************************************************************************\
*
*   GDI+ Image Attributes used with Graphics.DrawImage
*
* There are 5 possible sets of color adjustments:
*          ColorAdjustDefault,
*          ColorAdjustBitmap,
*          ColorAdjustBrush,
*          ColorAdjustPen,
*          ColorAdjustText,
*
* Bitmaps, Brushes, Pens, and Text will all use any color adjustments
* that have been set into the default ImageAttributes until their own
* color adjustments have been set.  So as soon as any "Set" method is
* called for Bitmaps, Brushes, Pens, or Text, then they start from
* scratch with only the color adjustments that have been set for them.
* Calling Reset removes any individual color adjustments for a type
* and makes it revert back to using all the default color adjustments
* (if any).  The SetToIdentity method is a way to force a type to
* have no color adjustments at all, regardless of what previous adjustments
* have been set for the defaults or for that type.
*
\********************************************************************F******)

  TGPImageAttributes = class(TGdiplusBase)
  protected
    nativeImageAttr: GpImageAttributes;
    lastResult: TStatus;
    procedure SetNativeImageAttr(nativeImageAttr: GpImageAttributes);
    function SetStatus(status: TStatus): TStatus;
    constructor Create(imageAttr: GpImageAttributes;
      status: GpStatus); reintroduce; overload;
  public
    constructor Create; reintroduce; overload;
    destructor Destroy; override;
    function Clone: TGPImageAttributes;
    function SetToIdentity(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function Reset(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetColorMatrix(const colorMatrix: TColorMatrix;
      mode: TColorMatrixFlags = ColorMatrixFlagsDefault;
      type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function ClearColorMatrix(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetColorMatrices(const colorMatrix: TColorMatrix; const grayMatrix: TColorMatrix;
      mode: TColorMatrixFlags  = ColorMatrixFlagsDefault;
      type_: TColorAdjustType  = ColorAdjustTypeDefault): TStatus;
    function ClearColorMatrices(Type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetThreshold(const threshold: Single; type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function ClearThreshold(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetGamma(const gamma: Single; type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function ClearGamma( type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetNoOp(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function ClearNoOp(Type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetColorKey(colorLow, colorHigh: TGPColor; type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function ClearColorKey(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetOutputChannel(channelFlags: TColorChannelFlags; type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function ClearOutputChannel(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetOutputChannelColorProfile(colorProfileFilename: WideString;
      type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function ClearOutputChannelColorProfile(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetRemapTable(mapSize: Cardinal; map: PColorMap; type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function ClearRemapTable(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
    function SetBrushRemapTable(mapSize: Cardinal; map: PColorMap): TStatus;
    function ClearBrushRemapTable: TStatus;
    function SetWrapMode(wrap: TWrapMode; color: TGPColor = aclBlack; clamp: BOOL = FALSE): TStatus;
    // The flags of the palette are ignored.
    function GetAdjustedPalette(colorPalette: PColorPalette; colorAdjustType: TColorAdjustType): TStatus;
    function GetLastStatus: TStatus;
  end;

(**************************************************************************\
*
*   GDI+ Matrix class
*
\**************************************************************************)

  TMatrixArray = array[0..5] of Single;

  TGPMatrix = class(TGdiplusBase)
  protected
    nativeMatrix: GpMatrix;
    lastResult: GpStatus ;
    procedure SetNativeMatrix(nativeMatrix: GpMatrix);
    function SetStatus(status: GpStatus): TStatus;
    constructor Create(nativeMatrix: GpMatrix); reintroduce; overload;
  public
    // Default constructor is set to identity matrix.
    constructor Create; reintroduce; overload;
    constructor Create(const m11, m12, m21, m22, dx, dy: Single); reintroduce; overload;
    constructor Create(const rect: TGPRectF; const dstplg: TGPPointF); reintroduce; overload;
    constructor Create(const rect: TGPRect; const dstplg: TGPPoint); reintroduce; overload;
    destructor Destroy; override;
    function Clone: TGPMatrix;
    function GetElements(const m: TMatrixArray): TStatus;
    function SetElements(const m11, m12, m21, m22, dx, dy: Single): TStatus;
    function OffsetX: Single;
    function OffsetY: Single;
    function Reset: TStatus;
    function Multiply(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;                // ok
    function Translate(const offsetX, offsetY: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;      // ok
    function Scale(const scaleX, scaleY: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;            // ok
    function Rotate(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;                    // ok
    function RotateAt(const angle: Single; const center: TGPPointF; order: TMatrixOrder = MatrixOrderPrepend): TStatus; // ok
    function Shear(const shearX, shearY: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;            // ok
    function Invert: TStatus;                                                                             // ok

    function TransformPoints(pts: PGPPointF; count: Integer = 1): TStatus; overload;
    function TransformPoints(pts: PGPPoint; count: Integer = 1): TStatus; overload;

    function TransformVectors(pts: PGPPointF; count: Integer = 1): TStatus; overload;
    function TransformVectors(pts: PGPPoint; count: Integer = 1): TStatus; overload;

    function IsInvertible: BOOL;
    function IsIdentity: BOOL;
    function EqualsMatrix(matrix: TGPMatrix): BOOL;   // "Equals" name conflict in D2009 and up
    function GetLastStatus: TStatus;
  end;

(**************************************************************************\
*
*   GDI+ Brush class
*
\**************************************************************************)

  //--------------------------------------------------------------------------
  // Abstract base class for various brush types
  //--------------------------------------------------------------------------

  TGPBrush = class(TGdiplusBase)
  protected
    nativeBrush: GpBrush;
    lastResult: TStatus;
    procedure SetNativeBrush(nativeBrush: GpBrush);
    function SetStatus(status: TStatus): TStatus;
    constructor Create(nativeBrush: GpBrush; status: TStatus); overload;
  public
    constructor Create; overload;
    destructor Destroy; override;
    function Clone: TGPBrush; virtual;
    function GetType: TBrushType;
    function GetLastStatus: TStatus;
  end;

  //--------------------------------------------------------------------------
  // Solid Fill Brush Object
  //--------------------------------------------------------------------------

  TGPSolidBrush = class(TGPBrush)
  public
    constructor Create(color: TGPColor); reintroduce; overload;
    constructor Create; reintroduce; overload;
    function GetColor(out color: TGPColor): TStatus;
    function SetColor(color: TGPColor): TStatus;
  end;

  //--------------------------------------------------------------------------
  // Texture Brush Fill Object
  //--------------------------------------------------------------------------

  TGPTextureBrush = class(TGPBrush)
  public
    constructor Create(image: TGPImage; wrapMode: TWrapMode = WrapModeTile); reintroduce; overload;
    constructor Create(image: TGPImage; wrapMode: TWrapMode; const dstRect: TGPRectF); reintroduce; overload;
    constructor Create(image: TGPImage; const dstRect: TGPRectF; imageAttributes: TGPImageAttributes = nil); reintroduce; overload;
    constructor Create(image: TGPImage; const dstRect: TGPRect; imageAttributes: TGPImageAttributes = nil); reintroduce; overload;
    constructor Create(image: TGPImage; wrapMode: TWrapMode; const dstRect: TGPRect); reintroduce; overload;
    constructor Create(image: TGPImage; wrapMode: TWrapMode; const dstX, dstY, dstWidth,
      dstHeight: Single); reintroduce; overload;
    constructor Create(image: TGPImage; wrapMode: TWrapMode; dstX, dstY, dstWidth,
      dstHeight: Integer); reintroduce; overload;
    constructor Create; reintroduce; overload;
    function SetTransform(matrix: TGPMatrix): TStatus;
    function GetTransform(matrix: TGPMatrix): TStatus;
    function ResetTransform: TStatus;
    function MultiplyTransform(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function TranslateTransform(const dx, dy: Single; order: MatrixOrder = MatrixOrderPrepend): TStatus;
    function ScaleTransform(const sx, sy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function RotateTransform(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function SetWrapMode(wrapMode: TWrapMode): TStatus;
    function GetWrapMode: TWrapMode;
    function GetImage: TGPImage;
  end;

  //--------------------------------------------------------------------------
  // Linear Gradient Brush Object
  //--------------------------------------------------------------------------

  TGPLinearGradientBrush = class(TGPBrush)
  public
    constructor Create; reintroduce; overload;
    constructor Create(const point1, point2: TGPPointF; color1,
      color2: TGPColor); reintroduce; overload;
    constructor Create(const point1, point2: TGPPoint; color1,
      color2: TGPColor); reintroduce; overload;
    constructor Create(const rect: TGPRectF; color1, color2: TGPColor;
      mode: TLinearGradientMode); reintroduce; overload;
    constructor Create(const rect: TGPRect; color1, color2: TGPColor;
      mode: TLinearGradientMode); reintroduce; overload;
    constructor Create(const rect: TGPRectF; color1, color2: TGPColor; const angle: Single;
      isAngleScalable: BOOL = FALSE); overload;
    constructor Create(const rect: TGPRect; color1, color2: TGPColor; const angle: Single;
      isAngleScalable: BOOL = FALSE); overload;
    function SetLinearColors(color1, color2: TGPColor): TStatus;
    function GetLinearColors(out color1, color2: TGPColor): TStatus;
    function GetRectangle(out rect: TGPRectF): TStatus; overload;
    function GetRectangle(out rect: TGPRect): TStatus; overload;
    function SetGammaCorrection(useGammaCorrection: BOOL): TStatus;
    function GetGammaCorrection: BOOL;
    function GetBlendCount: Integer;
    function SetBlend(blendFactors, blendPositions: PSingle; count: Integer): TStatus;
    function GetBlend(blendFactors, blendPositions: PSingle; count: Integer): TStatus;
    function GetInterpolationColorCount: Integer;
    function SetInterpolationColors(presetColors: PGPColor; blendPositions: PSingle; count: Integer): TStatus;
    function GetInterpolationColors(presetColors: PGPColor; blendPositions: PSingle; count: Integer): TStatus;
    function SetBlendBellShape(const focus: Single; const scale: Single = 1.0): TStatus;
    function SetBlendTriangularShape(const focus: Single; const scale: Single = 1.0): TStatus;
    function SetTransform(matrix: TGPMatrix): TStatus;
    function GetTransform(matrix: TGPMatrix): TStatus;
    function ResetTransform: TStatus;
    function MultiplyTransform(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function TranslateTransform(const dx, dy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function ScaleTransform(const sx, sy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function RotateTransform(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function SetWrapMode(wrapMode: TWrapMode): TStatus;
    function GetWrapMode: TWrapMode;
  end;

  //--------------------------------------------------------------------------
  // Hatch Brush Object
  //--------------------------------------------------------------------------

  TGPHatchBrush = class(TGPBrush)
  public
    constructor Create; reintroduce; overload;
    constructor Create(hatchStyle: THatchStyle; foreColor: TGPColor; backColor: TGPColor = aclBlack); reintroduce; overload; // ok
    function GetHatchStyle: THatchStyle;
    function GetForegroundColor(out color: TGPColor): TStatus;
    function GetBackgroundColor(out color: TGPColor): TStatus;
  end;

(**************************************************************************\
*
*   GDI+ Pen class
*
\**************************************************************************)

//--------------------------------------------------------------------------
// Pen class 
//--------------------------------------------------------------------------

  TGPPen = class(TGdiplusBase)
  protected
    nativePen: GpPen;
    lastResult: TStatus;
    procedure SetNativePen(nativePen: GpPen);
    function SetStatus(status: TStatus): TStatus;
    constructor Create(nativePen: GpPen; status: TStatus); reintroduce; overload;
  public
    constructor Create(color: TGPColor; const width: Single = 1.0); reintroduce; overload;
    constructor Create(brush: TGPBrush; const width: Single = 1.0); reintroduce; overload;
    destructor Destroy; override;
    function Clone: TGPPen;
    function SetWidth(const width: Single): TStatus;
    function GetWidth: Single;
    // Set/get line caps: start, end, and dash
    // Line cap and join APIs by using LineCap and LineJoin enums.
    function SetLineCap(startCap, endCap: TLineCap; dashCap: TDashCap): TStatus;
    function SetStartCap(startCap: TLineCap): TStatus;
    function SetEndCap(endCap: TLineCap): TStatus;
    function SetDashCap(dashCap: TDashCap): TStatus;
    function GetStartCap: TLineCap;
    function GetEndCap: TLineCap;
    function GetDashCap: TDashCap;
    function SetLineJoin(lineJoin: TLineJoin): TStatus;
    function GetLineJoin: TLineJoin;
    function SetCustomStartCap(customCap: TGPCustomLineCap): TStatus;
    function GetCustomStartCap(customCap: TGPCustomLineCap): TStatus;
    function SetCustomEndCap(customCap: TGPCustomLineCap): TStatus;
    function GetCustomEndCap(customCap: TGPCustomLineCap): TStatus;
    function SetMiterLimit(const miterLimit: Single): TStatus;
    function GetMiterLimit: Single;
    function SetAlignment(penAlignment: TPenAlignment): TStatus;
    function GetAlignment: TPenAlignment;
    function SetWidthUnit(Value:TUnit):TStatus; //DB
    function GetWidthUnit:TUnit; //DB
    function SetTransform(matrix: TGPMatrix): TStatus;
    function GetTransform(matrix: TGPMatrix): TStatus;
    function ResetTransform: TStatus;
    function MultiplyTransform(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function TranslateTransform(const dx, dy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function ScaleTransform(const sx, sy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function RotateTransform(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function GetPenType: TPenType;
    function SetColor(color: TGPColor): TStatus;
    function SetBrush(brush: TGPBrush): TStatus;
    function GetColor(out Color: TGPColor): TStatus;
    function GetBrush: TGPBrush;
    function GetDashStyle: TDashStyle;
    function SetDashStyle(dashStyle: TDashStyle): TStatus;
    function GetDashOffset: Single;
    function SetDashOffset(const dashOffset: Single): TStatus;
    function SetDashPattern(dashArray: PSingle; count: Integer): TStatus;
    function GetDashPatternCount: Integer;
    function GetDashPattern(dashArray: PSingle; count: Integer): TStatus;
    function SetCompoundArray(compoundArray: PSingle; count: Integer): TStatus;
    function GetCompoundArrayCount: Integer;
    function GetCompoundArray(compoundArray: PSingle; count: Integer): TStatus;
    function GetLastStatus: TStatus;
  end;

(**************************************************************************\
*
*   GDI+ StringFormat class
*
\**************************************************************************)

  TGPStringFormat = class(TGdiplusBase)
  protected
    nativeFormat: GpStringFormat;
    lastError: TStatus;
    function SetStatus(newStatus: GpStatus): TStatus;
    procedure Assign(source: TGPStringFormat);
    constructor Create(clonedStringFormat: GpStringFormat; status: TStatus); reintroduce; overload;
  public
    constructor Create(formatFlags: Integer = 0; language: LANGID = LANG_NEUTRAL); reintroduce; overload;
    constructor Create(format: TGPStringFormat); reintroduce; overload;
    destructor Destroy; override;
    class function GenericDefault: TGPStringFormat;
    class function GenericTypographic: TGPStringFormat;
    function Clone: TGPStringFormat;
    function SetFormatFlags(flags: Integer): TStatus;
    function GetFormatFlags: Integer;
    function SetAlignment(align: TStringAlignment): TStatus;
    function GetAlignment: TStringAlignment;
    function SetLineAlignment(align: TStringAlignment): TStatus;
    function GetLineAlignment: TStringAlignment;
    function SetHotkeyPrefix(hotkeyPrefix: THotkeyPrefix): TStatus;
    function GetHotkeyPrefix: THotkeyPrefix;
    function SetTabStops(const firstTabOffset: Single; count: Integer; tabStops: PSingle): TStatus;
    function GetTabStopCount: Integer;
    function GetTabStops(count: Integer; firstTabOffset, tabStops: PSingle): TStatus;
    function SetDigitSubstitution(language: LANGID; substitute: TStringDigitSubstitute): TStatus;
    function GetDigitSubstitutionLanguage: LANGID;
    function GetDigitSubstitutionMethod: TStringDigitSubstitute;
    function SetTrimming(trimming: TStringTrimming): TStatus;
    function GetTrimming: TStringTrimming;
    function SetMeasurableCharacterRanges(rangeCount: Integer; ranges: PCharacterRange): TStatus;
    function GetMeasurableCharacterRangeCount: Integer;
    function GetLastStatus: TStatus;
  end;

(**************************************************************************\
*
*   GDI+ Graphics Path class
*
\**************************************************************************)

  TGPGraphicsPath = class(TGdiplusBase)
  protected
    nativePath: GpPath;
    lastResult: TStatus;
    procedure SetNativePath(nativePath: GpPath);
    function SetStatus(const status: TStatus): TStatus;
    constructor Create(nativePath: GpPath); reintroduce; overload;
  public
    constructor Create(path: TGPGraphicsPath); reintroduce; overload;
    constructor Create(fillMode: TFillMode = FillModeAlternate); reintroduce; overload;      
    constructor Create(points: PGPPointF; types: PBYTE; count: Integer;
      fillMode: TFillMode = FillModeAlternate); reintroduce; overload;
    constructor Create(points: PGPPoint; types: PBYTE; count: Integer;
      fillMode: TFillMode = FillModeAlternate); reintroduce; overload;
    destructor Destroy; override;
    function Clone: TGPGraphicsPath;
    // Reset the path object to empty (and fill mode to FillModeAlternate)
    function Reset: TStatus;
    function GetFillMode: TFillMode;
    function SetFillMode(fillmode: TFillMode): TStatus;
    function GetPathData(pathData: TPathData): TStatus;
    function StartFigure: TStatus;
    function CloseFigure: TStatus;
    function CloseAllFigures: TStatus;
    function SetMarker: TStatus;
    function ClearMarkers: TStatus;
    function Reverse: TStatus;
    function GetLastPoint(out lastPoint: TGPPointF): TStatus;

    function AddLine(const pt1, pt2: TGPPointF): TStatus; overload;
    function AddLine(const x1, y1, x2, y2: Single): TStatus; overload;
    function AddLines(points: PGPPointF; count: Integer): TStatus; overload;
    function AddLine(const pt1, pt2: TGPPoint): TStatus; overload;
    function AddLine(x1, y1, x2, y2: Integer): TStatus; overload;
    function AddLines(points: PGPPoint; count: Integer): TStatus; overload;

    function AddArc(const rect: TGPRectF; const startAngle, sweepAngle: Single): TStatus; overload;
    function AddArc(const x, y, width, height, startAngle, sweepAngle: Single): TStatus; overload;
    function AddArc(const rect: TGPRect; const startAngle, sweepAngle: Single): TStatus; overload;
    function AddArc(x, y, width, height: Integer; const startAngle, sweepAngle: Single): TStatus; overload;

    function AddBezier(const pt1, pt2, pt3, pt4: TGPPointF): TStatus; overload;
    function AddBezier(const x1, y1, x2, y2, x3, y3, x4, y4: Single): TStatus; overload;
    function AddBeziers(points: PGPPointF; count: Integer): TStatus; overload;
    function AddBezier(const pt1, pt2, pt3, pt4: TGPPoint): TStatus; overload;
    function AddBezier(x1, y1, x2, y2, x3, y3, x4, y4: Integer): TStatus; overload;
    function AddBeziers(points: PGPPoint; count: Integer): TStatus; overload;

    function AddCurve(points: PGPPointF; count: Integer): TStatus; overload;
    function AddCurve(points: PGPPointF; count: Integer; const tension: Single): TStatus; overload;
    function AddCurve(points: PGPPointF; count, offset, numberOfSegments: Integer; const tension: Single): TStatus; overload;
    function AddCurve(points: PGPPoint; count: Integer): TStatus; overload;
    function AddCurve(points: PGPPoint; count: Integer; const tension: Single): TStatus; overload;
    function AddCurve(points: PGPPoint; count, offset, numberOfSegments: Integer; const tension: Single): TStatus; overload;

    function AddClosedCurve(points: PGPPointF; count: Integer): TStatus; overload;
    function AddClosedCurve(points: PGPPointF; count: Integer; const tension: Single): TStatus; overload;
    function AddClosedCurve(points: PGPPoint; count: Integer): TStatus; overload;
    function AddClosedCurve(points: PGPPoint; count: Integer; const tension: Single): TStatus; overload;

    function AddRectangle(const rect: TGPRectF): TStatus; overload;
    function AddRectangles(rects: PGPRectF; count: Integer): TStatus; overload;
    function AddRectangle(const rect: TGPRect): TStatus; overload;
    function AddRectangles(rects: PGPRect; count: Integer): TStatus; overload;

    function AddEllipse(const rect: TGPRectF): TStatus; overload;
    function AddEllipse(const x, y, width, height: Single): TStatus; overload;
    function AddEllipse(const rect: TGPRect): TStatus; overload;
    function AddEllipse(x, y, width, height: Integer): TStatus; overload;

    function AddPie(const rect: TGPRectF; const startAngle, sweepAngle: Single): TStatus; overload;
    function AddPie(const x, y, width, height, startAngle, sweepAngle: Single): TStatus; overload;
    function AddPie(const rect: TGPRect; const startAngle, sweepAngle: Single): TStatus; overload;
    function AddPie(const x, y, width, height: Integer; const startAngle, sweepAngle: Single): TStatus; overload;

    function AddPolygon(points: PGPPointF; count: Integer): TStatus; overload;
    function AddPolygon(points: PGPPoint; count: Integer): TStatus; overload;

    function AddPath(addingPath: TGPGraphicsPath; connect: Bool): TStatus;

    function AddString(string_: WideString; length: Integer; family : TGPFontFamily;
      style  : Integer; const emSize : Single; const origin : TGPPointF; format : TGPStringFormat): TStatus; overload;
    function AddString(string_: WideString; length : Integer; family : TGPFontFamily;
      style  : Integer; const emSize : Single; const layoutRect: TGPRectF; format : TGPStringFormat): TStatus; overload;
    function AddString(string_: WideString; length : Integer; family : TGPFontFamily;
      style  : Integer; const emSize : Single; const origin : TGPPoint; format : TGPStringFormat): TStatus; overload;
    function AddString(string_: WideString; length : Integer; family : TGPFontFamily;
      style  : Integer; const emSize : Single; const layoutRect: TGPRect; format : TGPStringFormat): TStatus; overload;

    function Transform(matrix: TGPMatrix): TStatus;

    // This is not always the tightest bounds.
    function GetBounds(out bounds: TGPRectF; matrix: TGPMatrix = nil; pen: TGPPen = nil): TStatus; overload;
    function GetBounds(out bounds: TGPRect; matrix: TGPMatrix = nil; pen: TGPPen = nil): TStatus;  overload;
    // Once flattened, the resultant path is made of line segments and
    // the original path information is lost.  When matrix is NULL the
    // identity matrix is assumed.
    function Flatten(matrix: TGPMatrix = nil; const flatness: Single = FlatnessDefault): TStatus;
    function Widen(pen: TGPPen; matrix: TGPMatrix = nil; const flatness: Single = FlatnessDefault): TStatus;
    function Outline(matrix: TGPMatrix = nil; const flatness: Single = FlatnessDefault): TStatus;
    // Once this is called, the resultant path is made of line segments and
    // the original path information is lost.  When matrix is NULL, the
    // identity matrix is assumed.
    function Warp(destPoints: PGPPointF; count: Integer; const srcRect: TGPRectF;
      matrix: TGPMatrix = nil; warpMode: TWarpMode = WarpModePerspective;
      const flatness: Single = FlatnessDefault): TStatus;
    function GetPointCount: Integer;
    function GetPathTypes(types: PBYTE; count: Integer): TStatus;
    function GetPathPoints(points: PGPPointF; count: Integer): TStatus; overload;
    function GetPathPoints(points: PGPPoint; count: Integer): TStatus; overload;
    function GetLastStatus: TStatus;

    function IsVisible(const point: TGPPointF; g: TGPGraphics = nil): BOOL; overload;
    function IsVisible(const x, y: Single; g: TGPGraphics = nil): BOOL; overload;
    function IsVisible(const point: TGPPoint; g : TGPGraphics = nil): BOOL; overload;
    function IsVisible(x, y: Integer; g: TGPGraphics = nil): BOOL; overload;

    function IsOutlineVisible(const point: TGPPointF; pen: TGPPen; g: TGPGraphics = nil): BOOL; overload;
    function IsOutlineVisible(const x, y: Single; pen: TGPPen; g: TGPGraphics = nil): BOOL; overload;
    function IsOutlineVisible(const point: TGPPoint; pen: TGPPen; g: TGPGraphics = nil): BOOL; overload;
    function IsOutlineVisible(x, y: Integer; pen: TGPPen; g: TGPGraphics = nil): BOOL; overload;
  end;

//--------------------------------------------------------------------------
// GraphisPathIterator class
//--------------------------------------------------------------------------

  TGPGraphicsPathIterator = class(TGdiplusBase)
  protected
    nativeIterator: GpPathIterator;
    lastResult    : TStatus;
    procedure SetNativeIterator(nativeIterator: GpPathIterator);
    function SetStatus(status: TStatus): TStatus;
  public
    constructor Create(path: TGPGraphicsPath); reintroduce;
    destructor Destroy; override;
    function NextSubpath(out startIndex, endIndex: Integer; out isClosed: bool): Integer; overload;
    function NextSubpath(path: TGPGraphicsPath; out isClosed: BOOL): Integer; overload;
    function NextPathType(out pathType: TPathPointType; out startIndex, endIndex: Integer): Integer;
    function NextMarker(out startIndex, endIndex: Integer): Integer; overload;
    function NextMarker(path: TGPGraphicsPath): Integer; overload;
    function GetCount: Integer;
    function GetSubpathCount: Integer;
    function HasCurve: BOOL;
    procedure Rewind;
    function Enumerate(points: PGPPointF; types: PBYTE; count: Integer): Integer;
    function CopyData(points: PGPPointF; types: PBYTE; startIndex, endIndex: Integer): Integer;
    function GetLastStatus: TStatus;
  end;

//--------------------------------------------------------------------------
// Path Gradient Brush
//--------------------------------------------------------------------------

  TGPPathGradientBrush = class(TGPBrush)
  public
    constructor Create(points: PGPPointF; count: Integer;
      wrapMode: TWrapMode = WrapModeClamp); reintroduce; overload;
    constructor Create(points: PGPPoint; count: Integer;
      wrapMode: TWrapMode = WrapModeClamp); reintroduce; overload;
    constructor Create(path: TGPGraphicsPath); reintroduce; overload;
    constructor Create; reintroduce; overload;
    function GetCenterColor(out Color: TGPColor): TStatus;
    function SetCenterColor(color: TGPColor): TStatus;
    function GetPointCount: Integer;
    function GetSurroundColorCount: Integer;
    function GetSurroundColors(colors: PARGB; var count: Integer): TStatus;
    function SetSurroundColors(colors: PARGB; var count: Integer): TStatus;
    function GetGraphicsPath(path: TGPGraphicsPath): TStatus;
    function SetGraphicsPath(path: TGPGraphicsPath): TStatus;
    function GetCenterPoint(out point: TGPPointF): TStatus; overload;
    function GetCenterPoint(out point: TGPPoint): TStatus; overload;
    function SetCenterPoint(const point: TGPPointF): TStatus; overload;
    function SetCenterPoint(const point: TGPPoint): TStatus; overload;
    function GetRectangle(out rect: TGPRectF): TStatus; overload;
    function GetRectangle(out rect: TGPRect): TStatus; overload;
    function SetGammaCorrection(useGammaCorrection: BOOL): TStatus; overload;
    function GetGammaCorrection: BOOL; overload;
    function GetBlendCount: Integer;
    function GetBlend(blendFactors, blendPositions: PSingle; count: Integer): TStatus;
    function SetBlend(blendFactors, blendPositions: PSingle; count: Integer): TStatus;
    function GetInterpolationColorCount: Integer;
    function SetInterpolationColors(presetColors: PARGB; blendPositions: PSingle;
      count: Integer): TStatus;
    function GetInterpolationColors(presetColors: PARGB;
      blendPositions: PSingle; count: Integer): TStatus;
    function SetBlendBellShape(const focus: Single; const scale: Single = 1.0): TStatus;
    function SetBlendTriangularShape(const focus: Single; const scale: Single = 1.0): TStatus;
    function GetTransform(matrix: TGPMatrix): TStatus;
    function SetTransform(matrix: TGPMatrix): TStatus;
    function ResetTransform: TStatus;
    function MultiplyTransform(matrix: TGPMatrix;
      order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function TranslateTransform(const dx, dy: Single;
      order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function ScaleTransform(const sx, sy: Single;
      order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function RotateTransform(const angle: Single;
      order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function GetFocusScales(out xScale, yScale: Single): TStatus;
    function SetFocusScales(const xScale, yScale: Single): TStatus;
    function GetWrapMode: TWrapMode;
    function SetWrapMode(wrapMode: TWrapMode): TStatus;
  end;

(**************************************************************************\
*
*   GDI+ Graphics Object
*
\**************************************************************************)

  TGPGraphics = class(TGdiplusBase)
  protected
    nativeGraphics: GpGraphics;
    lastResult: TStatus;
    procedure SetNativeGraphics(graphics: GpGraphics);
    function SetStatus(status: TStatus): TStatus;
    function GetNativeGraphics: GpGraphics;
    function GetNativePen(pen: TGPPen): GpPen;
    constructor Create(graphics: GpGraphics); reintroduce; overload;
  public
    function FromHDC(hdc: HDC): TGPGraphics; overload;
    function FromHDC(hdc: HDC; hdevice: THANDLE): TGPGraphics; overload;
    function FromHWND(hwnd: HWND; icm: BOOL = FALSE): TGPGraphics;
    function FromImage(image: TGPImage): TGPGraphics;
    constructor Create(hdc: HDC); reintroduce; overload;
    constructor Create(hdc: HDC; hdevice: THANDLE); reintroduce; overload;
    constructor Create(hwnd: HWND; icm: BOOL{ = FALSE}); reintroduce; overload;
    constructor Create(image: TGPImage); reintroduce; overload;
    destructor Destroy; override;
    procedure Flush(intention: TFlushIntention = FlushIntentionFlush);
    //------------------------------------------------------------------------
    // GDI Interop methods
    //------------------------------------------------------------------------
    // Locks the graphics until ReleaseDC is called
    function GetHDC: HDC;
    procedure ReleaseHDC(hdc: HDC);
    //------------------------------------------------------------------------
    // Rendering modes
    //------------------------------------------------------------------------
    function SetRenderingOrigin(x, y: Integer): TStatus;
    function GetRenderingOrigin(out x, y: Integer): TStatus;
    function SetCompositingMode(compositingMode: TCompositingMode): TStatus;
    function GetCompositingMode: TCompositingMode;
    function SetCompositingQuality(compositingQuality: TCompositingQuality): TStatus;
    function GetCompositingQuality: TCompositingQuality;
    function SetTextRenderingHint(newMode: TTextRenderingHint): TStatus;
    function GetTextRenderingHint: TTextRenderingHint;
    function SetTextContrast(contrast: UINT): TStatus; // 0..12
    function GetTextContrast: UINT;
    function GetInterpolationMode: TInterpolationMode;
    function SetInterpolationMode(interpolationMode: TInterpolationMode): TStatus;
    function GetSmoothingMode: TSmoothingMode;
    function SetSmoothingMode(smoothingMode: TSmoothingMode): TStatus;
    function GetPixelOffsetMode: TPixelOffsetMode;
    function SetPixelOffsetMode(pixelOffsetMode: TPixelOffsetMode): TStatus;
    //------------------------------------------------------------------------
    // Manipulate current world transform
    //------------------------------------------------------------------------
    function SetTransform(matrix: TGPMatrix): TStatus;
    function ResetTransform: TStatus;
    function MultiplyTransform(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function TranslateTransform(const dx, dy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function ScaleTransform(const sx, sy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function RotateTransform(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
    function GetTransform(matrix: TGPMatrix): TStatus;
    function SetPageUnit(unit_: TUnit): TStatus;
    function SetPageScale(const scale: Single): TStatus;
    function GetPageUnit: TUnit;
    function GetPageScale: Single;
    function GetDpiX: Single;
    function GetDpiY: Single;
    function TransformPoints(destSpace: TCoordinateSpace; srcSpace: TCoordinateSpace;
      pts: PGPPointF; count: Integer): TStatus; overload;
    function TransformPoints(destSpace: TCoordinateSpace; srcSpace: TCoordinateSpace;
      pts: PGPPoint; count: Integer): TStatus; overload;
    //------------------------------------------------------------------------
    // GetNearestColor (for <= 8bpp surfaces).  Note: Alpha is ignored.
    //------------------------------------------------------------------------
    function GetNearestColor(var color: TGPColor): TStatus;

    // DrawLine(s)
    function DrawLine(pen: TGPPen; const x1, y1, x2, y2: Single): TStatus; overload;
    function DrawLine(pen: TGPPen; const pt1, pt2: TGPPointF): TStatus; overload;
    function DrawLines(pen: TGPPen; points: PGPPointF; count: Integer): TStatus; overload;
    function DrawLine(pen: TGPPen; x1, y1, x2, y2: Integer): TStatus; overload;
    function DrawLine(pen: TGPPen; const pt1, pt2: TGPPoint): TStatus; overload;
    function DrawLines(pen: TGPPen; points: PGPPoint; count: Integer): TStatus; overload;

    // Addition by Steema Software:
    procedure DrawLineFast(const pen: TGPPen; x1, y1, x2, y2: Integer);

    // DrawArc
    function DrawArc(pen: TGPPen; x, y, width, height, startAngle, sweepAngle: Single): TStatus; overload;
    function DrawArc(pen: TGPPen; const rect: TGPRectF; startAngle, sweepAngle: Single): TStatus; overload;
    function DrawArc(pen: TGPPen; x, y, width, height: Integer; startAngle, sweepAngle: Single): TStatus; overload;
    function DrawArc(pen: TGPPen; const rect: TGPRect; startAngle, sweepAngle: Single): TStatus; overload;

    // DrawBezier(s)
    function DrawBezier(pen: TGPPen; x1, y1, x2, y2, x3, y3, x4, y4: Single): TStatus; overload;
    function DrawBezier(pen: TGPPen; const pt1, pt2, pt3, pt4: TGPPointF): TStatus; overload;
    function DrawBeziers(pen: TGPPen; points: PGPPointF; count: Integer): TStatus; overload;
    function DrawBezier(pen: TGPPen; x1, y1, x2, y2, x3, y3, x4, y4: Integer): TStatus; overload;
    function DrawBezier(pen: TGPPen; const pt1, pt2, pt3, pt4: TGPPoint): TStatus; overload;
    function DrawBeziers(pen: TGPPen; points: PGPPoint; count: Integer): TStatus; overload;

    // DrawRectangle(s)
    function DrawRectangle(pen: TGPPen; const rect: TGPRectF): TStatus; overload;
    function DrawRectangle(pen: TGPPen; x, y, width, height: Single): TStatus; overload;
    function DrawRectangles(pen: TGPPen; rects: PGPRectF; count: Integer): TStatus; overload;
    function DrawRectangle(pen: TGPPen; const rect: TGPRect): TStatus; overload;
    function DrawRectangle(pen: TGPPen; x, y, width, height: Integer): TStatus; overload;
    function DrawRectangles(pen: TGPPen; rects: PGPRect; count: Integer): TStatus; overload;

    // DrawEllipse
    function DrawEllipse(pen: TGPPen; const rect: TGPRectF): TStatus; overload;
    function DrawEllipse(pen: TGPPen; x, y, width, height: Single): TStatus; overload;
    function DrawEllipse(pen: TGPPen; const rect: TGPRect): TStatus; overload;
    function DrawEllipse(pen: TGPPen; x, y, width, height: Integer): TStatus; overload;

    // DrawPie
    function DrawPie(pen: TGPPen; const rect: TGPRectF; startAngle, sweepAngle: Single): TStatus; overload;
    function DrawPie(pen: TGPPen; x, y, width, height, startAngle, sweepAngle: Single): TStatus; overload;
    function DrawPie(pen: TGPPen; const rect: TGPRect; startAngle, sweepAngle: Single): TStatus; overload;
    function DrawPie(pen: TGPPen; x, y, width, height: Integer; startAngle, sweepAngle: Single): TStatus; overload;

    // DrawPolygon
    function DrawPolygon(pen: TGPPen; points: PGPPointF; count: Integer): TStatus; overload;
    function DrawPolygon(pen: TGPPen; points: PGPPoint; count: Integer): TStatus; overload;

    // DrawPath
    function DrawPath(pen: TGPPen; path: TGPGraphicsPath): TStatus;

    // DrawCurve
    function DrawCurve(pen: TGPPen; points: PGPPointF; count: Integer): TStatus; overload;
    function DrawCurve(pen: TGPPen; points: PGPPointF; count: Integer; tension: Single): TStatus; overload;
    function DrawCurve(pen: TGPPen; points: PGPPointF; count, offset,
      numberOfSegments: Integer; tension: Single = 0.5): TStatus; overload;
    function DrawCurve(pen: TGPPen; points: PGPPoint; count: Integer): TStatus; overload;
    function DrawCurve(pen: TGPPen; points: PGPPoint; count: Integer; tension: Single): TStatus; overload;
    function DrawCurve(pen: TGPPen; points: PGPPoint; count, offset, numberOfSegments: Integer;
      tension: Single = 0.5): TStatus; overload;

    // DrawClosedCurve
    function DrawClosedCurve(pen: TGPPen; points: PGPPointF; count: Integer): TStatus; overload;
    function DrawClosedCurve(pen: TGPPen; points: PGPPointF; count: Integer; tension: Single): TStatus; overload;
    function DrawClosedCurve(pen: TGPPen; points: PGPPoint;  count: Integer): TStatus; overload;
    function DrawClosedCurve(pen: TGPPen; points: PGPPoint; count: Integer; tension: Single): TStatus; overload;

    // Clear
    function Clear(color: TGPColor): TStatus;

    // FillRectangle(s)
    function FillRectangle(brush: TGPBrush; const rect: TGPRectF): TStatus; overload;
    function FillRectangle(brush: TGPBrush; x, y, width, height: Single): TStatus; overload;
    function FillRectangles(brush: TGPBrush; rects: PGPRectF; count: Integer): TStatus; overload;
    function FillRectangle(brush: TGPBrush; const rect: TGPRect): TStatus; overload;
    function FillRectangle(brush: TGPBrush; x, y, width, height: Integer): TStatus; overload;
    function FillRectangles(brush: TGPBrush; rects: PGPRect; count: Integer): TStatus; overload;

    // FillPolygon
    function FillPolygon(brush: TGPBrush; points: PGPPointF; count: Integer): TStatus; overload;
    function FillPolygon(brush: TGPBrush; points: PGPPointF; count: Integer; fillMode: TFillMode): TStatus; overload;
    function FillPolygon(brush: TGPBrush; points: PGPPoint; count: Integer): TStatus; overload;
    function FillPolygon(brush: TGPBrush; points: PGPPoint; count: Integer; fillMode: TFillMode): TStatus; overload;

    // FillEllipse
    function FillEllipse(brush: TGPBrush; const rect: TGPRectF): TStatus; overload;
    function FillEllipse(brush: TGPBrush; x, y, width, height: Single): TStatus; overload;
    function FillEllipse(brush: TGPBrush; const rect: TGPRect): TStatus; overload;
    function FillEllipse(brush: TGPBrush; x, y, width, height: Integer): TStatus; overload;

    // FillPie
    function FillPie(brush: TGPBrush; const rect: TGPRectF; startAngle, sweepAngle: Single): TStatus; overload;
    function FillPie(brush: TGPBrush; x, y, width, height, startAngle, sweepAngle: Single): TStatus; overload;
    function FillPie(brush: TGPBrush; const rect: TGPRect; startAngle, sweepAngle: Single): TStatus; overload;
    function FillPie(brush: TGPBrush; x, y, width, height: Integer; startAngle, sweepAngle: Single): TStatus; overload;

    // FillPath
    function FillPath(brush: TGPBrush; path: TGPGraphicsPath): TStatus;

    // FillClosedCurve
    function FillClosedCurve(brush: TGPBrush; points: PGPPointF; count: Integer): TStatus; overload;
    function FillClosedCurve(brush: TGPBrush; points: PGPPointF; count: Integer;
      fillMode: TFillMode; tension: Single = 0.5 ): TStatus; overload;
    function FillClosedCurve(brush: TGPBrush; points: PGPPoint; count: Integer): TStatus; overload;
    function FillClosedCurve(brush: TGPBrush; points: PGPPoint; count: Integer;
      fillMode: TFillMode; tension: Single = 0.5): TStatus; overload;

    // FillRegion
    function FillRegion(brush: TGPBrush; region: TGPRegion): TStatus;

    // DrawString
    function DrawString(string_: WideString; length: Integer; font: TGPFont;
      const layoutRect: TGPRectF; stringFormat: TGPStringFormat; brush: TGPBrush): TStatus; overload;
    function DrawString(string_: WideString; length: Integer; font: TGPFont;
      const origin: TGPPointF; brush: TGPBrush): TStatus; overload;
    function DrawString(string_: WideString; length: Integer; font: TGPFont;
      const origin: TGPPointF; stringFormat: TGPStringFormat; brush: TGPBrush): TStatus; overload;

    // MeasureString
    function MeasureString(string_: WideString; length: Integer; font: TGPFont;
      const layoutRect: TGPRectF; stringFormat: TGPStringFormat; out boundingBox: TGPRectF;
      codepointsFitted: PInteger = nil; linesFilled: PInteger = nil): TStatus; overload;
    function MeasureString(string_: WideString; length: Integer; font: TGPFont;
      const layoutRectSize: TGPSizeF; stringFormat: TGPStringFormat; out size: TGPSizeF;
      codepointsFitted: PInteger = nil; linesFilled: PInteger = nil): TStatus; overload;
    function MeasureString(string_: WideString ; length: Integer; font: TGPFont;
      const origin: TGPPointF; stringFormat: TGPStringFormat;
      out boundingBox: TGPRectF): TStatus; overload;
    function MeasureString(string_: WideString; length: Integer; font: TGPFont;
      const layoutRect: TGPRectF; out boundingBox: TGPRectF): TStatus; overload;
    function MeasureString(string_: WideString; length: Integer; font: TGPFont;
      const origin: TGPPointF; out boundingBox: TGPRectF): TStatus; overload;

    // MeasureCharacterRanges
    function MeasureCharacterRanges(string_: WideString; length: Integer; font: TGPFont;
      const layoutRect: TGPRectF; stringFormat: TGPStringFormat; regionCount: Integer;
      const regions: array of TGPRegion): TStatus; overload;

    // DrawDriverString
    function DrawDriverString(text: PUINT16; length: Integer; font: TGPFont;
      brush: TGPBrush; positions: PGPPointF; flags: Integer; matrix: TGPMatrix): TStatus;

    // MeasureDriverString
    function MeasureDriverString(text: PUINT16; length: Integer; font: TGPFont;
       positions: PGPPointF; flags: Integer; matrix: TGPMatrix;
       out boundingBox: TGPRectF): TStatus;

    // Draw a cached bitmap on this graphics destination offset by
    // x, y. Note this will fail with WrongState if the CachedBitmap
    // native format differs from this Graphics.
    function DrawCachedBitmap(cb: TGPCachedBitmap;  x, y: Integer): TStatus;
    function DrawImage(image: TGPImage; const point: TGPPointF): TStatus; overload;
    function DrawImage(image: TGPImage; x, y: Single): TStatus; overload;
    function DrawImage(image: TGPImage; const rect: TGPRectF): TStatus; overload;
    function DrawImage(image: TGPImage; x, y, width, height: Single): TStatus; overload;
    function DrawImage(image: TGPImage; const point: TGPPoint): TStatus; overload;
    function DrawImage(image: TGPImage; x, y: Integer): TStatus; overload;
    function DrawImage(image: TGPImage; const rect: TGPRect): TStatus; overload;
    function DrawImage(image: TGPImage; x, y, width, height: Integer): TStatus; overload;

    // Affine Draw Image
    // destPoints.length = 3: rect => parallelogram
    //     destPoints[0] <=> top-left corner of the source rectangle
    //     destPoints[1] <=> top-right corner
    //     destPoints[2] <=> bottom-left corner
    // destPoints.length = 4: rect => quad
    //     destPoints[3] <=> bottom-right corner
    function DrawImage(image: TGPImage; destPoints: PGPPointF; count: Integer): TStatus; overload;
    function DrawImage(image: TGPImage; destPoints: PGPPoint; count: Integer): TStatus; overload;
    function DrawImage(image: TGPImage; x, y, srcx, srcy, srcwidth, srcheight: Single; srcUnit: TUnit): TStatus; overload;
    function DrawImage(image: TGPImage; const destRect: TGPRectF; srcx, srcy,
      srcwidth, srcheight: Single; srcUnit: TUnit;
      imageAttributes: TGPImageAttributes = nil; callback: DrawImageAbort = nil;
      callbackData: Pointer = nil): TStatus; overload;
    function DrawImage(image: TGPImage; destPoints: PGPPointF; count: Integer;
      srcx, srcy, srcwidth, srcheight: Single; srcUnit: TUnit;
      imageAttributes: TGPImageAttributes = nil; callback: DrawImageAbort = nil;
      callbackData: Pointer = nil): TStatus; overload;
    function DrawImage(image: TGPImage; x, y, srcx, srcy, srcwidth,
      srcheight: Integer; srcUnit: TUnit): TStatus; overload;
    function DrawImage(image: TGPImage; const destRect: TGPRect; srcx, srcy,
      srcwidth, srcheight: Integer; srcUnit: TUnit;
      imageAttributes: TGPImageAttributes = nil; callback: DrawImageAbort = nil;
      callbackData: Pointer = nil): TStatus; overload;
    function DrawImage(image: TGPImage; destPoints: PGPPoint;
      count, srcx, srcy, srcwidth, srcheight: Integer; srcUnit: TUnit;
      imageAttributes: TGPImageAttributes = nil; callback: DrawImageAbort = nil;
      callbackData: Pointer = nil): TStatus; overload;

    // The following methods are for playing an EMF+ to a graphics
    // via the enumeration interface.  Each record of the EMF+ is
    // sent to the callback (along with the callbackData).  Then
    // the callback can invoke the Metafile::PlayRecord method
    // to play the particular record.
    function EnumerateMetafile(metafile: TGPMetafile; const destPoint: TGPPointF;
      callback: EnumerateMetafileProc; callbackData: Pointer = nil;
      imageAttributes: TGPImageAttributes = nil): TStatus; overload;
    function EnumerateMetafile(metafile: TGPMetafile; const destPoint: TGPPoint;    
       callback: EnumerateMetafileProc; callbackData: pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus; overload;
    function EnumerateMetafile(metafile: TGPMetafile; const destRect: TGPRectF;
       callback: EnumerateMetafileProc; callbackData: Pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus; overload;
    function EnumerateMetafile(metafile: TGPMetafile; const destRect: TGPRect;
       callback: EnumerateMetafileProc; callbackData: Pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus; overload;
    function EnumerateMetafile(metafile: TGPMetafile; destPoints: PGPPointF;
       count: Integer; callback: EnumerateMetafileProc; callbackData: Pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus; overload;
    function EnumerateMetafile(metafile: TGPMetafile; destPoints: PGPPoint;
       count: Integer; callback: EnumerateMetafileProc; callbackData: Pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus; overload;
    function EnumerateMetafile(metafile: TGPMetafile; const destPoint: TGPPointF;
       const srcRect: TGPRectF; srcUnit: TUnit; callback: EnumerateMetafileProc;
       callbackData: pointer = nil; imageAttributes: TGPImageAttributes = nil
       ): TStatus; overload;
    function EnumerateMetafile(metafile : TGPMetafile; const destPoint : TGPPoint;
       const srcRect : TGPRect; srcUnit : TUnit; callback : EnumerateMetafileProc;
       callbackData : Pointer = nil; imageAttributes : TGPImageAttributes = nil
       ): TStatus; overload;
    function EnumerateMetafile(metafile: TGPMetafile; const destRect: TGPRectF;
       const srcRect: TGPRectF; srcUnit: TUnit; callback: EnumerateMetafileProc;
       callbackData: Pointer = nil; imageAttributes: TGPImageAttributes = nil): TStatus; overload;
    function EnumerateMetafile(metafile : TGPMetafile; const destRect, srcRect: TGPRect;
       srcUnit : TUnit; callback : EnumerateMetafileProc; callbackData : Pointer = nil;
       imageAttributes : TGPImageAttributes = nil): TStatus; overload;
    function EnumerateMetafile( metafile: TGPMetafile; destPoints: PGPPointF;
        count: Integer; const srcRect: TGPRectF; srcUnit: TUnit; callback: EnumerateMetafileProc;
        callbackData: Pointer = nil; imageAttributes: TGPImageAttributes = nil): TStatus; overload;
    function EnumerateMetafile(metafile: TGPMetafile; destPoints: PGPPoint;
        count: Integer; const srcRect: TGPRect; srcUnit: TUnit; callback: EnumerateMetafileProc;
        callbackData: Pointer = nil; imageAttributes: TGPImageAttributes = nil): TStatus; overload;

    // SetClip
    function SetClip(g: TGPGraphics; combineMode: TCombineMode = CombineModeReplace): TStatus; overload;
    function SetClip(const rect: TGPRectF; combineMode: TCombineMode = CombineModeReplace): TStatus; overload;
    function SetClip(const rect: TGPRect; combineMode: TCombineMode = CombineModeReplace): TStatus; overload;
    function SetClip(path: TGPGraphicsPath; combineMode: TCombineMode = CombineModeReplace): TStatus; overload;
    function SetClip(region: TGPRegion; combineMode: TCombineMode = CombineModeReplace): TStatus; overload;
    // This is different than the other SetClip methods because it assumes
    // that the HRGN is already in device units, so it doesn't transform
    // the coordinates in the HRGN.
    function SetClip(hRgn: HRGN; combineMode: TCombineMode = CombineModeReplace): TStatus; overload;

    // IntersectClip
    function IntersectClip(const rect: TGPRectF): TStatus; overload;
    function IntersectClip(const rect: TGPRect): TStatus; overload;
    function IntersectClip(region: TGPRegion): TStatus; overload;
    // ExcludeClip
    function ExcludeClip(const rect: TGPRectF): TStatus; overload;
    function ExcludeClip(const rect: TGPRect): TStatus; overload;
    function ExcludeClip(region: TGPRegion): TStatus; overload;

    function ResetClip: TStatus;

    function TranslateClip(dx, dy: Single): TStatus; overload;
    function TranslateClip(dx, dy: Integer): TStatus; overload;

    function GetClip(region: TGPRegion): TStatus;

    function GetClipBounds(out rect: TGPRectF): TStatus; overload;
    function GetClipBounds(out rect: TGPRect): TStatus; overload;

    function IsClipEmpty: Bool;

    function GetVisibleClipBounds(out rect: TGPRectF): TStatus; overload;
    function GetVisibleClipBounds(out rect: TGPRect): TStatus; overload;

    function IsVisibleClipEmpty: BOOL;

    function IsVisible(x, y: Integer): BOOL; overload;
    function IsVisible(const point: TGPPoint): BOOL; overload;
    function IsVisible(x, y, width, height: Integer): BOOL; overload;
    function IsVisible(const rect: TGPRect): BOOL; overload;
    function IsVisible(x, y: Single): BOOL; overload;
    function IsVisible(const point: TGPPointF): BOOL; overload;
    function IsVisible(x, y, width, height: Single): BOOL; overload;
    function IsVisible(const rect: TGPRectF): BOOL; overload;

    function Save: GraphicsState;
    function Restore(gstate: GraphicsState): TStatus;

    function BeginContainer(const dstrect,srcrect: TGPRectF; unit_: TUnit): GraphicsContainer; overload;
    function BeginContainer(const dstrect, srcrect: TGPRect; unit_: TUnit): GraphicsContainer; overload;
    function BeginContainer: GraphicsContainer; overload;
    function EndContainer(state: GraphicsContainer): TStatus;

    // Only valid when recording metafiles.
    function AddMetafileComment(data: PBYTE; sizeData: UINT): TStatus;

    function GetHalftonePalette: HPALETTE;                                      
    function GetLastStatus: TStatus;
  end;


(**************************************************************************\
*
*   GDI+ CustomLineCap APIs
*
\**************************************************************************)

  TGPAdjustableArrowCap = class(TGPCustomLineCap)
  public
    constructor Create(height, width: Single; isFilled: Bool = TRUE); 
    function SetHeight(height: Single): TStatus;
    function GetHeight: Single;
    function SetWidth(width: Single): TStatus;
    function GetWidth: Single;
    function SetMiddleInset(middleInset: Single): TStatus;
    function GetMiddleInset: Single;
    function SetFillState(isFilled: Bool): TStatus;
    function IsFilled: BOOL;
  end;

(**************************************************************************\
*
*   GDI+ Metafile class
*
\**************************************************************************)

  TGPMetafile = class(TGPImage)
  public
    // Playback a metafile from a HMETAFILE
    // If deleteWmf is TRUE, then when the metafile is deleted,
    // the hWmf will also be deleted.  Otherwise, it won't be.
    constructor Create(hWmf: HMETAFILE; var wmfPlaceableFileHeader: TWmfPlaceableFileHeader;
      deleteWmf: BOOL = FALSE); overload;
    // Playback a metafile from a HENHMETAFILE
    // If deleteEmf is TRUE, then when the metafile is deleted,
    // the hEmf will also be deleted.  Otherwise, it won't be.
    constructor Create(hEmf: HENHMETAFILE; deleteEmf: BOOL = FALSE); overload;
    constructor Create(filename: WideString); overload;
    // Playback a WMF metafile from a file.
    constructor Create(filename: WideString; var wmfPlaceableFileHeader: TWmfPlaceableFileHeader); overload;
    constructor Create(stream: IStream); overload;
    // Record a metafile to memory.
    constructor Create(referenceHdc: HDC; type_: TEmfType = EmfTypeEmfPlusDual;
      description: PWCHAR = nil); overload;
    // Record a metafile to memory.
    constructor Create(referenceHdc: HDC; const frameRect: TGPRectF;
      frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi;
      type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil); overload;
    // Record a metafile to memory.
    constructor Create(referenceHdc: HDC; const frameRect: TGPRect;
      frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi;
      type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil); overload;
    constructor Create(fileName: WideString;referenceHdc: HDC;
      type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil); overload;
    constructor Create(fileName: WideString; referenceHdc: HDC; const frameRect: TGPRectF;
      frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi;
      type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil); overload;
    constructor Create( fileName: WideString; referenceHdc: HDC; const frameRect: TGPRect;
      frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi;
      type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil); overload;
    constructor Create(stream: IStream; referenceHdc: HDC;
      type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil); overload;
    constructor Create(stream: IStream; referenceHdc: HDC; const frameRect: TGPRectF;
      frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi;
      type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil); overload;
    constructor Create(stream : IStream; referenceHdc : HDC; const frameRect : TGPRect;
     frameUnit : TMetafileFrameUnit = MetafileFrameUnitGdi;
     type_ : TEmfType = EmfTypeEmfPlusDual; description : PWCHAR = nil); overload;
    constructor Create; reintroduce; overload;

    // Bug in DCC32 generating hpp header (TMetafileHeader record "case")
    {$IFNDEF TEELITE}

    function GetMetafileHeader(hWmf: HMETAFILE; var wmfPlaceableFileHeader: TWmfPlaceableFileHeader;
      header: TMetafileHeader): TStatus; overload;
    function GetMetafileHeader(hEmf: HENHMETAFILE; header: TMetafileHeader): TStatus; overload;   // ok
    function GetMetafileHeader(filename: WideString; header: TMetafileHeader): TStatus; overload; // ok
    function GetMetafileHeader(stream: IStream; header: TMetafileHeader): TStatus; overload;      // ok
    function GetMetafileHeader(header: TMetafileHeader): TStatus; overload;                       // ok

    {$ENDIF}
    
    // Once this method is called, the Metafile object is in an invalid state
    // and can no longer be used.  It is the responsiblity of the caller to
    // invoke DeleteEnhMetaFile to delete this hEmf.                                              // ok
    function GetHENHMETAFILE: HENHMETAFILE;
    // Used in conjuction with Graphics::EnumerateMetafile to play an EMF+
    // The data must be DWORD aligned if it's an EMF or EMF+.  It must be
    // WORD aligned if it's a WMF.
    function PlayRecord(recordType: TEmfPlusRecordType; flags, dataSize: UINT; data: PBYTE): TStatus;
    // If you're using a printer HDC for the metafile, but you want the
    // metafile rasterized at screen resolution, then use this API to set
    // the rasterization dpi of the metafile to the screen resolution,
    // e.g. 96 dpi or 120 dpi.
    function SetDownLevelRasterizationLimit(metafileRasterizationLimitDpi: UINT): TStatus;
    function GetDownLevelRasterizationLimit: UINT;
    function EmfToWmfBits(hemf: HENHMETAFILE; cbData16: UINT; pData16: PBYTE;
      iMapMode: Integer = MM_ANISOTROPIC; eFlags: TEmfToWmfBitsFlags = EmfToWmfBitsFlagsDefault): UINT;
  end;

////////////////////////////////////////////////////////////////////////////////

var
   GenericSansSerifFontFamily : TGPFontFamily = nil;
   GenericSerifFontFamily     : TGPFontFamily = nil;
   GenericMonospaceFontFamily : TGPFontFamily = nil;

   GenericTypographicStringFormatBuffer: TGPStringFormat = nil;
   GenericDefaultStringFormatBuffer    : TGPStringFormat = nil;

   StartupInput: TGDIPlusStartupInput;
   StartupOutput: TGDIPlusStartupOutput;
   BGThreadToken: ULONG=0;
   gdiplusToken: ULONG=0;
   {$IFDEF TEEOCX}
   ocxShutdown: Boolean=False;
   {$ENDIF}

////////////////////////////////////////////////////////////////////////////////

procedure TeeGDIPlusStartup;
procedure TeeGDIPlusShutdown;

implementation

(**************************************************************************\
*
* Image Attributes
*
* Abstract:
*
*   GDI+ Image Attributes used with Graphics.DrawImage
*
* There are 5 possible sets of color adjustments:
*          ColorAdjustDefault,
*          ColorAdjustBitmap,
*          ColorAdjustBrush,
*          ColorAdjustPen,
*          ColorAdjustText,
*
* Bitmaps, Brushes, Pens, and Text will all use any color adjustments
* that have been set into the default ImageAttributes until their own
* color adjustments have been set.  So as soon as any "Set" method is
* called for Bitmaps, Brushes, Pens, or Text, then they start from
* scratch with only the color adjustments that have been set for them.
* Calling Reset removes any individual color adjustments for a type
* and makes it revert back to using all the default color adjustments
* (if any).  The SetToIdentity method is a way to force a type to
* have no color adjustments at all, regardless of what previous adjustments
* have been set for the defaults or for that type.
*
\********************************************************************F******)

  constructor TGPImageAttributes.Create;
  begin
    lastResult := GdipCreateImageAttributes(nativeImageAttr);
  end;

  destructor TGPImageAttributes.Destroy;
  begin
    GdipDisposeImageAttributes(nativeImageAttr);
    inherited Destroy;
  end;

  function TGPImageAttributes.Clone: TGPImageAttributes;
  var clone: GpImageAttributes;
  begin
    SetStatus(GdipCloneImageAttributes(nativeImageAttr, clone));
    result := TGPImageAttributes.Create(clone, lastResult);
  end;

  function TGPImageAttributes.SetToIdentity(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesToIdentity(nativeImageAttr, type_));
  end;

  function TGPImageAttributes.Reset(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipResetImageAttributes(nativeImageAttr, type_));
  end;

  function TGPImageAttributes.SetColorMatrix(const colorMatrix: TColorMatrix;
    mode: TColorMatrixFlags = ColorMatrixFlagsDefault;
    type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesColorMatrix(nativeImageAttr,
      type_, TRUE, @colorMatrix, nil, mode));
  end;

  function TGPImageAttributes.ClearColorMatrix(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesColorMatrix(nativeImageAttr, type_,
      FALSE, nil, nil, ColorMatrixFlagsDefault));
  end;

    
  function TGPImageAttributes.SetColorMatrices(const colorMatrix: TColorMatrix;
    const grayMatrix: TColorMatrix; mode: TColorMatrixFlags  = ColorMatrixFlagsDefault;
    type_: TColorAdjustType  = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesColorMatrix(nativeImageAttr, type_,
      TRUE, @colorMatrix, @grayMatrix, mode));
  end;

  function TGPImageAttributes.ClearColorMatrices(Type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesColorMatrix( nativeImageAttr,
      type_, FALSE, nil, nil, ColorMatrixFlagsDefault));
  end;

  function TGPImageAttributes.SetThreshold(const threshold: Single; type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesThreshold( nativeImageAttr, type_,
      TRUE, threshold));
  end;

  function TGPImageAttributes.ClearThreshold(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesThreshold(nativeImageAttr, type_,
      FALSE, 0.0));
  end;

  function TGPImageAttributes.SetGamma(const gamma: Single; type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesGamma(nativeImageAttr, type_, TRUE, gamma));
  end;

  function TGPImageAttributes.ClearGamma(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesGamma(nativeImageAttr, type_, FALSE, 0.0));
  end;

  function TGPImageAttributes.SetNoOp(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesNoOp(nativeImageAttr, type_, TRUE));
  end;

  function TGPImageAttributes.ClearNoOp(Type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesNoOp( nativeImageAttr, type_, FALSE));
  end;

  function TGPImageAttributes.SetColorKey(colorLow, colorHigh: TGPColor;
    type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesColorKeys(nativeImageAttr, type_,
      TRUE, colorLow, colorHigh));
  end;

  function TGPImageAttributes.ClearColorKey(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesColorKeys(nativeImageAttr, type_,
      FALSE, 0, 0));
  end;

  function TGPImageAttributes.SetOutputChannel(channelFlags: TColorChannelFlags;
        type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesOutputChannel(nativeImageAttr,
      type_, TRUE, channelFlags));
  end;

  function TGPImageAttributes.ClearOutputChannel(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesOutputChannel(nativeImageAttr,
      type_, FALSE, ColorChannelFlagsLast));
  end;

  function TGPImageAttributes.SetOutputChannelColorProfile(colorProfileFilename: WideString;
    type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesOutputChannelColorProfile(nativeImageAttr,
      type_, TRUE, PWideChar(colorProfileFilename)));
  end;

  function TGPImageAttributes.ClearOutputChannelColorProfile(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesOutputChannelColorProfile(nativeImageAttr,
      type_, FALSE, nil));
  end;

  function TGPImageAttributes.SetRemapTable(mapSize: Cardinal; map: PColorMap;
    type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesRemapTable(nativeImageAttr, type_,
      TRUE, mapSize, map));
  end;

  function TGPImageAttributes.ClearRemapTable(type_: TColorAdjustType = ColorAdjustTypeDefault): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesRemapTable(nativeImageAttr, type_,
      FALSE, 0, nil));
  end;

  function TGPImageAttributes.SetBrushRemapTable(mapSize: Cardinal; map: PColorMap): TStatus;
  begin
    result := SetRemapTable(mapSize, map, ColorAdjustTypeBrush);
  end;

  function TGPImageAttributes.ClearBrushRemapTable: TStatus;
  begin
    result := ClearRemapTable(ColorAdjustTypeBrush);
  end;

  function TGPImageAttributes.SetWrapMode(wrap: TWrapMode; color: TGPColor = aclBlack;
    clamp: BOOL = FALSE): TStatus;
  begin
    result := SetStatus(GdipSetImageAttributesWrapMode(nativeImageAttr, wrap, color, clamp));
  end;

  // The flags of the palette are ignored.

  function TGPImageAttributes.GetAdjustedPalette(colorPalette: PColorPalette;
    colorAdjustType: TColorAdjustType): TStatus;
  begin
    result := SetStatus(GdipGetImageAttributesAdjustedPalette(nativeImageAttr,
      colorPalette, colorAdjustType));
  end;

  function TGPImageAttributes.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  constructor TGPImageAttributes.Create(imageAttr: GpImageAttributes; status: TStatus);
  begin
    SetNativeImageAttr(imageAttr);
    lastResult := status;
  end;

  procedure TGPImageAttributes.SetNativeImageAttr(nativeImageAttr: GpImageAttributes);
  begin
    self.nativeImageAttr := nativeImageAttr;
  end;

  function TGPImageAttributes.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

(**************************************************************************\
*
*   GDI+ Matrix class
*
\**************************************************************************)

  // Default constructor is set to identity matrix.
  constructor TGPMatrix.Create;
  var matrix: GpMatrix;
  begin
    matrix := nil;
    lastResult := GdipCreateMatrix(matrix);
    SetNativeMatrix(matrix);
  end;

  constructor TGPMatrix.Create(const m11, m12, m21, m22, dx, dy: Single);
  var matrix: GpMatrix;
  begin
    matrix := nil;
    lastResult := GdipCreateMatrix2(m11, m12, m21, m22, dx, dy, matrix);
    SetNativeMatrix(matrix);
  end;

  constructor TGPMatrix.Create(const rect: TGPRectF; const dstplg: TGPPointF);
  var matrix: GpMatrix;
  begin
    matrix := nil;
    lastResult := GdipCreateMatrix3(@rect, @dstplg, matrix);
    SetNativeMatrix(matrix);
  end;

  constructor TGPMatrix.Create(const rect: TGPRect; const dstplg: TGPPoint);
  var matrix: GpMatrix;
  begin
    matrix := nil;
    lastResult := GdipCreateMatrix3I(@rect, @dstplg, matrix);
    SetNativeMatrix(matrix);
  end;

  destructor TGPMatrix.Destroy;
  begin
    GdipDeleteMatrix(nativeMatrix);
    inherited;
  end;

  function TGPMatrix.Clone: TGPMatrix;
  var cloneMatrix: GpMatrix;
  begin
    cloneMatrix := nil;
    SetStatus(GdipCloneMatrix(nativeMatrix, cloneMatrix));
    if (lastResult <> Ok) then
    begin
      result := nil;
      exit;
    end;
    result := TGPMatrix.Create(cloneMatrix);
  end;

  function TGPMatrix.GetElements(const m: TMatrixArray): TStatus;
  begin
    result := SetStatus(GdipGetMatrixElements(nativeMatrix, @m));
  end;

  function TGPMatrix.SetElements(const m11, m12, m21, m22, dx, dy: Single): TStatus;
  begin
        result := SetStatus(GdipSetMatrixElements(nativeMatrix,
                            m11, m12, m21, m22, dx, dy));
  end;

  function TGPMatrix.OffsetX: Single;
  var elements: TMatrixArray;
  begin
    if (GetElements(elements) = Ok) then
      result := elements[4]
    else
      result := 0.0;
  end;

  function TGPMatrix.OffsetY: Single;
  var elements: TMatrixArray;
  begin
    if (GetElements(elements) = Ok) then result := elements[5]
                                        else result := 0.0;
  end;

  function TGPMatrix.Reset: TStatus;
  begin
    // set identity matrix elements
    result := SetStatus(GdipSetMatrixElements(nativeMatrix, 1.0, 0.0, 0.0, 1.0,
                0.0, 0.0));
  end;

  function TGPMatrix.Multiply(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipMultiplyMatrix(nativeMatrix, matrix.nativeMatrix, order));
  end;

  function TGPMatrix.Translate(const offsetX, offsetY: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipTranslateMatrix(nativeMatrix, offsetX, offsetY, order));
  end;

  function TGPMatrix.Scale(const scaleX, scaleY: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipScaleMatrix(nativeMatrix, scaleX, scaleY, order));
  end;

  function TGPMatrix.Rotate(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipRotateMatrix(nativeMatrix, angle, order));
  end;

  function TGPMatrix.RotateAt(const angle: Single; const center: TGPPointF; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    if(order = MatrixOrderPrepend) then
    begin
      SetStatus(GdipTranslateMatrix(nativeMatrix, center.X, center.Y, order));
      SetStatus(GdipRotateMatrix(nativeMatrix, angle, order));
      result := SetStatus(GdipTranslateMatrix(nativeMatrix, -center.X, -center.Y,
                  order));
    end
    else
    begin
      SetStatus(GdipTranslateMatrix(nativeMatrix, - center.X, - center.Y, order));
      SetStatus(GdipRotateMatrix(nativeMatrix, angle, order));
      result := SetStatus(GdipTranslateMatrix(nativeMatrix, center.X, center.Y,
                  order));
    end;
  end;

  function TGPMatrix.Shear(const shearX, shearY: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipShearMatrix(nativeMatrix, shearX, shearY, order));
  end;

  function TGPMatrix.Invert: TStatus;
  begin
    result := SetStatus(GdipInvertMatrix(nativeMatrix));
  end;

  // float version
  function TGPMatrix.TransformPoints(pts: PGPPointF; count: Integer = 1): TStatus;
  begin
    result := SetStatus(GdipTransformMatrixPoints(nativeMatrix, pts, count));
  end;

  function TGPMatrix.TransformPoints(pts: PGPPoint; count: Integer = 1): TStatus;
  begin
    result := SetStatus(GdipTransformMatrixPointsI(nativeMatrix, pts, count));
  end;

  function TGPMatrix.TransformVectors(pts: PGPPointF; count: Integer = 1): TStatus;
  begin
    result := SetStatus(GdipVectorTransformMatrixPoints( nativeMatrix, pts, count));
  end;

  function TGPMatrix.TransformVectors(pts: PGPPoint; count: Integer = 1): TStatus;
  begin
    result := SetStatus(GdipVectorTransformMatrixPointsI(nativeMatrix, pts, count));
  end;

  function TGPMatrix.IsInvertible: BOOL;
  begin
    result := FALSE;
    SetStatus(GdipIsMatrixInvertible(nativeMatrix, result));
  end;

  function TGPMatrix.IsIdentity: BOOL;
  begin
    result := False;
    SetStatus(GdipIsMatrixIdentity(nativeMatrix, result));
  end;

  function TGPMatrix.EqualsMatrix(matrix: TGPMatrix): BOOL;
  begin
    result := FALSE;
    SetStatus(GdipIsMatrixEqual(nativeMatrix, matrix.nativeMatrix, result));
  end;

  function TGPMatrix.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  constructor TGPMatrix.Create(nativeMatrix: GpMatrix);
  begin
    lastResult := Ok;
    SetNativeMatrix(nativeMatrix);
  end;

  procedure TGPMatrix.SetNativeMatrix(nativeMatrix: GpMatrix);
  begin
    self.nativeMatrix := nativeMatrix;
  end;

  function TGPMatrix.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;


(**************************************************************************\
*
*   GDI+ StringFormat class
*
\**************************************************************************)

  constructor TGPStringFormat.Create(formatFlags: Integer = 0; language: LANGID = LANG_NEUTRAL);
  begin
    lastError := GdipCreateStringFormat(formatFlags, language, nativeFormat);
  end;

  class function TGPStringFormat.GenericDefault: TGPStringFormat;
  begin
    if not assigned(GenericDefaultStringFormatBuffer) then
    begin
      GenericDefaultStringFormatBuffer := TGPStringFormat.Create;
      GenericDefaultStringFormatBuffer.lastError :=
        GdipStringFormatGetGenericDefault(GenericDefaultStringFormatBuffer.nativeFormat);
    end;
    result := GenericDefaultStringFormatBuffer;
  end;

  class function TGPStringFormat.GenericTypographic: TGPStringFormat;
  begin
    if not assigned(GenericTypographicStringFormatBuffer) then
    begin
      GenericTypographicStringFormatBuffer := TGPStringFormat.Create;
      GenericTypographicStringFormatBuffer.lastError :=
        GdipStringFormatGetGenericTypographic(GenericTypographicStringFormatBuffer.nativeFormat);
    end;
    result := GenericTypographicStringFormatBuffer;
  end;

  constructor TGPStringFormat.Create(format: TGPStringFormat);
  var gpstf: GPSTRINGFORMAT;
  begin
    if assigned(format) then gpstf := format.nativeFormat
                        else gpstf := nil;
    lastError := GdipCloneStringFormat(gpstf, nativeFormat);
  end;

  function TGPStringFormat.Clone: TGPStringFormat;
  var
    clonedStringFormat: GpStringFormat;
  begin
    clonedStringFormat := nil;
    lastError := GdipCloneStringFormat(nativeFormat, clonedStringFormat);
    if (lastError = Ok) then
      result := TGPStringFormat.Create(clonedStringFormat, lastError)
    else
      result := nil;
  end;

  destructor TGPStringFormat.Destroy;
  begin
    GdipDeleteStringFormat(nativeFormat);
    inherited;
  end;

  function TGPStringFormat.SetFormatFlags(flags: Integer): TStatus;
  begin
    result := SetStatus(GdipSetStringFormatFlags(nativeFormat, flags));
  end;

  function TGPStringFormat.GetFormatFlags: Integer;
  begin
    SetStatus(GdipGetStringFormatFlags(nativeFormat, result));
  end;

  function TGPStringFormat.SetAlignment(align: TStringAlignment): TStatus;
  begin
    result := SetStatus(GdipSetStringFormatAlign(nativeFormat, align));
  end;

  function TGPStringFormat.GetAlignment: TStringAlignment;
  begin
    SetStatus(GdipGetStringFormatAlign(nativeFormat, result));
  end;

  function TGPStringFormat.SetLineAlignment(align: TStringAlignment): TStatus;
  begin
    result := SetStatus(GdipSetStringFormatLineAlign(nativeFormat, align));
  end;

  function TGPStringFormat.GetLineAlignment: TStringAlignment;
  begin
    SetStatus(GdipGetStringFormatLineAlign(nativeFormat, result));
  end;

  function TGPStringFormat.SetHotkeyPrefix(hotkeyPrefix: THotkeyPrefix): TStatus;
  begin
    result := SetStatus(GdipSetStringFormatHotkeyPrefix(nativeFormat, Integer(hotkeyPrefix)));
  end;

  function TGPStringFormat.GetHotkeyPrefix: THotkeyPrefix;
  var HotkeyPrefix: Integer;
  begin
    SetStatus(GdipGetStringFormatHotkeyPrefix(nativeFormat, HotkeyPrefix));
    result := THotkeyPrefix(HotkeyPrefix);
  end;

  function TGPStringFormat.SetTabStops(const firstTabOffset: Single; count: Integer; tabStops: PSingle): TStatus;
  begin
    result := SetStatus(GdipSetStringFormatTabStops(nativeFormat, firstTabOffset, count, tabStops));
  end;

  function TGPStringFormat.GetTabStopCount: Integer;
  begin
    SetStatus(GdipGetStringFormatTabStopCount(nativeFormat, result));
  end;

  function TGPStringFormat.GetTabStops(count: Integer; firstTabOffset, tabStops: PSingle): TStatus;
  begin
    result := SetStatus(GdipGetStringFormatTabStops(nativeFormat, count, firstTabOffset, tabStops));
  end;

  function TGPStringFormat.SetDigitSubstitution(language: LANGID; substitute: TStringDigitSubstitute): TStatus;
  begin
    result := SetStatus(GdipSetStringFormatDigitSubstitution(nativeFormat, language, substitute));
  end;

  function TGPStringFormat.GetDigitSubstitutionLanguage: LANGID;
  begin
    SetStatus(GdipGetStringFormatDigitSubstitution(nativeFormat, @result, nil));
  end;

  function TGPStringFormat.GetDigitSubstitutionMethod: TStringDigitSubstitute;
  begin
    SetStatus(GdipGetStringFormatDigitSubstitution(nativeFormat, nil, @result));
  end;

  function TGPStringFormat.SetTrimming(trimming: TStringTrimming): TStatus;
  begin
    result := SetStatus(GdipSetStringFormatTrimming(nativeFormat, trimming));
  end;

  function TGPStringFormat.GetTrimming: TStringTrimming;
  begin
    SetStatus(GdipGetStringFormatTrimming(nativeFormat, result));
  end;

  function TGPStringFormat.SetMeasurableCharacterRanges(rangeCount: Integer;
    ranges: PCharacterRange): TStatus;
  begin
    result := SetStatus(GdipSetStringFormatMeasurableCharacterRanges(nativeFormat,
      rangeCount, ranges));
  end;

  function TGPStringFormat.GetMeasurableCharacterRangeCount: Integer;
  begin
    SetStatus(GdipGetStringFormatMeasurableCharacterRangeCount(nativeFormat, result));
  end;

  function TGPStringFormat.GetLastStatus: TStatus;
  begin
    result := lastError;
    lastError := Ok;
  end;

  function TGPStringFormat.SetStatus(newStatus: GpStatus): TStatus;
  begin
    if (newStatus <> Ok) then lastError := newStatus;
    result := newStatus;
  end;

  // operator =
  procedure TGPStringFormat.Assign(source: TGPStringFormat);
  begin
    assert(assigned(source));
    GdipDeleteStringFormat(nativeFormat);
    lastError := GdipCloneStringFormat(source.nativeFormat, nativeFormat);
  end;

  constructor TGPStringFormat.Create(clonedStringFormat: GpStringFormat; status: TStatus);
  begin
    lastError := status;
    nativeFormat := clonedStringFormat;
  end;



  // ---------------------------------------------------------------------------
  //  TAdjustableArrowCap
  // ---------------------------------------------------------------------------

  constructor TGPAdjustableArrowCap.Create(height, width: Single; isFilled: Bool = TRUE);
  var cap: GpAdjustableArrowCap;
  begin
    cap := nil;
    lastResult := GdipCreateAdjustableArrowCap(height, width, isFilled, cap);
    SetNativeCap(cap);
  end;

  function TGPAdjustableArrowCap.SetHeight(height: Single): TStatus;
  begin
    result := SetStatus(GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap(nativeCap), height));
  end;

  function TGPAdjustableArrowCap.GetHeight: Single;
  begin
    SetStatus(GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap(nativeCap), result));
  end;

  function TGPAdjustableArrowCap.SetWidth(width: Single): TStatus;
  begin
    result := SetStatus(GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap(nativeCap), width));
  end;

  function TGPAdjustableArrowCap.GetWidth: Single;
  begin
    SetStatus(GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap(nativeCap), result));
  end;

  function TGPAdjustableArrowCap.SetMiddleInset(middleInset: Single): TStatus;
  begin
    result := SetStatus(GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap(nativeCap), middleInset));
  end;

  function TGPAdjustableArrowCap.GetMiddleInset: Single;
  begin
    SetStatus(GdipGetAdjustableArrowCapMiddleInset(
      GpAdjustableArrowCap(nativeCap), result));
  end;

  function TGPAdjustableArrowCap.SetFillState(isFilled: Bool): TStatus;
  begin
    result := SetStatus(GdipSetAdjustableArrowCapFillState(
      GpAdjustableArrowCap(nativeCap), isFilled));
  end;

  function TGPAdjustableArrowCap.IsFilled: BOOL;
  begin
    SetStatus(GdipGetAdjustableArrowCapFillState(
      GpAdjustableArrowCap(nativeCap), result));
  end;

(**************************************************************************\
*
*   GDI+ Metafile class
*
\**************************************************************************)

    // Playback a metafile from a HMETAFILE
    // If deleteWmf is TRUE, then when the metafile is deleted,
    // the hWmf will also be deleted.  Otherwise, it won't be.

  constructor TGPMetafile.Create(hWmf: HMETAFILE;
    var wmfPlaceableFileHeader: TWmfPlaceableFileHeader; deleteWmf: BOOL = FALSE);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipCreateMetafileFromWmf(hWmf, deleteWmf, @wmfPlaceableFileHeader, metafile);
    SetNativeImage(metafile);
  end;

    // Playback a metafile from a HENHMETAFILE
    // If deleteEmf is TRUE, then when the metafile is deleted,
    // the hEmf will also be deleted.  Otherwise, it won't be.

  constructor TGPMetafile.Create(hEmf: HENHMETAFILE; deleteEmf: BOOL = FALSE);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipCreateMetafileFromEmf(hEmf, deleteEmf, metafile);
    SetNativeImage(metafile);
  end;

  constructor TGPMetafile.Create(filename: WideString);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipCreateMetafileFromFile(PWideChar(filename), metafile);
    SetNativeImage(metafile);
  end;

    // Playback a WMF metafile from a file.

  constructor TGPMetafile.Create(filename: Widestring; var wmfPlaceableFileHeader: TWmfPlaceableFileHeader);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipCreateMetafileFromWmfFile(PWideChar(filename), @wmfPlaceableFileHeader, metafile);
    SetNativeImage(metafile);
  end;

  constructor TGPMetafile.Create(stream: IStream);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipCreateMetafileFromStream(stream, metafile);
    SetNativeImage(metafile);
  end;

    // Record a metafile to memory.

  constructor TGPMetafile.Create(referenceHdc: HDC; type_: TEmfType = EmfTypeEmfPlusDual;
    description: PWCHAR = nil);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipRecordMetafile(referenceHdc, type_, nil, MetafileFrameUnitGdi,
       description, metafile);
    SetNativeImage(metafile);
  end;

    // Record a metafile to memory.

  constructor TGPMetafile.Create(referenceHdc: HDC; const frameRect: TGPRectF;
     frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi;
     type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil);
  var metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipRecordMetafile(referenceHdc, type_, @frameRect, frameUnit,
      description, metafile);
    SetNativeImage(metafile);
  end;

    // Record a metafile to memory.

  constructor TGPMetafile.Create(referenceHdc: HDC; const frameRect: TGPRect;
    frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi;
    type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipRecordMetafileI(referenceHdc, type_, @frameRect, frameUnit,
      description, metafile);
    SetNativeImage(metafile);
  end;

  constructor TGPMetafile.Create(fileName: WideString; referenceHdc: HDC;
    type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipRecordMetafileFileName(PWideChar(fileName),
      referenceHdc, type_, nil, MetafileFrameUnitGdi, description, metafile);
    SetNativeImage(metafile);
  end;

  constructor TGPMetafile.Create(fileName: WideString; referenceHdc: HDC; const frameRect: TGPRectF;
    frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi; type_: TEmfType = EmfTypeEmfPlusDual;
    description: PWCHAR = nil);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipRecordMetafileFileName(PWideChar(fileName), referenceHdc,
      type_, @frameRect, frameUnit, description, metafile);
    SetNativeImage(metafile);
  end;

  constructor TGPMetafile.Create(fileName: WideString; referenceHdc: HDC; const frameRect: TGPRect;
    frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi; type_: TEmfType = EmfTypeEmfPlusDual;
    description: PWCHAR = nil);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipRecordMetafileFileNameI(PWideChar(fileName),
      referenceHdc, type_, @frameRect, frameUnit, description, metafile);
    SetNativeImage(metafile);
  end;

  constructor TGPMetafile.Create(stream: IStream; referenceHdc: HDC;
    type_: TEmfType = EmfTypeEmfPlusDual; description: PWCHAR = nil);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipRecordMetafileStream(stream, referenceHdc, type_, nil,
      MetafileFrameUnitGdi, description, metafile);
    SetNativeImage(metafile);
  end;

  constructor TGPMetafile.Create(stream: IStream; referenceHdc: HDC; const frameRect: TGPRectF;
    frameUnit: TMetafileFrameUnit = MetafileFrameUnitGdi; type_: TEmfType = EmfTypeEmfPlusDual;
    description: PWCHAR = nil);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipRecordMetafileStream(stream, referenceHdc, type_,
      @frameRect, frameUnit, description, metafile);
    SetNativeImage(metafile);
  end;

  constructor TGPMetafile.Create(stream : IStream; referenceHdc : HDC; const frameRect : TGPRect;
    frameUnit : TMetafileFrameUnit = MetafileFrameUnitGdi; type_ : TEmfType = EmfTypeEmfPlusDual;
    description : PWCHAR = nil);
  var
    metafile: GpMetafile;
  begin
    metafile := nil;
    lastResult := GdipRecordMetafileStreamI(stream, referenceHdc, type_,
      @frameRect, frameUnit, description, metafile);
    SetNativeImage(metafile);
  end;

  // Bug in DCC32 generating hpp header (TMetafileHeader record "case")
  {$IFNDEF TEELITE}

  function TGPMetafile.GetMetafileHeader(hWmf: HMETAFILE;
    var wmfPlaceableFileHeader: TWmfPlaceableFileHeader; header: TMetafileHeader): TStatus;
  begin
    result := GdipGetMetafileHeaderFromWmf(hWmf, @wmfPlaceableFileHeader, @header.Type_);
  end;

  function TGPMetafile.GetMetafileHeader(hEmf: HENHMETAFILE; header: TMetafileHeader): TStatus;
  begin
    result := GdipGetMetafileHeaderFromEmf(hEmf, @header.Type_);
  end;

  function TGPMetafile.GetMetafileHeader(filename: WideString; header: TMetafileHeader): TStatus;
  begin
    result := GdipGetMetafileHeaderFromFile(PWideChar(filename), @header.Type_);
  end;

  function TGPMetafile.GetMetafileHeader(stream: IStream; header: TMetafileHeader): TStatus;
  begin
    result := GdipGetMetafileHeaderFromStream(stream, @header.Type_);
  end;

  function TGPMetafile.GetMetafileHeader(header: TMetafileHeader): TStatus;
  begin
    result := SetStatus(GdipGetMetafileHeaderFromMetafile(GpMetafile(nativeImage),
      @header.Type_));
  end;
  {$ENDIF}
  
    // Once this method is called, the Metafile object is in an invalid state
    // and can no longer be used.  It is the responsiblity of the caller to
    // invoke DeleteEnhMetaFile to delete this hEmf.

  function TGPMetafile.GetHENHMETAFILE: HENHMETAFILE;
  begin
    SetStatus(GdipGetHemfFromMetafile(GpMetafile(nativeImage), result));
  end;

    // Used in conjuction with Graphics::EnumerateMetafile to play an EMF+
    // The data must be DWORD aligned if it's an EMF or EMF+.  It must be
    // WORD aligned if it's a WMF.

  function TGPMetafile.PlayRecord(recordType: TEmfPlusRecordType; flags, dataSize: UINT;
    data: PBYTE): TStatus;
  begin
    result := SetStatus(GdipPlayMetafileRecord(GpMetafile(nativeImage),
      recordType, flags, dataSize, data));
  end;

    // If you're using a printer HDC for the metafile, but you want the
    // metafile rasterized at screen resolution, then use this API to set
    // the rasterization dpi of the metafile to the screen resolution,
    // e.g. 96 dpi or 120 dpi.

  function TGPMetafile.SetDownLevelRasterizationLimit(metafileRasterizationLimitDpi: UINT): TStatus;
  begin
    result := SetStatus(GdipSetMetafileDownLevelRasterizationLimit(
      GpMetafile(nativeImage), metafileRasterizationLimitDpi));
  end;

  function TGPMetafile.GetDownLevelRasterizationLimit: UINT;
  var metafileRasterizationLimitDpi: UINT;
  begin
    metafileRasterizationLimitDpi := 0;
    SetStatus(GdipGetMetafileDownLevelRasterizationLimit(
      GpMetafile(nativeImage), metafileRasterizationLimitDpi));
    result := metafileRasterizationLimitDpi;
  end;

  function TGPMetafile.EmfToWmfBits(hemf: HENHMETAFILE; cbData16: UINT; pData16: PBYTE;
    iMapMode: Integer = MM_ANISOTROPIC; eFlags: TEmfToWmfBitsFlags = EmfToWmfBitsFlagsDefault): UINT;
  begin
    result := GdipEmfToWmfBits(hemf, cbData16, pData16, iMapMode, Integer(eFlags));
  end;

  constructor TGPMetafile.Create;
  begin
    SetNativeImage(nil);
    lastResult := Ok;
  end;

(**************************************************************************\
*
*   GDI+ Codec Image APIs
*
\**************************************************************************)

//--------------------------------------------------------------------------
// Codec Management APIs
//--------------------------------------------------------------------------

  function GetImageDecodersSize(out numDecoders, size: UINT): TStatus;
  begin
    result := GdipGetImageDecodersSize(numDecoders, size);
  end;

  function GetImageDecoders(numDecoders, size: UINT;
     decoders: PImageCodecInfo): TStatus;
  begin
    result := GdipGetImageDecoders(numDecoders, size, decoders);
  end;


  function GetImageEncodersSize(out numEncoders, size: UINT): TStatus;
  begin
    result := GdipGetImageEncodersSize(numEncoders, size);
  end;

  function GetImageEncoders(numEncoders, size: UINT;
     encoders: PImageCodecInfo): TStatus;
  begin
    result := GdipGetImageEncoders(numEncoders, size, encoders);
  end;

(**************************************************************************\
*
*   GDI+ Region class implementation
*
\**************************************************************************)

  constructor TGPRegion.Create;
  var
    region: GpRegion;
  begin
    region := nil;
    lastResult := GdipCreateRegion(region);
    SetNativeRegion(region);
  end;

  constructor TGPRegion.Create(const rect: TGPRectF);
  var
    region: GpRegion;
  begin
    region := nil;
    lastResult := GdipCreateRegionRect(@rect, region);
    SetNativeRegion(region);
  end;

  constructor TGPRegion.Create(const rect: TGPRect);
  var
    region: GpRegion;
  begin
    region := nil;
    lastResult := GdipCreateRegionRectI(@rect, region);
    SetNativeRegion(region);
  end;

  constructor TGPRegion.Create(path: TGPGraphicsPath);
  var
    region: GpRegion;
  begin
    region := nil;
    lastResult := GdipCreateRegionPath(path.nativePath, region);
    SetNativeRegion(region);
  end;

  constructor TGPRegion.Create(regionData: PBYTE; size: Integer);
  var
    region: GpRegion;
  begin
    region := nil;
    lastResult := GdipCreateRegionRgnData(regionData, size, region);
    SetNativeRegion(region);
  end;

  constructor TGPRegion.Create(hRgn: HRGN);
  var
    region: GpRegion;
  begin
    region := nil;
    lastResult := GdipCreateRegionHrgn(hRgn, region);
    SetNativeRegion(region);
  end;

  function TGPRegion.FromHRGN(hRgn: HRGN): TGPRegion;
  var
    region: GpRegion;
  begin
    region := nil;
    if (GdipCreateRegionHrgn(hRgn, region) = Ok) then
    begin
        result := TGPRegion.Create(region);
        if (result = nil) then
            GdipDeleteRegion(region);
        exit;
    end
    else
      result := nil;
  end;

  destructor TGPRegion.Destroy;
  begin
    GdipDeleteRegion(nativeRegion);
  end;

  function TGPRegion.Clone: TGPRegion;
  var region: GpRegion;
  begin
    region := nil;
    SetStatus(GdipCloneRegion(nativeRegion, region));
    result := TGPRegion.Create(region);
  end;

  function TGPRegion.MakeInfinite: TStatus;
  begin
    result := SetStatus(GdipSetInfinite(nativeRegion));
  end;

  function TGPRegion.MakeEmpty: TStatus;
  begin
    result := SetStatus(GdipSetEmpty(nativeRegion));
  end;

  // Get the size of the buffer needed for the GetData method
  function TGPRegion.GetDataSize: UINT;
  var bufferSize: UINT;
  begin
    bufferSize := 0;
    SetStatus(GdipGetRegionDataSize(nativeRegion, bufferSize));
    result := bufferSize;
  end;


    // buffer     - where to put the data
    // bufferSize - how big the buffer is (should be at least as big as GetDataSize())
    // sizeFilled - if not nil, this is an OUT param that says how many bytes
    //              of data were written to the buffer.

  function TGPRegion.GetData(buffer: PBYTE; bufferSize: UINT; sizeFilled: PUINT = nil): TStatus;
  begin
    result := SetStatus(GdipGetRegionData(nativeRegion, buffer, bufferSize, sizeFilled));
  end;

  function TGPRegion.Intersect(const rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRectI(nativeRegion, @rect, CombineModeIntersect));
  end;

  function TGPRegion.Intersect(const rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRect(nativeRegion, @rect, CombineModeIntersect));
  end;

  function TGPRegion.Intersect(path: TGPGraphicsPath): TStatus;
  begin
    result := SetStatus(GdipCombineRegionPath(nativeRegion, path.nativePath,
      CombineModeIntersect));
  end;

  function TGPRegion.Intersect(region: TGPRegion): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRegion(nativeRegion, region.nativeRegion,
      CombineModeIntersect));
  end;

  function TGPRegion.Union(const rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRectI(nativeRegion, @rect, CombineModeUnion));
  end;

  function TGPRegion.Union(const rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRect(nativeRegion, @rect, CombineModeUnion));
  end;

  function TGPRegion.Union(path: TGPGraphicsPath): TStatus;
  begin
    result := SetStatus(GdipCombineRegionPath(nativeRegion, path.nativePath, CombineModeUnion));
  end;

  function TGPRegion.Union(region: TGPRegion): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRegion(nativeRegion, region.nativeRegion,
      CombineModeUnion));
  end;

  function TGPRegion.Xor_(const rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRectI(nativeRegion, @rect, CombineModeXor));
  end;

  function TGPRegion.Xor_(const rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRect(nativeRegion, @rect, CombineModeXor));
  end;

  function TGPRegion.Xor_(path: TGPGraphicsPath): TStatus;
  begin
    result := SetStatus(GdipCombineRegionPath(nativeRegion, path.nativePath, CombineModeXor));
  end;

  function TGPRegion.Xor_(region: TGPRegion): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRegion(nativeRegion, region.nativeRegion,
      CombineModeXor));
  end;

  function TGPRegion.Exclude(const rect: TGPRect): TStatus;
  begin
     result := SetStatus(GdipCombineRegionRectI(nativeRegion, @rect, CombineModeExclude));
  end;

  function TGPRegion.Exclude(const rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRect(nativeRegion, @rect, CombineModeExclude));
  end;

  function TGPRegion.Exclude(path: TGPGraphicsPath): TStatus;
  begin
    result := SetStatus(GdipCombineRegionPath(nativeRegion, path.nativePath, CombineModeExclude));
  end;

  function TGPRegion.Exclude(region: TGPRegion): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRegion(nativeRegion,
                                               region.nativeRegion,
                                                         CombineModeExclude));
  end;

  function TGPRegion.Complement(const rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRectI(nativeRegion, @rect,
                                                        CombineModeComplement));
  end;

  function TGPRegion.Complement(const rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRect(nativeRegion, @rect,
                                                       CombineModeComplement));
  end;

  function TGPRegion.Complement(path: TGPGraphicsPath): TStatus;
  begin
    result := SetStatus(GdipCombineRegionPath(nativeRegion,
                                                path.nativePath,
                                                CombineModeComplement));
  end;

  function TGPRegion.Complement(region: TGPRegion): TStatus;
  begin
    result := SetStatus(GdipCombineRegionRegion(nativeRegion,
                                                  region.nativeRegion,
                                                         CombineModeComplement));
  end;

  function TGPRegion.Translate(const dx, dy: Single): TStatus;
  begin
    result := SetStatus(GdipTranslateRegion(nativeRegion, dx, dy));
  end;

  function TGPRegion.Translate(dx, dy: Integer): TStatus;
  begin
    result := SetStatus(GdipTranslateRegionI(nativeRegion, dx, dy));
  end;

  function TGPRegion.Transform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipTransformRegion(nativeRegion,
                                                     matrix.nativeMatrix));
  end;

  function TGPRegion.GetBounds(out rect: TGPRect; g: TGPGraphics): TStatus;
  begin
    result := SetStatus(GdipGetRegionBoundsI(nativeRegion,
                                                g.nativeGraphics,
                                                @rect));
  end;

  function TGPRegion.GetBounds(out rect: TGPRectF; g: TGPGraphics): TStatus;
  begin
    result := SetStatus(GdipGetRegionBounds(nativeRegion,
                                                g.nativeGraphics,
                                                @rect));
  end;

  function TGPRegion.GetHRGN(g: TGPGraphics): HRGN;
  begin
    SetStatus(GdipGetRegionHRgn(nativeRegion, g.nativeGraphics, result));
  end;

  function TGPRegion.IsEmpty(g: TGPGraphics): BOOL;
  var booln: BOOL;
  begin
    booln := FALSE;
    SetStatus(GdipIsEmptyRegion(nativeRegion, g.nativeGraphics, booln));
    result := booln;
  end;

  function TGPRegion.IsInfinite(g: TGPGraphics): BOOL ;
  var booln: BOOL;
  begin
    booln := FALSE;
    SetStatus(GdipIsInfiniteRegion(nativeRegion, g.nativeGraphics, booln));
    result := booln;
  end;

  function TGPRegion.IsVisible(x, y: Integer; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    GPX: GpGraphics;
  begin
    booln := FALSE;
    if assigned(g) then gpx := g.nativeGraphics else gpx := nil;
    SetStatus(GdipIsVisibleRegionPointI(nativeRegion, X, Y, gpx, booln));
    result := booln;
  end;

  function TGPRegion.IsVisible(const point: TGPPoint; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    GPX: GpGraphics;
  begin
    booln := FALSE;
    if assigned(g) then gpx := g.nativeGraphics else gpx := nil;
    SetStatus(GdipIsVisibleRegionPointI(nativeRegion, point.X, point.Y, gpx, booln));
    result := booln;
  end;

  function TGPRegion.IsVisible(const x, y: Single; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    GPX: GpGraphics;
  begin
    booln := FALSE;
    if assigned(g) then gpx := g.nativeGraphics else gpx := nil;
    SetStatus(GdipIsVisibleRegionPoint(nativeRegion, X, Y, gpx, booln));
    result := booln;
  end;

  function TGPRegion.IsVisible(const point: TGPPointF; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    GPX: GpGraphics;
  begin
    booln := FALSE;
    if assigned(g) then gpx := g.nativeGraphics else gpx := nil;
    SetStatus(GdipIsVisibleRegionPoint(nativeRegion, point.X, point.Y, gpx, booln));
    result := booln;
  end;

  function TGPRegion.IsVisible(x, y, width, height: Integer; g: TGPGraphics): BOOL;
  var
    booln: BOOL;
    GPX: GpGraphics;
  begin
    booln := FALSE;
    if assigned(g) then gpx := g.nativeGraphics else gpx := nil;
    SetStatus(GdipIsVisibleRegionRectI(nativeRegion,
                                                  X,
                                                  Y,
                                                  Width,
                                                  Height,
                                                  gpx,
                                                  booln));
    result := booln;
  end;

  function TGPRegion.IsVisible(const rect: TGPRect; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    GPX: GpGraphics;
  begin
    booln := FALSE;
    if assigned(g) then gpx := g.nativeGraphics else gpx := nil;
    SetStatus(GdipIsVisibleRegionRectI(nativeRegion,
                                                  rect.X,
                                                  rect.Y,
                                                  rect.Width,
                                                  rect.Height,
                                                  gpx,
                                                  booln));
    result := booln;
  end;

  function TGPRegion.IsVisible(const x, y, width, height: Single; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    GPX: GpGraphics;
  begin
    booln := FALSE;
    if assigned(g) then gpx := g.nativeGraphics else gpx := nil;
    SetStatus(GdipIsVisibleRegionRect(nativeRegion, X,
                                                    Y, Width,
                                                    Height,
                                                    gpx,
                                                    booln));
    result := booln;
  end;

  function TGPRegion.IsVisible(const rect: TGPRectF; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    GPX: GpGraphics;
  begin
    booln := FALSE;
    if assigned(g) then gpx := g.nativeGraphics else gpx := nil;
    SetStatus(GdipIsVisibleRegionRect(nativeRegion, rect.X,
                                                    rect.Y, rect.Width,
                                                    rect.Height,
                                                    gpx,
                                                    booln));
    result := booln;
  end;

  function TGPRegion.EqualsRegion(region: TGPRegion; g: TGPGraphics): BOOL;
  var
    booln: BOOL;
  begin
    booln := FALSE;
    SetStatus(GdipIsEqualRegion(nativeRegion,
                                              region.nativeRegion,
                                              g.nativeGraphics,
                                              booln));
    result := booln;
  end;

  function TGPRegion.GetRegionScansCount(matrix: TGPMatrix): UINT;
  var Count: UINT;
  begin
    count := 0;
    SetStatus(GdipGetRegionScansCount(nativeRegion, count, matrix.nativeMatrix));
    result := count;
  end;

  // If rects is nil, result := the count of rects in the region.
  // Otherwise, assume rects is big enough to hold all the region rects
  // and fill them in and result := the number of rects filled in.
  // The rects are result :=ed in the units specified by the matrix
  // (which is typically a world-to-device transform).
  // Note that the number of rects result :=ed can vary, depending on the
  // matrix that is used.

  function TGPRegion.GetRegionScans(matrix: TGPMatrix; rects: PGPRectF; out count: Integer): TStatus;
  begin
    result := SetStatus(GdipGetRegionScans(nativeRegion,
                                          rects,
                                          count,
                                          matrix.nativeMatrix));
  end;

  function TGPRegion.GetRegionScans(matrix: TGPMatrix; rects: PGPRect; out count: Integer): TStatus;
  begin
    result := SetStatus(GdipGetRegionScansI(nativeRegion,
                                          rects,
                                          count,
                                          matrix.nativeMatrix));
  end;

  function TGPRegion.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  function TGPRegion.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

  constructor TGPRegion.Create(nativeRegion: GpRegion);
  begin
    SetNativeRegion(nativeRegion);
  end;

  procedure TGPRegion.SetNativeRegion(nativeRegion: GpRegion);
  begin
    self.nativeRegion := nativeRegion;
  end;

(**************************************************************************\
*
*   GDI+ CustomLineCap APIs
*
\**************************************************************************)

  constructor TGPCustomLineCap.Create(fillPath, strokePath: TGPGraphicsPath;
                  baseCap: TLineCap = LineCapFlat; const baseInset: Single = 0);
  var nativeFillPath, nativeStrokePath: GpPath;
  begin
    nativeCap := nil;
    nativeFillPath := nil;
    nativeStrokePath := nil;

    if assigned(fillPath) then nativeFillPath := fillPath.nativePath;
    if assigned(strokePath) then nativeStrokePath := strokePath.nativePath;

    lastResult := GdipCreateCustomLineCap(nativeFillPath, nativeStrokePath,
                    baseCap, baseInset, nativeCap);
  end;

  destructor TGPCustomLineCap.Destroy;
  begin
    GdipDeleteCustomLineCap(nativeCap);
  end;

  function TGPCustomLineCap.Clone: TGPCustomLineCap;
  var newNativeLineCap: GpCustomLineCap;
  begin
    newNativeLineCap := nil;
    SetStatus(GdipCloneCustomLineCap(nativeCap, newNativeLineCap));
    if (lastResult = Ok) then
    begin
      result := TGPCustomLineCap.Create(newNativeLineCap, lastResult);
      if (result = nil) then
         SetStatus(GdipDeleteCustomLineCap(newNativeLineCap));
    end
    else
      result := nil;
  end;

  // This changes both the start and end cap.
  function TGPCustomLineCap.SetStrokeCap(strokeCap: TLineCap): TStatus;
  begin
    result := SetStrokeCaps(strokeCap, strokeCap);
  end;

  function TGPCustomLineCap.SetStrokeCaps(startCap, endCap: TLineCap): TStatus;
  begin
    result := SetStatus(GdipSetCustomLineCapStrokeCaps(nativeCap, startCap, endCap));
  end;

  function TGPCustomLineCap.GetStrokeCaps(out startCap, endCap: TLineCap): TStatus;
  begin
    result := SetStatus(GdipGetCustomLineCapStrokeCaps(nativeCap, startCap, endCap));
  end;

  function TGPCustomLineCap.SetStrokeJoin(lineJoin: TLineJoin): TStatus;
  begin
    result := SetStatus(GdipSetCustomLineCapStrokeJoin(nativeCap, lineJoin));
  end;

  function TGPCustomLineCap.GetStrokeJoin: TLineJoin;
  begin
    SetStatus(GdipGetCustomLineCapStrokeJoin(nativeCap, result));
  end;

  function TGPCustomLineCap.SetBaseCap(baseCap: TLineCap): TStatus;
  begin
    result := SetStatus(GdipSetCustomLineCapBaseCap(nativeCap, baseCap));
  end;

  function TGPCustomLineCap.GetBaseCap: TLineCap;
  begin
    SetStatus(GdipGetCustomLineCapBaseCap(nativeCap, result));
  end;

  function TGPCustomLineCap.SetBaseInset(const inset: Single): TStatus;
  begin
    result := SetStatus(GdipSetCustomLineCapBaseInset(nativeCap, inset));
  end;

  function TGPCustomLineCap.GetBaseInset: Single;
  begin
    SetStatus(GdipGetCustomLineCapBaseInset(nativeCap, result));
  end;

  function TGPCustomLineCap.SetWidthScale(const widthScale: Single): TStatus;
  begin
    result := SetStatus(GdipSetCustomLineCapWidthScale(nativeCap, widthScale));
  end;

  function TGPCustomLineCap.GetWidthScale: Single;
  begin
    SetStatus(GdipGetCustomLineCapWidthScale(nativeCap, result));
  end;

  function TGPCustomLineCap.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  constructor TGPCustomLineCap.Create;
  begin
    lastResult := Ok;
  end;

  constructor TGPCustomLineCap.Create(nativeCap: GpCustomLineCap; status: TStatus);
  begin
    lastResult := status;
    SetNativeCap(nativeCap);
  end;

  procedure TGPCustomLineCap.SetNativeCap(nativeCap: GpCustomLineCap);
  begin
    self.nativeCap := nativeCap;
  end;

  function TGPCustomLineCap.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

(**************************************************************************
*
* CachedBitmap class definition
*
*   GDI+ CachedBitmap is a representation of an accelerated drawing
*   that has restrictions on what operations are allowed in order
*   to accelerate the drawing to the destination.
*
**************************************************************************)

  constructor TGPCachedBitmap.Create(bitmap: TGPBitmap; graphics: TGPGraphics);
  begin
    lastResult := GdipCreateCachedBitmap(
        GpBitmap(bitmap.nativeImage),
        graphics.nativeGraphics,
        nativeCachedBitmap);
  end;

  destructor TGPCachedBitmap.Destroy;
  begin
    GdipDeleteCachedBitmap(nativeCachedBitmap);
  end;

  function TGPCachedBitmap.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

(**************************************************************************\
*
*   GDI+ Pen class
*
\**************************************************************************)

  //--------------------------------------------------------------------------
  // Pen class
  //--------------------------------------------------------------------------

  constructor TGPPen.Create(color: TGPColor; const width: Single = 1.0);
  var unit_: TUnit;
  begin
    unit_ := UnitWorld;
    lastResult := GdipCreatePen1(color, width, unit_, nativePen);
  end;

  constructor TGPPen.Create(brush: TGPBrush; const width: Single = 1.0);
  var unit_: TUnit;
  begin
    unit_ := UnitWorld;
    lastResult := GdipCreatePen2(brush.nativeBrush, width, unit_, nativePen);
  end;

  destructor TGPPen.Destroy;
  begin
    GdipDeletePen(nativePen);
  end;

  function TGPPen.Clone: TGPPen;
  var clonePen: GpPen;
  begin
    clonePen := nil;
    lastResult := GdipClonePen(nativePen, clonePen);
    result := TGPPen.Create(clonePen, lastResult);
  end;

  function TGPPen.SetWidth(const width: Single): TStatus;
  begin
    result := SetStatus(GdipSetPenWidth(nativePen, width));
  end;

  function TGPPen.GetWidth: Single;
  begin
    SetStatus(GdipGetPenWidth(nativePen, result));
  end;
    
  // Set/get line caps: start, end, and dash
  // Line cap and join APIs by using LineCap and LineJoin enums.

  function TGPPen.SetLineCap(startCap, endCap: TLineCap; dashCap: TDashCap): TStatus;
  begin
    result := SetStatus(GdipSetPenLineCap197819(nativePen, startCap, endCap, dashCap));
  end;

  function TGPPen.SetStartCap(startCap: TLineCap): TStatus;
  begin
    result := SetStatus(GdipSetPenStartCap(nativePen, startCap));
  end;

  function TGPPen.SetEndCap(endCap: TLineCap): TStatus;
  begin
    result := SetStatus(GdipSetPenEndCap(nativePen, endCap));
  end;

  function TGPPen.SetDashCap(dashCap: TDashCap): TStatus;
  begin
    result := SetStatus(GdipSetPenDashCap197819(nativePen, dashCap));
  end;

  function TGPPen.GetStartCap: TLineCap;
  begin
    SetStatus(GdipGetPenStartCap(nativePen, result));
  end;

  function TGPPen.GetEndCap: TLineCap;
  begin
    SetStatus(GdipGetPenEndCap(nativePen, result));
  end;

  function TGPPen.GetDashCap: TDashCap;
  begin
    SetStatus(GdipGetPenDashCap197819(nativePen, result));
  end;

  function TGPPen.SetLineJoin(lineJoin: TLineJoin): TStatus;
  begin
    result := SetStatus(GdipSetPenLineJoin(nativePen, lineJoin));
  end;

  function TGPPen.GetLineJoin: TLineJoin;
  begin
    SetStatus(GdipGetPenLineJoin(nativePen, result));
  end;

  function TGPPen.SetCustomStartCap(customCap: TGPCustomLineCap): TStatus;
  var nativeCap: GpCustomLineCap;
  begin
    nativeCap := nil;
    if assigned(customCap) then nativeCap := customCap.nativeCap;
    result := SetStatus(GdipSetPenCustomStartCap(nativePen, nativeCap));
  end;

  function TGPPen.GetCustomStartCap(customCap: TGPCustomLineCap): TStatus;
  begin
    if(customCap = nil) then
      result := SetStatus(InvalidParameter)
    else
      result := SetStatus(GdipGetPenCustomStartCap(nativePen, customCap.nativeCap));
  end;

  function TGPPen.SetCustomEndCap(customCap: TGPCustomLineCap): TStatus;
  var nativeCap: GpCustomLineCap;
  begin
    nativeCap := nil;
    if assigned(customCap) then nativeCap := customCap.nativeCap;
    result := SetStatus(GdipSetPenCustomEndCap(nativePen, nativeCap));
  end;

  function TGPPen.GetCustomEndCap(customCap: TGPCustomLineCap): TStatus;
  begin
    if(customCap = nil) then
      result := SetStatus(InvalidParameter)
    else
      result := SetStatus(GdipGetPenCustomEndCap(nativePen, customCap.nativeCap));
  end;

  function TGPPen.SetMiterLimit(const miterLimit: Single): TStatus;
  begin
    result := SetStatus(GdipSetPenMiterLimit(nativePen, miterLimit));
  end;

  function TGPPen.GetMiterLimit: Single;
  begin
    SetStatus(GdipGetPenMiterLimit(nativePen, result));
  end;

  function TGPPen.SetAlignment(penAlignment: TPenAlignment): TStatus;
  begin
    result := SetStatus(GdipSetPenMode(nativePen, penAlignment));
  end;

  function TGPPen.GetAlignment: TPenAlignment;
  begin
    SetStatus(GdipGetPenMode(nativePen, result));
  end;

  function TGPPen.SetWidthUnit(Value:TUnit):TStatus; //DB
  begin
    result := SetStatus(GdipSetPenUnit(nativePen, Value));
  end;

  function TGPPen.GetWidthUnit:TUnit; //DB
  begin
    SetStatus(GdipGetPenUnit(nativePen,result));
  end;

  function TGPPen.SetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipSetPenTransform(nativePen, matrix.nativeMatrix));
  end;

  function TGPPen.GetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipGetPenTransform(nativePen, matrix.nativeMatrix));
  end;

  function TGPPen.ResetTransform: TStatus;
  begin
    result := SetStatus(GdipResetPenTransform(nativePen));
  end;

  function TGPPen.MultiplyTransform(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipMultiplyPenTransform(nativePen, matrix.nativeMatrix, order));
  end;

  function TGPPen.TranslateTransform(const dx, dy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipTranslatePenTransform(nativePen, dx, dy, order));
  end;

  function TGPPen.ScaleTransform(const sx, sy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipScalePenTransform(nativePen, sx, sy, order));
  end;

  function TGPPen.RotateTransform(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipRotatePenTransform(nativePen, angle, order));
  end;

  function TGPPen.GetPenType: TPenType;
  begin
    SetStatus(GdipGetPenFillType(nativePen, result));
  end;

  function TGPPen.SetColor(color: TGPColor): TStatus;
  begin
    result := SetStatus(GdipSetPenColor(nativePen, color));
  end;

  function TGPPen.SetBrush(brush: TGPBrush): TStatus;
  begin
    result := SetStatus(GdipSetPenBrushFill(nativePen, brush.nativeBrush));
  end;

  function TGPPen.GetColor(out Color: TGPColor): TStatus;
  var
    type_: TPenType;
    argb: DWORD;
  begin
    type_ := GetPenType;

    if (type_ <> PenTypeSolidColor) then
    begin
      result := WrongState;
      exit;
    end;

    SetStatus(GdipGetPenColor(nativePen, argb));
    if (lastResult = Ok) then color := argb;
    result := lastResult;
  end;

  function TGPPen.GetBrush: TGPBrush;
  var
    type_: TPenType;
    Brush: TGPBrush;
    nativeBrush: GpBrush;
  begin
    type_ := GetPenType;
    brush := nil;

    case type_ of
       PenTypeSolidColor     : brush := TGPSolidBrush.Create;
       PenTypeHatchFill      : brush := TGPHatchBrush.Create;
       PenTypeTextureFill    : brush := TGPTextureBrush.Create;
       PenTypePathGradient   : brush := TGPBrush.Create;
       PenTypeLinearGradient : brush := TGPLinearGradientBrush.Create;
     end;

     if (brush <> nil) then
     begin
       SetStatus(GdipGetPenBrushFill(nativePen, nativeBrush));
       brush.SetNativeBrush(nativeBrush);
     end;

     result := brush;
  end;

  function TGPPen.GetDashStyle: TDashStyle;
  begin
    SetStatus(GdipGetPenDashStyle(nativePen, result));
  end;

  function TGPPen.SetDashStyle(dashStyle: TDashStyle): TStatus;
  begin
    result := SetStatus(GdipSetPenDashStyle(nativePen, dashStyle));
  end;

  function TGPPen.GetDashOffset: Single;
  begin
    SetStatus(GdipGetPenDashOffset(nativePen, result));
  end;

  function TGPPen.SetDashOffset(const dashOffset: Single): TStatus;
  begin
    result := SetStatus(GdipSetPenDashOffset(nativePen, dashOffset));
  end;
    
  function TGPPen.SetDashPattern(dashArray: PSingle; count: Integer): TStatus;
  begin
    result := SetStatus(GdipSetPenDashArray(nativePen, dashArray, count));
  end;

  function TGPPen.GetDashPatternCount: Integer;
  begin
    SetStatus(GdipGetPenDashCount(nativePen, result));
  end;

  function TGPPen.GetDashPattern(dashArray: PSingle; count: Integer): TStatus;
  begin
    result := SetStatus(GdipGetPenDashArray(nativePen, dashArray, count));
  end;

  function TGPPen.SetCompoundArray(compoundArray: PSingle; count: Integer): TStatus;
  begin
    result := SetStatus(GdipSetPenCompoundArray(nativePen, compoundArray, count));
  end;

  function TGPPen.GetCompoundArrayCount: Integer;
  begin
    SetStatus(GdipGetPenCompoundCount(nativePen, result));
  end;

  function TGPPen.GetCompoundArray(compoundArray: PSingle; count: Integer): TStatus;
  begin
    if (count <= 0) then
      result := SetStatus(InvalidParameter)
    else
      result := SetStatus(GdipGetPenCompoundArray(nativePen, compoundArray, count));
  end;

  function TGPPen.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  constructor TGPPen.Create(nativePen: GpPen; status: TStatus);
  begin
    lastResult := status;
    SetNativePen(nativePen);
  end;

  procedure TGPPen.SetNativePen(nativePen: GpPen);
  begin
    self.nativePen := nativePen;
  end;

  function TGPPen.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

(**************************************************************************\
*
*   GDI+ Brush class
*
\**************************************************************************)

//--------------------------------------------------------------------------
// Abstract base class for various brush types
//--------------------------------------------------------------------------

  destructor TGPBrush.Destroy;
  begin
    GdipDeleteBrush(nativeBrush);
  end;

  function TGPBrush.Clone: TGPBrush;
  var
    brush: GpBrush;
    newBrush: TGPBrush;
  begin
    brush := nil;
    SetStatus(GdipCloneBrush(nativeBrush, brush));
    newBrush := TGPBrush.Create(brush, lastResult);
    if (newBrush = nil) then
      GdipDeleteBrush(brush);
    result := newBrush;
  end;

  function TGPBrush.GetType: TBrushType;
  var type_: TBrushType;
  begin
    type_ := TBrushType(-1);
    SetStatus(GdipGetBrushType(nativeBrush, type_));
    result := type_;
  end;

  function TGPBrush.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  constructor TGPBrush.Create;
  begin
    SetStatus(NotImplemented);
  end;

  constructor TGPBrush.Create(nativeBrush: GpBrush; status: TStatus);
  begin
    lastResult := status;
    SetNativeBrush(nativeBrush);
  end;

  procedure TGPBrush.SetNativeBrush(nativeBrush: GpBrush);
  begin
    self.nativeBrush := nativeBrush;
  end;

  function TGPBrush.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

//--------------------------------------------------------------------------
// Solid Fill Brush Object
//--------------------------------------------------------------------------

  constructor TGPSolidBrush.Create(color: TGPColor);
  var
    brush: GpSolidFill;
  begin
    brush := nil;
    lastResult := GdipCreateSolidFill(color, brush);
    SetNativeBrush(brush);
  end;

  function TGPSolidBrush.GetColor(out color: TGPColor): TStatus;
  begin
    SetStatus(GdipGetSolidFillColor(GPSOLIDFILL(nativeBrush), color));
    result := lastResult;
  end;

  function TGPSolidBrush.SetColor(color: TGPColor): TStatus;
  begin
    result := SetStatus(GdipSetSolidFillColor(GpSolidFill(nativeBrush),
                color));
  end;

  constructor TGPSolidBrush.Create;
  begin
    // hide parent function
  end;

//--------------------------------------------------------------------------
// Texture Brush Fill Object
//--------------------------------------------------------------------------

  constructor TGPTextureBrush.Create(image: TGPImage; wrapMode: TWrapMode = WrapModeTile);
  var texture: GpTexture;
  begin
    //texture := nil;
    lastResult := GdipCreateTexture(image.nativeImage, wrapMode, texture);
    SetNativeBrush(texture);
  end;

  // When creating a texture brush from a metafile image, the dstRect
  // is used to specify the size that the metafile image should be
  // rendered at in the device units of the destination graphics.
  // It is NOT used to crop the metafile image, so only the width
  // and height values matter for metafiles.

  constructor TGPTextureBrush.Create(image: TGPImage; wrapMode: TWrapMode; const dstRect: TGPRectF);
  var texture: GpTexture;
  begin
    texture := nil;
    lastResult := GdipCreateTexture2(image.nativeImage, wrapMode, dstRect.X,
                    dstRect.Y, dstRect.Width, dstRect.Height, texture);
    SetNativeBrush(texture);
  end;

  constructor TGPTextureBrush.Create(image: TGPImage; const dstRect: TGPRectF; imageAttributes: TGPImageAttributes = nil);
  var texture: GpTexture;
      ImgAtt: GpImageAttributes;
  begin
    texture := nil;
    if assigned(imageAttributes) then ImgAtt := imageAttributes.nativeImageAttr
                                 else ImgAtt := nil;

    lastResult := GdipCreateTextureIA(image.nativeImage, ImgAtt, dstRect.X,
                    dstRect.Y, dstRect.Width, dstRect.Height, texture);
    SetNativeBrush(texture);
  end;

  constructor TGPTextureBrush.Create(image: TGPImage; const dstRect: TGPRect; imageAttributes: TGPImageAttributes = nil);
  var texture: GpTexture;
      ImgAtt: GpImageAttributes;
  begin
    texture := nil;
    if assigned(imageAttributes) then ImgAtt := imageAttributes.nativeImageAttr
                                 else ImgAtt := nil;
    lastResult := GdipCreateTextureIAI(image.nativeImage, ImgAtt, dstRect.X,
                    dstRect.Y, dstRect.Width, dstRect.Height, texture);
     SetNativeBrush(texture);
  end;

  constructor TGPTextureBrush.Create(image: TGPImage; wrapMode: TWrapMode; const dstRect: TGPRect);
  var texture: GpTexture;
  begin
    texture := nil;
    lastResult := GdipCreateTexture2I(image.nativeImage, wrapMode, dstRect.X,
                    dstRect.Y, dstRect.Width, dstRect.Height, texture);
    SetNativeBrush(texture);
  end;

  constructor TGPTextureBrush.Create(image: TGPImage; wrapMode: TWrapMode; const dstX, dstY, dstWidth, dstHeight: Single);
  var texture: GpTexture;
  begin
    texture := nil;
    lastResult := GdipCreateTexture2(image.nativeImage, wrapMode, dstX, dstY,
                    dstWidth, dstHeight, texture);
    SetNativeBrush(texture);
  end;

  constructor TGPTextureBrush.Create(image: TGPImage; wrapMode: TWrapMode; dstX, dstY, dstWidth, dstHeight: Integer);
  var texture: GpTexture;
  begin
    texture := nil;
    lastResult := GdipCreateTexture2I(image.nativeImage, wrapMode, dstX, dstY,
                    dstWidth, dstHeight, texture);
    SetNativeBrush(texture);
  end;

  function TGPTextureBrush.SetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipSetTextureTransform(GpTexture(nativeBrush),
                matrix.nativeMatrix));
  end;

  function TGPTextureBrush.GetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipGetTextureTransform(GpTexture(nativeBrush),
                matrix.nativeMatrix));
  end;

  function TGPTextureBrush.ResetTransform: TStatus;
  begin
    result := SetStatus(GdipResetTextureTransform(GpTexture(nativeBrush)));
  end;

  function TGPTextureBrush.MultiplyTransform(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipMultiplyTextureTransform(GpTexture(nativeBrush),
                matrix.nativeMatrix, order));
  end;

  function TGPTextureBrush.TranslateTransform(const dx, dy: Single; order: MatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipTranslateTextureTransform(GpTexture(nativeBrush),
                dx, dy, order));
  end;

  function TGPTextureBrush.ScaleTransform(const sx, sy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipScaleTextureTransform(GpTexture(nativeBrush),
                 sx, sy, order));
  end;

  function TGPTextureBrush.RotateTransform(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipRotateTextureTransform(GpTexture(nativeBrush),
                                                              angle, order));
  end;

  function TGPTextureBrush.SetWrapMode(wrapMode: TWrapMode): TStatus;
  begin
    result := SetStatus(GdipSetTextureWrapMode(GpTexture(nativeBrush), wrapMode));
  end;

  function TGPTextureBrush.GetWrapMode: TWrapMode;
  begin
    SetStatus(GdipGetTextureWrapMode(GpTexture(nativeBrush), result));
  end;

  function TGPTextureBrush.GetImage: TGPImage;
  var image: GpImage;
  begin
    SetStatus(GdipGetTextureImage(GpTexture(nativeBrush), image));
    result := TGPImage.Create(image, lastResult);
    if (result = nil) then
      GdipDisposeImage(image);
  end;

  constructor TGPTextureBrush.Create;
  begin
    // hide parent function
  end;

//--------------------------------------------------------------------------
// Linear Gradient Brush Object
//--------------------------------------------------------------------------

  constructor TGPLinearGradientBrush.Create(const point1, point2: TGPPointF; color1, color2: TGPColor);
  var brush: GpLineGradient;
  begin
    brush := nil;
    lastResult := GdipCreateLineBrush(@point1, @point2, color1, color2, WrapModeTile, brush);
    SetNativeBrush(brush);
  end;

  constructor TGPLinearGradientBrush.Create(const point1, point2: TGPPoint; color1, color2: TGPColor);
  var brush: GpLineGradient;
  begin
    brush := nil;
    lastResult := GdipCreateLineBrushI(@point1, @point2, color1,
                    color2, WrapModeTile, brush);
    SetNativeBrush(brush);
  end;

  constructor TGPLinearGradientBrush.Create(const rect: TGPRectF; color1, color2: TGPColor; mode: TLinearGradientMode);
  var brush: GpLineGradient;
  begin
    brush := nil;
    lastResult := GdipCreateLineBrushFromRect(@rect, color1,
                    color2, mode, WrapModeTile, brush);
    SetNativeBrush(brush);
  end;

  constructor TGPLinearGradientBrush.Create(const rect: TGPRect; color1, color2: TGPColor; mode: TLinearGradientMode);
  var brush: GpLineGradient;
  begin
    brush := nil;
    lastResult := GdipCreateLineBrushFromRectI(@rect, color1,
                    color2, mode, WrapModeTile, brush);
    SetNativeBrush(brush);
  end;

  constructor TGPLinearGradientBrush.Create(const rect: TGPRectF; color1, color2: TGPColor; const angle: Single; isAngleScalable: BOOL = FALSE);
  var brush: GpLineGradient;
  begin
    brush := nil;
    lastResult := GdipCreateLineBrushFromRectWithAngle(@rect, color1,
                    color2, angle, isAngleScalable, WrapModeTile, brush);
    SetNativeBrush(brush);
  end;

  constructor TGPLinearGradientBrush.Create(const rect: TGPRect; color1, color2: TGPColor; const angle: Single; isAngleScalable: BOOL = FALSE);
  var brush: GpLineGradient;
  begin
    brush := nil;
    lastResult := GdipCreateLineBrushFromRectWithAngleI(@rect, color1,
                    color2, angle, isAngleScalable, WrapModeTile, brush);
    SetNativeBrush(brush);
  end;

  function TGPLinearGradientBrush.SetLinearColors(color1, color2: TGPColor): TStatus;
  begin
    result := SetStatus(GdipSetLineColors(GpLineGradient(nativeBrush),
                color1, color2));
  end;

  function TGPLinearGradientBrush.GetLinearColors(out color1, color2: TGPColor): TStatus;
  var colors: array[0..1] of TGPColor;
  begin
    SetStatus(GdipGetLineColors(GpLineGradient(nativeBrush), @colors));
    if (lastResult = Ok) then
    begin
      color1 := colors[0];
      color2 := colors[1];
    end;
    result := lastResult;
  end;

  function TGPLinearGradientBrush.GetRectangle(out rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipGetLineRect(GpLineGradient(nativeBrush), @rect));
  end;

  function TGPLinearGradientBrush.GetRectangle(out rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipGetLineRectI(GpLineGradient(nativeBrush), @rect));
  end;

  function TGPLinearGradientBrush.SetGammaCorrection(useGammaCorrection: BOOL): TStatus;
  begin
    result := SetStatus(GdipSetLineGammaCorrection(GpLineGradient(nativeBrush),
                useGammaCorrection));
  end;
    
  function TGPLinearGradientBrush.GetGammaCorrection: BOOL;
  var useGammaCorrection: BOOL;
  begin
    SetStatus(GdipGetLineGammaCorrection(GpLineGradient(nativeBrush),
                useGammaCorrection));
    result := useGammaCorrection;
  end;

  function TGPLinearGradientBrush.GetBlendCount: Integer;
  var count: Integer;
  begin
    count := 0;
    SetStatus(GdipGetLineBlendCount(GpLineGradient(nativeBrush), count));
    result := count;
  end;

  function TGPLinearGradientBrush.SetBlend(blendFactors, blendPositions: PSingle; count: Integer): TStatus;
  begin
    result := SetStatus(GdipSetLineBlend(GpLineGradient(nativeBrush),
                          blendFactors, blendPositions, count));
  end;

  function TGPLinearGradientBrush.GetBlend(blendFactors, blendPositions: PSingle; count: Integer): TStatus;
  begin
    if ((count <= 0) or (blendFactors = nil) or (blendPositions = nil)) then
      result := SetStatus(InvalidParameter)
    else
      result := SetStatus(GdipGetLineBlend(GpLineGradient(nativeBrush), blendFactors,
        blendPositions, count));
  end;

  function TGPLinearGradientBrush.GetInterpolationColorCount: Integer;
  var count: Integer;
  begin
    count := 0;
    SetStatus(GdipGetLinePresetBlendCount(GpLineGradient(nativeBrush), count));
    result := count;
  end;

  function TGPLinearGradientBrush.SetInterpolationColors(presetColors: PGPColor;
    blendPositions: PSingle; count: Integer): TStatus;
  begin
    if (count <= 0)  then
      result := SetStatus(InvalidParameter)
    else
      result := SetStatus(GdipSetLinePresetBlend(GpLineGradient(nativeBrush),
        PARGB(presetColors), blendPositions, count));
  end;

  function TGPLinearGradientBrush.GetInterpolationColors(presetColors: PGPColor; blendPositions: PSingle; count: Integer): TStatus;
  begin
    if (count <= 0) then
      result := SetStatus(InvalidParameter)
    else
      result := SetStatus(GdipGetLinePresetBlend(GpLineGradient(nativeBrush),
                          PARGB(presetColors), blendPositions, count));
  end;

  function TGPLinearGradientBrush.SetBlendBellShape(const focus: Single; const scale: Single = 1.0): TStatus;
  begin
    result := SetStatus(GdipSetLineSigmaBlend(GpLineGradient(nativeBrush), focus, scale));
  end;

  function TGPLinearGradientBrush.SetBlendTriangularShape(const focus: Single; const scale: Single = 1.0): TStatus;
  begin
    result := SetStatus(GdipSetLineLinearBlend(GpLineGradient(nativeBrush), focus, scale));
  end;

  function TGPLinearGradientBrush.SetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipSetLineTransform(GpLineGradient(nativeBrush),
                                                          matrix.nativeMatrix));
  end;

  function TGPLinearGradientBrush.GetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipGetLineTransform(GpLineGradient(nativeBrush),
                                                     matrix.nativeMatrix));
  end;

  function TGPLinearGradientBrush.ResetTransform: TStatus;
  begin
    result := SetStatus(GdipResetLineTransform(GpLineGradient(nativeBrush)));
  end;

  function TGPLinearGradientBrush.MultiplyTransform(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipMultiplyLineTransform(GpLineGradient(nativeBrush),
                                                                matrix.nativeMatrix,
                                                                order));
  end;

  function TGPLinearGradientBrush.TranslateTransform(const dx, dy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipTranslateLineTransform(GpLineGradient(nativeBrush),
                                                               dx, dy, order));
  end;

  function TGPLinearGradientBrush.ScaleTransform(const sx, sy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipScaleLineTransform(GpLineGradient(nativeBrush),
                                                             sx, sy, order));
  end;

  function TGPLinearGradientBrush.RotateTransform(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipRotateLineTransform(GpLineGradient(nativeBrush),
                                                              angle, order));
  end;

  function TGPLinearGradientBrush.SetWrapMode(wrapMode: TWrapMode): TStatus;
  begin
    result := SetStatus(GdipSetLineWrapMode(GpLineGradient(nativeBrush), wrapMode));
  end;

  function TGPLinearGradientBrush.GetWrapMode: TWrapMode;
  begin
     SetStatus(GdipGetLineWrapMode(GpLineGradient(nativeBrush), result));
  end;

  constructor TGPLinearGradientBrush.Create;
  begin
    // hide parent function
  end;

//--------------------------------------------------------------------------
// Hatch Brush Object
//--------------------------------------------------------------------------

  constructor TGPHatchBrush.Create(hatchStyle: THatchStyle; foreColor: TGPColor; backColor: TGPColor = aclBlack);
  var
    brush: GpHatch;
  begin
    brush := nil;
    lastResult := GdipCreateHatchBrush(Integer(hatchStyle), foreColor, backColor, brush);
    SetNativeBrush(brush);
  end;

  function TGPHatchBrush.GetHatchStyle: THatchStyle;
  begin
    SetStatus(GdipGetHatchStyle(GpHatch(nativeBrush), result));
  end;

  function TGPHatchBrush.GetForegroundColor(out color: TGPColor): TStatus;
  begin
    result := SetStatus(GdipGetHatchForegroundColor(GpHatch(nativeBrush), color));
  end;

  function TGPHatchBrush.GetBackgroundColor(out color: TGPColor): TStatus;
  begin
    result := SetStatus(GdipGetHatchBackgroundColor(GpHatch(nativeBrush), color));
  end;

  constructor TGPHatchBrush.Create;
  begin
  end;

  constructor TGPImage.Create(filename: WideString;
                  useEmbeddedColorManagement: BOOL = FALSE);
  begin
    nativeImage := nil;
    if(useEmbeddedColorManagement) then
    begin
        lastResult := GdipLoadImageFromFileICM(
            PWideChar(filename),
            nativeImage
        );
    end
    else
    begin
        lastResult := GdipLoadImageFromFile(
            PWideChar(filename),
            nativeImage
        );
    end;
  end;

  constructor TGPImage.Create(stream: IStream;
                  useEmbeddedColorManagement: BOOL  = FALSE);
  begin
    nativeImage := nil;
    if(useEmbeddedColorManagement) then
         lastResult := GdipLoadImageFromStreamICM(stream, nativeImage)
    else lastResult := GdipLoadImageFromStream(stream, nativeImage);
  end;

  function TGPImage.FromFile(filename: WideString;
               useEmbeddedColorManagement: BOOL = FALSE): TGPImage;
  begin
    result := TGPImage.Create(
        PWideChar(filename),
        useEmbeddedColorManagement
    );
  end;

  function TGPImage.FromStream(stream: IStream;
               useEmbeddedColorManagement: BOOL = FALSE): TGPImage;
  begin
    result := TGPImage.Create(
        stream,
        useEmbeddedColorManagement
    );
  end;

  destructor TGPImage.Destroy;
  begin
    GdipDisposeImage(nativeImage);
  end;

  function TGPImage.Clone: TGPImage;
  var cloneimage: GpImage;
  begin
    cloneimage := nil;
    SetStatus(GdipCloneImage(nativeImage, cloneimage));
    result := TGPImage.Create(cloneimage, lastResult);
  end;

  function TGPImage.Save(filename: WideString; const clsidEncoder: TGUID;
               encoderParams: PEncoderParameters = nil): TStatus;
  begin
    result := SetStatus(GdipSaveImageToFile(nativeImage,
                                                     PWideChar(filename),
                                                     @clsidEncoder,
                                                     encoderParams));
  end;

  function TGPImage.Save(stream: IStream; const clsidEncoder: TGUID;
               encoderParams: PEncoderParameters  = nil): TStatus;
  begin
    result := SetStatus(GdipSaveImageToStream(nativeImage,
                                                       stream,
                                                       @clsidEncoder,
                                                       encoderParams));
  end;

  function TGPImage.SaveAdd(encoderParams: PEncoderParameters): TStatus;
  begin
    result := SetStatus(GdipSaveAdd(nativeImage,
                                             encoderParams));
  end;

  function TGPImage.SaveAdd(newImage: TGPImage;
               encoderParams: PEncoderParameters): TStatus;
  begin
    if (newImage = nil) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;
    result := SetStatus(GdipSaveAddImage(nativeImage,
                                                  newImage.nativeImage,
                                                  encoderParams));
  end;

  function TGPImage.GetType: TImageType;
  begin
    SetStatus(GdipGetImageType(nativeImage, result));
  end;

  function TGPImage.GetPhysicalDimension(out size: TGPSizeF): TStatus;
  var
    width, height: Single;
    status: TStatus;
  begin
    status := SetStatus(GdipGetImageDimension(nativeImage, width, height));
    size.Width  := width;
    size.Height := height;
    result := status;
  end;

  function TGPImage.GetBounds(out srcRect: TGPRectF; out srcUnit: TUnit): TStatus;
  begin
    result := SetStatus(GdipGetImageBounds(nativeImage, @srcRect, srcUnit));
  end;

  function TGPImage.GetWidth: UINT;
  var width: UINT;
  begin
    width := 0;
    SetStatus(GdipGetImageWidth(nativeImage, width));
    result := width;
  end;

  function TGPImage.GetHeight: UINT;
  var height: UINT;
  begin
    height := 0;
    SetStatus(GdipGetImageHeight(nativeImage, height));
    result := height;
  end;

  function TGPImage.GetHorizontalResolution: Single;
  var resolution: Single;
  begin
    resolution := 0.0;
    SetStatus(GdipGetImageHorizontalResolution(nativeImage, resolution));
    result := resolution;
  end;

  function TGPImage.GetVerticalResolution: Single;
  var resolution: Single;
  begin
    resolution := 0.0;
    SetStatus(GdipGetImageVerticalResolution(nativeImage, resolution));
    result := resolution;
  end;

  function TGPImage.GetFlags: UINT;
  var flags: UINT;
  begin
    flags := 0;
    SetStatus(GdipGetImageFlags(nativeImage, flags));
    result := flags;
  end;

  function TGPImage.GetRawFormat(out format: TGUID): TStatus;
  begin
    result := SetStatus(GdipGetImageRawFormat(nativeImage, @format));
  end;

  function TGPImage.GetPixelFormat: TPixelFormat;
  begin
    SetStatus(GdipGetImagePixelFormat(nativeImage, result));
  end;

  function TGPImage.GetPaletteSize: Integer;
  var size: Integer;
  begin
    size := 0;
    SetStatus(GdipGetImagePaletteSize(nativeImage, size));
    result := size;
  end;

  function TGPImage.GetPalette(palette: PColorPalette; size: Integer): TStatus;
  begin
    result := SetStatus(GdipGetImagePalette(nativeImage, palette, size));
  end;

  function TGPImage.SetPalette(palette: PColorPalette): TStatus;
  begin
    result := SetStatus(GdipSetImagePalette(nativeImage, palette));
  end;

  function TGPImage.GetThumbnailImage(thumbWidth, thumbHeight: UINT;
                callback: GetThumbnailImageAbort = nil;
                callbackData: pointer = nil): TGPImage;
  var
    thumbimage: GpImage;
    newImage: TGPImage;
  begin
    thumbimage := nil;
    SetStatus(GdipGetImageThumbnail(nativeImage,
                                                thumbWidth, thumbHeight,
                                                thumbimage,
                                                callback, callbackData));

    newImage := TGPImage.Create(thumbimage, lastResult);
    if (newImage = nil) then
        GdipDisposeImage(thumbimage);

    result := newImage;
  end;

  function TGPImage.GetFrameDimensionsCount: UINT;
  var count: UINT;
  begin
    count := 0;
    SetStatus(GdipImageGetFrameDimensionsCount(nativeImage, count));
    result := count;
  end;

  function TGPImage.GetFrameDimensionsList(dimensionIDs: PGUID; count: UINT): TStatus;
  begin
    result := SetStatus(GdipImageGetFrameDimensionsList(nativeImage, dimensionIDs, count));
  end;

  function TGPImage.GetFrameCount(const dimensionID: TGUID): UINT;
  var count: UINT;
  begin
    count := 0;
    SetStatus(GdipImageGetFrameCount(nativeImage, @dimensionID, count));
    result := count;
  end;

  function TGPImage.SelectActiveFrame(const dimensionID: TGUID; frameIndex: UINT): TStatus;
  begin
    result := SetStatus(GdipImageSelectActiveFrame(nativeImage,
                                                            @dimensionID,
                                                            frameIndex));
  end;

  function TGPImage.RotateFlip(rotateFlipType: TRotateFlipType): TStatus;
  begin
    result := SetStatus(GdipImageRotateFlip(nativeImage,
                                                     rotateFlipType));
  end;

  function TGPImage.GetPropertyCount: UINT;
  var numProperty: UINT;
  begin
    numProperty := 0;
    SetStatus(GdipGetPropertyCount(nativeImage, numProperty));
    result := numProperty;
  end;

  function TGPImage.GetPropertyIdList(numOfProperty: UINT; list: PPropID): TStatus;
  begin
    result := SetStatus(GdipGetPropertyIdList(nativeImage, numOfProperty, list));
  end;

  function TGPImage.GetPropertyItemSize(propId: PROPID): UINT;
  var size: UINT;
  begin
    size := 0;
    SetStatus(GdipGetPropertyItemSize(nativeImage, propId, size));
    result := size;
  end;

  function TGPImage.GetPropertyItem(propId: PROPID; propSize: UINT;
               buffer: PPropertyItem): TStatus;
  begin
    result := SetStatus(GdipGetPropertyItem(nativeImage,
                                                     propId, propSize, buffer));
  end;

  function TGPImage.GetPropertySize(out totalBufferSize, numProperties : UINT): TStatus;
  begin
    result := SetStatus(GdipGetPropertySize(nativeImage,
                                                     totalBufferSize,
                                                     numProperties));
  end;

  function TGPImage.GetAllPropertyItems(totalBufferSize, numProperties: UINT;
               allItems: PPROPERTYITEM): TStatus;
  begin
    result := SetStatus(GdipGetAllPropertyItems(nativeImage,
                                                         totalBufferSize,
                                                         numProperties,
                                                         allItems));
  end;

  function TGPImage.RemovePropertyItem(propId: TPROPID): TStatus;
  begin
    result := SetStatus(GdipRemovePropertyItem(nativeImage, propId));
  end;

  function TGPImage.SetPropertyItem(const item: TPropertyItem): TStatus;
  begin
    result := SetStatus(GdipSetPropertyItem(nativeImage, @item));
  end;

  function TGPImage.GetEncoderParameterListSize(const clsidEncoder: TGUID): UINT;
  var size: UINT;
  begin
    size := 0;
    SetStatus(GdipGetEncoderParameterListSize(nativeImage, @clsidEncoder, size));
    result := size;
  end;

  function TGPImage.GetEncoderParameterList(const clsidEncoder: TGUID; size: UINT;
               buffer: PEncoderParameters): TStatus;
  begin
    result := SetStatus(GdipGetEncoderParameterList(nativeImage,
                                                             @clsidEncoder,
                                                             size,
                                                             buffer));
  end;

  function TGPImage.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  constructor TGPImage.Create(nativeImage: GpImage; status: TStatus);
  begin
    SetNativeImage(nativeImage);
    lastResult := status;
  end;

  procedure TGPImage.SetNativeImage(nativeImage: GpImage);
  begin
    self.nativeImage := nativeImage;
  end;

  function TGPImage.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

  // TGPBitmap

  constructor TGPBitmap.Create(filename: WideString; useEmbeddedColorManagement: BOOL = FALSE);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    if(useEmbeddedColorManagement) then
      lastResult := GdipCreateBitmapFromFileICM(PWideChar(filename), bitmap)
    else
        lastResult := GdipCreateBitmapFromFile(PWideChar(filename), bitmap);
    SetNativeImage(bitmap);
  end;

  constructor TGPBitmap.Create(stream: IStream; useEmbeddedColorManagement: BOOL = FALSE);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    if(useEmbeddedColorManagement) then
      lastResult := GdipCreateBitmapFromStreamICM(stream, bitmap)
    else
        lastResult := GdipCreateBitmapFromStream(stream, bitmap);
    SetNativeImage(bitmap);
  end;

  function TGPBitmap.FromFile(filename: WideString; useEmbeddedColorManagement: BOOL = FALSE): TGPBitmap;
  begin
    result := TGPBitmap.Create(
        PWideChar(filename),
        useEmbeddedColorManagement
    );
  end;

  function TGPBitmap.FromStream(stream: IStream; useEmbeddedColorManagement: BOOL = FALSE): TGPBitmap;
  begin
    result := TGPBitmap.Create(
        stream,
        useEmbeddedColorManagement
    );
  end;

  constructor TGPBitmap.Create(width, height, stride: Integer; format: TPixelFormat; scan0: PBYTE);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    lastResult := GdipCreateBitmapFromScan0(width,
                                                       height,
                                                       stride,
                                                       format,
                                                       scan0,
                                                       bitmap);

    SetNativeImage(bitmap);
  end;

  constructor TGPBitmap.Create(width, height: Integer; format: TPixelFormat = PixelFormat32bppARGB);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    lastResult := GdipCreateBitmapFromScan0(width,
                                                       height,
                                                       0,
                                                       format,
                                                       nil,
                                                       bitmap);

    SetNativeImage(bitmap);
  end;

  constructor TGPBitmap.Create(width, height: Integer; target: TGPGraphics);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    lastResult := GdipCreateBitmapFromGraphics(width,
                                                          height,
                                                          target.nativeGraphics,
                                                          bitmap);

    SetNativeImage(bitmap);
  end;

  function TGPBitmap.Clone(const rect: TGPRect; format: TPixelFormat): TGPBitmap;
  begin
    result := Clone(rect.X, rect.Y, rect.Width, rect.Height, format);
  end;

  function TGPBitmap.Clone(x, y, width, height: Integer; format: TPixelFormat): TGPBitmap;
  var
    bitmap: TGPBitmap;
    gpdstBitmap: GpBitmap;
  begin
    gpdstBitmap := nil;
    lastResult := GdipCloneBitmapAreaI(
                               x,
                               y,
                               width,
                               height,
                               format,
                               GpBitmap(nativeImage),
                               gpdstBitmap);

    if (lastResult = Ok) then
    begin
       bitmap := TGPBitmap.Create(gpdstBitmap);
       if (bitmap = nil) then
         GdipDisposeImage(gpdstBitmap);
       result := bitmap;
       exit;
    end
    else
       result := nil;
  end;

  function TGPBitmap.Clone(const rect: TGPRectF; format: TPixelFormat): TGPBitmap;
  begin
    result := Clone(rect.X, rect.Y, rect.Width, rect.Height, format);
  end;

  function TGPBitmap.Clone(const x, y, width, height: Single; format: TPixelFormat): TGPBitmap;
  var
    bitmap: TGPBitmap;
    gpdstBitmap: GpBitmap;
  begin
    gpdstBitmap := nil;
    SetStatus(GdipCloneBitmapArea(
                               x,
                               y,
                               width,
                               height,
                               format,
                               GpBitmap(nativeImage),
                               gpdstBitmap));

   if (lastResult = Ok) then
   begin
     bitmap := TGPBitmap.Create(gpdstBitmap);
     if (bitmap = nil) then
       GdipDisposeImage(gpdstBitmap);
       result := bitmap;
   end
   else
       result := nil;
  end;

  function TGPBitmap.LockBits(const rect: TGPRect; flags: UINT; format: TPixelFormat;
               out lockedBitmapData: TBitmapData): TStatus;
  begin
    result := SetStatus(GdipBitmapLockBits(
                                    GpBitmap(nativeImage),
                                    @rect,
                                    flags,
                                    format,
                                    @lockedBitmapData));
  end;

  function TGPBitmap.UnlockBits(var lockedBitmapData: TBitmapData): TStatus;
  begin
    result := SetStatus(GdipBitmapUnlockBits(
                                    GpBitmap(nativeImage),
                                    @lockedBitmapData));
  end;

  function TGPBitmap.GetPixel(x, y: Integer; out color: TGPColor): TStatus;
  begin
    result := SetStatus(GdipBitmapGetPixel(GpBitmap(nativeImage), x, y, color));
  end;

  function TGPBitmap.SetPixel(x, y: Integer; color: TGPColor): TStatus;
  begin
    result := SetStatus(GdipBitmapSetPixel(
        GpBitmap(nativeImage),
        x, y,
        color));
  end;

  function TGPBitmap.SetResolution(const xdpi, ydpi: Single): TStatus;
  begin
    result := SetStatus(GdipBitmapSetResolution(
        GpBitmap(nativeImage),
        xdpi, ydpi));
  end;

(*
  constructor TGPBitmap.Create(surface: IDirectDrawSurface7);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    lastResult := GdipCreateBitmapFromDirectDrawSurface(surface, bitmap);
    SetNativeImage(bitmap);
  end;
*)

  constructor TGPBitmap.Create(var gdiBitmapInfo: TBITMAPINFO; gdiBitmapData: Pointer);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    lastResult := GdipCreateBitmapFromGdiDib(@gdiBitmapInfo, gdiBitmapData, bitmap);
    SetNativeImage(bitmap);
  end;

  constructor TGPBitmap.Create(hbm: HBITMAP; hpal: HPALETTE);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    lastResult := GdipCreateBitmapFromHBITMAP(hbm, hpal, bitmap);
    SetNativeImage(bitmap);
  end;

  constructor TGPBitmap.Create(hicon: HICON);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    lastResult := GdipCreateBitmapFromHICON(hicon, bitmap);
    SetNativeImage(bitmap);
  end;

  constructor TGPBitmap.Create(hInstance: HMODULE; bitmapName: WideString);
  var bitmap: GpBitmap;
  begin
    bitmap := nil;
    lastResult := GdipCreateBitmapFromResource(hInstance, PWideChar(bitmapName), bitmap);
    SetNativeImage(bitmap);
  end;

(*
  function TGPBitmap.FromDirectDrawSurface7(surface: IDirectDrawSurface7): TGPBitmap;
  begin
    result := TGPBitmap.Create(surface);
  end;
*)

  function TGPBitmap.FromBITMAPINFO(var gdiBitmapInfo: TBITMAPINFO; gdiBitmapData: Pointer): TGPBitmap;
  begin
    result := TGPBitmap.Create(gdiBitmapInfo, gdiBitmapData);
  end;

  function TGPBitmap.FromHBITMAP(hbm: HBITMAP; hpal: HPALETTE): TGPBitmap;
  begin
    result := TGPBitmap.Create(hbm, hpal);
  end;

  function TGPBitmap.FromHICON(hicon: HICON): TGPBitmap;
  begin
    result := TGPBitmap.Create(hicon);
  end;

  function TGPBitmap.FromResource(hInstance: HMODULE; bitmapName: WideString): TGPBitmap;
  begin
    result := TGPBitmap.Create(hInstance, PWideChar(bitmapName));
  end;

  function TGPBitmap.GetHBITMAP(colorBackground: TGPColor; out hbmreturn: HBITMAP): TStatus;
  begin
    result := SetStatus(GdipCreateHBITMAPFromBitmap(
                                        GpBitmap(nativeImage),
                                        hbmreturn,
                                        colorBackground));
  end;

  function TGPBitmap.GetHICON(out hicon: HICON): TStatus;
  begin
    result := SetStatus(GdipCreateHICONFromBitmap(
                                        GpBitmap(nativeImage),
                                        hicon));
  end;

  constructor TGPBitmap.Create(nativeBitmap: GpBitmap);
  begin
    lastResult := Ok;
    SetNativeImage(nativeBitmap);
  end;

(**************************************************************************\
*
*   GDI+ Graphics Object
*
\**************************************************************************)

  function TGPGraphics.FromHDC(hdc: HDC): TGPGraphics;
  begin
    result := TGPGraphics.Create(hdc);
  end;

  function TGPGraphics.FromHDC(hdc: HDC; hdevice: THANDLE): TGPGraphics;
  begin
    result := TGPGraphics.Create(hdc, hdevice);
  end;

  function TGPGraphics.FromHWND(hwnd: HWND; icm: BOOL = FALSE): TGPGraphics;
  begin
    result := TGPGraphics.Create(hwnd, icm);
  end;

  function TGPGraphics.FromImage(image: TGPImage): TGPGraphics;
  begin
    result := TGPGraphics.Create(image);
  end;

  constructor TGPGraphics.Create(hdc: HDC);
  var graphics: GpGraphics;
  begin
    graphics:= nil;
    lastResult := GdipCreateFromHDC(hdc, graphics);
    SetNativeGraphics(graphics);
  end;

  constructor TGPGraphics.Create(hdc: HDC; hdevice: THANDLE);
  var graphics: GpGraphics;
  begin
    graphics:= nil;
    lastResult := GdipCreateFromHDC2(hdc, hdevice, graphics);
    SetNativeGraphics(graphics);
  end;

  constructor TGPGraphics.Create(hwnd: HWND; icm: BOOL{ = FALSE});
  var graphics: GpGraphics;
  begin
    graphics:= nil;
    if icm then lastResult := GdipCreateFromHWNDICM(hwnd, graphics)
           else lastResult := GdipCreateFromHWND(hwnd, graphics);
    SetNativeGraphics(graphics);
  end;

  constructor TGPGraphics.Create(image: TGPImage);
  var graphics: GpGraphics;
  begin
    graphics:= nil;
    if (image <> nil) then
      lastResult := GdipGetImageGraphicsContext(image.nativeImage, graphics);
    SetNativeGraphics(graphics);
  end;

  destructor TGPGraphics.Destroy;
  begin
    GdipDeleteGraphics(nativeGraphics);
  end;

  procedure TGPGraphics.Flush(intention: TFlushIntention = FlushIntentionFlush);
  begin
    GdipFlush(nativeGraphics, intention);
  end;

    //------------------------------------------------------------------------
    // GDI Interop methods
    //------------------------------------------------------------------------

    // Locks the graphics until ReleaseDC is called

  function TGPGraphics.GetHDC: HDC;
  begin
    SetStatus(GdipGetDC(nativeGraphics, result));
  end;

  procedure TGPGraphics.ReleaseHDC(hdc: HDC);
  begin
    SetStatus(GdipReleaseDC(nativeGraphics, hdc));
  end;

    //------------------------------------------------------------------------
    // Rendering modes
    //------------------------------------------------------------------------

  function TGPGraphics.SetRenderingOrigin(x, y: Integer): TStatus;
  begin
    result := SetStatus(GdipSetRenderingOrigin(nativeGraphics, x, y));
  end;

  function TGPGraphics.GetRenderingOrigin(out x, y: Integer): TStatus;
  begin
    result := SetStatus(GdipGetRenderingOrigin(nativeGraphics, x, y));
  end;

  function TGPGraphics.SetCompositingMode(compositingMode: TCompositingMode): TStatus;
  begin
    result := SetStatus(GdipSetCompositingMode(nativeGraphics,
                                compositingMode));
  end;

  function TGPGraphics.GetCompositingMode: TCompositingMode;
  begin
    SetStatus(GdipGetCompositingMode(nativeGraphics, result));
  end;

  function TGPGraphics.SetCompositingQuality(compositingQuality: TCompositingQuality): TStatus;
  begin
    result := SetStatus(GdipSetCompositingQuality( nativeGraphics, compositingQuality));
  end;

  function TGPGraphics.GetCompositingQuality: TCompositingQuality;
  begin
    SetStatus(GdipGetCompositingQuality(nativeGraphics, result));
  end;

  function TGPGraphics.SetTextRenderingHint(newMode: TTextRenderingHint): TStatus;
  begin
    result := SetStatus(GdipSetTextRenderingHint(nativeGraphics, newMode));
  end;

  function TGPGraphics.GetTextRenderingHint: TTextRenderingHint;
  begin
    SetStatus(GdipGetTextRenderingHint(nativeGraphics, result));
  end;

  function TGPGraphics.SetTextContrast(contrast: UINT): TStatus;
  begin
    result := SetStatus(GdipSetTextContrast(nativeGraphics, contrast));
  end;

  function TGPGraphics.GetTextContrast: UINT;
  begin
    SetStatus(GdipGetTextContrast(nativeGraphics, result));
  end;

  function TGPGraphics.GetInterpolationMode: TInterpolationMode;
  var mode: TInterpolationMode;
  begin
    mode := InterpolationModeInvalid;
    SetStatus(GdipGetInterpolationMode(nativeGraphics, mode));
    result := mode;
  end;

  function TGPGraphics.SetInterpolationMode(interpolationMode: TInterpolationMode): TStatus;
  begin
    result := SetStatus(GdipSetInterpolationMode(nativeGraphics,
                               interpolationMode));
  end;

  function TGPGraphics.GetSmoothingMode: TSmoothingMode;
  var smoothingMode: TSmoothingMode;
  begin
    smoothingMode := SmoothingModeInvalid;
    SetStatus(GdipGetSmoothingMode(nativeGraphics,  smoothingMode));
    result := smoothingMode;
  end;

  function TGPGraphics.SetSmoothingMode(smoothingMode: TSmoothingMode): TStatus;
  begin
    result := SetStatus(GdipSetSmoothingMode(nativeGraphics, smoothingMode));
  end;

  function TGPGraphics.GetPixelOffsetMode: TPixelOffsetMode;
  var pixelOffsetMode: TPixelOffsetMode;
  begin
    pixelOffsetMode := PixelOffsetModeInvalid;
    SetStatus(GdipGetPixelOffsetMode(nativeGraphics, pixelOffsetMode));
    result := pixelOffsetMode;
  end;

  function TGPGraphics.SetPixelOffsetMode(pixelOffsetMode: TPixelOffsetMode): TStatus;
  begin
    result := SetStatus(GdipSetPixelOffsetMode(nativeGraphics, pixelOffsetMode));
  end;

    //------------------------------------------------------------------------
    // Manipulate current world transform
    //------------------------------------------------------------------------

  function TGPGraphics.SetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipSetWorldTransform(nativeGraphics, matrix.nativeMatrix));
  end;

  function TGPGraphics.ResetTransform: TStatus;
  begin
    result := SetStatus(GdipResetWorldTransform(nativeGraphics));
  end;

  function TGPGraphics.MultiplyTransform(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipMultiplyWorldTransform(nativeGraphics,
                                matrix.nativeMatrix,
                                order));
  end;

  function TGPGraphics.TranslateTransform(const dx, dy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipTranslateWorldTransform(nativeGraphics,
                                   dx, dy, order));
  end;

  function TGPGraphics.ScaleTransform(const sx, sy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipScaleWorldTransform(nativeGraphics,
                                 sx, sy, order));
  end;

  function TGPGraphics.RotateTransform(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipRotateWorldTransform(nativeGraphics,
                                  angle, order));
  end;

  function TGPGraphics.GetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipGetWorldTransform(nativeGraphics,
                               matrix.nativeMatrix));
  end;

  function TGPGraphics.SetPageUnit(unit_: TUnit): TStatus;
  begin
    result := SetStatus(GdipSetPageUnit(nativeGraphics,
                             unit_));
  end;

  function TGPGraphics.SetPageScale(const scale: Single): TStatus;
  begin
    result := SetStatus(GdipSetPageScale(nativeGraphics,
                              scale));
  end;

  function TGPGraphics.GetPageUnit: TUnit;
  begin
    SetStatus(GdipGetPageUnit(nativeGraphics, result));
  end;

  function TGPGraphics.GetPageScale: Single;
  begin
    SetStatus(GdipGetPageScale(nativeGraphics, result));
  end;

  function TGPGraphics.GetDpiX: Single;
  begin
    SetStatus(GdipGetDpiX(nativeGraphics, result));
  end;

  function TGPGraphics.GetDpiY: Single;
  begin
    SetStatus(GdipGetDpiY(nativeGraphics, result));
  end;

  function TGPGraphics.TransformPoints(destSpace: TCoordinateSpace;
               srcSpace: TCoordinateSpace;
               pts: PGPPointF;
               count: Integer): TStatus;
  begin
    result := SetStatus(GdipTransformPoints(nativeGraphics,
                             destSpace,
                             srcSpace,
                             pts,
                             count));
  end;

  function TGPGraphics.TransformPoints(destSpace: TCoordinateSpace;
               srcSpace: TCoordinateSpace;
               pts: PGPPoint;
               count: Integer): TStatus;
  begin

    result := SetStatus(GdipTransformPointsI(nativeGraphics,
                              destSpace,
                              srcSpace,
                              pts,
                              count));
  end;

    //------------------------------------------------------------------------
    // GetNearestColor (for <= 8bpp surfaces).  Note: Alpha is ignored.
    //------------------------------------------------------------------------

  function TGPGraphics.GetNearestColor(var color: TGPColor): TStatus;
  begin
    result := SetStatus(GdipGetNearestColor(nativeGraphics, @color));
  end;

  function TGPGraphics.DrawLine(pen: TGPPen; const x1, y1, x2, y2: Single): TStatus;
  begin
    result := SetStatus(GdipDrawLine(nativeGraphics,
                          pen.nativePen, x1, y1, x2,
                          y2));
  end;

  function TGPGraphics.DrawLine(pen: TGPPen; const pt1, pt2: TGPPointF): TStatus;
  begin
    result := DrawLine(pen, pt1.X, pt1.Y, pt2.X, pt2.Y);
  end;

  function TGPGraphics.DrawLines(pen: TGPPen; points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawLines(nativeGraphics,
                           pen.nativePen,
                           points, count));
  end;

  function TGPGraphics.DrawLine(pen: TGPPen; x1, y1, x2, y2: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawLineI(nativeGraphics,
                           pen.nativePen,
                           x1,
                           y1,
                           x2,
                           y2));
  end;

  procedure TGPGraphics.DrawLineFast(const pen: TGPPen; x1, y1, x2, y2: Integer);
  begin
    // Disable SetStatus for performance reasons.
    // Use the floating point GdipDrawLine version instead of the "I" integer
    // because the "I" internally calls the floating point.
    {result := SetStatus}(GdipDrawLine(nativeGraphics,
                           pen.nativePen,
                           x1,
                           y1,
                           x2,
                           y2));
  end;

  function TGPGraphics.DrawLine(pen: TGPPen; const pt1, pt2: TGPPoint): TStatus;
  begin
    result := DrawLine(pen,
            pt1.X,
            pt1.Y,
            pt2.X,
            pt2.Y);
  end;

  function TGPGraphics.DrawLines(pen: TGPPen; points: PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawLinesI(nativeGraphics,
                            pen.nativePen,
                            points,
                            count));
  end;

  function TGPGraphics.DrawArc(pen: TGPPen; x, y, width, height, startAngle, sweepAngle: Single): TStatus;
  begin
    result := SetStatus(GdipDrawArc(nativeGraphics,
                         pen.nativePen,
                         x,
                         y,
                         width,
                         height,
                         startAngle,
                         sweepAngle));
  end;

  function TGPGraphics.DrawArc(pen: TGPPen; const rect: TGPRectF; startAngle, sweepAngle: Single): TStatus;
  begin
    result := DrawArc(pen, rect.X, rect.Y, rect.Width, rect.Height,
               startAngle, sweepAngle);
  end;

  function TGPGraphics.DrawArc(pen: TGPPen; x, y, width, height: Integer; startAngle,
           sweepAngle: Single): TStatus; 
  begin
    result := SetStatus(GdipDrawArcI(nativeGraphics,
                          pen.nativePen,
                          x,
                          y,
                          width,
                          height,
                          startAngle,
                          sweepAngle));
  end;


  function TGPGraphics.DrawArc(pen: TGPPen; const rect: TGPRect; startAngle, sweepAngle: Single): TStatus;
  begin
    result := DrawArc(pen,
               rect.X,
               rect.Y,
               rect.Width,
               rect.Height,
               startAngle,
               sweepAngle);
  end;

  function TGPGraphics.DrawBezier(pen: TGPPen; x1, y1, x2, y2, x3, y3, x4, y4: Single): TStatus;
  begin
    result := SetStatus(GdipDrawBezier(nativeGraphics,
                            pen.nativePen, x1, y1,
                            x2, y2, x3, y3, x4, y4));
  end;

  function TGPGraphics.DrawBezier(pen: TGPPen; const pt1, pt2, pt3, pt4: TGPPointF): TStatus;
  begin
    result := DrawBezier(pen,
              pt1.X,
              pt1.Y,
              pt2.X,
              pt2.Y,
              pt3.X,
              pt3.Y,
              pt4.X,
              pt4.Y);
  end;

  function TGPGraphics.DrawBeziers(pen: TGPPen; points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawBeziers(nativeGraphics,
                             pen.nativePen,
                             points,
                             count));
  end;

  function TGPGraphics.DrawBezier(pen: TGPPen; x1, y1, x2, y2, x3, y3, x4, y4: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawBezierI(nativeGraphics,
                             pen.nativePen,
                             x1,
                             y1,
                             x2,
                             y2,
                             x3,
                             y3,
                             x4,
                             y4));
  end;

  function TGPGraphics.DrawBezier(pen: TGPPen; const pt1, pt2, pt3, pt4: TGPPoint): TStatus;
  begin
    result := DrawBezier(pen,
              pt1.X,
              pt1.Y,
              pt2.X,
              pt2.Y,
              pt3.X,
              pt3.Y,
              pt4.X,
              pt4.Y);
  end;

  function TGPGraphics.DrawBeziers(pen: TGPPen; points: PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawBeziersI(nativeGraphics,
                              pen.nativePen,
                              points,
                              count));
  end;

  function TGPGraphics.DrawRectangle(pen: TGPPen; const rect: TGPRectF): TStatus;
  begin
    result := DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
  end;

  function TGPGraphics.DrawRectangle(pen: TGPPen; x, y, width, height: Single): TStatus;
  begin
    result := SetStatus(GdipDrawRectangle(nativeGraphics,
                               pen.nativePen, x, y,
                               width, height));
  end;

  function TGPGraphics.DrawRectangles(pen: TGPPen;  rects: PGPRectF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawRectangles(nativeGraphics,
                            pen.nativePen,
                            rects, count));
  end;

  function TGPGraphics.DrawRectangle(pen: TGPPen; const rect: TGPRect): TStatus;
  begin
    result := DrawRectangle(pen,
                 rect.X,
                 rect.Y,
                 rect.Width,
                 rect.Height);
  end;

  function TGPGraphics.DrawRectangle(pen: TGPPen; x, y, width, height: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawRectangleI(nativeGraphics,
                            pen.nativePen,
                            x,
                            y,
                            width,
                            height));
  end;

  function TGPGraphics.DrawRectangles(pen: TGPPen; rects: PGPRect; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawRectanglesI(nativeGraphics,
                             pen.nativePen,
                             rects,
                             count));
  end;

  function TGPGraphics.DrawEllipse(pen: TGPPen; const rect: TGPRectF): TStatus;
  begin
    result := DrawEllipse(pen, rect.X, rect.Y, rect.Width, rect.Height);
  end;

  function TGPGraphics.DrawEllipse(pen: TGPPen; x, y, width, height: Single): TStatus;
  begin
    result := SetStatus(GdipDrawEllipse(nativeGraphics,
                             pen.nativePen,
                             x,
                             y,
                             width,
                             height));
  end;

  function TGPGraphics.DrawEllipse(pen: TGPPen; const rect: TGPRect): TStatus;
  begin
    result := DrawEllipse(pen,
               rect.X,
               rect.Y,
               rect.Width,
               rect.Height);
  end;

  function TGPGraphics.DrawEllipse(pen: TGPPen; x, y, width, height: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawEllipseI(nativeGraphics,
                              pen.nativePen,
                              x,
                              y,
                              width,
                              height));
  end;

  function TGPGraphics.DrawPie(pen: TGPPen; const rect: TGPRectF; startAngle, sweepAngle: Single): TStatus;
  begin
    result := DrawPie(pen,
               rect.X,
               rect.Y,
               rect.Width,
               rect.Height,
               startAngle,
               sweepAngle);
  end;

  function TGPGraphics.DrawPie(pen: TGPPen; x, y, width, height, startAngle, sweepAngle: Single): TStatus;
  begin
    result := SetStatus(GdipDrawPie(nativeGraphics,
                         pen.nativePen,
                         x,
                         y,
                         width,
                         height,
                         startAngle,
                         sweepAngle));
  end;

  function TGPGraphics.DrawPie(pen: TGPPen; const rect: TGPRect; startAngle, sweepAngle: Single): TStatus;
  begin
    result := DrawPie(pen,
               rect.X,
               rect.Y,
               rect.Width,
               rect.Height,
               startAngle,
               sweepAngle);
  end;

  function TGPGraphics.DrawPie(pen: TGPPen; x, y, width, height: Integer;
                 startAngle, sweepAngle: Single): TStatus;
  begin
    result := SetStatus(GdipDrawPieI(nativeGraphics,
                          pen.nativePen,
                          x,
                          y,
                          width,
                          height,
                          startAngle,
                          sweepAngle));
  end;

  function TGPGraphics.DrawPolygon(pen: TGPPen; points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawPolygon(nativeGraphics,
                             pen.nativePen,
                             points,
                             count));
  end;

  function TGPGraphics.DrawPolygon(pen: TGPPen; points: PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawPolygonI(nativeGraphics,
                              pen.nativePen,
                              points,
                              count));
  end;

  function TGPGraphics.DrawPath(pen: TGPPen; path: TGPGraphicsPath): TStatus;
  var
    nPen: GpPen;
    nPath: GpPath;
  begin
    if assigned(pen) then nPen := pen.nativePen else nPen  := nil;
    if assigned(path) then nPath := path.nativePath else nPath := nil;
    result := SetStatus(GdipDrawPath(nativeGraphics, nPen, nPath));
  end;

  function TGPGraphics.DrawCurve(pen: TGPPen; points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawCurve(nativeGraphics,
                           pen.nativePen, points,
                           count));
  end;

  function TGPGraphics.DrawCurve(pen: TGPPen; points: PGPPointF; count: Integer; tension: Single): TStatus;
  begin
    result := SetStatus(GdipDrawCurve2(nativeGraphics,
                            pen.nativePen, points,
                            count, tension));
  end;

  function TGPGraphics.DrawCurve(pen: TGPPen; points: PGPPointF; count, offset,
           numberOfSegments: Integer; tension: Single = 0.5): TStatus;
  begin
    result := SetStatus(GdipDrawCurve3(nativeGraphics,
                            pen.nativePen, points,
                            count, offset,
                            numberOfSegments, tension));
  end;

  function TGPGraphics.DrawCurve(pen: TGPPen; points: PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawCurveI(nativeGraphics,
                            pen.nativePen,
                            points,
                            count));
  end;

  function TGPGraphics.DrawCurve(pen: TGPPen; points: PGPPoint; count: Integer; tension: Single): TStatus;
  begin
    result := SetStatus(GdipDrawCurve2I(nativeGraphics,
                             pen.nativePen,
                             points,
                             count,
                             tension));
  end;

  function TGPGraphics.DrawCurve(pen: TGPPen; points: PGPPoint; count, offset,
           numberOfSegments: Integer; tension: Single = 0.5): TStatus; 
  begin
    result := SetStatus(GdipDrawCurve3I(nativeGraphics,
                             pen.nativePen,
                             points,
                             count,
                             offset,
                             numberOfSegments,
                             tension));
  end;

  function TGPGraphics.DrawClosedCurve(pen: TGPPen; points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawClosedCurve(nativeGraphics,
                             pen.nativePen,
                             points, count));
  end;

  function TGPGraphics.DrawClosedCurve(pen: TGPPen; points: PGPPointF; count: Integer;
           tension: Single): TStatus;
  begin
    result := SetStatus(GdipDrawClosedCurve2(nativeGraphics,
                              pen.nativePen,
                              points, count,
                              tension));
  end;

  function TGPGraphics.DrawClosedCurve(pen: TGPPen; points: PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawClosedCurveI(nativeGraphics,
                              pen.nativePen,
                              points,
                              count));
  end;

  function TGPGraphics.DrawClosedCurve(pen: TGPPen; points: PGPPoint;
           count: Integer; tension: Single): TStatus; 
  begin
    result := SetStatus(GdipDrawClosedCurve2I(nativeGraphics,
                               pen.nativePen,
                               points,
                               count,
                               tension));
  end;

  function TGPGraphics.Clear(color: TGPColor): TStatus;
  begin
    result := SetStatus(GdipGraphicsClear(
        nativeGraphics,
        color));
  end;

  function TGPGraphics.FillRectangle(brush: TGPBrush; const rect: TGPRectF): TStatus;
  begin
    result := FillRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height);
  end;

  function TGPGraphics.FillRectangle(brush: TGPBrush; x, y, width, height: Single): TStatus;
  begin
    result := SetStatus(GdipFillRectangle(nativeGraphics,
                               brush.nativeBrush, x, y,
                               width, height));
  end;

  function TGPGraphics.FillRectangles(brush: TGPBrush; rects: PGPRectF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipFillRectangles(nativeGraphics,
                            brush.nativeBrush,
                            rects, count));
  end;

  function TGPGraphics.FillRectangle(brush: TGPBrush; const rect: TGPRect): TStatus;
  begin
    result := FillRectangle(brush,
                 rect.X,
                 rect.Y,
                 rect.Width,
                 rect.Height);
  end;

  function TGPGraphics.FillRectangle(brush: TGPBrush; x, y, width, height: Integer): TStatus;
  begin
    result := SetStatus(GdipFillRectangleI(nativeGraphics,
                            brush.nativeBrush,
                            x,
                            y,
                            width,
                            height));
  end;

  function TGPGraphics.FillRectangles(brush: TGPBrush; rects: PGPRect; count: Integer): TStatus;
  begin
    result := SetStatus(GdipFillRectanglesI(nativeGraphics,
                             brush.nativeBrush,
                             rects,
                             count));
  end;

  function TGPGraphics.FillPolygon(brush: TGPBrush; points: PGPPointF; count: Integer): TStatus;
  begin
    result := FillPolygon(brush, points, count, FillModeAlternate);
  end;

  function TGPGraphics.FillPolygon(brush: TGPBrush; points: PGPPointF; count: Integer;
               fillMode: TFillMode): TStatus;
  begin
    result := SetStatus(GdipFillPolygon(nativeGraphics,
                             brush.nativeBrush,
                             points, count, fillMode));
  end;

  function TGPGraphics.FillPolygon(brush: TGPBrush; points: PGPPoint; count: Integer): TStatus;
  begin
    result := FillPolygon(brush, points, count, FillModeAlternate);
  end;

  function TGPGraphics.FillPolygon(brush: TGPBrush; points: PGPPoint; count: Integer;
               fillMode: TFillMode): TStatus;
  begin
    result := SetStatus(GdipFillPolygonI(nativeGraphics,
                              brush.nativeBrush,
                              points, count,
                              fillMode));
  end;

  function TGPGraphics.FillEllipse(brush: TGPBrush; const rect: TGPRectF): TStatus;
  begin
    result := FillEllipse(brush, rect.X, rect.Y, rect.Width, rect.Height);
  end;

  function TGPGraphics.FillEllipse(brush: TGPBrush; x, y, width, height: Single): TStatus;
  begin
    result := SetStatus(GdipFillEllipse(nativeGraphics,
                             brush.nativeBrush, x, y,
                             width, height));
  end;

  function TGPGraphics.FillEllipse(brush: TGPBrush; const rect: TGPRect): TStatus;
  begin
    result := FillEllipse(brush, rect.X, rect.Y, rect.Width, rect.Height);
  end;

  function TGPGraphics.FillEllipse(brush: TGPBrush; x, y, width, height: Integer): TStatus;
  begin
    result := SetStatus(GdipFillEllipseI(nativeGraphics,
                              brush.nativeBrush,
                              x,
                              y,
                              width,
                              height));
  end;

  function TGPGraphics.FillPie(brush: TGPBrush; const rect: TGPRectF; startAngle, sweepAngle: Single): TStatus;
  begin
    result := FillPie(brush, rect.X, rect.Y, rect.Width, rect.Height,
               startAngle, sweepAngle);
  end;

  function TGPGraphics.FillPie(brush: TGPBrush; x, y, width, height, startAngle, sweepAngle: Single): TStatus;
  begin
    result := SetStatus(GdipFillPie(nativeGraphics,
                         brush.nativeBrush, x, y,
                         width, height, startAngle,
                         sweepAngle));
  end;

  function TGPGraphics.FillPie(brush: TGPBrush; const rect: TGPRect; startAngle, sweepAngle: Single): TStatus;
  begin
    result := FillPie(brush, rect.X, rect.Y, rect.Width, rect.Height,
               startAngle, sweepAngle);
  end;

  function TGPGraphics.FillPie(brush: TGPBrush; x, y, width, height: Integer; startAngle,
           sweepAngle: Single): TStatus; 
  begin
    result := SetStatus(GdipFillPieI(nativeGraphics,
                          brush.nativeBrush,
                          x,
                          y,
                          width,
                          height,
                          startAngle,
                          sweepAngle));
  end;

  function TGPGraphics.FillPath(brush: TGPBrush; path: TGPGraphicsPath): TStatus;
  begin
    result := SetStatus(GdipFillPath(nativeGraphics,
                          brush.nativeBrush,
                          path.nativePath));
  end;

  function TGPGraphics.FillClosedCurve(brush: TGPBrush; points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipFillClosedCurve(nativeGraphics,
                             brush.nativeBrush,
                             points, count));

  end;

  function TGPGraphics.FillClosedCurve(brush: TGPBrush; points: PGPPointF; count: Integer;
               fillMode: TFillMode; tension: Single = 0.5): TStatus;
  begin
    result := SetStatus(GdipFillClosedCurve2(nativeGraphics,
                              brush.nativeBrush,
                              points, count,
                              tension, fillMode));
  end;

  function TGPGraphics.FillClosedCurve(brush: TGPBrush; points:  PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipFillClosedCurveI(nativeGraphics,
                              brush.nativeBrush,
                              points,
                              count));
  end;

  function TGPGraphics.FillClosedCurve(brush: TGPBrush; points: PGPPoint;
           count: Integer; fillMode: TFillMode; tension: Single = 0.5): TStatus;
  begin
    result := SetStatus(GdipFillClosedCurve2I(nativeGraphics,
                               brush.nativeBrush,
                               points, count,
                               tension, fillMode));
  end;

  function TGPGraphics.FillRegion(brush: TGPBrush; region: TGPRegion): TStatus;
  begin
    result := SetStatus(GdipFillRegion(nativeGraphics,
                            brush.nativeBrush,
                            region.nativeRegion));
  end;


  function TGPGraphics.DrawString( string_: WideString; length: Integer; font: TGPFont;
     const layoutRect: TGPRectF; stringFormat: TGPStringFormat; brush: TGPBrush): TStatus;
  var
    nFont: GpFont;
    nStringFormat: GpStringFormat;
    nBrush: GpBrush;
  begin
    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    if assigned(stringFormat) then nstringFormat := stringFormat.nativeFormat else nstringFormat := nil;
    if assigned(brush) then nbrush := brush.nativeBrush else nbrush := nil;
    result := SetStatus(GdipDrawString(
        nativeGraphics,
        PWideChar(string_),
        length,
        nfont,
        @layoutRect,
        nstringFormat,
        nbrush));
  end;

  function TGPGraphics.DrawString(string_: WideString; length: Integer; font: TGPFont;
           const origin: TGPPointF; brush: TGPBrush): TStatus;
  var
    rect: TGPRectF;
    nfont: Gpfont;
    nBrush: GpBrush;
  begin
    rect.X := origin.X;
    rect.Y := origin.Y;
    rect.Width := 0.0;
    rect.Height := 0.0;
    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    if assigned(Brush) then nBrush := Brush.nativeBrush else nBrush := nil;
    result := SetStatus(GdipDrawString(
        nativeGraphics,
        PWideChar(string_),
        length,
        nfont,
        @rect,
        nil,
        nbrush));
  end;

  function TGPGraphics.DrawString(string_: WideString; length: Integer; font: TGPFont;
      const origin: TGPPointF; stringFormat: TGPStringFormat; brush: TGPBrush): TStatus;
  var
    rect: TGPRectF;
    nFont: GpFont;
    nStringFormat: GpStringFormat;
    nBrush: GpBrush;
  begin
    rect.X := origin.X;
    rect.Y := origin.Y;
    rect.Width := 0.0;
    rect.Height := 0.0;
    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    if assigned(stringFormat) then nstringFormat := stringFormat.nativeFormat else nstringFormat := nil;
    if assigned(brush) then nbrush := brush.nativeBrush else nbrush := nil;
    result := SetStatus(GdipDrawString(
        nativeGraphics,
        PWideChar(string_),
        length,
        nfont,
        @rect,
        nstringFormat,
        nbrush));
  end;


  function TGPGraphics.MeasureString(string_: WideString; length: Integer; font: TGPFont;
       const layoutRect: TGPRectF; stringFormat: TGPStringFormat; out boundingBox: TGPRectF;
       codepointsFitted: PInteger = nil; linesFilled: PInteger = nil): TStatus;
  var
    nFont: GpFont;
    nStringFormat: GpStringFormat;
  begin
    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    if assigned(stringFormat) then nstringFormat := stringFormat.nativeFormat else nstringFormat := nil;
    result := SetStatus(GdipMeasureString(
        nativeGraphics,
        PWideChar(string_),
        length,
        nfont,
        @layoutRect,
        nstringFormat,
        @boundingBox,
        codepointsFitted,
        linesFilled
    ));
  end;


  function TGPGraphics.MeasureString(string_: WideString; length: Integer; font: TGPFont;
       const layoutRectSize: TGPSizeF; stringFormat: TGPStringFormat; out size: TGPSizeF;
       codepointsFitted: PInteger = nil; linesFilled: PInteger = nil): TStatus;
  var
    layoutRect, boundingBox: TGPRectF;
    status: TStatus;
    nFont: GpFont;
    nStringFormat: GpStringFormat;
  begin
    layoutRect.X := 0;
    layoutRect.Y := 0;
    layoutRect.Width := layoutRectSize.Width;
    layoutRect.Height := layoutRectSize.Height;

    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    if assigned(stringFormat) then nstringFormat := stringFormat.nativeFormat else nstringFormat := nil;

    status := SetStatus(GdipMeasureString(
        nativeGraphics,
        PWideChar(string_),
        length,
        nfont,
        @layoutRect,
        nstringFormat,
        @boundingBox,
        codepointsFitted,
        linesFilled
    ));

    if (status = Ok) then
    begin
      size.Width  := boundingBox.Width;
      size.Height := boundingBox.Height;
    end;
    result := status;
  end;

    
  function TGPGraphics.MeasureString(string_: WideString ; length: Integer; font: TGPFont;
       const origin: TGPPointF; stringFormat: TGPStringFormat; out boundingBox: TGPRectF): TStatus;
  var
    rect: TGPRectF;
    nFont: GpFont;
    nstringFormat: GpstringFormat;
  begin
    rect.X := origin.X;
    rect.Y := origin.Y;
    rect.Width := 0.0;
    rect.Height := 0.0;

    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    if assigned(stringFormat) then nstringFormat := stringFormat.nativeFormat else nstringFormat := nil;

    result := SetStatus(GdipMeasureString(
        nativeGraphics,
        PWideChar(string_),
        length,
        nfont,
        @rect,
        nstringFormat,
        @boundingBox,
        nil,
        nil
    ));
  end;

    
  function TGPGraphics.MeasureString(string_: WideString; length: Integer; font: TGPFont;
       const layoutRect: TGPRectF; out boundingBox: TGPRectF): TStatus;
  var
    nFont: GpFont;
  begin
    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    result := SetStatus(GdipMeasureString(
        nativeGraphics,
        PWideChar(string_),
        length,
        nfont,
        @layoutRect,
        nil,
        @boundingBox,
        nil,
        nil
    ));
  end;

    
  function TGPGraphics.MeasureString(string_: WideString; length: Integer; font: TGPFont;
       const origin: TGPPointF; out boundingBox: TGPRectF): TStatus;
  var
    nFont: GpFont;
    rect: TGPRectF;
  begin
    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    rect.X := origin.X;
    rect.Y := origin.Y;
    rect.Width := 0.0;
    rect.Height := 0.0;

    result := SetStatus(GdipMeasureString(
        nativeGraphics,
        PWideChar(string_),
        length,
        nfont,
        @rect,
        nil,
        @boundingBox,
        nil,
        nil
    ));
  end;



  function TGPGraphics.MeasureCharacterRanges(string_: WideString; length: Integer; font: TGPFont;
       const layoutRect: TGPRectF; stringFormat: TGPStringFormat; regionCount: Integer;
       const regions: array of TGPRegion): TStatus;
  var
    nativeRegions: Pointer;
    i: Integer;
    Status: TStatus;
    nFont: GpFont;
    nstringFormat: GpstringFormat;
  type
    TArrayGpRegion = array of GpRegion;
  begin
    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    if assigned(stringFormat) then nstringFormat := stringFormat.nativeFormat else nstringFormat := nil;

    if (regionCount <= 0) then
    begin
      result := InvalidParameter;
      exit;
    end;

    getmem(nativeRegions, Sizeof(GpRegion)* regionCount);

    for i := 0 to regionCount - 1 do
      TArrayGpRegion(nativeRegions)[i] := regions[i].nativeRegion;

    status := SetStatus(GdipMeasureCharacterRanges(
        nativeGraphics,
        PWideChar(string_),
        length,
        nfont,
        @layoutRect,
        nstringFormat,
        regionCount,
        nativeRegions
    ));

    freemem(nativeRegions, Sizeof(GpRegion)* regionCount);
    result := status;
  end;

  function TGPGraphics.DrawDriverString(text: PUINT16; length: Integer; font: TGPFont
       ; brush: TGPBrush; positions: PGPPointF; flags: Integer
       ; matrix: TGPMatrix): TStatus;
  var
    nfont: Gpfont;
    nbrush: Gpbrush;
    nmatrix: Gpmatrix;
  begin
    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    if assigned(brush) then nbrush := brush.nativeBrush else nbrush := nil;
    if assigned(matrix) then nmatrix := matrix.nativeMatrix else nmatrix := nil;

    result := SetStatus(GdipDrawDriverString(
        nativeGraphics,
        text,
        length,
        nfont,
        nbrush,
        positions,
        flags,
        nmatrix));
  end;

  function TGPGraphics.MeasureDriverString(text: PUINT16; length: Integer; font: TGPFont;
       positions: PGPPointF; flags: Integer; matrix: TGPMatrix;
       out boundingBox: TGPRectF): TStatus;
  var
    nfont: Gpfont;
    nmatrix: Gpmatrix;
  begin
    if assigned(font) then nfont := font.nativeFont else nfont := nil;
    if assigned(matrix) then nmatrix := matrix.nativeMatrix else nmatrix := nil;

    result := SetStatus(GdipMeasureDriverString(
        nativeGraphics,
        text,
        length,
        nfont,
        positions,
        flags,
        nmatrix,
        @boundingBox
    ));
  end;

    // Draw a cached bitmap on this graphics destination offset by
    // x, y. Note this will fail with WrongState if the CachedBitmap
    // native format differs from this Graphics.

  function TGPGraphics.DrawCachedBitmap(cb: TGPCachedBitmap;  x, y: Integer): TStatus;
  begin
    result := SetStatus(GdipDrawCachedBitmap(
        nativeGraphics,
        cb.nativeCachedBitmap,
        x, y
    ));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; const point: TGPPointF): TStatus;
  begin
    result := DrawImage(image, point.X, point.Y);
  end;

  function TGPGraphics.DrawImage(image: TGPImage; x, y: Single): TStatus;
  var
   nImage: GpImage;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    result := SetStatus(GdipDrawImage(nativeGraphics, nImage, x, y));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; const rect: TGPRectF): TStatus;
  begin
    result := DrawImage(image, rect.X, rect.Y, rect.Width, rect.Height);
  end;

  function TGPGraphics.DrawImage(image: TGPImage; x, y, width, height: Single): TStatus;
  var
   nImage: GpImage;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    result := SetStatus(GdipDrawImageRect(nativeGraphics,
                               nimage,
                               x,
                               y,
                               width,
                               height));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; const point: TGPPoint): TStatus;
  begin
    result := DrawImage(image, point.X, point.Y);
  end;

  function TGPGraphics.DrawImage(image: TGPImage; x, y: Integer): TStatus;
  var
   nImage: GpImage;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    result := SetStatus(GdipDrawImageI(nativeGraphics,
                            nimage,
                            x,
                            y));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; const rect: TGPRect): TStatus;
  begin
    result := DrawImage(image,
             rect.X,
             rect.Y,
             rect.Width,
             rect.Height);
  end;

  function TGPGraphics.DrawImage(image: TGPImage; x, y, width, height: Integer): TStatus;
  var
   nImage: GpImage;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    result := SetStatus(GdipDrawImageRectI(nativeGraphics,
                            nimage,
                            x,
                            y,
                            width,
                            height));
  end;


    // Affine Draw Image
    // destPoints.length = 3: rect => parallelogram
    //     destPoints[0] <=> top-left corner of the source rectangle
    //     destPoints[1] <=> top-right corner
    //     destPoints[2] <=> bottom-left corner
    // destPoints.length = 4: rect => quad
    //     destPoints[3] <=> bottom-right corner

  function TGPGraphics.DrawImage(image: TGPImage; destPoints: PGPPointF; count: Integer): TStatus;
  var
   nImage: GpImage;
  begin
    if (((count <> 3) and (count <> 4)) or (destPoints = nil)) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    result := SetStatus(GdipDrawImagePoints(nativeGraphics,
                             nimage,
                             destPoints, count));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; destPoints: PGPPoint; count: Integer): TStatus;
  var
   nImage: GpImage;
  begin
    if (((count <> 3) and (count <> 4))or (destPoints = nil)) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;

    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    result := SetStatus(GdipDrawImagePointsI(nativeGraphics,
                              nimage,
                              destPoints,
                              count));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; x, y, srcx, srcy, srcwidth, srcheight: Single;
        srcUnit: TUnit): TStatus;
  var
    nImage: GpImage;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    result := SetStatus(GdipDrawImagePointRect(nativeGraphics,
                                nimage,
                                x, y,
                                srcx, srcy,
                                srcwidth, srcheight, srcUnit));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; const destRect: TGPRectF; srcx, srcy, srcwidth, srcheight: Single;
       srcUnit: TUnit; imageAttributes: TGPImageAttributes = nil; callback: DrawImageAbort = nil;
       callbackData: Pointer = nil): TStatus;
  var
    nImage: GpImage;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipDrawImageRectRect(nativeGraphics,
                               nimage,
                               destRect.X,
                               destRect.Y,
                               destRect.Width,
                               destRect.Height,
                               srcx, srcy,
                               srcwidth, srcheight,
                               srcUnit,
                               nimageAttributes,
                               callback,
                               callbackData));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; destPoints: PGPPointF; count: Integer;
       srcx, srcy, srcwidth, srcheight: Single; srcUnit: TUnit;
       imageAttributes: TGPImageAttributes = nil; callback: DrawImageAbort = nil;
       callbackData: Pointer = nil): TStatus;
  var
    nImage: GpImage;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipDrawImagePointsRect(nativeGraphics,
                                 nimage,
                                 destPoints, count,
                                 srcx, srcy,
                                 srcwidth,
                                 srcheight,
                                 srcUnit,
                                 nimageAttributes,
                                 callback,
                                 callbackData));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; x, y, srcx, srcy, srcwidth, srcheight: Integer;
       srcUnit: TUnit): TStatus;
  var
    nImage: GpImage;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    result := SetStatus(GdipDrawImagePointRectI(nativeGraphics,
                                 nimage,
                                 x,
                                 y,
                                 srcx,
                                 srcy,
                                 srcwidth,
                                 srcheight,
                                 srcUnit));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; const destRect: TGPRect; srcx, srcy, srcwidth,
       srcheight: Integer; srcUnit: TUnit; imageAttributes: TGPImageAttributes = nil;
       callback: DrawImageAbort = nil; callbackData: Pointer = nil): TStatus;
  var
    nImage: GpImage;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipDrawImageRectRectI(nativeGraphics,
                                nimage,
                                destRect.X,
                                destRect.Y,
                                destRect.Width,
                                destRect.Height,
                                srcx,
                                srcy,
                                srcwidth,
                                srcheight,
                                srcUnit,
                                nimageAttributes,
                                callback,
                                callbackData));
  end;

  function TGPGraphics.DrawImage(image: TGPImage; destPoints: PGPPoint;
       count, srcx, srcy, srcwidth, srcheight: Integer; srcUnit: TUnit;
       imageAttributes: TGPImageAttributes = nil; callback: DrawImageAbort = nil;
       callbackData: Pointer = nil): TStatus;
  var
    nImage: GpImage;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Image) then nImage := Image.nativeImage else nImage := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;

    result := SetStatus(GdipDrawImagePointsRectI(nativeGraphics,
                                  nimage,
                                  destPoints,
                                  count,
                                  srcx,
                                  srcy,
                                  srcwidth,
                                  srcheight,
                                  srcUnit,
                                  nimageAttributes,
                                  callback,
                                  callbackData));
  end;

    // The following methods are for playing an EMF+ to a graphics
    // via the enumeration interface.  Each record of the EMF+ is
    // sent to the callback (along with the callbackData).  Then
    // the callback can invoke the Metafile::PlayRecord method
    // to play the particular record.

    
  function TGPGraphics.EnumerateMetafile(metafile: TGPMetafile; const destPoint: TGPPointF;
      callback: EnumerateMetafileProc; callbackData: Pointer = nil;
      imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileDestPoint(
            nativeGraphics,
            nmetafile,
            @destPoint,
            callback,
            callbackData,
            nimageAttributes));
  end;

    
  function TGPGraphics.EnumerateMetafile(metafile: TGPMetafile; const destPoint: TGPPoint;
       callback: EnumerateMetafileProc; callbackData: pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileDestPointI(
            nativeGraphics,
            nmetafile,
            @destPoint,
            callback,
            callbackData,
            nimageAttributes));
  end;


  function TGPGraphics.EnumerateMetafile(metafile: TGPMetafile; const destRect: TGPRectF;
       callback: EnumerateMetafileProc; callbackData: Pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileDestRect(
            nativeGraphics,
            nmetafile,
            @destRect,
            callback,
            callbackData,
            nimageAttributes));
  end;


  function TGPGraphics.EnumerateMetafile(metafile: TGPMetafile; const destRect: TGPRect;
       callback: EnumerateMetafileProc; callbackData: Pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileDestRectI(
            nativeGraphics,
            nmetafile,
            @destRect,
            callback,
            callbackData,
            nimageAttributes));
  end;


  function TGPGraphics.EnumerateMetafile(metafile: TGPMetafile; destPoints: PGPPointF;
       count: Integer; callback: EnumerateMetafileProc; callbackData: Pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileDestPoints(
            nativeGraphics,
            nmetafile,
            destPoints,
            count,
            callback,
            callbackData,
            nimageAttributes));
  end;

    
  function TGPGraphics.EnumerateMetafile(metafile: TGPMetafile; destPoints: PGPPoint;
       count: Integer; callback: EnumerateMetafileProc; callbackData: Pointer = nil;
       imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileDestPointsI(
            nativeGraphics,
            nmetafile,
            destPoints,
            count,
            callback,
            callbackData,
            nimageAttributes));
  end;

    
  function TGPGraphics.EnumerateMetafile(metafile: TGPMetafile; const destPoint: TGPPointF;
       const srcRect: TGPRectF; srcUnit: TUnit; callback: EnumerateMetafileProc;
       callbackData: pointer = nil; imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileSrcRectDestPoint(
            nativeGraphics,
            nmetafile,
            @destPoint,
            @srcRect,
            srcUnit,
            callback,
            callbackData,
            nimageAttributes));
  end;

    
  function TGPGraphics.EnumerateMetafile(metafile : TGPMetafile; const destPoint : TGPPoint;
       const srcRect : TGPRect; srcUnit : TUnit; callback : EnumerateMetafileProc;
       callbackData : Pointer = nil; imageAttributes : TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileSrcRectDestPointI(
            nativeGraphics,
            nmetafile,
            @destPoint,
            @srcRect,
            srcUnit,
            callback,
            callbackData,
            nimageAttributes));
  end;


  function TGPGraphics.EnumerateMetafile(metafile: TGPMetafile; const destRect: TGPRectF;
       const srcRect: TGPRectF; srcUnit: TUnit; callback: EnumerateMetafileProc;
       callbackData: Pointer = nil; imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileSrcRectDestRect(
            nativeGraphics,
            nmetafile,
            @destRect,
            @srcRect,
            srcUnit,
            callback,
            callbackData,
            nimageAttributes));
  end;


  function TGPGraphics.EnumerateMetafile(metafile : TGPMetafile; const destRect, srcRect: TGPRect;
       srcUnit : TUnit; callback : EnumerateMetafileProc; callbackData : Pointer = nil;
       imageAttributes : TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileSrcRectDestRectI(
            nativeGraphics,
            nmetafile,
            @destRect,
            @srcRect,
            srcUnit,
            callback,
            callbackData,
            nimageAttributes));
  end;

    
  function TGPGraphics.EnumerateMetafile( metafile: TGPMetafile; destPoints: PGPPointF;
    count: Integer; const srcRect: TGPRectF; srcUnit: TUnit; callback: EnumerateMetafileProc;
    callbackData: Pointer = nil; imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileSrcRectDestPoints(
            nativeGraphics,
            nmetafile,
            destPoints,
            count,
            @srcRect,
            srcUnit,
            callback,
            callbackData,
            nimageAttributes));
  end;


  function TGPGraphics.EnumerateMetafile(metafile: TGPMetafile; destPoints: PGPPoint;
    count: Integer; const srcRect: TGPRect; srcUnit: TUnit; callback: EnumerateMetafileProc;
    callbackData: Pointer = nil; imageAttributes: TGPImageAttributes = nil): TStatus;
  var
    nMetafile: GpMetafile;
    nimageAttributes: GpimageAttributes;
  begin
    if assigned(Metafile) then nMetafile := GpMetafile(Metafile.nativeImage) else nMetafile := nil;
    if assigned(imageAttributes) then nimageAttributes := imageAttributes.nativeImageAttr else nimageAttributes := nil;
    result := SetStatus(GdipEnumerateMetafileSrcRectDestPointsI(
            nativeGraphics,
            nmetafile,
            destPoints,
            count,
            @srcRect,
            srcUnit,
            callback,
            callbackData,
            nimageAttributes));
  end;
    
  function TGPGraphics.SetClip(g: TGPGraphics; combineMode: TCombineMode = CombineModeReplace): TStatus;
  begin
    result := SetStatus(GdipSetClipGraphics(nativeGraphics,
                             g.nativeGraphics,
                             combineMode));
  end;

  function TGPGraphics.SetClip(const rect: TGPRectF; combineMode: TCombineMode = CombineModeReplace): TStatus;
  begin
    result := SetStatus(GdipSetClipRect(nativeGraphics,
                             rect.X, rect.Y,
                             rect.Width, rect.Height,
                             combineMode));
  end;

  function TGPGraphics.SetClip(const rect: TGPRect; combineMode: TCombineMode = CombineModeReplace): TStatus;
  begin
    result := SetStatus(GdipSetClipRectI(nativeGraphics,
                              rect.X, rect.Y,
                              rect.Width, rect.Height,
                              combineMode));
  end;

  function TGPGraphics.SetClip(path: TGPGraphicsPath; combineMode: TCombineMode = CombineModeReplace): TStatus;
  begin
    result := SetStatus(GdipSetClipPath(nativeGraphics,
                             path.nativePath,
                             combineMode));
  end;

  function TGPGraphics.SetClip(region: TGPRegion; combineMode: TCombineMode = CombineModeReplace): TStatus;
  begin
    result := SetStatus(GdipSetClipRegion(nativeGraphics,
                               region.nativeRegion,
                               combineMode));
  end;

    // This is different than the other SetClip methods because it assumes
    // that the HRGN is already in device units, so it doesn't transform
    // the coordinates in the HRGN.
    
  function TGPGraphics.SetClip(hRgn: HRGN; combineMode: TCombineMode = CombineModeReplace): TStatus;
  begin
    result := SetStatus(GdipSetClipHrgn(nativeGraphics, hRgn,
                             combineMode));
  end;

  function TGPGraphics.IntersectClip(const rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipSetClipRect(nativeGraphics,
                             rect.X, rect.Y,
                             rect.Width, rect.Height,
                             CombineModeIntersect));
  end;

  function TGPGraphics.IntersectClip(const rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipSetClipRectI(nativeGraphics,
                              rect.X, rect.Y,
                              rect.Width, rect.Height,
                              CombineModeIntersect));
  end;

  function TGPGraphics.IntersectClip(region: TGPRegion): TStatus;
  begin
    result := SetStatus(GdipSetClipRegion(nativeGraphics,
                               region.nativeRegion,
                               CombineModeIntersect));
  end;

  function TGPGraphics.ExcludeClip(const rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipSetClipRect(nativeGraphics,
                             rect.X, rect.Y,
                             rect.Width, rect.Height,
                             CombineModeExclude));
  end;

  function TGPGraphics.ExcludeClip(const rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipSetClipRectI(nativeGraphics,
                              rect.X, rect.Y,
                              rect.Width, rect.Height,
                              CombineModeExclude));
  end;

  function TGPGraphics.ExcludeClip(region: TGPRegion): TStatus;
  begin
    result := SetStatus(GdipSetClipRegion(nativeGraphics,
                               region.nativeRegion,
                               CombineModeExclude));
  end;

  function TGPGraphics.ResetClip: TStatus;
  begin
    result := SetStatus(GdipResetClip(nativeGraphics));
  end;

  function TGPGraphics.TranslateClip(dx, dy: Single): TStatus;
  begin
    result := SetStatus(GdipTranslateClip(nativeGraphics, dx, dy));
  end;

  function TGPGraphics.TranslateClip(dx, dy: Integer): TStatus;
  begin
    result := SetStatus(GdipTranslateClipI(nativeGraphics,
                            dx, dy));
  end;

  function TGPGraphics.GetClip(region: TGPRegion): TStatus;
  begin
    result := SetStatus(GdipGetClip(nativeGraphics,
                         region.nativeRegion));
  end;

  function TGPGraphics.GetClipBounds(out rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipGetClipBounds(nativeGraphics, @rect));
  end;

  function TGPGraphics.GetClipBounds(out rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipGetClipBoundsI(nativeGraphics, @rect));
  end;

  function TGPGraphics.IsClipEmpty: Bool;
  var booln: BOOL;
  begin
    booln := FALSE;
    SetStatus(GdipIsClipEmpty(nativeGraphics, @booln));
    result := booln;
  end;

  function TGPGraphics.GetVisibleClipBounds(out rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipGetVisibleClipBounds(nativeGraphics, @rect));
  end;

  function TGPGraphics.GetVisibleClipBounds(out rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipGetVisibleClipBoundsI(nativeGraphics, @rect));
  end;

  function TGPGraphics.IsVisibleClipEmpty: BOOL;
  var booln: BOOL;
  begin
    booln := FALSE;
    SetStatus(GdipIsVisibleClipEmpty(nativeGraphics, booln));
    result := booln;
  end;

  function TGPGraphics.IsVisible(x, y: Integer): BOOL;
  var pt: TGPPoint;
  begin
    pt.X := x; pt.Y := y;
    result := IsVisible(pt);
  end;

  function TGPGraphics.IsVisible(const point: TGPPoint): BOOL;
  var booln: BOOL;
  begin
    booln := FALSE;
    SetStatus(GdipIsVisiblePointI(nativeGraphics,
                          point.X,
                          point.Y,
                          booln));
    result := booln;
  end;

  function TGPGraphics.IsVisible(x, y, width, height: Integer): BOOL;
  var booln: BOOL;
  begin
    booln := TRUE;
    SetStatus(GdipIsVisibleRectI(nativeGraphics,
                         X,
                         Y,
                         Width,
                         Height,
                         booln));
    result := booln;
  end;

  function TGPGraphics.IsVisible(const rect: TGPRect): BOOL;
  var booln: BOOL;
  begin
    booln := TRUE;
    SetStatus(GdipIsVisibleRectI(nativeGraphics,
                         rect.X,
                         rect.Y,
                         rect.Width,
                         rect.Height,
                         booln));
    result := booln;
  end;

  function TGPGraphics.IsVisible(x, y: Single): BOOL;
  var booln: BOOL;
  begin
    booln := FALSE;
    SetStatus(GdipIsVisiblePoint(nativeGraphics,
                         X,
                         Y,
                         booln));

    result := booln;
  end;

  function TGPGraphics.IsVisible(const point: TGPPointF): BOOL;
  var booln: BOOL;
  begin
    booln := FALSE;
    SetStatus(GdipIsVisiblePoint(nativeGraphics,
                         point.X,
                         point.Y,
                         booln));

    result := booln;
  end;

  function TGPGraphics.IsVisible(x, y, width, height: Single): BOOL;
  var booln: BOOL;
  begin
    booln := TRUE;
    SetStatus(GdipIsVisibleRect(nativeGraphics,
                        X,
                        Y,
                        Width,
                        Height,
                        booln));
    result := booln;
  end;

  function TGPGraphics.IsVisible(const rect: TGPRectF): BOOL;
  var booln: BOOL;
  begin
    booln := TRUE;
    SetStatus(GdipIsVisibleRect(nativeGraphics,
                        rect.X,
                        rect.Y,
                        rect.Width,
                        rect.Height,
                        booln));
    result := booln;
  end;

  function TGPGraphics.Save: GraphicsState;
  begin
    SetStatus(GdipSaveGraphics(nativeGraphics, result));
  end;

  function TGPGraphics.Restore(gstate: GraphicsState): TStatus;
  begin
    result := SetStatus(GdipRestoreGraphics(nativeGraphics,
                             gstate));
  end;

  function TGPGraphics.BeginContainer(const dstrect,srcrect: TGPRectF; unit_: TUnit): GraphicsContainer;
  begin
    SetStatus(GdipBeginContainer(nativeGraphics, @dstrect,
                         @srcrect, unit_, result));
  end;

  function TGPGraphics.BeginContainer(const dstrect, srcrect: TGPRect; unit_: TUnit): GraphicsContainer;
  begin
    SetStatus(GdipBeginContainerI(nativeGraphics, @dstrect,
                          @srcrect, unit_, result));
  end;

  function TGPGraphics.BeginContainer: GraphicsContainer;
  begin
    SetStatus(GdipBeginContainer2(nativeGraphics, result));
  end;

  function TGPGraphics.EndContainer(state: GraphicsContainer): TStatus;
  begin
    result := SetStatus(GdipEndContainer(nativeGraphics, state));
  end;

    // Only valid when recording metafiles.

  function TGPGraphics.AddMetafileComment(data: PBYTE; sizeData: UINT): TStatus;
  begin
    result := SetStatus(GdipComment(nativeGraphics, sizeData, data));
  end;

  function TGPGraphics.GetHalftonePalette: HPALETTE;
  begin
    result := GdipCreateHalftonePalette;
  end;

  function TGPGraphics.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  constructor TGPGraphics.Create(graphics: GpGraphics);
  begin
    lastResult := Ok;
    SetNativeGraphics(graphics);
  end;

  procedure TGPGraphics.SetNativeGraphics(graphics: GpGraphics);
  begin
    self.nativeGraphics := graphics;
  end;

  function TGPGraphics.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

  function TGPGraphics.GetNativeGraphics: GpGraphics;
  begin
    result := self.nativeGraphics;
  end;

  function TGPGraphics.GetNativePen(pen: TGPPen): GpPen;
  begin
    result := pen.nativePen;
  end;

(**************************************************************************\
*
*   GDI+ Font Family class
*
\**************************************************************************)

  constructor TGPFontFamily.Create;
  begin
    nativeFamily := nil;
    lastResult   := Ok;
  end;

  constructor TGPFontFamily.Create(name: WideString; fontCollection: TGPFontCollection = nil);
  var nfontCollection: GpfontCollection;
  begin
    nativeFamily := nil;
    if assigned(fontCollection) then nfontCollection := fontCollection.nativeFontCollection else nfontCollection := nil;
    lastResult := GdipCreateFontFamilyFromName(PWideChar(name), nfontCollection, nativeFamily);
  end;

  destructor TGPFontFamily.Destroy;
  begin
    GdipDeleteFontFamily (nativeFamily);
  end;

  class function TGPFontFamily.GenericSansSerif: TGPFontFamily;
  var
    nFontFamily: GpFontFamily;
  begin
    if not Assigned(GenericSansSerifFontFamily) then
    begin
      GenericSansSerifFontFamily := TGPFontFamily.Create;
      GenericSansSerifFontFamily.lastResult := GdipGetGenericFontFamilySansSerif(nFontFamily);
      GenericSansSerifFontFamily.nativeFamily := nFontFamily;
    end;

    result := GenericSansSerifFontFamily;
  end;

  class function TGPFontFamily.GenericSerif: TGPFontFamily;
  var nFontFamily: GpFontFamily;
  begin
    if not Assigned(GenericSerifFontFamily) then
    begin
      GenericSerifFontFamily := TGPFontFamily.Create;// (GenericSerifFontFamilyBuffer);
      GenericSerifFontFamily.lastResult := GdipGetGenericFontFamilySerif(nFontFamily);
      GenericSerifFontFamily.nativeFamily := nFontFamily;
    end;

    result := GenericSerifFontFamily;
  end;

  class function TGPFontFamily.GenericMonospace: TGPFontFamily;
  var nFontFamily: GpFontFamily;
  begin
    if not Assigned(GenericMonospaceFontFamily) then
    begin
      GenericMonospaceFontFamily := TGPFontFamily.Create;// (GenericMonospaceFontFamilyBuffer);
      GenericMonospaceFontFamily.lastResult := GdipGetGenericFontFamilyMonospace(nFontFamily);
      GenericMonospaceFontFamily.nativeFamily := nFontFamily;
    end;

    result := GenericMonospaceFontFamily;
  end;

  function TGPFontFamily.GetFamilyName(out name: string; language: LANGID = 0): TStatus;
  var str: array[0..LF_FACESIZE - 1] of WideChar;
  begin
    result := SetStatus(GdipGetFamilyName(nativeFamily, @str, language));
    name := str;
  end;

  function TGPFontFamily.Clone: TGPFontFamily;
  var
    clonedFamily: GpFontFamily;
  begin
    clonedFamily := nil;
    SetStatus(GdipCloneFontFamily (nativeFamily, clonedFamily));
    result := TGPFontFamily.Create(clonedFamily, lastResult);
  end;

  function TGPFontFamily.IsAvailable: BOOL;
  begin
    result := (nativeFamily <> nil);
  end;

  function TGPFontFamily.IsStyleAvailable(style: Integer): BOOL;
  var
    StyleAvailable: BOOL;
    status: TStatus;
  begin
    status := SetStatus(GdipIsStyleAvailable(nativeFamily, style, StyleAvailable));
    if (status <> Ok) then StyleAvailable := FALSE;
    result := StyleAvailable;
  end;

  function TGPFontFamily.GetEmHeight(style: Integer): UINT16;
  begin
    SetStatus(GdipGetEmHeight(nativeFamily, style, result));
  end;

  function TGPFontFamily.GetCellAscent(style: Integer): UINT16;
  begin
    SetStatus(GdipGetCellAscent(nativeFamily, style, result));
  end;

  function TGPFontFamily.GetCellDescent(style: Integer): UINT16;
  begin
    SetStatus(GdipGetCellDescent(nativeFamily, style, result));
  end;

  function TGPFontFamily.GetLineSpacing(style: Integer): UINT16;
  begin
    SetStatus(GdipGetLineSpacing(nativeFamily, style, result));
  end;

  function TGPFontFamily.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  function TGPFontFamily.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

  constructor TGPFontFamily.Create(nativeOrig: GpFontFamily; status: TStatus);
  begin
    lastResult  := status;
    nativeFamily := nativeOrig;
  end;

(**************************************************************************\
*
*   GDI+ Font class
*
\**************************************************************************)

  constructor TGPFont.Create(hdc: HDC);
  var font: GpFont;
  begin
    font := nil;
    lastResult := GdipCreateFontFromDC(hdc, font);
    SetNativeFont(font);
  end;

  constructor TGPFont.Create(hdc: HDC; logfont: PLogFontA);
  var font: GpFont;
  begin
    font := nil;
    if assigned(logfont) then
      lastResult := GdipCreateFontFromLogfontA(hdc, logfont, font)
    else
      lastResult := GdipCreateFontFromDC(hdc, font);
    SetNativeFont(font);
  end;

  constructor TGPFont.Create(hdc: HDC; logfont: PLogFontW);
  var font: GpFont;
  begin
    font := nil;
    if assigned(logfont) then
      lastResult := GdipCreateFontFromLogfontW(hdc, logfont, font)
    else
      lastResult := GdipCreateFontFromDC(hdc, font);
    SetNativeFont(font);
  end;

  constructor TGPFont.Create(hdc: HDC; hfont: HFONT);
  var
    font: GpFont;
    lf: LOGFONTA;
  begin
    font := nil;
    if BOOL(hfont) then
    begin
      if( BOOL(GetObjectA(hfont, sizeof(LOGFONTA), @lf))) then
            lastResult := GdipCreateFontFromLogfontA(hdc, @lf, font)
        else
            lastResult := GdipCreateFontFromDC(hdc, font);
    end
    else
      lastResult := GdipCreateFontFromDC(hdc, font);
    SetNativeFont(font);
  end;

  constructor TGPFont.Create(family: TGPFontFamily; const emSize: Single;
      style: TFontStyle = FontStyleRegular; unit_: TUnit = UnitPoint);
  var
    font: GpFont;
    nFontFamily: GpFontFamily;
  begin
    font := nil;
    if assigned(Family) then nFontFamily := Family.nativeFamily else nFontFamily := nil;
    lastResult := GdipCreateFont(nFontFamily, emSize, Integer(style), Integer(unit_), font);
    SetNativeFont(font);
  end;

  constructor TGPFont.Create(familyName: WideString; const emSize: Single;
      style: TFontStyle = FontStyleRegular; unit_: TUnit = UnitPoint;
      fontCollection: TGPFontCollection = nil);
  var
    family: TGPFontFamily;
    nativeFamily: GpFontFamily;
  begin
    nativeFont := nil;
    family := TGPFontFamily.Create(familyName, fontCollection);
    nativeFamily := family.nativeFamily;
    lastResult := family.GetLastStatus;
    if (lastResult <> Ok) then
    begin
      nativeFamily := TGPFontFamily.GenericSansSerif.nativeFamily;
      lastResult := TGPFontFamily.GenericSansSerif.lastResult;
      if (lastResult <> Ok) then
      begin
        family.Free;
        exit;
      end;
    end;

    lastResult := GdipCreateFont(nativeFamily,
                            emSize,
                            integer(style),
                            integer(unit_),
                            nativeFont);

    if (lastResult <> Ok) then
      begin
        nativeFamily := TGPFontFamily.GenericSansSerif.nativeFamily;
        lastResult := TGPFontFamily.GenericSansSerif.lastResult;
        if (lastResult <> Ok) then
        begin
          family.Free;
          exit;
        end;

        lastResult := GdipCreateFont(
            nativeFamily,
            emSize,
            Integer(style),
            Integer(unit_),
            nativeFont);
      end;
      family.Free;
  end;

  function TGPFont.GetLogFontA(g: TGPGraphics; out logfontA: TLogFontA): TStatus;
  var nGraphics: GpGraphics;
  begin
    if assigned(g) then nGraphics := g.nativeGraphics else nGraphics := nil;
    result := SetStatus(GdipGetLogFontA(nativeFont, nGraphics, logfontA));
  end;

  function TGPFont.GetLogFontW(g: TGPGraphics; out logfontW: TLogFontW): TStatus;
  var nGraphics: GpGraphics;
  begin
    if assigned(g) then nGraphics := g.nativeGraphics else nGraphics := nil;
    result := SetStatus(GdipGetLogFontW(nativeFont, nGraphics, logfontW));
  end;

  function TGPFont.Clone: TGPFont;
  var cloneFont: GpFont;
  begin
    cloneFont := nil;
    SetStatus(GdipCloneFont(nativeFont, cloneFont));
    result := TGPFont.Create(cloneFont, lastResult);
  end;

  destructor TGPFont.Destroy;
  begin
    GdipDeleteFont(nativeFont);
  end;

  function TGPFont.IsAvailable: BOOL;
  begin
    result := (nativeFont <> nil);
  end;

  function TGPFont.GetStyle: Integer;
  begin
    SetStatus(GdipGetFontStyle(nativeFont, result));
  end;

  function TGPFont.GetSize: Single;
  begin
    SetStatus(GdipGetFontSize(nativeFont, result));
  end;

  function TGPFont.GetUnit: TUnit;
  begin
    SetStatus(GdipGetFontUnit(nativeFont, result));
  end;

  function TGPFont.GetLastStatus: TStatus;
  begin
    result := lastResult;
  end;

  function TGPFont.GetHeight(graphics: TGPGraphics): Single;
  var ngraphics: Gpgraphics;
  begin
    if assigned(graphics) then ngraphics := graphics.nativeGraphics else ngraphics := nil;
    SetStatus(GdipGetFontHeight(nativeFont, ngraphics, result));
  end;

  function TGPFont.GetHeight(const dpi: Single): Single;
  begin
    SetStatus(GdipGetFontHeightGivenDPI(nativeFont, dpi, result));
  end;

  function TGPFont.GetFamily(family: TGPFontFamily): TStatus;
  var
    status: TStatus;
    nFamily: GpFontFamily;
  begin
    if (family = nil) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;

    status := GdipGetFamily(nativeFont, nFamily);
    family.nativeFamily := nFamily;
    family.SetStatus(status);
    result := SetStatus(status);
  end;

  constructor TGPFont.Create(font: GpFont; status: TStatus);
  begin
    lastResult := status;
    SetNativeFont(font);
  end;

  procedure TGPFont.SetNativeFont(Font: GpFont);
  begin
    nativeFont := Font;
  end;

  function TGPFont.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

(**************************************************************************\
*
*   Font collections (Installed and Private)
*
\**************************************************************************)

  constructor TGPFontCollection.Create;
  begin
    nativeFontCollection := nil;
  end;

  destructor TGPFontCollection.Destroy;
  begin
    inherited Destroy;
  end;

  function TGPFontCollection.GetFamilyCount: Integer;
  var
    numFound: Integer;
  begin
    numFound := 0;
    lastResult := GdipGetFontCollectionFamilyCount(nativeFontCollection, numFound);
    result := numFound;
  end;

  function TGPFontCollection.GetFamilies(numSought: Integer; out gpfamilies: array of TGPFontFamily;
      out numFound: Integer): TStatus;
  var
    nativeFamilyList: Pointer;
    Status: TStatus;
    i: Integer;
  type
    ArrGpFontFamily = array of GpFontFamily;
  begin
    if ((numSought <= 0) or (length(gpfamilies) = 0)) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;
    numFound := 0;

    getMem(nativeFamilyList, numSought * SizeOf(GpFontFamily));
    if nativeFamilyList = nil then
    begin
      result := SetStatus(OutOfMemory);
      exit;
    end;

    status := SetStatus(GdipGetFontCollectionFamilyList(
        nativeFontCollection,
        numSought,
        nativeFamilyList,
        numFound
    ));
    
    if (status = Ok) then
      for i := 0 to numFound - 1 do
         GdipCloneFontFamily(ArrGpFontFamily(nativeFamilyList)[i], gpfamilies[i].nativeFamily);
    Freemem(nativeFamilyList, numSought * SizeOf(GpFontFamily));
    result := status;
  end;

  function TGPFontCollection.GetLastStatus: TStatus;
  begin
    result := lastResult;
  end;

  function TGPFontCollection.SetStatus(status: TStatus): TStatus;
  begin
    lastResult := status;
    result := lastResult;
  end;


  constructor TGPInstalledFontCollection.Create;
  begin
    nativeFontCollection := nil;
    lastResult := GdipNewInstalledFontCollection(nativeFontCollection);
  end;

  destructor TGPInstalledFontCollection.Destroy;
  begin
    inherited Destroy;
  end;

  constructor TGPPrivateFontCollection.Create;
  begin
    nativeFontCollection := nil;
    lastResult := GdipNewPrivateFontCollection(nativeFontCollection);
  end;

  destructor TGPPrivateFontCollection.Destroy;
  begin
    GdipDeletePrivateFontCollection(nativeFontCollection);
    inherited Destroy;
  end;

  function TGPPrivateFontCollection.AddFontFile(filename: WideString): TStatus;
  begin
    result := SetStatus(GdipPrivateAddFontFile(nativeFontCollection, PWideChar(filename)));
  end;

  function TGPPrivateFontCollection.AddMemoryFont(memory: Pointer; length: Integer): TStatus;
  begin
    result := SetStatus(GdipPrivateAddMemoryFont(
        nativeFontCollection,
        memory,
        length));
  end;

(**************************************************************************\
*
*   GDI+ Graphics Path class
*
\**************************************************************************)

  constructor TGPGraphicsPath.Create(fillMode: TFillMode = FillModeAlternate);
  begin
    nativePath := nil;
    lastResult := GdipCreatePath(fillMode, nativePath);
  end;

  constructor TGPGraphicsPath.Create(points: PGPPointF; types: PBYTE; count: Integer;
              fillMode: TFillMode = FillModeAlternate);
  begin
    nativePath := nil;
    lastResult := GdipCreatePath2(points, types, count, fillMode, nativePath);
  end;

  constructor TGPGraphicsPath.Create(points: PGPPoint; types: PBYTE; count: Integer;
              fillMode: TFillMode = FillModeAlternate);
  begin
      nativePath := nil;
      lastResult := GdipCreatePath2I(points, types, count, fillMode, nativePath);
  end;

  destructor TGPGraphicsPath.Destroy;
  begin
    GdipDeletePath(nativePath);
  end;

  function TGPGraphicsPath.Clone: TGPGraphicsPath;
  var
    clonepath: GpPath;
  begin
    clonepath := nil;
    SetStatus(GdipClonePath(nativePath, clonepath));
    result := TGPGraphicsPath.Create(clonepath);
  end;

    // Reset the path object to empty (and fill mode to FillModeAlternate)

  function TGPGraphicsPath.Reset: TStatus;
  begin
    result := SetStatus(GdipResetPath(nativePath));
  end;

  function TGPGraphicsPath.GetFillMode: TFillMode;
  var FMode: TFillMode;
  begin
    FMode := FillModeAlternate;
    SetStatus(GdipGetPathFillMode(nativePath, result));
    result := FMode;
  end;

  function TGPGraphicsPath.SetFillMode(fillmode: TFillMode): TStatus;
  begin
    result := SetStatus(GdipSetPathFillMode(nativePath, fillmode));
  end;

  function TGPGraphicsPath.GetPathData(pathData: TPathData): TStatus;
  var
    count: Integer;
  begin
    count := GetPointCount;
    if ((count <= 0) or ((pathData.Count > 0) and (pathData.Count < Count))) then
    begin
      pathData.Count := 0;
      if assigned(pathData.Points) then
      begin
        FreeMem(pathData.Points);
        pathData.Points := nil;
      end;
      if assigned(pathData.Types) then
      begin
        freemem(pathData.Types);
        pathData.Types := nil;
      end;
      if (count <= 0) then
      begin
        result := lastResult;
        exit;
      end;
    end;

    if (pathData.Count = 0) then
    begin
      getmem(pathData.Points, SizeOf(TGPPointF) * count);
      if (pathData.Points = nil) then
      begin
        result := SetStatus(OutOfMemory);
        exit;
      end;
      Getmem(pathData.Types, count);
      if (pathData.Types = nil) then
      begin
        freemem(pathData.Points);
        pathData.Points := nil;
        result := SetStatus(OutOfMemory);
        exit;
      end;
      pathData.Count := count;
    end;

    result := SetStatus(GdipGetPathData(nativePath, @pathData.Count));
  end;

  function TGPGraphicsPath.StartFigure: TStatus;
  begin
    result := SetStatus(GdipStartPathFigure(nativePath));
  end;

  function TGPGraphicsPath.CloseFigure: TStatus;
  begin
    result := SetStatus(GdipClosePathFigure(nativePath));
  end;

  function TGPGraphicsPath.CloseAllFigures: TStatus;
  begin
    result := SetStatus(GdipClosePathFigures(nativePath));
  end;

  function TGPGraphicsPath.SetMarker: TStatus;
  begin
    result := SetStatus(GdipSetPathMarker(nativePath));
  end;

  function TGPGraphicsPath.ClearMarkers: TStatus;
  begin
    result := SetStatus(GdipClearPathMarkers(nativePath));
  end;

  function TGPGraphicsPath.Reverse: TStatus;
  begin
    result := SetStatus(GdipReversePath(nativePath));
  end;

  function TGPGraphicsPath.GetLastPoint(out lastPoint: TGPPointF): TStatus;
  begin
    result := SetStatus(GdipGetPathLastPoint(nativePath,
                                            @lastPoint));
  end;

  function TGPGraphicsPath.AddLine(const pt1, pt2: TGPPointF): TStatus;
  begin
    result := AddLine(pt1.X, pt1.Y, pt2.X, pt2.Y);
  end;

  function TGPGraphicsPath.AddLine(const x1, y1, x2, y2: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathLine(nativePath, x1, y1,
                                         x2, y2));
  end;

  function TGPGraphicsPath.AddLines(points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathLine2(nativePath, points, count));
  end;

  function TGPGraphicsPath.AddLine(const pt1, pt2: TGPPoint): TStatus;
  begin
    result := AddLine(pt1.X, pt1.Y, pt2.X, pt2.Y);
  end;

  function TGPGraphicsPath.AddLine(x1, y1, x2, y2: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathLineI(nativePath, x1, y1, x2, y2));
  end;

  function TGPGraphicsPath.AddLines(points: PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathLine2I(nativePath, points, count));
  end;

  function TGPGraphicsPath.AddArc(const rect: TGPRectF; const startAngle, sweepAngle: Single): TStatus;
  begin
    result := AddArc(rect.X, rect.Y, rect.Width, rect.Height,
                  startAngle, sweepAngle);
  end;

  function TGPGraphicsPath.AddArc(const x, y, width, height, startAngle, sweepAngle: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathArc(nativePath, x, y, width, height, startAngle, sweepAngle));
  end;

  function TGPGraphicsPath.AddArc(const rect: TGPRect; const startAngle, sweepAngle: Single): TStatus;
  begin
    result := AddArc(rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
  end;

  function TGPGraphicsPath.AddArc(x, y, width, height: Integer; const startAngle, sweepAngle: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathArcI(nativePath, x, y, width, height, startAngle, sweepAngle));
  end;

  function TGPGraphicsPath.AddBezier(const pt1, pt2, pt3, pt4: TGPPointF): TStatus;
  begin
    result := AddBezier(pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y);
  end;

  function TGPGraphicsPath.AddBezier(const x1, y1, x2, y2, x3, y3, x4, y4: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathBezier(nativePath, x1, y1, x2, y2, x3, y3, x4, y4));
  end;

  function TGPGraphicsPath.AddBeziers(points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathBeziers(nativePath, points, count));
  end;

  function TGPGraphicsPath.AddBezier(const pt1, pt2, pt3, pt4: TGPPoint): TStatus;
  begin
    result := AddBezier(pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y);
  end;

  function TGPGraphicsPath.AddBezier(x1, y1, x2, y2, x3, y3, x4, y4: Integer): TStatus;
  begin
       result := SetStatus(GdipAddPathBezierI(nativePath, x1, y1, x2, y2, x3, y3, x4, y4));
  end;

  function TGPGraphicsPath.AddBeziers(points: PGPPoint; count: Integer): TStatus;
  begin
       result := SetStatus(GdipAddPathBeziersI(nativePath, points, count));
  end;

  function TGPGraphicsPath.AddCurve(points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathCurve(nativePath, points, count));
  end;

  function TGPGraphicsPath.AddCurve(points: PGPPointF; count: Integer;
    const tension: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathCurve2(nativePath, points, count, tension));
  end;

  function TGPGraphicsPath.AddCurve(points: PGPPointF; count, offset,
    numberOfSegments: Integer; const tension: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathCurve3(nativePath, points, count, offset,
                          numberOfSegments, tension));
  end;

  function TGPGraphicsPath.AddCurve(points: PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathCurveI(nativePath, points, count));
  end;

  function TGPGraphicsPath.AddCurve(points: PGPPoint; count: Integer; const tension: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathCurve2I(nativePath, points, count, tension));
  end;

  function TGPGraphicsPath.AddCurve(points: PGPPoint; count, offset,
    numberOfSegments: Integer; const tension: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathCurve3I(nativePath, points, count, offset,
     numberOfSegments, tension));
  end;

  function TGPGraphicsPath.AddClosedCurve(points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathClosedCurve(nativePath, points, count));
  end;

  function TGPGraphicsPath.AddClosedCurve(points: PGPPointF; count: Integer; const tension: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathClosedCurve2(nativePath, points, count, tension));
  end;

  function TGPGraphicsPath.AddClosedCurve(points: PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathClosedCurveI(nativePath, points, count));
  end;


  function TGPGraphicsPath.AddClosedCurve(points: PGPPoint; count: Integer; const tension: Single): TStatus;
  begin
       result := SetStatus(GdipAddPathClosedCurve2I(nativePath, points, count, tension));
  end;

  function TGPGraphicsPath.AddRectangle(const rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipAddPathRectangle(nativePath,
                                            rect.X,
                                            rect.Y,
                                            rect.Width,
                                            rect.Height));
  end;

  function TGPGraphicsPath.AddRectangles(rects: PGPRectF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathRectangles(nativePath,
                                             rects,
                                             count));
  end;

  function TGPGraphicsPath.AddRectangle(const rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipAddPathRectangleI(nativePath,
                                            rect.X,
                                            rect.Y,
                                            rect.Width,
                                            rect.Height));
  end;

  function TGPGraphicsPath.AddRectangles(rects: PGPRect; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathRectanglesI(nativePath,
                                             rects,
                                             count));
  end;

  function TGPGraphicsPath.AddEllipse(const rect: TGPRectF): TStatus;
  begin
    result := AddEllipse(rect.X, rect.Y, rect.Width, rect.Height);
  end;

  function TGPGraphicsPath.AddEllipse(const x, y, width, height: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathEllipse(nativePath,
                                          x,
                                          y,
                                          width,
                                          height));
  end;

  function TGPGraphicsPath.AddEllipse(const rect: TGPRect): TStatus;
  begin
    result := AddEllipse(rect.X, rect.Y, rect.Width, rect.Height);
  end;

  function TGPGraphicsPath.AddEllipse(x, y, width, height: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathEllipseI(nativePath,
                                          x,
                                          y,
                                          width,
                                          height));
  end;

  function TGPGraphicsPath.AddPie(const rect: TGPRectF; const startAngle, sweepAngle: Single): TStatus;
  begin
    result := AddPie(rect.X, rect.Y, rect.Width, rect.Height, startAngle,
                  sweepAngle);
  end;

  function TGPGraphicsPath.AddPie(const x, y, width, height, startAngle, sweepAngle: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathPie(nativePath, x, y, width,
                                        height, startAngle,
                                        sweepAngle));
  end;

  function TGPGraphicsPath.AddPie(const rect: TGPRect; const startAngle, sweepAngle: Single): TStatus;
  begin
    result := AddPie(rect.X,
                  rect.Y,
                  rect.Width,
                  rect.Height,
                  startAngle,
                  sweepAngle);
  end;

  function TGPGraphicsPath.AddPie(const x, y, width, height: Integer; const startAngle, sweepAngle: Single): TStatus;
  begin
    result := SetStatus(GdipAddPathPieI(nativePath,
                                        x,
                                        y,
                                        width,
                                        height,
                                        startAngle,
                                        sweepAngle));
  end;

  function TGPGraphicsPath.AddPolygon(points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipAddPathPolygon(nativePath, points, count));
  end;

  function TGPGraphicsPath.AddPolygon(points: PGPPoint; count: Integer): TStatus;
  begin
       result := SetStatus(GdipAddPathPolygonI(nativePath, points,
                                          count));
  end;

  function TGPGraphicsPath.AddPath(addingPath: TGPGraphicsPath; connect: Bool): TStatus;
  var
    nativePath2: GpPath;
  begin
    nativePath2 := nil;
    if assigned(addingPath) then nativePath2 := addingPath.nativePath;
    result := SetStatus(GdipAddPathPath(nativePath, nativePath2, connect));
  end;

  function TGPGraphicsPath.AddString(
      string_: WideString; length: Integer;
      family : TGPFontFamily;
      style  : Integer;
      const emSize : Single;  // World units
      const origin : TGPPointF;
      format : TGPStringFormat): TStatus;
  var
    rect : TGPRectF;
    gpff : GPFONTFAMILY;
    gpsf : GPSTRINGFORMAT;
  begin
    rect.X := origin.X;
    rect.Y := origin.Y;
    rect.Width := 0.0;
    rect.Height := 0.0;

    gpff := nil;
    gpsf := nil;
    if assigned(family) then gpff := family.nativeFamily;
    if assigned(format) then gpsf := format.nativeFormat;
    result := SetStatus(GdipAddPathString(nativePath, PWideChar(string_), length, gpff,
          style, emSize, @rect, gpsf));
  end;

  function TGPGraphicsPath.AddString(
      string_: WideString;
      length : Integer;
      family : TGPFontFamily;
      style  : Integer;
      const emSize : Single;  // World units
      const layoutRect: TGPRectF;
      format : TGPStringFormat): TStatus;
  var
    gpff : GPFONTFAMILY;
    gpsf : GPSTRINGFORMAT;
  begin
    gpff := nil;
    gpsf := nil;
    if assigned(family) then gpff := family.nativeFamily;
    if assigned(format) then gpsf := format.nativeFormat;
    result := SetStatus(GdipAddPathString( nativePath, PWideChar(string_), length, gpff,
          style, emSize, @layoutRect, gpsf));
  end;

  function TGPGraphicsPath.AddString(
      string_: WideString;
      length : Integer;
      family : TGPFontFamily;
      style  : Integer;
      const emSize : Single;  // World units
      const origin : TGPPoint;
      format : TGPStringFormat): TStatus;
  var
    rect : TGPRect;
    gpff : GPFONTFAMILY;
    gpsf : GPSTRINGFORMAT;
  begin
    rect.X := origin.X;
    rect.Y := origin.Y;
    rect.Width := 0;
    rect.Height := 0;
    gpff := nil;
    gpsf := nil;
    if assigned(family) then gpff := family.nativeFamily;
    if assigned(format) then gpsf := format.nativeFormat;
    result := SetStatus(GdipAddPathStringI(nativePath, PWideChar(string_), length, gpff,
          style, emSize, @rect, gpsf));
  end;

  function TGPGraphicsPath.AddString(
      string_: WideString;
      length : Integer;
      family : TGPFontFamily;
      style  : Integer;
      const emSize : Single;  // World units
      const layoutRect: TGPRect;
      format : TGPStringFormat): TStatus;
  var
    gpff : GPFONTFAMILY;
    gpsf : GPSTRINGFORMAT;
  begin
    gpff := nil;
    gpsf := nil;
    if assigned(family) then gpff := family.nativeFamily;
    if assigned(format) then gpsf := format.nativeFormat;
    result := SetStatus(GdipAddPathStringI( nativePath, PWideChar(string_), length, gpff,
          style, emSize, @layoutRect, gpsf));
  end;

  function TGPGraphicsPath.Transform(matrix: TGPMatrix): TStatus;
  begin
      if assigned(matrix) then
        result := SetStatus(GdipTransformPath(nativePath, matrix.nativeMatrix))
      else
        result := Ok;
  end;

    // This is not always the tightest bounds.

  function TGPGraphicsPath.GetBounds(out bounds: TGPRectF; matrix: TGPMatrix = nil; pen: TGPPen = nil): TStatus;
  var
    nativeMatrix: GpMatrix;
    nativePen: GpPen;
  begin
    nativeMatrix := nil;
    nativePen    := nil;
    if assigned(matrix) then nativeMatrix := matrix.nativeMatrix;
    if assigned(pen) then nativePen := pen.nativePen;

    result := SetStatus(GdipGetPathWorldBounds(nativePath, @bounds, nativeMatrix, nativePen));
  end;

  function TGPGraphicsPath.GetBounds(out bounds: TGPRect; matrix: TGPMatrix = nil; pen: TGPPen = nil): TStatus;
  var
    nativeMatrix: GpMatrix;
    nativePen: GpPen;
  begin
    nativeMatrix := nil;
    nativePen    := nil;
    if assigned(matrix) then nativeMatrix := matrix.nativeMatrix;
    if assigned(pen) then nativePen := pen.nativePen;

    result := SetStatus(GdipGetPathWorldBoundsI(nativePath, @bounds, nativeMatrix, nativePen));
  end;

    // Once flattened, the resultant path is made of line segments and
    // the original path information is lost.  When matrix is nil the
    // identity matrix is assumed.

  function TGPGraphicsPath.Flatten(matrix: TGPMatrix = nil; const flatness: Single = FlatnessDefault): TStatus;
  var nativeMatrix: GpMatrix;
  begin
    nativeMatrix := nil;
    if assigned(matrix) then nativeMatrix := matrix.nativeMatrix;
    result := SetStatus(GdipFlattenPath(nativePath, nativeMatrix, flatness));
  end;

  function TGPGraphicsPath.Widen(pen: TGPPen; matrix: TGPMatrix = nil; const flatness: Single = FlatnessDefault): TStatus;
  var nativeMatrix: GpMatrix;
  begin
    nativeMatrix := nil;
    if assigned(matrix) then nativeMatrix := matrix.nativeMatrix;
    result := SetStatus(GdipWidenPath(nativePath, pen.nativePen, nativeMatrix, flatness));
  end;

  function TGPGraphicsPath.Outline(matrix: TGPMatrix = nil; const flatness: Single = FlatnessDefault): TStatus;
  var nativeMatrix: GpMatrix;
  begin
    nativeMatrix := nil;
    if assigned(matrix) then nativeMatrix := matrix.nativeMatrix;
    result := SetStatus(GdipWindingModeOutline(nativePath, nativeMatrix, flatness));
  end;

    // Once this is called, the resultant path is made of line segments and
    // the original path information is lost.  When matrix is nil, the
    // identity matrix is assumed.

  function TGPGraphicsPath.Warp(destPoints: PGPPointF; count: Integer; const srcRect: TGPRectF;
            matrix: TGPMatrix = nil; warpMode: TWarpMode = WarpModePerspective;
            const flatness: Single = FlatnessDefault): TStatus;
  var nativeMatrix: GpMatrix;
  begin
    nativeMatrix := nil;
    if assigned(matrix) then nativeMatrix := matrix.nativeMatrix;
    result := SetStatus(GdipWarpPath(nativePath, nativeMatrix, destPoints,
                count, srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height,
                warpMode, flatness));
  end;

  function TGPGraphicsPath.GetPointCount: Integer;
  var count: Integer;
  begin
    count := 0;
    SetStatus(GdipGetPointCount(nativePath, count));
    result := count;
  end;

  function TGPGraphicsPath.GetPathTypes(types: PBYTE; count: Integer): TStatus;
  begin
    result := SetStatus(GdipGetPathTypes(nativePath, types, count));
  end;

  function TGPGraphicsPath.GetPathPoints(points: PGPPointF; count: Integer): TStatus;
  begin
    result := SetStatus(GdipGetPathPoints(nativePath, points, count));
  end;

  function TGPGraphicsPath.GetPathPoints(points: PGPPoint; count: Integer): TStatus;
  begin
    result := SetStatus(GdipGetPathPointsI(nativePath, points, count));
  end;

  function TGPGraphicsPath.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  function TGPGraphicsPath.IsVisible(const point: TGPPointF; g: TGPGraphics = nil): BOOL;
  begin
    result := IsVisible(point.X, point.Y, g);
  end;

  function TGPGraphicsPath.IsVisible(const x, y: Single; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    nativeGraphics: GpGraphics;
  begin
    booln := FALSE;
    nativeGraphics := nil;
    if assigned(g) then nativeGraphics := g.nativeGraphics;
    SetStatus(GdipIsVisiblePathPoint(nativePath, x, y, nativeGraphics, booln));
    result := booln;
  end;

  function TGPGraphicsPath.IsVisible(const point: TGPPoint; g : TGPGraphics = nil): BOOL;
  begin
    result := IsVisible(point.X, point.Y, g);
  end;

  function TGPGraphicsPath.IsVisible(x, y: Integer; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    nativeGraphics: GpGraphics;
  begin
    booln := FALSE;
    nativeGraphics := nil;
    if assigned(g) then nativeGraphics := g.nativeGraphics;
    SetStatus(GdipIsVisiblePathPointI(nativePath, x, y, nativeGraphics, booln));
    result := booln;
  end;

  function TGPGraphicsPath.IsOutlineVisible(const point: TGPPointF; pen: TGPPen; g: TGPGraphics = nil): BOOL;
  begin
    result := IsOutlineVisible(point.X, point.Y, pen, g);
  end;

  function TGPGraphicsPath.IsOutlineVisible(const x, y: Single; pen: TGPPen; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    nativeGraphics: GpGraphics;
    nativePen: GpPen;
  begin
    booln := FALSE;
    nativeGraphics := nil;
    nativePen := nil;
    if assigned(g) then nativeGraphics := g.nativeGraphics;
    if assigned(pen) then nativePen := pen.nativePen;
    SetStatus(GdipIsOutlineVisiblePathPoint(nativePath, x, y, nativePen,
        nativeGraphics, booln));
    result := booln;
  end;

  function TGPGraphicsPath.IsOutlineVisible(const point: TGPPoint; pen: TGPPen; g: TGPGraphics = nil): BOOL;
  begin
    result := IsOutlineVisible(point.X, point.Y, pen, g);
  end;

  function TGPGraphicsPath.IsOutlineVisible(x, y: Integer; pen: TGPPen; g: TGPGraphics = nil): BOOL;
  var
    booln: BOOL;
    nativeGraphics: GpGraphics;
    nativePen: GpPen;
  begin
    booln := FALSE;
    nativeGraphics := nil;
    nativePen := nil;
    if assigned(g) then nativeGraphics := g.nativeGraphics;
    if assigned(pen) then nativePen := pen.nativePen;
    SetStatus(GdipIsOutlineVisiblePathPointI(nativePath, x, y, nativePen,
       nativeGraphics, booln));
    result := booln;
  end;

  constructor TGPGraphicsPath.Create(path: TGPGraphicsPath);
  var clonepath: GpPath;
  begin
    clonepath := nil;
    SetStatus(GdipClonePath(path.nativePath, clonepath));
    SetNativePath(clonepath);
  end;

  constructor TGPGraphicsPath.Create(nativePath: GpPath);
  begin
    lastResult := Ok;
    SetNativePath(nativePath);
  end;

  procedure TGPGraphicsPath.SetNativePath(nativePath: GpPath);
  begin
    self.nativePath := nativePath;
  end;

  function TGPGraphicsPath.SetStatus(const status: TStatus): TStatus;
  begin
    result := status;
    if (result <> Ok) then LastResult := result;
  end;

//--------------------------------------------------------------------------
// GraphisPathIterator class
//--------------------------------------------------------------------------

  constructor TGPGraphicsPathIterator.Create(path: TGPGraphicsPath);
  var
    nativePath: GpPath;
    iter: GpPathIterator;
  begin
    nativePath := nil;
    if assigned(path) then nativePath := path.nativePath;
    iter := nil;
    lastResult := GdipCreatePathIter(iter, nativePath);
    SetNativeIterator(iter);
  end;

  destructor TGPGraphicsPathIterator.Destroy;
  begin
    GdipDeletePathIter(nativeIterator);
  end;

  function TGPGraphicsPathIterator.NextSubpath(out startIndex, endIndex: Integer; out isClosed: bool): Integer;
  begin
    SetStatus(GdipPathIterNextSubpath(nativeIterator, result, startIndex, endIndex, isClosed));
  end;

  function TGPGraphicsPathIterator.NextSubpath(path: TGPGraphicsPath; out isClosed: BOOL): Integer;
  var
    nativePath: GpPath;
    resultCount: Integer;
  begin
    nativePath := nil;
    if assigned(path) then nativePath := path.nativePath;
    SetStatus(GdipPathIterNextSubpathPath(nativeIterator, resultCount,
      nativePath, isClosed));
    result := resultCount;
  end;

  function TGPGraphicsPathIterator.NextPathType(out pathType: TPathPointType; out startIndex, endIndex: Integer): Integer;
  var
    resultCount: Integer;
  begin
    SetStatus(GdipPathIterNextPathType(nativeIterator, resultCount, @pathType,
       startIndex, endIndex));
    result := resultCount;
  end;

  function TGPGraphicsPathIterator.NextMarker(out startIndex, endIndex: Integer): Integer;
  begin
    SetStatus(GdipPathIterNextMarker(nativeIterator, result, startIndex, endIndex));
  end;

  function TGPGraphicsPathIterator.NextMarker(path: TGPGraphicsPath): Integer;
  var nativePath: GpPath;
  begin
    nativePath := nil;
    if assigned(path) then nativePath := path.nativePath;
    SetStatus(GdipPathIterNextMarkerPath(nativeIterator, result, nativePath));
  end;

  function TGPGraphicsPathIterator.GetCount: Integer;
  begin
    SetStatus(GdipPathIterGetCount(nativeIterator, result));
  end;

  function TGPGraphicsPathIterator.GetSubpathCount: Integer;
  begin
    SetStatus(GdipPathIterGetSubpathCount(nativeIterator, result));
  end;

  function TGPGraphicsPathIterator.HasCurve: BOOL;
  begin
    SetStatus(GdipPathIterHasCurve(nativeIterator, result));
  end;

  procedure TGPGraphicsPathIterator.Rewind;
  begin
    SetStatus(GdipPathIterRewind(nativeIterator));
  end;

  function TGPGraphicsPathIterator.Enumerate(points: PGPPointF; types: PBYTE;
    count: Integer): Integer;
  begin
    SetStatus(GdipPathIterEnumerate(nativeIterator, result, points, types, count));
  end;

  function TGPGraphicsPathIterator.CopyData(points: PGPPointF; types: PBYTE;
    startIndex, endIndex: Integer): Integer;
  begin
    SetStatus(GdipPathIterCopyData(nativeIterator, result, points, types,
      startIndex, endIndex));
  end;

  function TGPGraphicsPathIterator.GetLastStatus: TStatus;
  begin
    result := lastResult;
    lastResult := Ok;
  end;

  procedure TGPGraphicsPathIterator.SetNativeIterator(nativeIterator: GpPathIterator);
  begin
    self.nativeIterator := nativeIterator;
  end;

  function TGPGraphicsPathIterator.SetStatus(status: TStatus): TStatus;
  begin
    if (status <> Ok) then lastResult := status;
    result := status;
  end;

//--------------------------------------------------------------------------
// Path Gradient Brush
//--------------------------------------------------------------------------

  constructor TGPPathGradientBrush.Create(points: PGPPointF; count: Integer; wrapMode: TWrapMode = WrapModeClamp);
  var brush: GpPathGradient;
  begin
    brush := nil;
    lastResult := GdipCreatePathGradient(points, count, wrapMode, brush);
    SetNativeBrush(brush);
  end;

  constructor TGPPathGradientBrush.Create(points: PGPPoint; count: Integer; wrapMode: TWrapMode = WrapModeClamp);
  var brush: GpPathGradient;
  begin
    brush := nil;
    lastResult := GdipCreatePathGradientI(points, count, wrapMode, brush);
    SetNativeBrush(brush);
  end;

  constructor TGPPathGradientBrush.Create(path: TGPGraphicsPath);
  var brush: GpPathGradient;
  begin
    brush := nil;
    lastResult := GdipCreatePathGradientFromPath(path.nativePath, brush);
    SetNativeBrush(brush);
  end;

  function TGPPathGradientBrush.GetCenterColor(out Color: TGPColor): TStatus;
  begin
    SetStatus(GdipGetPathGradientCenterColor(GpPathGradient(nativeBrush), Color));
    result := lastResult;
  end;

  function TGPPathGradientBrush.SetCenterColor(color: TGPColor): TStatus;
  begin
    SetStatus(GdipSetPathGradientCenterColor(GpPathGradient(nativeBrush),color));
    result := lastResult;
  end;

  function TGPPathGradientBrush.GetPointCount: Integer;
  begin
    SetStatus(GdipGetPathGradientPointCount(GpPathGradient(nativeBrush), result));
  end;

  function TGPPathGradientBrush.GetSurroundColorCount: Integer;
  begin
    SetStatus(GdipGetPathGradientSurroundColorCount(GpPathGradient(nativeBrush), result));
  end;

  function TGPPathGradientBrush.GetSurroundColors(colors: PARGB; var count: Integer): TStatus;
  var
    count1: Integer;
  begin
    if not assigned(colors) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;

    SetStatus(GdipGetPathGradientSurroundColorCount(GpPathGradient(nativeBrush), count1));

    if(lastResult <> Ok) then
    begin
      result := lastResult;
      exit;
    end;

    if((count < count1) or (count1 <= 0)) then
    begin
      result := SetStatus(InsufficientBuffer);
      exit;
    end;

    SetStatus(GdipGetPathGradientSurroundColorsWithCount(GpPathGradient(nativeBrush), colors, count1));
    if(lastResult = Ok) then
      count := count1;

    result := lastResult;
  end;

  function TGPPathGradientBrush.SetSurroundColors(colors: PARGB; var count: Integer): TStatus;
  var
    count1: Integer;
  type
    TDynArrDWORD = array of DWORD;
  begin
    if (colors = nil) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;

    count1 := GetPointCount;

    if((count > count1) or (count1 <= 0)) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;

    count1 := count;

    SetStatus(GdipSetPathGradientSurroundColorsWithCount(
                GpPathGradient(nativeBrush), colors, count1));

    if(lastResult = Ok) then count := count1;
    result := lastResult;
  end;

  function TGPPathGradientBrush.GetGraphicsPath(path: TGPGraphicsPath): TStatus;
  begin
    if(path = nil) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;
    result := SetStatus(GdipGetPathGradientPath(GpPathGradient(nativeBrush), path.nativePath));
  end;

  function TGPPathGradientBrush.SetGraphicsPath(path: TGPGraphicsPath): TStatus;
  begin
    if(path = nil) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;
    result := SetStatus(GdipSetPathGradientPath(GpPathGradient(nativeBrush), path.nativePath));
  end;

  function TGPPathGradientBrush.GetCenterPoint(out point: TGPPointF): TStatus;
  begin
    result := SetStatus(GdipGetPathGradientCenterPoint(GpPathGradient(nativeBrush), @point));
  end;

  function TGPPathGradientBrush.GetCenterPoint(out point: TGPPoint): TStatus;
  begin
    result := SetStatus(GdipGetPathGradientCenterPointI(GpPathGradient(nativeBrush), @point));
  end;

  function TGPPathGradientBrush.SetCenterPoint(const point: TGPPointF): TStatus;
  begin
    result := SetStatus(GdipSetPathGradientCenterPoint(GpPathGradient(nativeBrush), @point));
  end;

  function TGPPathGradientBrush.SetCenterPoint(const point: TGPPoint): TStatus;
  begin
    result := SetStatus(GdipSetPathGradientCenterPointI(GpPathGradient(nativeBrush), @point));
  end;

  function TGPPathGradientBrush.GetRectangle(out rect: TGPRectF): TStatus;
  begin
    result := SetStatus(GdipGetPathGradientRect(GpPathGradient(nativeBrush), @rect));
  end;

  function TGPPathGradientBrush.GetRectangle(out rect: TGPRect): TStatus;
  begin
    result := SetStatus(GdipGetPathGradientRectI(GpPathGradient(nativeBrush), @rect));
  end;

  function TGPPathGradientBrush.SetGammaCorrection(useGammaCorrection: BOOL): TStatus;
  begin
    result := SetStatus(GdipSetPathGradientGammaCorrection(GpPathGradient(nativeBrush),
      useGammaCorrection));
  end;

  function TGPPathGradientBrush.GetGammaCorrection: BOOL;
  begin
    SetStatus(GdipGetPathGradientGammaCorrection(GpPathGradient(nativeBrush), result));
  end;

  function TGPPathGradientBrush.GetBlendCount: Integer;
  var count: Integer;
  begin
    count := 0;
    SetStatus(GdipGetPathGradientBlendCount(GpPathGradient(nativeBrush), count));
    result := count;
  end;

  function TGPPathGradientBrush.GetBlend(blendFactors, blendPositions:PSingle; count: Integer): TStatus;
  begin
    result := SetStatus(GdipGetPathGradientBlend(
                      GpPathGradient(nativeBrush),
                      blendFactors, blendPositions, count));
  end;

  function TGPPathGradientBrush.SetBlend(blendFactors, blendPositions: PSingle; count: Integer): TStatus;
  begin
    result := SetStatus(GdipSetPathGradientBlend(
                      GpPathGradient(nativeBrush),
                      blendFactors, blendPositions, count));
  end;

  function TGPPathGradientBrush.GetInterpolationColorCount: Integer;
  var count: Integer;
  begin
    count := 0;
    SetStatus(GdipGetPathGradientPresetBlendCount(GpPathGradient(nativeBrush), count));
    result := count;
  end;

  function TGPPathGradientBrush.SetInterpolationColors(presetColors: PARGB;
    blendPositions: PSingle; count: Integer): TStatus;
  var
    status: TStatus;
  begin
    if ((count <= 0) or (presetColors = nil)) then
    begin
      result := SetStatus(InvalidParameter);
      exit;
    end;

    status := SetStatus(GdipSetPathGradientPresetBlend(GpPathGradient(nativeBrush),
                          presetColors, blendPositions, count));
    result := status;
  end;

  function TGPPathGradientBrush.GetInterpolationColors(presetColors: PARGB;
    blendPositions: PSingle; count: Integer): TStatus;
  var
    status: GpStatus;
    i: Integer;
    argbs: PARGB;
  begin
        if ((count <= 0) or (presetColors = nil)) then
        begin
          result := SetStatus(InvalidParameter);
          exit;
        end;
        getmem(argbs, count*SizeOf(ARGB));
        if (argbs = nil) then
        begin
          result := SetStatus(OutOfMemory);
          exit;
        end;

        status := SetStatus(GdipGetPathGradientPresetBlend(nativeBrush, argbs,
                     blendPositions, count));

        for i := 0 to count - 1 do
          TColorDynArray(presetColors)[i] := TColorDynArray(argbs)[i];

        freemem(argbs);

        result := status;
  end;

  function TGPPathGradientBrush.SetBlendBellShape(const focus: Single; const scale: Single = 1.0): TStatus;
  begin
    result := SetStatus(GdipSetPathGradientSigmaBlend(GpPathGradient(nativeBrush), focus, scale));
  end;

  function TGPPathGradientBrush.SetBlendTriangularShape(const focus: Single; const scale: Single = 1.0): TStatus;
  begin
    result := SetStatus(GdipSetPathGradientLinearBlend(GpPathGradient(nativeBrush), focus, scale));
  end;

  function TGPPathGradientBrush.GetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipGetPathGradientTransform(GpPathGradient(nativeBrush),
                      matrix.nativeMatrix));
  end;

  function TGPPathGradientBrush.SetTransform(matrix: TGPMatrix): TStatus;
  begin
    result := SetStatus(GdipSetPathGradientTransform(
                      GpPathGradient(nativeBrush),
                      matrix.nativeMatrix));
  end;

  function TGPPathGradientBrush.ResetTransform: TStatus;
  begin
    result := SetStatus(GdipResetPathGradientTransform(
                      GpPathGradient(nativeBrush)));
  end;

  function TGPPathGradientBrush.MultiplyTransform(matrix: TGPMatrix; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipMultiplyPathGradientTransform(
                      GpPathGradient(nativeBrush),
                      matrix.nativeMatrix,
                      order));
  end;

  function TGPPathGradientBrush.TranslateTransform(const dx, dy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipTranslatePathGradientTransform(
                      GpPathGradient(nativeBrush),
                      dx, dy, order));
  end;

  function TGPPathGradientBrush.ScaleTransform(const sx, sy: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipScalePathGradientTransform(
                      GpPathGradient(nativeBrush),
                      sx, sy, order));
  end;

  function TGPPathGradientBrush.RotateTransform(const angle: Single; order: TMatrixOrder = MatrixOrderPrepend): TStatus;
  begin
    result := SetStatus(GdipRotatePathGradientTransform(
                      GpPathGradient(nativeBrush),
                      angle, order));
  end;

  function TGPPathGradientBrush.GetFocusScales(out xScale, yScale: Single): TStatus;
  begin
    result := SetStatus(GdipGetPathGradientFocusScales(
                      GpPathGradient(nativeBrush), xScale, yScale));
  end;

  function TGPPathGradientBrush.SetFocusScales(const xScale, yScale: Single): TStatus;
  begin
    result := SetStatus(GdipSetPathGradientFocusScales(
                      GpPathGradient(nativeBrush), xScale, yScale));
  end;

  function TGPPathGradientBrush.GetWrapMode: TWrapMode;
  begin
    SetStatus(GdipGetPathGradientWrapMode(GpPathGradient(nativeBrush), result));
  end;

  function TGPPathGradientBrush.SetWrapMode(wrapMode: TWrapMode): TStatus;
  begin
    result := SetStatus(GdipSetPathGradientWrapMode(
                      GpPathGradient(nativeBrush), wrapMode));
  end;

  constructor TGPPathGradientBrush.Create;
  begin
     // écrase la fonction parent
  end;

procedure TeeGDIPlusStartup;
begin
  if gdiPlusToken=0 then
  begin
    TeeGDIPlusLoadDLL;

    // Initialize StartupInput structure
    StartupInput.DebugEventCallback := nil;
    StartupInput.SuppressBackgroundThread := True;
    StartupInput.SuppressExternalCodecs   := False;
    StartupInput.GdiplusVersion := 1;

    // Initialize GDI+
    GdiplusStartup(gdiplusToken, @StartupInput, @StartupOutput);

    {$IFDEF TEEOCX}
    ocxShutDown:=False;
    {$ENDIF}

    if Assigned(StartupOutput.NotificationHook) then
       StartupOutput.NotificationHook(BGThreadToken);
  end;
end;

procedure TeeGDIPlusShutdown;
begin
{$IFDEF TEEOCX}
if gdiplusToken<>0 then
begin
{$ENDIF}
  if Assigned(GenericSansSerifFontFamily) {$IFDEF TEEOCX} and (GenericSansSerifFontFamily.lastResult = Status.Ok) {$ENDIF} then
     GenericSansSerifFontFamily.Free;

  if Assigned(GenericSerifFontFamily) then
     GenericSerifFontFamily.Free;

  if Assigned(GenericMonospaceFontFamily) then
     GenericMonospaceFontFamily.Free;

  if Assigned(GenericTypographicStringFormatBuffer) then
  Begin
     GenericTypographicStringFormatBuffer.free;
     {$IFDEF TEEOCX}  //B1122
     GenericTypographicStringFormatBuffer := nil;
     {$ENDIF}
  End;

  if Assigned(GenericDefaultStringFormatBuffer) then
     GenericDefaultStringFormatBuffer.Free;
{$IFDEF TEEOCX}
end;
{$ENDIF}

  // Close GDI +
  if gdiplusToken<>0 then
  Begin
    if Assigned(StartupOutput.NotificationUnhook) then
       StartupOutput.NotificationUnhook(BGThreadToken);

    GdiplusShutdown(gdiplusToken);
    {$IFDEF TEEOCX}
    ocxShutDown:=True;
    {$ENDIF}
    gdiplusToken:=0;
    TeeGDIPlusFreeDLL;
  End;
end;

initialization
finalization
  TeeGDIPlusShutdown;
end.
