{********************************************************************}
{                                                                    }
{ written by TMS Software                                            }
{            copyright © 2013                                        }
{            Email : info@tmssoftware.com                            }
{            Web : http://www.tmssoftware.com                        }
{                                                                    }
{ The source code is given as is. The author is not responsible      }
{ for any possible damage done due to the use of this code.          }
{ The complete source code remains property of the author and may    }
{ not be distributed, published, given or sold in any form as such.  }
{ No parts of the source code can be included in any other component }
{ or application without written authorization of the author.        }
{********************************************************************}

unit FMX.TMSGridPDFIO;

interface

{$I TMSDEFS.INC}

{$IFDEF MACOS}
{$IFNDEF IOS}
{$DEFINE MACOSONLY}
{$ENDIF}
{$ENDIF}

{$IFDEF IOS}
{$DEFINE GENERALOSX}
{$ENDIF}
{$IFDEF MACOS}
{$DEFINE GENERALOSX}
{$ENDIF}

uses
  {$IFNDEF IOS}
  {$IFNDEF MACOS}
  {$IFNDEF ANDROID}
  Windows
  {$ENDIF}
  {$ELSE}
  Macapi.CoreFoundation, Macapi.CocoaTypes, Macapi.CoreGraphics, Macapi.Foundation, Macapi.CoreText, Macapi.AppKit, Macapi.ImageIO
  {$IFDEF DELPHIXE6_LVL}
  , MacApi.Helpers
  {$ENDIF}
  {$ENDIF}
  {$ENDIF}
  {$IFDEF IOS}
  Macapi.CoreFoundation, iOSapi.CocoaTypes, iOSapi.CoreGraphics, iOSapi.Foundation, iOSapi.CoreText, iOSapi.CoreImage, iOSapi.UIKit
  {$IFDEF DELPHIXE6_LVL}
  , MacApi.Helpers
  {$ENDIF}
  {$ENDIF}
  {$IFNDEF ANDROID},{$ENDIF}Classes, SysUtils, Types, FMX.Types, FMX.TMSGrid, FMX.TMSGridOptions, FMX.TMSBaseControl, FMX.TMSPDFRenderLib,
  FMX.TMSGridData, FMX.TMSGridCell, Math, UITypes, FMX.TMSXUtil, FMX.TMSBitmap, FMX.Controls, FMX.Dialogs
  {$IFDEF DELPHIXE5_LVL}
  , FMX.Graphics
  {$ENDIF}
  ;


const
  MAJ_VER = 1; // Major version nr.
  MIN_VER = 5; // Minor version nr.
  REL_VER = 0; // Release nr.
  BLD_VER = 0; // Build nr.

  // version history
  // v1.0.0.0 : first release
  // v1.0.0.1 : Improved : BeginExport and EndExport functionality in PDF Render library for memory improvement
  // v1.5.0.0 : New : support for XE4

type
  TTMSFMXGridPDFIO = class;

  TTMSFMXGridCellExport = class helper for TTMSFMXGridCell
  {$IFDEF GENERALOSX}
    procedure ExportToPDF(APDFIO: TTMSFMXGridPDFIO; pdfContext: CGContextRef; ARect, ATextRect: TRectF; ADrawText: Boolean; ADrawBackGround: Boolean);
  {$ELSE}
    procedure ExportToPDF(APDFIO: TTMSFMXGridPDFIO; APDFLib: TTMSFMXPDFRenderLib; ARect, ATextRect: TRectF; ADrawText: Boolean; ADrawBackGround: Boolean);
  {$ENDIF}
  end;

  TProGrid = class(TTMSFMXGrid)
  end;

  TTMSFMXGridPDFIOGlyphs = class(TPersistent)
  private
    FRadioButtonChecked: TBitmap;
    FRadioButtonUnChecked: TBitmap;
    FCheckBoxChecked: TBitmap;
    FCheckBoxUnChecked: TBitmap;
  public
    constructor Create(AOwner: TPersistent);
    procedure Assign(Source: TPersistent); override;
    destructor Destroy; override;
  published
    property CheckBoxChecked: TBitmap read FCheckBoxChecked write FCheckBoxChecked;
    property CheckBoxUnChecked: TBitmap read FCheckBoxUnChecked write FCheckBoxUnChecked;
    property RadioButtonChecked: TBitmap read FRadioButtonChecked write FRadioButtonChecked;
    property RadioButtonUnChecked: TBitmap read FRadioButtonUnChecked write FRadioButtonUnChecked;
  end;

  TTMSFMXGridPDFIOInformation = class(TPersistent)
  private
    FModificationDate: String;
    FAuthor: String;
    FProducer: String;
    FCreator: String;
    FSubject: String;
    FTitle: String;
    FPDFVersion: String;
    FKeywords: String;
    FCreationDate: String;
  public
    procedure Assign(Source: TPersistent); override;
  published
    property PDFVersion: String read FPDFVersion write FPDFVersion;
    property Author: String read FAuthor write FAuthor;
    property Title: String read FTitle write FTitle;
    property Subject: String read FSubject write FSubject;
    property Keywords: String read FKeywords write FKeywords;
    property Creator: String read FCreator write FCreator;
    property Producer: String read FProducer write FProducer;
    property CreationDate: String read FCreationDate write FCreationDate;
    property ModificationDate: String read FModificationDate write FModificationDate;
  end;

  TTMSFMXGridPDFIOOptions = class(TPersistent)
  private
    FGlyphs: TTMSFMXGridPDFIOGlyphs;
    FInformation: TTMSFMXGridPDFIOInformation;
  public
    constructor Create(AOwner: TComponent);
    procedure Assign(Source: TPersistent); override;
    destructor Destroy; override;
    property Information: TTMSFMXGridPDFIOInformation read FInformation write FInformation;
  published
    property Glyphs: TTMSFMXGridPDFIOGlyphs read FGlyphs write FGlyphs;
  end;

  TGridListArray = array of TTMSFMXGrid;

  TTMSFMXGridPDFIOOnPrintProgress = procedure(Sender: TObject; APageIndex: Integer; APrintProgress: Single) of object;
  TTMSFMXGridPDFIOOnPrintNewPage = procedure(Sender: TObject; APageIndex: Integer) of object;
  TTMSFMXGridPDFIOOnPrintEndPage = procedure(Sender: TObject; APageIndex: Integer) of object;
  TTMSFMXGridPDFIOOnPrintEvent = procedure(Sender: TObject) of object;

  [ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 or pidiOSSimulator or pidiOSDevice)]
  TTMSFMXGridPDFIO = class(TComponent)
  private
    FPageIndex, APageIndex: Integer;
    AProgress: Integer;
    FGrid: TTMSFMXGrid;
    FGridList: TGridListArray;
    FOptions: TTMSFMXGridPDFIOOptions;
    FOnPrintNewPage: TTMSFMXGridPDFIOOnPrintNewPage;
    FOnPrintProgress: TTMSFMXGridPDFIOOnPrintProgress;
    FOnPrintEndPage: TTMSFMXGridPDFIOOnPrintEndPage;
    FOnPrintEnd: TTMSFMXGridPDFIOOnPrintEvent;
    FOnPrintBegin: TTMSFMXGridPDFIOOnPrintEvent;
    FPDFRenderLib: TTMSFMXPDFRenderLib;
    function GetVersion: String;
    function GetVersionNr: integer;
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    {$IFDEF GENERALOSX}
    procedure DoExportPDF(AGrid: TTMSFMXGrid; AContext: CGContextRef;  pageRect: CGRect;ASelection: TCellRange; APages: array of Integer; AResetPosition: Boolean = False);
    procedure DrawTitle(AGrid: TTMSFMXGrid; APageIndex: Integer; AContext: CGContextRef; ARect: TRectF);
    procedure DrawDescription(AGrid: TTMSFMXGrid; APageIndex: Integer; AContext: CGContextRef; ARect: TRectF);
    procedure DrawPageNumber(AGrid: TTMSFMXGrid; APageIndex: Integer; AContext: CGContextRef; ARect: TRectF);
    {$ELSE}
    procedure DoExportPDF(AGrid: TTMSFMXGrid; APDFLib: TTMSFMXPDFRenderLib; pageRect: TRectF; ASelection: TCellRange; APages: array of Integer; AResetPosition: Boolean = False);
    procedure DrawTitle(AGrid: TTMSFMXGrid; APDFLib: TTMSFMXPDFRenderLib; APageIndex: Integer; ARect: TRectF);
    procedure DrawDescription(AGrid: TTMSFMXGrid; APDFLib: TTMSFMXPDFRenderLib; APageIndex: Integer; ARect: TRectF);
    procedure DrawPageNumber(AGrid: TTMSFMXGrid; APDFLib: TTMSFMXPDFRenderLib; APageIndex: Integer; ARect: TRectF);
    {$ENDIF}
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure ExportPDF(const AFileName: String);
    procedure AppendGridToList(const AGrid: TTMSFMXGrid);
    procedure ClearGridList;
  published
    property Grid: TTMSFMXGrid read FGrid write FGrid;
    property Options: TTMSFMXGridPDFIOOptions read FOptions write FOptions;
    property OnPrintBegin: TTMSFMXGridPDFIOOnPrintEvent read FOnPrintBegin write FOnPrintBegin;
    property OnPrintNewPage: TTMSFMXGridPDFIOOnPrintNewPage read FOnPrintNewPage write FOnPrintNewPage;
    property OnPrintProgress: TTMSFMXGridPDFIOOnPrintProgress read FOnPrintProgress write FOnPrintProgress;
    property OnPrintEnd: TTMSFMXGridPDFIOOnPrintEvent read FOnPrintEnd write FOnPrintEnd;
    property OnPrintEndPage: TTMSFMXGridPDFIOOnPrintEndPage read FOnPrintEndPage write FOnPrintEndPage;
    property PDFRenderLib: TTMSFMXPDFRenderLib read FPDFRenderLib write FPDFRenderLib;
    property Version: String read GetVersion;
  end;

implementation

function TTMSFMXGridPDFIO.GetVersion: String;
var
  vn: Integer;
begin
  vn := GetVersionNr;
  Result := IntToStr(Hi(Hiword(vn)))+'.'+IntToStr(Lo(Hiword(vn)))+'.'+IntToStr(Hi(Loword(vn)))+'.'+IntToStr(Lo(Loword(vn)));
end;

function TTMSFMXGridPDFIO.GetVersionNr: integer;
begin
  Result := MakeLong(MakeWord(BLD_VER,REL_VER),MakeWord(MIN_VER,MAJ_VER));
end;

function GetBValue(rgb: DWORD): Byte;
begin
  Result := Byte(rgb);
end;

function GetGValue(rgb: DWORD): Byte;
begin
  Result := Byte(rgb shr 8);
end;

function GetRValue(rgb: DWORD): Byte;
begin
  Result := Byte(rgb shr 16);
end;

{$IFDEF GENERALOSX}
function measureFrame(frame: CTFrameRef): CGSize;
var
  framePath: CGPathRef;
  frameRect: CGRect;
  lines: CFArrayRef;
  numLines: CFIndex;
  maxWidth: CGFloat;
  textheight: CGFloat;
  i, lastLineIndex: CFIndex;
  ascent, descent, leading, width: CGFloat;
  line: CTLineRef;
  lastLineOrigin: CGPoint;
begin
  framePath := CTFrameGetPath(frame);
  frameRect := CGPathGetBoundingBox(framePath);
  lines := CTFrameGetLines(frame);
  numLines := CFArrayGetCount(lines);
  maxwidth := 0;
  textheight := 0;
  lastLineIndex := numLines - 1;
  for i := 0 to numLines - 1 do
  begin
    line := CFArrayGetValueAtIndex(lines, i);
    width := CTLineGetTypographicBounds(line, @ascent, @descent, @leading);
    if width > maxwidth then
      maxWidth := width;

    if i = lastLineIndex then
    begin
      CTFrameGetLineOrigins(frame, CFRangeMake(lastLineIndex, 1), @lastLineOrigin);
      textheight := CGRectGetMaxY(frameRect) - lastLineOrigin.y + descent;
    end;
  end;


  Result.width := Ceil(maxWidth);
  Result.height := Ceil(textheight);
end;

function sizeWithAttributes(AString: String; AFontSize: Single; AWidth: CGFloat): CGSize;
var
  attrString: CFAttributedStringRef;
  framesetter: CTFramesetterRef;
  path: CGMutablePathRef;
  rec: CGRect;
  range: CFRange;
  frame: CTFrameRef;
  size: CGSize;
  attr: CFDictionaryRef;
  values: array[0..0] of CFTypeRef;
  keys: array[0..0] of CFStringRef;
  font: CTFontRef;
begin
  font := CTFontCreateWithName(CFSTR('Helvetica'), AFontSize, nil);
  keys[0] := kCTFontAttributeName;
  values[0] := font;
  attr := CFDictionaryCreate(nil, @keys, @values,
			       SizeOf(keys) div SizeOf(keys[0]),
             nil,
             nil
             );

  attrString := CFAttributedStringCreate(kCFAllocatorDefault, CFSTR(AString), attr);

  
  CFRelease(attr);

  framesetter := CTFramesetterCreateWithAttributedString(attrString);
  path := CGPathCreateMutable;
  rec.origin.x := 0;
  rec.origin.y := 0;
  rec.size.width := AWidth;
  rec.size.height := 9999;
  CGPathAddRect(path, nil, rec);
  range := CFRangeMake(0, Length(AString));
  frame := CTFramesetterCreateFrame(framesetter, range, path, nil);
  size := measureframe(frame);
  CFRelease(framesetter);
  CFRelease(frame);
  CFRelease(path);
  CFRelease(attrString);
  Result := size;
end;
{$ENDIF}

function GetResourceStream(AResourceName: String): TResourceStream;
var
  hst: NativeUInt;
begin
  Result := nil;
  hst := HInstance;
  if FindRCData(hst, AResourceName) then
    Result := TResourceStream.Create(hst, AResourceName, RT_RCDATA);
end;

{ TTMSFMXGridPDFIO }

procedure TTMSFMXGridPDFIO.AppendGridToList(const AGrid: TTMSFMXGrid);
begin
  SetLength(FGridList, Length(FGridList) + 1);
  FGridList[Length(FGridList) - 1] := AGrid;
end;

procedure TTMSFMXGridPDFIO.ClearGridList;
begin
  SetLength(FGridList, 0);;
end;

constructor TTMSFMXGridPDFIO.Create(AOwner: TComponent);
begin
  inherited;
  FOptions := TTMSFMXGridPDFIOOptions.Create(Self);
end;

destructor TTMSFMXGridPDFIO.Destroy;
begin
  FOptions.Free;
  inherited;
end;

{$IFDEF GENERALOSX}
procedure TTMSFMXGridPDFIO.DrawDescription(AGrid: TTMSFMXGrid; APageIndex: Integer; AContext: CGContextRef; ARect: TRectF);
var
  allowtxt: Boolean;
  x, y: Single;
  strf: NSString;
  sz: CGSize;
  tw, th: Single;
  strc: NSString;
  str: String;
  rc, gc, bc: Byte;
begin
  if AGrid.Options.Printing.Description <> '' then
  begin
    allowtxt := True;
    str := AGrid.Options.Printing.Description;
    {$IFDEF DELPHIXE6_LVL}
    strc := StrToNSStr(str);
    {$ELSE}
    strc := NSStr(str);
    {$ENDIF}
//    DoPrintDrawDescription(APageIndex, ACanvas, r, str, allowtxt);
    if Allowtxt then
    begin
      rc := GetRValue(AGrid.Options.Printing.DescriptionColor);
      gc := GetGValue(AGrid.Options.Printing.DescriptionColor);
      bc := GetBValue(AGrid.Options.Printing.DescriptionColor);
      CGContextSetRGBFillColor(AContext, rc / 255.0, gc / 255.0, bc / 255.0, 1.0);

      x := ARect.Left;
      y := ARect.Top;
      {$IFDEF DELPHIXE6_LVL}
      strf := StrToNSStr('Helvetica');
      {$ELSE}
      strf := NSStr('Helvetica');
      {$ENDIF}
      CGContextSelectFont(AContext, strf.cString, AGrid.Options.Printing.DescriptionFont.Size, kCGEncodingMacRoman);

      sz := sizeWithAttributes(str, AGrid.Options.Printing.DescriptionFont.Size, ARect.Width);

      tw := sz.width;
      th := sz.height;

      y := y + th / 2;

      case AGrid.Options.Printing.DescriptionPosition of
        ppTopCenter: x := x + (ARect.Width - tw) / 2;
        ppTopRight: x := x + ARect.Width - tw;
        ppBottomLeft: y := y + (ARect.Height - (th / 2)) / 2;
        ppBottomCenter:
        begin
          x := x + (ARect.Width - tw) / 2;
          y := y + ARect.Height - (th / 2);
        end;
        ppBottomRight:
        begin
          x := x + ARect.Width - tw;
          y := y + ARect.Height - (th / 2);
        end;
      end;

      CGContextShowTextAtPoint(AContext, x, y, strc.cString, strc.length);
    end;
  end;
end;

procedure TTMSFMXGridPDFIO.DrawPageNumber(AGrid: TTMSFMXGrid; APageIndex: Integer; AContext: CGContextRef; ARect: TRectF);
var
  allowtxt: Boolean;
  x, y: Single;
  strf: NSString;
  sz: CGSize;
  tw, th: Single;
  strc: NSString;
  str: String;
  d: Double;
  rc, gc, bc: Byte;
begin
  allowtxt := True;
  d := APageIndex;
  str := Format(AGrid.Options.Printing.PageNumberFormat, [d]);
  {$IFDEF DELPHIXE6_LVL}
  strc := StrToNSStr(str);
  {$ELSE}
  strc := NSStr(str);
  {$ENDIF}
//    DoPrintDrawPageNumber(APageIndex, ACanvas, r, str, allowtxt);
  if Allowtxt then
  begin
    rc := GetRValue(AGrid.Options.Printing.PageNumberColor);
    gc := GetGValue(AGrid.Options.Printing.PageNumberColor);
    bc := GetBValue(AGrid.Options.Printing.PageNumberColor);
    CGContextSetRGBFillColor(AContext, rc / 255.0, gc / 255.0, bc / 255.0, 1.0);

    x := ARect.Left;
    y := ARect.Top;
    {$IFDEF DELPHIXE6_LVL}
    strf := StrToNSStr('Helvetica');
    {$ELSE}
    strf := NSStr('Helvetica');
    {$ENDIF}
    CGContextSelectFont(AContext, strf.cString, AGrid.Options.Printing.PageNumberFont.Size, kCGEncodingMacRoman);

    sz := sizeWithAttributes(str, AGrid.Options.Printing.PageNumberFont.Size, ARect.Width);

    tw := sz.width;
    th := sz.height;

    y := y + th / 2;

    case AGrid.Options.Printing.PageNumberPosition of
      ppTopCenter: x := x + (ARect.Width - tw) / 2;
      ppTopRight: x := x + ARect.Width - tw;
      ppBottomLeft: y := y + (ARect.Height - (th / 2)) / 2;
      ppBottomCenter:
      begin
        x := x + (ARect.Width - tw) / 2;
        y := y + ARect.Height - (th / 2);
      end;
      ppBottomRight:
      begin
        x := x + ARect.Width - tw;
        y := y + ARect.Height - (th / 2);
      end;
    end;

    CGContextShowTextAtPoint(AContext, x, y, strc.cString, strc.length);
  end;
end;

procedure TTMSFMXGridPDFIO.DrawTitle(AGrid: TTMSFMXGrid; APageIndex: Integer; AContext: CGContextRef; ARect: TRectF);
var
  allowtxt: Boolean;
  x, y: Single;
  strf: NSString;
  sz: CGSize;
  tw, th: Single;
  strc: NSString;
  str: String;
  rc, gc, bc: Byte;
begin
  if AGrid.Options.Printing.Title <> '' then
  begin
    allowtxt := True;
    str := AGrid.Options.Printing.Title;
    {$IFDEF DELPHIXE6_LVL}
    strc := StrToNSStr(str);
    {$ELSE}
    strc := NSStr(str);
    {$ENDIF}
//    DoPrintDrawTitle(APageIndex, ACanvas, r, str, allowtxt);
    if Allowtxt then
    begin
      rc := GetRValue(AGrid.Options.Printing.TitleColor);
      gc := GetGValue(AGrid.Options.Printing.TitleColor);
      bc := GetBValue(AGrid.Options.Printing.TitleColor);
      CGContextSetRGBFillColor(AContext, rc / 255.0, gc / 255.0, bc / 255.0, 1.0);

      x := ARect.Left;
      y := ARect.Top;
      {$IFDEF DELPHIXE6_LVL}
      strf := StrToNSStr('Helvetica');
      {$ELSE}
      strf := NSStr('Helvetica');
      {$ENDIF}
      CGContextSelectFont(AContext, strf.cString, AGrid.Options.Printing.TitleFont.Size, kCGEncodingMacRoman);

      sz := sizeWithAttributes(str, AGrid.Options.Printing.TitleFont.Size, ARect.Width);

      tw := sz.width;
      th := sz.height;

      y := y + th / 2;

      case AGrid.Options.Printing.TitlePosition of
        ppTopCenter: x := x + (ARect.Width - tw) / 2;
        ppTopRight: x := x + ARect.Width - tw;
        ppBottomLeft: y := y + (ARect.Height - (th / 2)) / 2;
        ppBottomCenter:
        begin
          x := x + (ARect.Width - tw) / 2;
          y := y + ARect.Height - (th / 2);
        end;
        ppBottomRight:
        begin
          x := x + ARect.Width - tw;
          y := y + ARect.Height - (th / 2);
        end;
      end;

      CGContextShowTextAtPoint(AContext, x, y, strc.cString, strc.length);
    end;
  end;
end;

{$IFDEF MACOSONLY}
function NSImageToCGImageRef(const AImage: NSImage): CGImageRef;
var
  imagedata: NSData;
  imgd: CFDataRef;
  imagesource: CGImageSourceRef;
begin
  imagedata := AImage.TIFFRepresentation;
  imgd := CFDataCreate(nil, imagedata.bytes, imagedata.length);
  imagesource := CGImageSourceCreateWithData(imgd, nil);
  Result := CGImageSourceCreateImageAtIndex(imagesource, 0, nil);
end;
{$ENDIF}

procedure DrawCGImageFromBitmap(const AContext: CGContextRef; const ARect: CGRect; const ABitmap: TBitmap);
var
  ms: TMemoryStream;
  {$IFDEF MACOSONLY}
  img: NSImage;
  {$ELSE}
  img: UIImage;
  {$ENDIF}
  dt: NSData;
  r: CGRect;
begin
  ms := TMemoryStream.Create;
  ABitmap.SaveToStream(ms);

  dt := TNSData.Wrap(TNSData.OCClass.dataWithBytes(ms.Memory, ms.Size));

  ms.Free;

  {$IFDEF MACOSONLY}
  img := TNSImage.Wrap(TNSImage.OCClass.alloc);
  img.initWithData(dt);
  {$ELSE}
  img := TUIImage.Wrap(TUIImage.OCClass.imageWithData(dt));
  {$ENDIF}

  CGContextSaveGState(AContext);

  CGContextTranslateCTM(AContext, ARect.origin.x, ARect.origin.y + ARect.size.height);
  CGContextScaleCTM(AContext, 1.0, -1.0);

  r.origin.x := 0;
  r.origin.y := 0;
  r.size.width := ARect.size.width;
  r.size.height := ARect.size.height;
 
  {$IFDEF MACOSONLY}
  CGContextDrawImage(AContext, r, NSImageToCGImageRef(img));
  {$ELSE}
  CGContextDrawImage(AContext, r, img.CGImage);
  {$ENDIF}
  CGContextRestoreGState(AContext);
end;

procedure TTMSFMXGridCellExport.ExportToPDF(APDFIO: TTMSFMXGridPDFIO; pdfContext: CGContextRef; ARect,
  ATextRect: TRectF; ADrawText, ADrawBackGround: Boolean);
var
  r: CGRect;
  str: String;
  strc, strf: NSString;
  rt: TRectF;
  AllowDraw: Boolean;
  rc, gc, bc: Byte;
  grd: CGGradientRef;
  cspc: CGColorSpaceRef;
  loc: array[0..1] of CGFloat;
  comp: array[0..7] of CGFloat;
  pts: TGradientPoint;
  startPoint, endpoint: CGPoint;
  fs, tw, th: Single;
  x, y: Single;
  sz: CGSize;
  rct: CGRect;
  ctl: TControl;
  bmp: TBitmap;
  rctr: TRectF;
begin
  r.origin.x := ARect.Left;
  r.origin.y := ARect.Top;
  r.size.width := ARect.Width;
  r.size.height := ARect.Height;

  AllowDraw := True;
  if AllowDraw then
  begin
    if ADrawBackGround then
    begin
      case Layout.Fill.Kind of
        {$IFDEF DELPHIXE6_LVL}
        TBrushKind.Gradient:
        {$ELSE}
        TBrushKind.bkGradient:
        {$ENDIF}
        begin
          if Layout.Fill.Gradient.Points.Count > 1 then
          begin
            pts := Layout.Fill.Gradient.Points[0];
            rc := GetRValue(pts.Color);
            gc := GetGValue(pts.Color);
            bc := GetBValue(pts.Color);
            loc[0] := pts.Offset;
            comp[0] := rc / 255;
            comp[1] := gc / 255;
            comp[2] := bc / 255;
            comp[3] := 1.0;

            pts := Layout.Fill.Gradient.Points[1];
            rc := GetRValue(pts.Color);
            gc := GetGValue(pts.Color);
            bc := GetBValue(pts.Color);
            loc[1] := pts.Offset;
            comp[4] := rc / 255;
            comp[5] := gc / 255;
            comp[6] := bc / 255;
            comp[7] := 1.0;


            cspc := CGColorSpaceCreateDeviceRGB();
            grd := CGGradientCreateWithColorComponents(cspc, @comp, @loc, Layout.Fill.Gradient.Points.Count);
            startPoint := r.origin;
            endPoint.x := r.origin.x;
            endPoint.y := r.origin.y + r.size.Height;
            CGContextBeginPath(pdfcontext);
            CGContextMoveToPoint(pdfcontext, CGRectGetMinX(r), CGRectGetMinY(r));
            CGContextAddLineToPoint(pdfcontext, CGRectGetMaxX(r), CGRectGetMinY(r));
            CGContextAddLineToPoint(pdfcontext, CGRectGetMaxX(r), CGRectGetMaxY(r));
            CGContextAddLineToPoint(pdfcontext, CGRectGetMinX(r), CGRectGetMaxY(r));
            CGContextClosePath(pdfcontext);
            CGContextSaveGState(pdfcontext);
            CGContextClip(pdfcontext);
            CGContextDrawLinearGradient(pdfcontext, grd, startPoint, endPoint, 0);
            CGContextRestoreGState(pdfcontext);
            CGColorSpaceRelease(cspc);
            CGGradientRelease(grd);
          end;
        end;
        {$IFDEF DELPHIXE6_LVL}
        TBrushKind.Solid:
        {$ELSE}
        TBrushKind.bkSolid:
        {$ENDIF}
        begin
          rc := GetRValue(Layout.Fill.Color);
          gc := GetGValue(Layout.Fill.Color);
          bc := GetBValue(Layout.Fill.Color);
          CGContextSetRGBFillColor(pdfContext, rc / 255.0, gc / 255.0, bc / 255.0, 1.0);
          CGContextFillRect(pdfcontext, r);
        end;
      end;
    end;

    str := Text;
    if (str <> '') and ADrawText then
    begin
//      ACanvas.Fill.Assign(Layout.FontFill);
//      ACanvas.Font.Assign(Layout.Font);
      rt := ATextRect;
      rt.Left := rt.Left + 2;
      rt.Right := rt.Right - 2;
      rt.Top := rt.Top + 2;
      rt.Bottom := rt.Bottom - 2;

      if IsHTML then
//        HTMLDraw(ACanvas, rt, false,-1,-1,str)
      else
      begin
        {$IFDEF DELPHIXE6_LVL}
      	strc := StrToNSStr(str);
        {$ELSE}
       	strc := NSStr(str);
        {$ENDIF}
        if str <> '' then
        begin
          rc := GetRValue(Layout.FontFill.Color);
          gc := GetGValue(Layout.FontFill.Color);
          bc := GetBValue(Layout.FontFill.Color);
          CGContextSetRGBFillColor(pdfContext, rc / 255.0, gc / 255.0, bc / 255.0, 1.0);

          x := rt.Left;
          y := rt.Top;
          fs := Layout.Font.Size;
          {$IFDEF DELPHIXE6_LVL}
          strf := StrToNSStr('Helvetica');
          if (TFontStyle.fsItalic in Layout.Font.Style) and (TFontStyle.fsBold in Layout.Font.Style) then
            strf := StrToNSStr('Helvetica-BoldOblique')
          else if TFontStyle.fsBold in Layout.Font.Style then
            strf := StrToNSStr('Helvetica-Bold')
          else if TFontStyle.fsItalic in Layout.Font.Style then
            strf := StrToNSStr('Helvetica-Oblique');
          {$ELSE}
          strf := NSStr('Helvetica');
          if (TFontStyle.fsItalic in Layout.Font.Style) and (TFontStyle.fsBold in Layout.Font.Style) then
            strf := NSStr('Helvetica-BoldOblique')
          else if TFontStyle.fsBold in Layout.Font.Style then
            strf := NSStr('Helvetica-Bold')
          else if TFontStyle.fsItalic in Layout.Font.Style then
            strf := NSStr('Helvetica-Oblique');
          {$ENDIF}

          CGContextSelectFont(pdfcontext, strf.cString, fs, kCGEncodingMacRoman);

          sz := sizeWithAttributes(str, fs, rt.Width);

          tw := sz.width;
          th := sz.height;

          y := y + th / 2;

          {$IFDEF DELPHIXE6_LVL}
          case Layout.TextAlign of
            TTextAlign.Center: x := x + (rt.Width - tw) / 2;
            TTextAlign.Trailing: x := x + rt.Width - tw;
          end;

          case Layout.VerticalTextAlign of
            TTextAlign.Center: y := y + (rt.Height - (th / 2)) / 2;
            TTextAlign.Trailing: y := y + rt.Height - (th / 2);
          end;
          {$ELSE}
          case Layout.TextAlign of
            TTextAlign.taCenter: x := x + (rt.Width - tw) / 2;
            TTextAlign.taTrailing: x := x + rt.Width - tw;
          end;

          case Layout.VerticalTextAlign of
            TTextAlign.taCenter: y := y + (rt.Height - (th / 2)) / 2;
            TTextAlign.taTrailing: y := y + rt.Height - (th / 2);
          end;
          {$ENDIF}

          CGContextShowTextAtPoint(pdfContext, x, y, strc.cString, strc.length);
        //  ACanvas.FillText(rt, str, Layout.WordWrapping, AbsoluteOpacity, Layout.FontFlags, Layout.TextAlign, Layout.VerticalTextAlign);
        end;
      end;
    end;

    R.origin.x := R.origin.x + 0.5;
    R.size.width := R.size.width - 0.5;
    R.origin.y := R.origin.y + 0.5;
    R.size.height := R.size.height - 0.5;

    rc := GetRValue(Layout.Stroke.Color);
    gc := GetGValue(Layout.Stroke.Color);
    bc := GetBValue(Layout.Stroke.Color);
    CGContextSetRGBStrokeColor(pdfContext, rc / 255.0, gc / 255.0, bc / 255.0, 1.0);

    {$IFDEF DELPHIXE6_LVL}
    if TSide.Top in Layout.Sides then
    begin
      CGContextMoveToPoint(pdfContext, r.origin.x, r.origin.y);
      CGContextAddLineToPoint(pdfContext, r.origin.x + r.size.width, r.origin.y);
      CGContextStrokePath(pdfContext);
    end;
    if TSide.Left in Layout.Sides then
    begin
      CGContextMoveToPoint(pdfContext, r.origin.x, r.origin.y);
      CGContextAddLineToPoint(pdfContext, r.origin.x, r.origin.y + r.size.height);
      CGContextStrokePath(pdfContext);
    end;
    if TSide.Bottom in Layout.Sides then
    begin
      CGContextMoveToPoint(pdfContext, r.origin.x, r.origin.y + r.size.height);
      CGContextAddLineToPoint(pdfContext, r.origin.x + r.size.width, r.origin.y + r.size.height);
      CGContextStrokePath(pdfContext);
    end;
    if TSide.Right in Layout.Sides then
    begin
      CGContextMoveToPoint(pdfContext, r.origin.x + r.size.width, r.origin.y);
      CGContextAddLineToPoint(pdfContext, r.origin.x + r.size.width, r.origin.y + r.size.height);
      CGContextStrokePath(pdfContext);
    end;
    {$ELSE}
    if TSide.sdTop in Layout.Sides then
    begin
      CGContextMoveToPoint(pdfContext, r.origin.x, r.origin.y);
      CGContextAddLineToPoint(pdfContext, r.origin.x + r.size.width, r.origin.y);
      CGContextStrokePath(pdfContext);
    end;
    if TSide.sdLeft in Layout.Sides then
    begin
      CGContextMoveToPoint(pdfContext, r.origin.x, r.origin.y);
      CGContextAddLineToPoint(pdfContext, r.origin.x, r.origin.y + r.size.height);
      CGContextStrokePath(pdfContext);
    end;
    if TSide.sdBottom in Layout.Sides then
    begin
      CGContextMoveToPoint(pdfContext, r.origin.x, r.origin.y + r.size.height);
      CGContextAddLineToPoint(pdfContext, r.origin.x + r.size.width, r.origin.y + r.size.height);
      CGContextStrokePath(pdfContext);
    end;
    if TSide.sdRight in Layout.Sides then
    begin
      CGContextMoveToPoint(pdfContext, r.origin.x + r.size.width, r.origin.y);
      CGContextAddLineToPoint(pdfContext, r.origin.x + r.size.width, r.origin.y + r.size.height);
      CGContextStrokePath(pdfContext);
    end;
    {$ENDIF}
  end;

  ctl := GetPrintControl;
  if Assigned(ctl) then
  begin
    rct.origin.x := ARect.Left + ctl.Position.X;
    rct.origin.y := ARect.Top + ctl.Position.Y;
    rct.size.width := ctl.Width;
    rct.size.height := ctl.Height;

    if (ctl is TTMSFMXRadioButton) or (ctl is TTMSFMXCheckBox) then
    begin
      rct.origin.x := rct.origin.x + ((rct.size.width - 17) / 2);
      rct.origin.y := rct.origin.y + ((rct.size.height - 17) / 2);
      rct.size.width := 17;
      rct.size.height := 17;
    end;

    if ctl is TTMSFMXBitmap then
    begin
      rctr := (ctl as TTMSFMXBitmap).GetPaintRectangle;
      rct.origin.x := rct.origin.x + rctr.Left;
      rct.origin.y := rct.origin.y + rctr.Top;
      rct.size.width := rctr.Width;
      rct.size.height := rctr.Height;
      if not (ctl as TTMSFMXBitmap).Bitmap.IsEmpty then
        DrawCGImageFromBitmap(pdfContext, rct, (ctl as TTMSFMXBitmap).Bitmap)
      else if ((ctl as TTMSFMXBitmap).BitmapName <> '') and Assigned((ctl as TTMSFMXBitmap).BitmapContainer) then
      begin
        bmp := (ctl as TTMSFMXBitmap).BitmapContainer.FindBitmap((ctl as TTMSFMXBitmap).BitmapName);
        if Assigned(bmp) and not bmp.IsEmpty then
          DrawCGImageFromBitmap(pdfContext, rct, bmp);
      end;
    end
    else if ctl is TTMSFMXCheckBox then
    begin
      if (ctl as TTMSFMXCheckBox).IsChecked then
        DrawCGImageFromBitmap(pdfContext, rct, APDFIO.Options.Glyphs.CheckBoxChecked)
      else
        DrawCGImageFromBitmap(pdfContext, rct, APDFIO.Options.Glyphs.CheckBoxUnChecked);
    end
    else if ctl is TTMSFMXRadioButton then
    begin
      if (ctl as TTMSFMXRadioButton).IsChecked then
        DrawCGImageFromBitmap(pdfContext, rct, APDFIO.Options.Glyphs.RadioButtonChecked)
      else
        DrawCGImageFromBitmap(pdfContext, rct, APDFIO.Options.Glyphs.RadioButtonUnChecked);
    end;
  end;
end;

procedure TTMSFMXGridPDFIO.ExportPDF(const AFileName: String);
var
  pdfContext: CGContextRef;
  path: CFStringRef;
  filename: NSString;
  url: CFURLRef;
  pageRect: CGRect;
  I: Integer;
  grd: TTMSFMXGrid;
begin
  if Assigned(OnPrintBegin) then
    OnPrintBegin(Self);

  //72 dpi (web) = 595 X 842 pixels
  //300 dpi (print) = 2480 X 3508 pixels
  //600 dpi (print) = 4960 X 7016 pixels
  pageRect.origin.x := 0;
  pageRect.origin.y := 0;
  pageRect.size.width := 595;
  pageRect.size.height := 842;

  {$IFDEF DELPHIXE6_LVL}
  filename := StrToNSStr(AFileName);
  {$ELSE}
  filename := NSStr(AFileName);
  {$ENDIF}

  path := CFStringCreateWithCString(nil, filename.cString,
                    kCFStringEncodingUTF8);
  url := CFURLCreateWithFileSystemPath(nil, path,
                     kCFURLPOSIXPathStyle, False);
  CFRelease (path);


  pdfContext := CGPDFContextCreateWithURL(url, @pageRect, nil);

  CFRelease(url);

  CGContextSetTextMatrix(pdfContext,  CGAffineTransformMake(1, 0, 0, -1, 0, 0));

  AProgress := 0;
  FPageIndex := 0;

  if Assigned(Grid) then
    DoExportPDF(Grid, pdfContext, pageRect, CellRange(0, 0, Grid.ColumnCount - 1, Grid.RowCount - 1), []);

  FPageIndex := FPageIndex + APageIndex;

  for I := 0 to Length(FGridList) - 1 do
  begin
    grd := FGridList[I];
    if Assigned(grd) then
    begin
      DoExportPDF(grd, pdfContext, pageRect, CellRange(0, 0, grd.ColumnCount - 1, grd.RowCount - 1), []);
      FPageIndex := FPageIndex + APageIndex;
    end;
  end;

  CGContextRelease (pdfContext);

  if Assigned(OnPrintEnd) then
    OnPrintEnd(Self);
end;
{$ELSE}

procedure TTMSFMXGridPDFIO.DrawDescription(AGrid: TTMSFMXGrid;
  APDFLib: TTMSFMXPDFRenderLib; APageIndex: Integer; ARect: TRectF);
var
  allowtxt: Boolean;
  x, y: Single;
  tw, th: Single;
  str: String;
  FontID: Integer;
  rc, gc, bc: Byte;
begin
  if not Assigned(FPDFRenderLib) then
    Exit;

  if AGrid.Options.Printing.Description <> '' then
  begin
    allowtxt := True;
    str := AGrid.Options.Printing.Description;
//    DoPrintDrawDescription(APageIndex, ACanvas, r, str, allowtxt);
    if Allowtxt then
    begin
      x := ARect.Left;
      y := ARect.Top;

      rc := GetRValue(AGrid.Options.Printing.DescriptionColor);
      gc := GetGValue(AGrid.Options.Printing.DescriptionColor);
      bc := GetBValue(AGrid.Options.Printing.DescriptionColor);

      FPDFRenderLib.SetTextColor(rc/255, gc/255, bc/255);
      FontID := APDFLib.AddTrueTypeFont(AGrid.Options.Printing.DescriptionFont.Family);
      APDFLib.SelectFont(FontID);
      APDFLib.SetTextSize(AGrid.Options.Printing.DescriptionFont.Size);

      tw := FPDFRenderLib.GetTextWidth(str);
      th := FPDFRenderLib.GetTextHeight;

      y := y + th / 2;

      case AGrid.Options.Printing.DescriptionPosition of
        ppTopCenter: x := x + (ARect.Width - tw) / 2;
        ppTopRight: x := x + ARect.Width - tw;
        ppBottomLeft: y := y + (ARect.Height - (th / 2)) / 2;
        ppBottomCenter:
        begin
          x := x + (ARect.Width - tw) / 2;
          y := y + ARect.Height - (th / 2);
        end;
        ppBottomRight:
        begin
          x := x + ARect.Width - tw;
          y := y + ARect.Height - (th / 2);
        end;
      end;

      FPDFRenderLib.DrawText(x, y, str);
    end;
  end;
end;

procedure TTMSFMXGridPDFIO.DrawPageNumber(AGrid: TTMSFMXGrid;
  APDFLib: TTMSFMXPDFRenderLib; APageIndex: Integer; ARect: TRectF);
var
  allowtxt: Boolean;
  x, y: Single;
  tw, th: Single;
  str: String;
  FontID: Integer;
  d: Double;
  rc, gc, bc: Byte;
begin
  if not Assigned(FPDFRenderLib) then
    Exit;

  allowtxt := True;
  d := APageIndex;
  str := Format(AGrid.Options.Printing.PageNumberFormat, [d]);
//    DoPrintDrawPageNumber(APageIndex, ACanvas, r, str, allowtxt);
  if Allowtxt then
  begin
    x := ARect.Left;
    y := ARect.Top;

    rc := GetRValue(AGrid.Options.Printing.PageNumberColor);
    gc := GetGValue(AGrid.Options.Printing.PageNumberColor);
    bc := GetBValue(AGrid.Options.Printing.PageNumberColor);

    FPDFRenderLib.SetTextColor(rc/255, gc/255, bc/255);

    FontID := APDFLib.AddTrueTypeFont(AGrid.Options.Printing.PageNumberFont.Family);
    APDFLib.SelectFont(FontID);
    APDFLib.SetTextSize(AGrid.Options.Printing.PageNumberFont.Size);

    tw := FPDFRenderLib.GetTextWidth(str);
    th := FPDFRenderLib.GetTextHeight;

    y := y + th / 2;

    case AGrid.Options.Printing.PageNumberPosition of
      ppTopCenter: x := x + (ARect.Width - tw) / 2;
      ppTopRight: x := x + ARect.Width - tw;
      ppBottomLeft: y := y + (ARect.Height - (th / 2)) / 2;
      ppBottomCenter:
      begin
        x := x + (ARect.Width - tw) / 2;
        y := y + ARect.Height - (th / 2);
      end;
      ppBottomRight:
      begin
        x := x + ARect.Width - tw;
        y := y + ARect.Height - (th / 2);
      end;
    end;

    FPDFRenderLib.DrawText(x, y, str);
  end;
end;

procedure TTMSFMXGridPDFIO.DrawTitle(AGrid: TTMSFMXGrid; APDFLib: TTMSFMXPDFRenderLib; APageIndex: Integer;
  ARect: TRectF);
var
  allowtxt: Boolean;
  x, y: Single;
  tw, th: Single;
  str: String;
  FontID: Integer;
  rc, gc, bc: Byte;
begin
  if not Assigned(FPDFRenderLib) then
    Exit;

  if AGrid.Options.Printing.Title <> '' then
  begin
    allowtxt := True;
    str := AGrid.Options.Printing.Title;
//    DoPrintDrawTitle(APageIndex, ACanvas, r, str, allowtxt);
    if Allowtxt then
    begin
      x := ARect.Left;
      y := ARect.Top;

      rc := GetRValue(AGrid.Options.Printing.TitleColor);
      gc := GetGValue(AGrid.Options.Printing.TitleColor);
      bc := GetBValue(AGrid.Options.Printing.TitleColor);

      FPDFRenderLib.SetTextColor(rc/255, gc/255, bc/255);

      FontID := APDFLib.AddTrueTypeFont(AGrid.Options.Printing.TitleFont.Family);
      APDFLib.SelectFont(FontID);
      APDFLib.SetTextSize(AGrid.Options.Printing.TitleFont.Size);

      tw := FPDFRenderLib.GetTextWidth(str);
      th := FPDFRenderLib.GetTextHeight;

      y := y + th / 2;

      case AGrid.Options.Printing.TitlePosition of
        ppTopCenter: x := x + (ARect.Width - tw) / 2;
        ppTopRight: x := x + ARect.Width - tw;
        ppBottomLeft: y := y + (ARect.Height - (th / 2)) / 2;
        ppBottomCenter:
        begin
          x := x + (ARect.Width - tw) / 2;
          y := y + ARect.Height - (th / 2);
        end;
        ppBottomRight:
        begin
          x := x + ARect.Width - tw;
          y := y + ARect.Height - (th / 2);
        end;
      end;

      FPDFRenderLib.DrawText(x, y, str);
    end;
  end;
end;

{ TTMSFMXGridCellExport }

procedure TTMSFMXGridCellExport.ExportToPDF(APDFIO: TTMSFMXGridPDFIO; APDFLib:TTMSFMXPDFRenderLib; ARect,
  ATextRect: TRectF; ADrawText, ADrawBackGround: Boolean);
var
  str: String;
  rt: TRectF;
  AllowDraw: Boolean;
  rc, gc, bc, rcto, gcto, bcto: Byte;
  tw, th: Single;
  x, y: Single;
  ctl: TControl;
  r, rct: TRectF;
  FontID: Integer;
  bmp: TBitmap;
  ms: TMemoryStream;
  pts: TGradientPoint;
  rctr: TRectF;

begin
  r := ARect;

  AllowDraw := True;
  if AllowDraw then
  begin
    if ADrawBackGround then
    begin
      {$IFDEF DELPHIXE6_LVL}
      case Layout.Fill.Kind of
        TBrushKind.Solid, TBrushKind.Gradient:
        begin
          if Layout.Fill.Kind = TBrushKind.Solid then
          begin
      {$ELSE}
      case Layout.Fill.Kind of
        TBrushKind.bkSolid, TBrushKind.bkGradient:
        begin
          if Layout.Fill.Kind = TBrushKind.bkSolid then
          begin
      {$ENDIf}
            rc := GetRValue(Layout.Fill.Color);
            gc := GetGValue(Layout.Fill.Color);
            bc := GetBValue(Layout.Fill.Color);
            APDFLib.SetFillColor(rc/255,gc/255,bc/255);
            APDFLib.DrawBox(r);
          end
          {$IFDEF DELPHIXE6_LVL}
          else if Layout.Fill.Kind = TBrushKind.Gradient then
          {$ELSE}
          else if Layout.Fill.Kind = TBrushKind.bkGradient then
          {$ENDIF}
          begin
            if Layout.Fill.Gradient.Points.Count > 1 then
            begin
              pts := Layout.Fill.Gradient.Points[0];
              rc := GetRValue(pts.Color);
              gc := GetGValue(pts.Color);
              bc := GetBValue(pts.Color);

              pts := Layout.Fill.Gradient.Points[1];
              rcto := GetRValue(pts.Color);
              gcto := GetGValue(pts.Color);
              bcto := GetBValue(pts.Color);

              APDFLib.DrawGradient(r, rc / 255, gc / 255, bc / 255, rcto / 255, gcto / 255, bcto / 255);
            end;
          end;
        end;
      end;
    end;

    str := Text;
    if (str <> '') and ADrawText then
    begin
      rt := ATextRect;
      rt.Left := rt.Left + 2;
      rt.Right := rt.Right - 2;
      rt.Top := rt.Top + 2;
      rt.Bottom := rt.Bottom - 2;

      if IsHTML then
//        HTMLDraw(ACanvas, rt, false,-1,-1,str)
      else
      begin
        if str <> '' then
        begin
          rc := GetRValue(Layout.FontFill.Color);
          gc := GetGValue(Layout.FontFill.Color);
          bc := GetBValue(Layout.FontFill.Color);
          APDFLib.SetTextColor(rc/255, gc/255, bc/255);

          x := rt.Left;
          y := rt.Top;

          FontID := APDFLib.AddTrueTypeFont(Layout.Font.Family);
          APDFLib.SelectFont(FontID);
          APDFLib.SetTextSize(Layout.Font.Size);
          tw := APDFLib.GetTextWidth(str);
          th := APDFLib.GetTextHeight;

          y := y + th / 2;

          {$IFDEF DELPHIXE6_LVL}

          case Layout.TextAlign of
            TTextAlign.Center: x := x + (rt.Width - tw) / 2;
            TTextAlign.Trailing: x := x + rt.Width - tw;
          end;

          case Layout.VerticalTextAlign of
            TTextAlign.Center: y := y + (rt.Height - (th / 2)) / 2;
            TTextAlign.Trailing: y := y + rt.Height - (th / 2);
          end;

          {$ELSE}

          case Layout.TextAlign of
            TTextAlign.taCenter: x := x + (rt.Width - tw) / 2;
            TTextAlign.taTrailing: x := x + rt.Width - tw;
          end;

          case Layout.VerticalTextAlign of
            TTextAlign.taCenter: y := y + (rt.Height - (th / 2)) / 2;
            TTextAlign.taTrailing: y := y + rt.Height - (th / 2);
          end;

          {$ENDIF}

          APDFLib.DrawText(x, y, str);
        end;
      end;
    end;

    r.Left := R.Left + 0.5;
    R.Width := r.Width - 0.5;
    R.Top := R.Top + 0.5;
    R.height := R.height - 0.5;

    rc := GetRValue(Layout.Stroke.Color);
    gc := GetGValue(Layout.Stroke.Color);
    bc := GetBValue(Layout.Stroke.Color);
    APDFLib.SetLineWidth(0.5);
    APDFLib.SetLineColor(rc / 255, gc/255, bc/255);

    {$IFDEF DELPHIXE6_LVL}
    if TSide.Top in Layout.Sides then
      APDFLib.DrawLine(r.Left, r.Top, r.Left + r.size.width, r.Top);
    if TSide.Left in Layout.Sides then
      APDFLib.DrawLine(r.Left, r.Top, r.Left, r.Top + r.size.height);
    if TSide.Bottom in Layout.Sides then
      APDFLib.DrawLine(r.Left, r.Top + r.size.height, r.Left + r.size.width, r.Top + r.size.height);
    if TSide.Right in Layout.Sides then
      APDFLib.DrawLine(r.Left + r.size.width, r.Top, r.Left + r.size.width, r.Top + r.size.height);
    {$ELSE}
    if TSide.sdTop in Layout.Sides then
      APDFLib.DrawLine(r.Left, r.Top, r.Left + r.size.width, r.Top);
    if TSide.sdLeft in Layout.Sides then
      APDFLib.DrawLine(r.Left, r.Top, r.Left, r.Top + r.size.height);
    if TSide.sdBottom in Layout.Sides then
      APDFLib.DrawLine(r.Left, r.Top + r.size.height, r.Left + r.size.width, r.Top + r.size.height);
    if TSide.sdRight in Layout.Sides then
      APDFLib.DrawLine(r.Left + r.size.width, r.Top, r.Left + r.size.width, r.Top + r.size.height);
    {$ENDIF}
  end;

  ctl := GetPrintControl;
  if Assigned(ctl) then
  begin
    rct.Left := ARect.Left + ctl.Position.X;
    rct.Top := ARect.Top + ctl.Position.Y;
    rct.Width := ctl.Width;
    rct.Height := ctl.Height;

    if (ctl is TTMSFMXRadioButton) or (ctl is TTMSFMXCheckBox) then
    begin
      rct.Left := rct.Left + ((rct.width - 17) / 2);
      rct.Top := rct.Top + ((rct.height - 17) / 2);
      rct.width := 17;
      rct.height := 17;
    end;

    bmp := nil;
    if ctl is TTMSFMXBitmap then
    begin
      rctr := (ctl as TTMSFMXBitmap).GetPaintRectangle;
      rct.Left := rct.Left + rctr.Left;
      rct.Top := rct.Top + rctr.Top;
      rct.width := rctr.Width;
      rct.height := rctr.Height;

      if not (ctl as TTMSFMXBitmap).Bitmap.IsEmpty then
        bmp := (ctl as TTMSFMXBitmap).Bitmap
      else if ((ctl as TTMSFMXBitmap).BitmapName <> '') and Assigned((ctl as TTMSFMXBitmap).BitmapContainer) then
        bmp := (ctl as TTMSFMXBitmap).BitmapContainer.FindBitmap((ctl as TTMSFMXBitmap).BitmapName);
    end
    else if ctl is TTMSFMXCheckBox then
    begin
      if (ctl as TTMSFMXCheckBox).IsChecked then
        bmp := APDFIO.Options.Glyphs.CheckBoxChecked
      else
        bmp := APDFIO.Options.Glyphs.CheckBoxUnChecked;
    end
    else if ctl is TTMSFMXRadioButton then
    begin
      if (ctl as TTMSFMXRadioButton).IsChecked then
        bmp := APDFIO.Options.Glyphs.RadioButtonChecked
      else
        bmp := APDFIO.Options.Glyphs.RadioButtonUnChecked;
    end;

    if Assigned(bmp) then
    begin
      ms := TMemoryStream.Create;
      bmp.SaveToStream(ms);
      APDFLib.AddImageFromStream(ms);
      APDFLib.DrawImage(rct);
      ms.Free;
    end;
  end;
end;

procedure TTMSFMXGridPDFIO.ExportPDF(const AFileName: String);
var
  UnlockResult: Integer;
  pageRect: TRectF;
  I: Integer;
  grd: TTMSFMXGrid;
begin
  if not Assigned(PDFRenderLib) then
  begin
    raise Exception.Create('No PDF Render Library Assigned');
    Exit;
  end;

  try
    UnlockResult := PDFRenderLib.CreateInstance;
    if UnlockResult = 1 then
    begin
      PDFRenderLib.BeginExport(AFileName);
      PDFRenderLib.SetInformation(0, Options.Information.PDFVersion);
      PDFRenderLib.SetInformation(1, Options.Information.Author);
      PDFRenderLib.SetInformation(2, Options.Information.Title);
      PDFRenderLib.SetInformation(3, Options.Information.Subject);
      PDFRenderLib.SetInformation(4, Options.Information.Keywords);
      PDFRenderLib.SetInformation(5, Options.Information.Creator);
      PDFRenderLib.SetInformation(6, Options.Information.Producer);
      PDFRenderLib.SetInformation(7, Options.Information.CreationDate);
      PDFRenderLib.SetInformation(8, Options.Information.ModificationDate);
      PDFRenderLib.SetOrigin(1);
      if Assigned(OnPrintBegin) then
        OnPrintBegin(Self);

      pageRect.Left := 0;
      pageRect.Top := 0;
      pageRect.Width := 595;
      pageRect.Height := 842;

      AProgress := 0;
      FPageIndex := 0;

      if Assigned(Grid) then
        DoExportPDF(Grid, PDFRenderLib, pageRect, CellRange(0, 0, Grid.ColumnCount - 1, Grid.RowCount - 1), []);

      FPageIndex := FPageIndex + APageIndex;

      for I := 0 to Length(FGridList) - 1 do
      begin
        grd := FGridList[I];
        if Assigned(grd) then
        begin
          DoExportPDF(grd, PDFRenderLib, pageRect, CellRange(0, 0, grd.ColumnCount - 1, grd.RowCount - 1), []);
          FPageIndex := FPageIndex + APageIndex;
        end;
      end;

      PDFRenderLib.EndExport;

      if Assigned(OnPrintEnd) then
        OnPrintEnd(Self);
    end
    else
    begin
      ShowMessage('Invalid license key');
    end;
  finally
    PDFRenderLib.DestroyInstance;
  end;
end;

{$ENDIF}

{$IFDEF GENERALOSX}
procedure TTMSFMXGridPDFIO.DoExportPDF(AGrid: TTMSFMXGrid; AContext: CGContextRef; pageRect: CGRect; ASelection: TCellRange; APages: array of Integer; AResetPosition: Boolean = False);
{$ELSE}
procedure TTMSFMXGridPDFIO.DoExportPDF(AGrid: TTMSFMXGrid; APDFLib: TTMSFMXPDFRenderLib; pageRect: TRectF; ASelection: TCellRange; APages: array of Integer; AResetPosition: Boolean = False);
{$ENDIF}
function CanPrintPage(APageIndex: Integer): Boolean;
  var
    I: Integer;
begin
  Result := False;
  if Length(APages) = 0 then
    Result := True
  else
  begin
    for I := 0 to Length(APages) - 1 do
    begin
      if APages[I] = APageIndex then
      begin
        Result := True;
        Break;
      end;
    end;
  end;
end;

var
  cell: TFMXObject;
  cellclasstype,prevclasstype: TFmxObjectClass;
  l: TTMSFMXGridCellLayout;
  c, r: Integer;
  cellstr: String;
  cwr, rhr, cw, rh, cwrt, rhrt: Single;
  I: Integer;
  xr, yr: Single;
  bc, br: Integer;
  cs, rs: Integer;
  cellr, cellrtxt: TRectF;
  x, y: Single;
  ctl: TTMSFMXGridCell;
  AllowDraw: Boolean;
  rSt, csave, cSt: Integer;
  chk: Boolean;
  FFirstPage: Boolean;
  rDrawText: TRectF;
  rText: TRectF;
  FFixedRowsSave, FFixedColumnsSave: Integer;
  FCSave, FRSave: Integer;
  st: TCellState;
  nml, fix: TTMSFMXGridCell;
  FFixedRowGet, FFixedColGet: Boolean;
  FSetRSave, FSetCSave: Boolean;
  j: Integer;
  xs, ys: Single;
  ph, pw: Single;
  xts, yts: Single;
  FSaveXBounds: Single;
  FSaveYBounds: Single;
  w, h: Single;
  AControl: TFMXObject;
  cgrid: TProGrid;


procedure DrawHeader;
begin
  rText := rDrawText;
  {$IFDEF GENERALOSX}
  DrawTitle(cgrid, FPageIndex + APageIndex, AContext, rText);
  {$ELSE}
  DrawTitle(cgrid, APDFLib, FPageIndex + APageIndex, rText);
  {$ENDIF}

  {$IFDEF GENERALOSX}
  DrawDescription(cgrid, FPageIndex + APageIndex, AContext, rText);
  {$ELSE}
  DrawDescription(cgrid, APDFLib, FPageIndex + APageIndex, rText);
  {$ENDIF}

  {$IFDEF GENERALOSX}
  DrawPageNumber(cgrid, FPageIndex + APageIndex, AContext, rText);
  {$ELSE}
  DrawPageNumber(cgrid, APDFLib, FPageIndex + APageIndex, rText);
  {$ENDIF}
end;

begin
  if not Assigned(AGrid) then
    Exit;

  APageIndex := 1;

  cgrid := TProGrid(AGrid);
  nml := cgrid.GetDefaultNormalLayout;
  fix := cgrid.GetDefaultFixedLayout;

  {$IFDEF GENERALOSX}
    CGContextBeginPage(AContext, @pageRect);
    CGContextTranslateCTM(AContext, 0.0, pageRect.size.height);
    CGContextScaleCTM(AContext, 1.0, -1.0);
  {$ELSE}
    APDFLib.SetPageDimensions(pageRect.Width, pageRect.Height);
  {$ENDIF}

  if Assigned(OnPrintNewPage) then
    OnPrintNewPage(Self, APageIndex);

  w := pagerect.size.width;
  h := pagerect.size.height;

  x := cgrid.Options.Printing.PrintMargins.Left;
  y := cgrid.Options.Printing.PrintMargins.Top;

  rDrawText := RectF(cgrid.Options.Printing.PrintMargins.Left + 2, 2, w - cgrid.Options.Printing.PrintMargins.Right - 2, h - 2);
  DrawHeader;

  l := TTMSFMXGridCellLayout.Create(nil);
  prevclasstype := TTMSFMXGridCell;
  cell := TTMSFMXGridCell.Create(Self);
  rSt := ASelection.StartRow;
  FFixedRowsSave := 0;
  FFixedColumnsSave := 0;
  cSave := -1;
  cSt := -1;
  FFirstPage := True;
  FFixedRowGet := False;
  FFixedColGet := False;
  FSetRSave := True;
  FSetCSave := True;


  FSaveXBounds := cgrid.Options.Printing.PrintMargins.Left + cgrid.GetFixedPrintWidth;

  for I := ASelection.StartCol to ASelection.EndCol do
  begin
    FSaveXBounds := FSaveXBounds + cgrid.ColumnWidths[I];
    if (FSaveXBounds + cgrid.ColumnWidths[I] > w - cgrid.Options.Printing.PrintMargins.Right) then
      Break;
  end;

  FSaveYBounds := cgrid.Options.Printing.PrintMargins.Top + cgrid.GetFixedPrintHeight;

  for I := ASelection.StartRow to ASelection.EndRow do
  begin
    if (FSaveYBounds + cgrid.RowHeights[I] > h - cgrid.Options.Printing.PrintMargins.Bottom) then
      Break;

    FSaveYBounds := FSaveYBounds + cgrid.RowHeights[I];
  end;

  c := ASelection.StartCol;


  for i := ASelection.StartCol to ASelection.EndCol do
    for j := ASelection.StartRow to ASelection.EndRow do
      cgrid.MergeCellPrintPageNr[i,j] := -1;


  pw := cgrid.GetFixedPrintWidth;
  ph := cgrid.GetFixedPrintHeight;

  FCSave := -1;
  while c <= ASelection.EndCol do
  begin
    if cSt = -1 then
      cSt := c;

    if cgrid.Options.Printing.RepeatFixedColumns and (cgrid.FixedColumns > 0) then
    begin
      if (FFixedColumnsSave < cgrid.FixedColumns) then
      begin
        FFixedColGet := True;
        if FSetCSave then
        begin
          FSetCSave := False;
          FCSave := cSt;
        end;

        cst := FFixedColumnsSave;
        c := cst;
        Inc(FFixedColumnsSave);
      end
      else if FFixedColGet then
      begin
        FFixedColGet := False;
        cSt := FCSave;
        c := FCSave;

        if cst < cgrid.FixedColumns then
        begin
          cst := cgrid.FixedColumns;
          c := cst;
        end;
      end;
    end;

    cw := cgrid.ColumnWidths[c];

    r := rst;
    FRSave := rst;
    while r <= ASelection.EndRow do
    begin
      if cgrid.Options.Printing.RepeatFixedRows and (cgrid.FixedRows > 0) then
      begin
        if (FFixedRowsSave < cgrid.FixedRows) then
        begin
          FFixedRowGet := True;
          if FSetRSave then
          begin
            FSetRSave := False;
            FRSave := rSt;
          end;

          rSt := FFixedRowsSave;
          r := rst;
          Inc(FFixedRowsSave);
        end
        else if FFixedRowGet then
        begin
          FFixedRowGet := False;
          rSt := FRSave;
          r := FRSave;

          if rst < cgrid.FixedRows then
          begin
            rst := cgrid.FixedRows;
            r := rst;
          end;
        end;
      end;

      bc := c;
      br := r;
      cs := 0;
      rs := 0;

      rh := cgrid.RowHeights[r];

      cgrid.DoGetCellMergeInfo(c, r, bc, br, cs, rs);

      chk := (c = bc) and (r = br);
      if chk then
        cgrid.MergeCellPrintPageNr[bc, br] := APageIndex
      else if (bc <> c) and (br <> r) then
        chk := cgrid.MergeCellPrintPageNr[bc, br] <> APageIndex;

      if chk then
      begin
        AControl := nil;
        cgrid.DoGetCellControl(bc, br, AControl);
        cgrid.DoGetCellClass(bc,  br, cellclasstype);
        cgrid.DoGetCellData(bc, br, cellstr);

        if (prevclasstype <> cellclasstype) and (prevclasstype <> nil) and Assigned(cell) then
          cell.Free;

        if (prevclasstype <> cellclasstype) then
          cell := cellclasstype.Create(cgrid);

        prevclasstype := cellclasstype;

        cgrid.ApplyCellState(bc, br, cell);

        if (Cell is TTMSFMXGridCell) then
        begin
          if Assigned(nml) and Assigned(fix) then
          begin
            if cgrid.Options.Printing.PrintCellBackGround <> cbFull then
            begin
              st := cgrid.GetCellState(bc, br);
              case st of
                csFocused: (cell as TTMSFMXGridCell).Layout.Assign(nml.Layout);
                csFixedSelected: (cell as TTMSFMXGridCell).Layout.Assign(fix.Layout);
                csSelected: (cell as TTMSFMXGridCell).Layout.Assign(nml.Layout);
              end;
            end;
          end;

          l.Assign((Cell as TTMSFMXGridCell).Layout);
          cgrid.DoGetCellLayout(bc, br, l, cgrid.GetCellState(bc, br));
          (Cell as TTMSFMXGridCell).AssignLayout(l);
        end;

        cgrid.DoGetCellAppearance(bc, br, cell, cgrid.GetCellState(c, r));
        cgrid.DoGetCellProperties(bc, br, cell);

        cwr := cw;
        rhr := rh;

        cwrt := 0;
        for I := bc to bc + cs - 1 do
          cwrt := cwrt + cgrid.ColumnWidths[I];

        if cwrt > 0 then
          cwr := cwrt;

        rhrt := 0;
        for I := br to br + rs - 1 do
          rhrt := rhrt + cgrid.RowHeights[I];

        if rhrt > 0 then
          rhr := rhrt;

        xr := 0;
        for I := bc to c - 1 do
          xr := xr + cgrid.ColumnWidths[I];

        yr := 0;
        for I := br to r - 1 do
          yr := yr + cgrid.RowHeights[I];


        xts := x - xr;
        yts := y - yr;
        xs := xts + cwr;
        ys := yts + rhr;

        if FSaveXBounds > -1 then
          xs := Min(FSaveXBounds, xs);

        if ((APageIndex = 0) or (cgrid.Options.Printing.RepeatFixedColumns)) and (c > cgrid.FixedColumns) then
          xts := Max(cgrid.Options.Printing.PrintMargins.Left + pw, xts)
        else
          xts := Max(cgrid.Options.Printing.PrintMargins.Left, xts);


        if FSaveYBounds > -1 then
          ys := Min(FSaveYBounds, ys);


        if ((APageIndex = 0) or (cgrid.Options.Printing.RepeatFixedRows)) and (r > cgrid.FixedRows) then
          yts := Max(cgrid.Options.Printing.PrintMargins.Top + ph, yts)
        else
          yts := Max(cgrid.Options.Printing.PrintMargins.Top, yts);

        cellr := RectF(xts, yts, xs, ys);

        if cell is TTMSFMXGridCell then
        begin
          ctl := (Cell as TTMSFMXGridCell);
          ctl.Width := cellr.Width;
          ctl.Height := cellr.Height;
          ctl.Text := cellstr;
          if cgrid.Options.Printing.PrintCellBackGround <> cbFull then
          begin
            ctl.Layout.Stroke.Color := TAlphaColorRec.Black;
            {$IFDEF DELPHIXE6_LVL}
            ctl.Layout.StrokeDash := TStrokeDash.Solid;
            ctl.Layout.Sides := [TSide.Right, tSide.Bottom];
            {$ELSE}
            ctl.Layout.StrokeDash := TStrokeDash.sdSolid;
            ctl.Layout.Sides := [TSide.sdRight, tSide.sdBottom];
            {$ENDIF}
            if cgrid.Options.Printing.PrintCellBackGround = cbNone then
              ctl.Layout.FontFill.Color := TAlphaColorRec.Black;
          end;

          if cgrid.Options.Printing.PrintCellBackGround <> cbFull then
          begin
            if cgrid.Options.Printing.RepeatFixedColumns and (cgrid.FixedColumns > 0) then
            begin
              if (c = 0) then
                {$IFDEF DELPHIXE6_LVL}
                ctl.Layout.Sides := ctl.Layout.Sides + [tSide.Left];
                {$ELSE}
                ctl.Layout.Sides := ctl.Layout.Sides + [tSide.sdLeft];
                {$ENDIf}
            end
            else
            begin
              if (c = cst) then
                {$IFDEF DELPHIXE6_LVL}
                ctl.Layout.Sides := ctl.Layout.Sides + [tSide.Left];
                {$ELSE}
                ctl.Layout.Sides := ctl.Layout.Sides + [tSide.sdLeft];
                {$ENDIf}
            end;

            if cgrid.Options.Printing.RepeatFixedRows and (cgrid.FixedRows > 0) then
            begin
              if (r = 0) then
                {$IFDEF DELPHIXE6_LVL}
                ctl.Layout.Sides := ctl.Layout.Sides + [tSide.Top];
                {$ELSE}
                ctl.Layout.Sides := ctl.Layout.Sides + [tSide.sdTop];
                {$ENDIf}
            end
            else
            begin
              if (r = rst) then
                {$IFDEF DELPHIXE6_LVL}
                ctl.Layout.Sides := ctl.Layout.Sides + [tSide.Top];
                {$ELSE}
                ctl.Layout.Sides := ctl.Layout.Sides + [tSide.sdTop];
                {$ENDIf}
            end;
          end;
        end;

        AllowDraw := True;
        if AllowDraw then
        begin
          if (cell is TTMSFMXGridCell) then
          begin
            ctl := (Cell as TTMSFMXGridCell);
            cellrtxt := ctl.GetTextRectBase(cellr);
            cgrid.AddObject(ctl);
            {$IFDEF GENERALOSX}
            ctl.ExportToPDF(Self, AContext, cellr, cellrtxt, True, cgrid.Options.Printing.PrintCellBackGround <> cbNone);
            {$ELSE}
            ctl.ExportToPDF(Self, APDFLib, cellr, cellrtxt, True, cgrid.Options.Printing.PrintCellBackGround <> cbNone);
            {$ENDIF}

            if Assigned(AControl) and (AControl is TControl) then
            begin
              // paint control
            end;

            cgrid.RemoveObject(ctl);
          end
          else if cell is TControl then
          begin
            // paint control
          end;
        end;
      end;

      AProgress := AProgress + 1;
      if Assigned(OnPrintProgress) then
        OnPrintProgress(Self, APageIndex, ((AProgress / ((ASelection.EndCol - ASelection.StartCol + 1) * (ASelection.EndRow - ASelection.StartRow + 1))) * 100) / (Length(FGridList) + 1));

      y := y + rh;
      if (y + cgrid.RowHeights[r + 1] > h - cgrid.Options.Printing.PrintMargins.Bottom) then
      begin
        FSaveYBounds := Y + cgrid.RowHeights[r + 1];
        Break;
      end;

      Inc(r);
    end;

    y := cgrid.Options.Printing.PrintMargins.Top;
    x := x + cw;
    Inc(c);

    FFixedRowsSave := 0;

    if (x + cgrid.ColumnWidths[c] > w - cgrid.Options.Printing.PrintMargins.Right) or (c = ASelection.EndCol + 1) then
    begin
      FSaveXBounds := x;

      rst := r + 1;

      if cSave = -1 then
        cSave := c;

      if r = ASelection.EndRow + 1 then
      begin
        c := cSave;
        cst := -1;
        rst := ASelection.StartRow;
        cSave := -1;
      end
      else
        c := cst;

      FFixedRowsSave := 0;
      FFixedColumnsSave := 0;
      FSetRSave := True;
      FSetCSave := True;

      if (c < ASelection.EndCol + 1) then
      begin
        Inc(APageIndex);
        if CanPrintPage(APageIndex) then
        begin
          if FFirstPage then
          begin
            FFirstPage := False;
            if CanPrintPage(1) then
            begin
              {$IFDEF GENERALOSX}
                CGContextEndPage(AContext);
                if Assigned(OnPrintEndPage) then
                  OnPrintEndPage(Self, APageIndex - 1);
                CGContextBeginPage(AContext, @pageRect);
                CGContextTranslateCTM(AContext, 0.0, pageRect.size.height);
                CGContextScaleCTM(AContext, 1.0, -1.0);
              {$ELSE}
                APDFLib.NewPage;
                APDFLib.SetPageDimensions(pageRect.Width, pageRect.Height);
              {$ENDIF}

              if Assigned(OnPrintNewPage) then
                OnPrintNewPage(Self, APageIndex);
            end;
          end
          else
          begin
            {$IFDEF GENERALOSX}
              CGContextEndPage(AContext);
              if Assigned(OnPrintEndPage) then
                OnPrintEndPage(Self, APageIndex - 1);
              CGContextBeginPage(AContext, @pageRect);
              CGContextTranslateCTM(AContext, 0.0, pageRect.size.height);
              CGContextScaleCTM(AContext, 1.0, -1.0);
            {$ELSE}
              APDFLib.NewPage;
              APDFLib.SetPageDimensions(pageRect.Width, pageRect.Height);
            {$ENDIF}

            if Assigned(OnPrintNewPage) then
              OnPrintNewPage(Self, APageIndex);
          end;
        end;

        x := cgrid.Options.Printing.PrintMargins.Left;
        y := cgrid.Options.Printing.PrintMargins.Top;
        DrawHeader;
      end;
    end;
  end;


  if Assigned(cell) then
    cell.Free;

  l.Free;

  {$IFDEF GENERALOSX}
  CGContextEndPage(AContext);
  {$ENDIF}
end;

procedure TTMSFMXGridPDFIO.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited;
  if Operation = opRemove then
  begin
    if AComponent = FGrid then
      FGrid := nil;

    if AComponent = FPDFRenderLib then
      FPDFRenderLib := nil;
  end;
end;

{ TTMSFMXGridPDFIOGlyphs }

procedure TTMSFMXGridPDFIOGlyphs.Assign(Source: TPersistent);
begin
  if (Source is TTMSFMXGridPDFIOGlyphs) then
  begin
    FRadioButtonChecked.Assign((Source as TTMSFMXGridPDFIOGlyphs).RadioButtonChecked);
    FRadioButtonUnChecked.Assign((Source as TTMSFMXGridPDFIOGlyphs).RadioButtonUnChecked);
    FCheckBoxChecked.Assign((Source as TTMSFMXGridPDFIOGlyphs).CheckBoxChecked);
    FCheckBoxUnChecked.Assign((Source as TTMSFMXGridPDFIOGlyphs).CheckBoxUnChecked);
  end;
end;

constructor TTMSFMXGridPDFIOGlyphs.Create(AOwner: TPersistent);
var
  R: TResourceStream;
begin
  FRadioButtonChecked := TBitmap.Create(0, 0);
  FRadioButtonUnChecked := TBitmap.Create(0, 0);
  FCheckBoxChecked := TBitmap.Create(0, 0);
  FCheckBoxUnChecked := TBitmap.Create(0, 0);

  R := GetResourceStream('radio_checked');
  if Assigned(R) then
  begin
    FRadioButtonChecked.LoadFromStream(R);
    R.free;
  end;

  R := GetResourceStream('radio_unchecked');
  if Assigned(R) then
  begin
    FRadioButtonUnChecked.LoadFromStream(R);
    R.free;
  end;

  R := GetResourceStream('check_checked');
  if Assigned(R) then
  begin
    FCheckBoxChecked.LoadFromStream(R);
    R.free;
  end;

  R := GetResourceStream('check_unchecked');
  if Assigned(R) then
  begin
    FCheckBoxUnChecked.LoadFromStream(R);
    R.free;
  end;
end;

destructor TTMSFMXGridPDFIOGlyphs.Destroy;
begin
  FRadioButtonChecked.Free;
  FRadioButtonUnChecked.Free;
  FCheckBoxChecked.Free;
  FCheckBoxUnChecked.Free;
  inherited;
end;

{ TTMSFMXGridPDFIOOptions }

procedure TTMSFMXGridPDFIOOptions.Assign(Source: TPersistent);
begin
  if (Source is TTMSFMXGridPDFIOOptions) then
    FGlyphs.Assign((Source as TTMSFMXGridPDFIOOptions).Glyphs);
end;

constructor TTMSFMXGridPDFIOOptions.Create(AOwner: TComponent);
begin
  FGlyphs := TTMSFMXGridPDFIOGlyphs.Create(Self);
  FInformation := TTMSFMXGridPDFIOInformation.Create;
end;

destructor TTMSFMXGridPDFIOOptions.Destroy;
begin
  FInformation.Free;
  FGlyphs.Free;
  inherited;
end;

{ TTMSFMXGridPDFIOInformation }

procedure TTMSFMXGridPDFIOInformation.Assign(Source: TPersistent);
begin
  if Source is TTMSFMXGridPDFIOInformation then
  begin
    FModificationDate := (Source as TTMSFMXGridPDFIOInformation).ModificationDate;
    FAuthor := (Source as TTMSFMXGridPDFIOInformation).Author;
    FProducer := (Source as TTMSFMXGridPDFIOInformation).Producer;
    FCreator := (Source as TTMSFMXGridPDFIOInformation).Creator;
    FSubject := (Source as TTMSFMXGridPDFIOInformation).Subject;
    FTitle := (Source as TTMSFMXGridPDFIOInformation).Title;
    FPDFVersion := (Source as TTMSFMXGridPDFIOInformation).PDFVersion;
    FKeywords := (Source as TTMSFMXGridPDFIOInformation).Keywords;
    FCreationDate := (Source as TTMSFMXGridPDFIOInformation).CreationDate;
  end;
end;

end.
