1 {
2 LazReport PDF export
3
4 Copyright (C) 2016 alexs alexs75.at.yandex.ru
5
6 The module is designed to create an image of the report with the exact
7 positioning of objects and subsequent binding to the worksheet
8
9 This library is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Library General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or (at your
12 option) any later version with the following modification:
13
14 As a special exception, the copyright holders of this library give you
15 permission to link this library with independent modules to produce an
16 executable, regardless of the license terms of these independent modules,and
17 to copy and distribute the resulting executable under terms of your choice,
18 provided that you also meet, for each linked independent module, the terms
19 and conditions of the license of that module. An independent module is a
20 module which is not derived from or based on this library. If you modify
21 this library, you may extend this exception to your version of the library,
22 but you are not obligated to do so. If you do not wish to do so, delete this
23 exception statement from your version.
24
25 This program is distributed in the hope that it will be useful, but WITHOUT
26 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
27 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
28 for more details.
29
30 You should have received a copy of the GNU Library General Public License
31 along with this library; if not, write to the Free Software Foundation,
32 Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.
33 }
34
35
36 unit lr_e_fclpdf;
37
38 {$mode objfpc}{$H+}
39
40 interface
41
42 uses
43 Classes, SysUtils,
44 Graphics,
45 LazStringUtils,
46 LR_Class, LR_ChBox, LR_BarC, LR_Shape, LR_RRect, fpPDF, fpTTF;
47
48 type
49 TExportFonts = class;
50 TlrPdfExportFilter = class;
51
52 { TExportFontItem }
53
54 TExportFontItem = class
55 private
56 FFontColor: TColor;
57 FFontName: string;
58 FFontSize: Integer;
59 FFontStyle: TFontStyles;
60 FOwner:TExportFonts;
61 FDefaultFont: boolean;
62 //
63 FPdfFont:integer;
64 FTTFFontInfo: TFPFontCacheItem;
GetBoldnull65 function GetBold: boolean;
GetItalicnull66 function GetItalic: boolean;
67 procedure SetFontSize(AValue: Integer);
68 //
TextWidthnull69 function TextWidth(const AText: utf8string) : single;
TextHeightnull70 function TextHeight(const AText: utf8string) : single;
71 public
72 constructor Create(AOwner:TExportFonts; AFontName:string; AFontStyle: TFontStyles);
73 destructor Destroy; override;
74 procedure Activate;
75 property FontStyle: TFontStyles read FFontStyle;
76 property FontSize:Integer read FFontSize write SetFontSize;
77 property FontColor:TColor read FFontColor write FFontColor;
78 property Bold:boolean read GetBold;
79 property Italic:boolean read GetItalic;
80 property DefaultFont:boolean read FDefaultFont;
81 property FontName:string read FFontName;
82 end;
83
84 { TExportFonts }
85
86 TExportFonts = class
87 private
88 //FDefaultFontBold: TExportFontItem;
89 FDefaultFontNormal: TExportFontItem;
90 FOwner:TlrPdfExportFilter;
91 FList:TFPList;
GetCountnull92 function GetCount: integer;
GetItemnull93 function GetItem(Index: integer): TExportFontItem;
94 public
95 constructor Create(AOwner:TlrPdfExportFilter);
96 destructor Destroy; override;
97 procedure Clear;
AddItemnull98 function AddItem(AFontName: string; AFontStyle:TFontStyles = []): TExportFontItem;
FindItemnull99 function FindItem(AFontName: string; AFontStyle:TFontStyles = []):TExportFontItem;
100 property DefaultFontNormal:TExportFontItem read FDefaultFontNormal;
101 //property DefaultFontBold:TExportFontItem read FDefaultFontBold;
102 property Count:integer read GetCount;
103 property Item[Index:integer]:TExportFontItem read GetItem;
104 end;
105
106 { TlrPdfExportFilter }
107
108 TlrPdfExportFilter = class(TfrExportFilter)
109 private
110 FPDFDocument: TPDFDocument;
111 FCurSection: TPDFSection;
112 FCurPageNo : integer;
113 FCurPage: TPDFPage;
114 FFontItems:TExportFonts;
115 FCurFont: TExportFontItem;
116 procedure SetupFonts;
117 procedure InitFonts;
118 private
119 InternalGapX:integer;
120 InternalGapY:integer;
121 procedure WriteTextRectJustify(AExportFont: TExportFontItem; X, Y, W, H: TPDFFloat; const Text: string; Trimmed: boolean);
122 procedure WriteTextRect(AExportFont:TExportFontItem; X, Y, W{, H}:TPDFFloat; AText:string; AHAlign:TAlignment; angle: TPDFFloat);
123 procedure DrawRect(X, Y, W, H: TPDFFloat; ABorderColor, AFillColor: TColor;
124 AFrames: TfrFrameBorders; ABorderWidth: TPDFFloat);
125 procedure DrawRectView(AView: TfrView);
126 procedure WriteURL(X, Y, W, H: TPDFFloat; AUrlText:string);
127 procedure DrawLine(X1, Y1, X2, Y2: TPDFFloat; ABorderColor: TColor; ABorderWidth: TPDFFloat);
128 procedure DrawEllipse(X, Y, W, H: TPDFFloat; ABorderColor, AFillColor: TColor;
129 AFrames: TfrFrameBorders; ABorderWidth: TPDFFloat);
130 procedure DrawImage(X, Y, W, H: integer; ABmp:TLazreportBitmap);
131 procedure DrawLRObjectInternal(View:TfrView);
132 private
133 procedure DoMemoView(View:TfrMemoView);
134 procedure DoImageView(View:TfrPictureView);
135 procedure DoLineView(View:TfrLineView);
136 procedure DoCheckBoxView(View:TfrCheckBoxView);
137 procedure DoShapeView(View:TfrShapeView);
138 procedure DoBarCodeView(View:TfrCustomBarCodeView);
139 procedure DoRoundRectView(View:TfrRoundRectView);
140 public
141 constructor Create(AStream: TStream); override;
142 destructor Destroy; override;
143 procedure OnBeginDoc; override;
144 procedure OnEndDoc; override;
145 procedure OnBeginPage; override;
146 procedure OnEndPage; override;
147 procedure OnData(x, y: Integer; View: TfrView); override;
148 procedure OnText({%H-}x, {%H-}y: Integer; const {%H-}Text: String; {%H-}View: TfrView); override;
149 procedure OnExported({%H-}x, {%H-}y: Integer; {%H-}View: TfrView); override;
150 end;
151
152 implementation
153 uses LazFileUtils, Forms, LR_Utils, LazUTF8, Printers, FPReadBMP, FPReadPNG, FPReadJPEG;
154
155 const
156 cInchToMM = 25.4;
157
ConvetUnitsnull158 function ConvetUnits(AUnits:TPDFFloat):TPDFFloat; inline;
159 begin
160 Result := (AUnits * cInchToMM) / gTTFontCache.DPI;
161 end;
162
ConvetUnits1null163 function ConvetUnits1(AUnits:TPDFFloat):TPDFFloat; inline;
164 begin
165 Result:= AUnits * gTTFontCache.DPI / cInchToMM;
166 end;
167
ColorToPdfColornull168 function ColorToPdfColor(C:Graphics.TColor):TARGBColor;
169 var
170 A:array [1..4] of byte absolute C;
171 begin
172 if C = clWindow then
173 Result:=clWhite
174 else
175 Result:={A[1] shl 24 +} A[1] shl 16 + A[2] shl 8 + A[3];
176 end;
177
178 type
179 TfrHackView = class(TfrView);
180
181 { TExportFonts }
182
GetCountnull183 function TExportFonts.GetCount: integer;
184 begin
185 Result:=FList.Count;
186 end;
187
GetItemnull188 function TExportFonts.GetItem(Index: integer): TExportFontItem;
189 begin
190 Result:=TExportFontItem(FList[Index]);
191 end;
192
193 constructor TExportFonts.Create(AOwner: TlrPdfExportFilter);
194 begin
195 inherited Create;
196 FOwner:=AOwner;
197 FList:=TFPList.Create;
198 end;
199
200 destructor TExportFonts.Destroy;
201 begin
202 Clear;
203 FreeAndNil(FList);
204 inherited Destroy;
205 end;
206
207 procedure TExportFonts.Clear;
208 var
209 I: Integer;
210 begin
211 for I:=0 to FList.Count-1 do
212 TExportFontItem(FList[i]).Free;
213 FList.Clear;
214 end;
215
MakePSNamenull216 function MakePSName(AFontName: string; AFontStyle: TFontStyles):string;
217 begin
218 Result:=AFontName;
219
220 if Graphics.fsBold in AFontStyle then
221 Result:=Result + '-Bold';
222
223 if Graphics.fsItalic in AFontStyle then
224 Result:=Result + '-Oblique';
225
226 if Graphics.fsUnderline in AFontStyle then
227 Result:=Result + '-Underline';
228
229 if Graphics.fsStrikeOut in AFontStyle then
230 Result:=Result + '-StrikeOut';
231 end;
232
TExportFonts.AddItemnull233 function TExportFonts.AddItem(AFontName: string; AFontStyle: TFontStyles
234 ): TExportFontItem;
235 var
236 S1, S2, S3, S: String;
237
238 begin
239 Result:=FindItem(AFontName, AFontStyle);
240 if Assigned(Result) then exit;
241
242 if Assigned(gTTFontCache.Find(AFontName, Graphics.fsBold in AFontStyle, Graphics.fsItalic in AFontStyle)) then
243 begin
244 Result:=TExportFontItem.Create(Self, AFontName, AFontStyle);
245 S1:=ExtractFileDir(Result.FTTFFontInfo.FileName);
246 S2:=ExtractFileName(Result.FTTFFontInfo.FileName);
247 S3:=AFontName;
248 FOwner.FPDFDocument.FontDirectory:=S1;
249 S:=MakePSName(AFontName, AFontStyle);
250 Result.FPdfFont:=FOwner.FPDFDocument.AddFont(S2, S);
251 end
252 else
253 Result:=FDefaultFontNormal;
254 end;
255
FindItemnull256 function TExportFonts.FindItem(AFontName: string; AFontStyle: TFontStyles
257 ): TExportFontItem;
258 var
259 K: TExportFontItem;
260 i: Integer;
261 begin
262 Result:=nil;
263
264 if AFontName = 'default' then
265 begin
266 { if Graphics.fsBold in AFontStyle then
267 Result:=FDefaultFontBold
268 else}
269 Result:=FDefaultFontNormal;
270 end
271 else
272 begin
273 for i:=0 to FList.Count-1 do
274 begin
275 K:=TExportFontItem(FList[i]);
276 if (K.FontName = AFontName) and (K.FontStyle = AFontStyle) then
277 begin
278 Result:=K;
279 exit;
280 end
281 end;
282 end;
283 end;
284
285 { TExportFontItem }
286
TExportFontItem.GetBoldnull287 function TExportFontItem.GetBold: boolean;
288 begin
289 Result:=Graphics.fsBold in FFontStyle;
290 end;
291
GetItalicnull292 function TExportFontItem.GetItalic: boolean;
293 begin
294 Result:=Graphics.fsItalic in FFontStyle;
295 end;
296
297 procedure TExportFontItem.SetFontSize(AValue: Integer);
298 begin
299 if AValue = 0 then
300 FFontSize:=10
301 else
302 FFontSize:=AValue;
303 end;
304
TExportFontItem.TextWidthnull305 function TExportFontItem.TextWidth(const AText: utf8string): single;
306 begin
307 Result:=ConvetUnits(FTTFFontInfo.TextWidth(AText, FFontSize));
308 end;
309
TextHeightnull310 function TExportFontItem.TextHeight(const AText: utf8string): single;
311 var
312 ADescender: single;
313 begin
314 Result:=FTTFFontInfo.TextHeight(AText, FFontSize, ADescender);
315 Result:=ConvetUnits(Result + ADescender);
316 { FTH:=ConvetUnits(AExportFont.FTTFFontInfo.TextHeight(AText, AExportFont.FontSize, ADescender));
317 FTH:=FTH + ConvetUnits(ADescender);}
318 end;
319
320 constructor TExportFontItem.Create(AOwner: TExportFonts; AFontName: string;
321 AFontStyle: TFontStyles);
322 begin
323 inherited Create;
324 FOwner:=AOwner;
325 FOwner.FList.Add(Self);
326 FFontStyle:=AFontStyle;
327 FFontName:=AFontName;
328 FTTFFontInfo:=gTTFontCache.Find(AFontName, Graphics.fsBold in AFontStyle, Graphics.fsItalic in AFontStyle);
329 if not Assigned(FTTFFontInfo) then
330 raise Exception.CreateFmt('fpTTF:in gTTFontCache not found font "%s" info.', [AFontName]);
331 end;
332
333 destructor TExportFontItem.Destroy;
334 begin
335 inherited Destroy;
336 end;
337
338 procedure TExportFontItem.Activate;
339 begin
340 FOwner.FOwner.FCurPage.SetFont(FPdfFont, FontSize);
341 FOwner.FOwner.FCurPage.SetColor(ColorToPdfColor(FontColor), false);
342 end;
343
344 { TlrPdfExportFilter }
345
346 procedure TlrPdfExportFilter.SetupFonts;
347 //Find default font name
DefFontNamenull348 function DefFontName:string;
349 const
350 DefFontNames : array [1..4] of string =
351 // TODO: Check if Arial is better default choice in windows/linux/mac
352 {$IFDEF MSWINDOWS}
353 ('Arial', 'Liberation Sans', 'FreeSans', 'DejaVu Sans');
354 {$ELSE}
355 ('Liberation Sans', 'Arial', 'FreeSans', 'DejaVu Sans');
356 {$ENDIF}
357 var
358 i: Integer;
359 begin
360 for i:=1 to 4 do
361 if Assigned(gTTFontCache.Find(DefFontNames[i], false, false)) then
362 begin
363 Result:=DefFontNames[i];
364 exit;
365 end;
366 raise Exception.Create('Not found Sans font');
367 end;
368
369 var
370 i: Integer;
371 sDefFontName:string;
372 begin
373 sDefFontName:=DefFontName;
374 FFontItems.FDefaultFontNormal:=FFontItems.AddItem(sDefFontName, []);
375 end;
376
377 procedure TlrPdfExportFilter.InitFonts;
378 procedure CreateFontDirList;
379 {$IFDEF WINDOWS}
380 var
381 s: String;
382 {$ENDIF}
383 begin
384 {$IFDEF WINDOWS}
385 s := SHGetFolderPathUTF8(20); // CSIDL_FONTS = 20
386 if s <> '' then
387 gTTFontCache.SearchPath.Add(s);
388 {$ENDIF}
389 {$IFDEF linux}
390 //tested on Fedora 24
391 gTTFontCache.SearchPath.Add('/usr/share/cups/fonts/');
392 gTTFontCache.SearchPath.Add('/usr/share/fonts/');
393 gTTFontCache.SearchPath.Add('/usr/share/wine/fonts/');
394 gTTFontCache.SearchPath.Add('/usr/local/lib/X11/fonts/');
395 gTTFontCache.SearchPath.Add(GetUserDir + '.fonts/');
396 {$ENDIF}
397
398 end;
399 begin
400 if gTTFontCache.Count = 0 then
401 begin
402 {$IF (FPC_FULLVERSION >= 30101)}
403 gTTFontCache.BuildFontCacheIgnoresErrors:=true;
404 {$ENDIF}
405 {$IFDEF WINDOWS}
406 CreateFontDirList;
407 {$ELSE}
408 gTTFontCache.ReadStandardFonts;
409 {$ENDIF}
410 gTTFontCache.BuildFontCache;
411 end;
412 end;
413
414 procedure TlrPdfExportFilter.DoMemoView(View: TfrMemoView);
415 var
416 S: String;
417 begin
418 DrawRectView(View);
419
420 S:=TfrMemoView(View).URLInfo;
421 if LazStartsText('HTTP://', S) or LazStartsText('HTTPS://', S) then
422 WriteURL(View.Left, View.Top, View.Width, View.Height, TfrMemoView(View).URLInfo);
423
424 //prepare font
425 FCurFont:=FFontItems.AddItem(View.Font.Name, View.Font.Style);
426 if Assigned(FCurFont) then
427 begin
428 FCurFont.FontSize:=View.Font.Size;
429 FCurFont.FontColor:=View.Font.Color;
430 FCurFont.Activate;
431 end;
432 end;
433
434 procedure TlrPdfExportFilter.DoImageView(View: TfrPictureView);
435 var
436 IDX: Integer;
437
LoadImagenull438 function LoadImage:boolean;
439 var
440 S: TMemoryStream;
441 begin
442 Result:=false;
443 S:=TMemoryStream.Create;
444 try
445 View.Picture.SaveToStream(S);
446 S.Position:=0;
447 if View.Picture.Graphic is TJPegImage then
448 IDX := FPDFDocument.Images.AddFromStream(S, TFPReaderJPEG, False)
449 else
450 if View.Picture.Graphic is TPortableNetworkGraphic then
451 IDX := FPDFDocument.Images.AddFromStream(S, TFPReaderPNG, False)
452 else
453 IDX := FPDFDocument.Images.AddFromStream(S, TFPReaderBMP, False);
454 Result:=true;
455 finally
456 S.Free;
457 end;
458 end;
459
460 var
461 fX, fY, fW, fH: TPDFFloat;
462 X, Y, W, H, L: Double;
463 R: Extended;
464 begin
465 DrawRectView(View);
466
467 if not ((View.Picture.Graphic = nil) or View.Picture.Graphic.Empty) then
468 begin
469 if not LoadImage then exit;
470
471 if View.Stretched then
472 begin
473 X:=View.Left;
474 Y:=View.Top;
475 W:=View.Width;
476 H:=View.Height;
477
478 if View.KeepAspect then
479 begin
480 R:=FPDFDocument.Images[IDX].Width / FPDFDocument.Images[IDX].Height;
481 if (W / H) < R then
482 begin
483 L := H;
484 H := W/R;
485 if View.Centered then
486 Y := Y + (L - H) / 2;
487 end
488 else
489 begin
490 L := W;
491 W := H * R;
492 if View.Centered then
493 X := X + (L - W) / 2;
494 end;
495 end;
496 end
497 else
498 if View.Centered then
499 begin
500 if FPDFDocument.Images[IDX].Width < View.dx then
501 begin
502 X:=View.X + (View.dx - FPDFDocument.Images[IDX].Width) div 2;
503 W:=FPDFDocument.Images[IDX].Width;
504 end
505 else
506 begin
507 X:=View.x;
508 W:=View.dx;
509 end;
510
511 if FPDFDocument.Images[IDX].Height < View.dy then
512 begin
513 Y:=View.y + (View.dy - FPDFDocument.Images[IDX].Height) div 2;
514 H:=FPDFDocument.Images[IDX].Height;
515 end
516 else
517 begin
518 Y:=View.y;
519 H:=View.dy;
520 end;
521 end
522 else
523 begin
524 X:=View.X;
525 Y:=View.Y;
526 W:=FPDFDocument.Images[IDX].Width;
527 H:=FPDFDocument.Images[IDX].Height;
528 end;
529
530 fX:=ConvetUnits(X);
531 fY:=ConvetUnits(Y);
532 fW:=ConvetUnits(W);
533 fH:=ConvetUnits(H);
534
535 FCurPage.DrawImage(fX, fY + fH, fW, fH, IDX); // left-bottom coordinate of image
536 end;
537 end;
538
539 procedure TlrPdfExportFilter.DoLineView(View: TfrLineView);
540 begin
541 DrawRect(View.Left, View.Top, View.Width, View.Height, View.FrameColor, clNone, View.Frames, View.FrameWidth);
542 end;
543
544 procedure TlrPdfExportFilter.DoCheckBoxView(View: TfrCheckBoxView);
545 var
546 C: Boolean;
547 GX, GY: Integer;
548 begin
549 DrawRectView(View);
550 C:=View.Checked;
551 if View.Memo.Count > 0 then
552 C:=View.Memo[0] = '1';
553
554 View.CalcGaps;
555 GX:= TfrHackView(View).InternalGapX * 2; //View.GapX + View.FrameWidth + 2;
556 GY:= TfrHackView(View).InternalGapY * 2; //View.GapY + View.FrameWidth + 2;
557
558 if C then
559 begin
560 DrawLine(
561 View.X + GX,
562 View.Y + GY,
563 View.X + View.DX - GX * 2,
564 View.Y + View.DY - GY * 2,
565 View.FrameColor,
566 ConvetUnits1(3)
567 );
568
569 DrawLine(
570 View.X + View.DX - GX * 2,
571 View.Y + GY,
572 View.X + GX * 2,
573 View.Y + View.DY - GY * 2,
574 View.FrameColor,
575 ConvetUnits1(3)
576 );
577 end;
578 end;
579
580 procedure TlrPdfExportFilter.DoShapeView(View: TfrShapeView);
581 begin
582 case View.ShapeType of
583 frstRectangle:
584 DrawRect(View.X, View.Y, View.DX, View.DY, View.FrameColor, View.FillColor, [frbLeft, frbTop, frbRight, frbBottom], View.FrameWidth);
585 frstRoundRect:
586 DrawLRObjectInternal(View);
587 frstEllipse:
588 DrawEllipse(View.X, View.Y, View.DX, View.DY, View.FrameColor, View.FillColor, View.Frames, View.FrameWidth);
589 frstTriangle:
590 DrawLRObjectInternal(View);
591 frstDiagonal1:
592 DrawLine( View.X, View.Y, View.X + View.DX, View.Y + View.DY, View.FrameColor,View.FrameWidth);
593 frstDiagonal2:
594 DrawLine( View.X + View.DX, View.Y, View.X, View.Y + View.DY, View.FrameColor,View.FrameWidth);
595 end;
596 end;
597
598 procedure TlrPdfExportFilter.DoBarCodeView(View: TfrCustomBarCodeView);
599 var
600 FBmp: TLazreportBitmap;
601 X, Y: Integer;
602 begin
603 DrawRectView(View);
604 FBmp:=View.GenerateBitmap;
605 try
606 DrawImage(View.X, View.Y, FBmp.Width, FBmp.Height, FBmp);
607 finally
608 FBmp.Free;
609 end;
610 end;
611
612 procedure TlrPdfExportFilter.DoRoundRectView(View: TfrRoundRectView);
613 begin
614 // DrawRectView(View);
615 DrawLRObjectInternal(View);
616 end;
617
618 procedure TlrPdfExportFilter.WriteTextRectJustify(AExportFont: TExportFontItem;
619 X, Y, W, H: TPDFFloat; const Text: string; Trimmed: boolean);
620 var
621 S: String;
622 Arr: TArrUTF8Item;
623 AvailWidth, PxSpc, RxSpc, Extra: TPDFFloat;
624 WordCount, SpcCount, SpcSize, Cini, CEnd, i: Integer;
625 SpaceWidth, FTH: Single;
626 begin
627 //Calc text height
628 FTH:=AExportFont.TextHeight('Wg');
629
630 X:=ConvetUnits(X);
631 Y:=ConvetUnits(Y);
632 W:=ConvetUnits(W);
633 H:=ConvetUnits(H);
634
635 AvailWidth:=W;
636 // count words
637 Arr := UTF8CountWords(Text, WordCount, SpcCount, SpcSize);
638 // handle trimmed text
639 S := Text;
640 if (SpcCount>0) then
641 begin
642 Cini := 0;
643 CEnd := Length(Arr)-1;
644 if Trimmed then
645 begin
646 s := UTF8Trim(Text, [u8tKeepStart]);
647 if Arr[CEnd].Space then
648 begin
649 Dec(CEnd);
650 Dec(SpcCount);
651 end;
652 end;
653 AvailWidth := AvailWidth - AExportFont.TextWidth(S);
654 end;
655
656 // check if long way is needed
657 if (SpcCount>0) and (AvailWidth>0) then
658 begin
659
660 SpaceWidth := AExportFont.TextWidth(' ');
661 PxSpc := AvailWidth / SpcCount;
662 RxSpc := AvailWidth - PxSpc * SpcCount;
663 if PxSPC=0 then
664 begin
665 PxSPC := 1;
666 RxSpc := 0;
667 end;
668
669 for i:=CIni to CEnd do
670 if Arr[i].Space then
671 begin
672 X := X + Arr[i].Count * SpaceWidth;
673 if AvailWidth>0 then
674 begin
675 Extra := PxSpc;
676 if RxSpc>0 then
677 begin
678 Extra:=Extra + ConvetUnits1(1);
679 RxSpc:=RxSpc - ConvetUnits1(1);
680 end;
681 X := X + Extra;
682 AvailWidth:=AvailWidth - Extra;
683 end;
684 end
685 else
686 begin
687 s := Copy(Text, Arr[i].Index, Arr[i].Count);
688 FCurPage.WriteText(X, Y + FTH, S);
689 X := X + AExportFont.TextWidth(S)
690 end;
691
692 end
693 else
694 FCurPage.WriteText(X, Y + FTH, S);
695
696 SetLength(Arr, 0);
697 end;
698
699 procedure TlrPdfExportFilter.WriteTextRect(AExportFont: TExportFontItem; X, Y,
700 W: TPDFFloat; AText: string; AHAlign: TAlignment; angle: TPDFFloat);
701 var
702 FTW, FTH: Single;
703 X1: TPDFFloat;
704 Y1, fX, fY, fW: TPDFFloat;
705 begin
706 fX := ConvetUnits(X);
707 fY := ConvetUnits(Y);
708 fW := ConvetUnits(W);
709
710 //Calc text width
711 FTW:=AExportFont.TextWidth(AText);
712 //Calc text height
713 FTH:=AExportFont.TextHeight(AText);
714
715 case AHAlign of
716 taLeftJustify:
717 begin
718 Y1:=fY + FTH;
719 X1:=fX;
720 end;
721 taRightJustify:
722 begin
723 Y1:=fY + FTH;
724 X1:=fX + fW - FTW;
725 if X1 < fX then
726 X1:=fX;
727 end;
728 taCenter:
729 begin
730 Y1:=fY + FTH;
731 X1:=fX + fW / 2 - FTW / 2;
732 if X1 < fX then
733 X1:=fX;
734 end;
735 end;
736 FCurPage.WriteText(X1, Y1, AText, angle);
737 end;
738
739 procedure TlrPdfExportFilter.DrawRect(X, Y, W, H: TPDFFloat; ABorderColor,
740 AFillColor: TColor; AFrames: TfrFrameBorders; ABorderWidth: TPDFFloat);
741 var
742 fX, fY, fW, fH: Extended;
743 begin
744 if (AFillColor = clNone) and (ABorderColor = clNone) then exit;
745
746 if ABorderColor <> clNone then
747 FCurPage.SetColor(ColorToPdfColor(ABorderColor), true);
748
749 if (AFillColor <> clNone) then
750 FCurPage.SetColor(ColorToPdfColor(AFillColor), false);
751
752 fW:= ConvetUnits(W);
753 fH:= ConvetUnits(H);
754 fX:= ConvetUnits(X);
755 fY:= ConvetUnits(Y);
756 ABorderWidth:=ConvetUnits(ABorderWidth);
757
758 if AFrames = [frbLeft, frbTop, frbRight, frbBottom] then
759 FCurPage.DrawRect(fX, fY + fH, fW, fH, ABorderWidth, (AFillColor <> clNone), (ABorderColor <> clNone))
760 else
761 begin
762 if frbLeft in AFrames then
763 FCurPage.DrawLine(fX, fY, fX, fY + fH, ABorderWidth);
764
765 if frbTop in AFrames then
766 FCurPage.DrawLine(fX, fY, fX + fW, fY, ABorderWidth);
767
768 if frbRight in AFrames then
769 FCurPage.DrawLine(fX + fW, fY, fX + fW, fY + fH, ABorderWidth);
770
771 if frbBottom in AFrames then
772 FCurPage.DrawLine(fX, fY + fH, fX + fW, fY + fH, ABorderWidth);
773 end;
774 end;
775
776 procedure TlrPdfExportFilter.DrawRectView(AView: TfrView);
777 begin
778 if AView.Frames <> [] then
779 DrawRect(AView.Left, AView.Top, AView.Width, AView.Height, AView.FrameColor, AView.FillColor, AView.Frames, AView.FrameWidth);
780 end;
781
782 procedure TlrPdfExportFilter.WriteURL(X, Y, W, H: TPDFFloat; AUrlText: string);
783 begin
784 {$IF (FPC_FULLVERSION >= 30101)}
785 X := ConvetUnits(X);
786 Y := ConvetUnits(Y);
787 W := ConvetUnits(W);
788 H := ConvetUnits(H);
789 FCurPage.AddExternalLink(X, Y + H, W, H, AUrlText, false);
790 {$ENDIF}
791 end;
792
793 procedure TlrPdfExportFilter.DrawLine(X1, Y1, X2, Y2: TPDFFloat;
794 ABorderColor: TColor; ABorderWidth: TPDFFloat);
795 begin
796 if (ABorderColor = clNone) then exit;
797
798 if ABorderColor <> clNone then
799 FCurPage.SetColor(ColorToPdfColor(ABorderColor), true);
800
801
802 FCurPage.DrawLine(
803 ConvetUnits(X1),
804 ConvetUnits(Y1),
805 ConvetUnits(X2),
806 ConvetUnits(Y2),
807 ConvetUnits(ABorderWidth));
808 end;
809
810 procedure TlrPdfExportFilter.DrawEllipse(X, Y, W, H: TPDFFloat; ABorderColor,
811 AFillColor: TColor; AFrames: TfrFrameBorders; ABorderWidth: TPDFFloat);
812 var
813 fX, fY, fW, fH: Extended;
814 begin
815 if (AFillColor = clNone) and (ABorderColor = clNone) then exit;
816
817 if ABorderColor <> clNone then
818 FCurPage.SetColor(ColorToPdfColor(ABorderColor), true);
819
820 if (AFillColor <> clNone) then
821 FCurPage.SetColor(ColorToPdfColor(AFillColor), false);
822
823 fW:= ConvetUnits(W);
824 fH:= ConvetUnits(H);
825 fX:= ConvetUnits(X);
826 fY:= ConvetUnits(Y);
827 ABorderWidth:=ConvetUnits(ABorderWidth);
828
829 FCurPage.DrawEllipse(fX, fY + fH, fW, fH, ABorderWidth, (AFillColor <> clNone), (ABorderColor <> clNone))
830 end;
831
832 procedure TlrPdfExportFilter.DrawImage(X, Y, W, H: integer; ABmp: TLazreportBitmap);
833 var
834 X1, Y1, W1, H1: TPDFFloat;
835 S: TMemoryStream;
836 IDX: Integer;
837 begin
838 begin
839 S:=TMemoryStream.Create;
840 try
841 ABmp.SaveToStream(S);
842 S.Position:=0;
843 IDX := FPDFDocument.Images.AddFromStream(S, TFPReaderBMP, False);
844 X1:=ConvetUnits(X);
845 Y1:=ConvetUnits(Y);
846 W1 := ConvetUnits(W); // FPDFDocument.Images[IDX].Width);
847 H1 := ConvetUnits(H); // FPDFDocument.Images[IDX].Height);
848 FCurPage.DrawImage(X1, Y1 + H1, W1, H1, IDX); // left-bottom coordinate of image
849 finally
850 S.Free;
851 end;
852 end;
853 end;
854
855 procedure TlrPdfExportFilter.DrawLRObjectInternal(View: TfrView);
856 var
857 FBmp: TLazReportBitmap;
858 X, Y: Integer;
859 begin
860 X:=View.X;
861 Y:=View.Y;
862 FBmp:=TLazReportBitmap.Create;
863 try
864 FBmp.Width:=View.DX + 1;
865 FBmp.Height:=View.DY + 1;
866 FBmp.Canvas.Brush.Color := clWhite;
867 FBmp.Canvas.Brush.style := bsSolid;
868 FBmp.Canvas.FillRect(0, 0, FBmp.Width, FBmp.Height);
869 View.X:=0;
870 View.Y:=0;
871 View.Draw(FBmp.Canvas);
872 DrawImage(X, Y, FBmp.Width, FBmp.Height, FBmp);
873 finally
874 FBmp.Free;
875 end;
876 end;
877
878 constructor TlrPdfExportFilter.Create(AStream: TStream);
879 begin
880 inherited Create(AStream);
881 FPDFDocument:=TPDFDocument.Create(nil);
882 FFontItems:=TExportFonts.Create(Self);
883 InitFonts;
884 end;
885
886 destructor TlrPdfExportFilter.Destroy;
887 begin
888 FreeAndNil(FFontItems);
889 FreeAndNil(FPDFDocument);
890 inherited Destroy;
891 end;
892
893 procedure TlrPdfExportFilter.OnBeginDoc;
894 begin
895 inherited OnBeginDoc;
896 FCurPageNo:=-1;
897 FPDFDocument.Infos.Title := Application.Title;
898 { FPDFDocument.Infos.Author := FAuthorPDF;
899 FPDFDocument.Infos.Producer := FProducerPDF;}
900 FPDFDocument.Infos.ApplicationName := ApplicationName;
901 FPDFDocument.Infos.CreationDate := Now;
902
903 FPDFDocument.Options:=FPDFDocument.Options + [poPageOriginAtTop, poUseRawJPEG, poSubsetFont];
904 FPDFDocument.DefaultOrientation := ppoPortrait;
905
906 FPDFDocument.StartDocument;
907 FCurSection := FPDFDocument.Sections.AddSection;
908
909 SetupFonts;
910 end;
911
912 procedure TlrPdfExportFilter.OnEndDoc;
913 begin
914 inherited OnEndDoc;
915 FPDFDocument.SaveToStream(Stream);
916 end;
917
918 procedure TlrPdfExportFilter.OnBeginPage;
919 var
920 lrPg: PfrPageInfo;
921 begin
922 inherited OnBeginPage;
923 Inc(FCurPageNo);
924 FCurPage := FPDFDocument.Pages.AddPage;
925 FCurPage.UnitOfMeasure := uomMillimeters; //normal work only whis mm ??
926 FCurSection.AddPage(FCurPage);
927
928 //setup page size
929 lrPg:=CurReport.EMFPages[FCurPageNo];
930 case lrPg^.pgSize of
931 9:FCurPage.PaperType := ptA4;
932 11:FCurPage.PaperType := ptA5;
933 1,2:FCurPage.PaperType := ptLetter;
934 5:FCurPage.PaperType := ptLegal;
935 7:FCurPage.PaperType := ptExecutive;
936 //:FCurPage.PaperType := ptComm10;
937 37:FCurPage.PaperType := ptMonarch;
938 27:FCurPage.PaperType := ptDL;
939 28:FCurPage.PaperType := ptC5;
940 34:FCurPage.PaperType := ptB5;
941 else
942 FCurPage.PaperType := ptA4;
943 end;
944
945 if lrPg^.pgOr in [poPortrait, poReversePortrait] then
946 FCurPage.Orientation:=ppoPortrait
947 else //poReverseLandscape, poLandscape,
948 FCurPage.Orientation:=ppoLandscape;
949 end;
950
951 procedure TlrPdfExportFilter.OnEndPage;
952 begin
953 inherited OnEndPage;
954 end;
955
956 procedure TlrPdfExportFilter.OnData(x, y: Integer; View: TfrView);
957 begin
958 InternalGapX:=2 + View.GapX;
959 InternalGapY:=2 + View.GapY;
960
961 if (View is TfrRoundRectView) then
962 DoRoundRectView(TfrRoundRectView(View))
963 else
964 if (View is TfrMemoView) then
965 DoMemoView(TfrMemoView(View))
966 else
967 if (View is TfrPictureView) then
968 DoImageView(TfrPictureView(View))
969 else
970 if (View is TfrLineView) then
971 DoLineView(TfrLineView(View))
972 else
973 if (View is TfrCheckBoxView) then
974 DoCheckBoxView(TfrCheckBoxView(View))
975 else
976 if (View is TfrShapeView) then
977 DoShapeView(TfrShapeView(View))
978 else
979 if (View is TfrCustomBarCodeView) then
980 DoBarCodeView(TfrCustomBarCodeView(View))
981
982 ;
983 end;
984
985 procedure TlrPdfExportFilter.OnText(x, y: Integer; const Text: String;
986 View: TfrView);
987 var
988 W: Double;
989 begin
990 if (View is TfrMemoView) and Assigned(FCurFont) then
991 begin
992 if TfrMemoView(View).FirstLine then
993 W:=TfrMemoView(View).Width - TfrMemoView(View).ParagraphGap - InternalGapX * 2
994 else
995 W:=TfrMemoView(View).Width - InternalGapX * 2;
996
997 if TfrMemoView(View).Justify and not TfrMemoView(View).LastLine then
998 WriteTextRectJustify(FCurFont, X + InternalGapX, Y, W, View.dy, Text, true)
999 else
1000 WriteTextRect(FCurFont, X + InternalGapX, Y, W, Text, TfrMemoView(View).Alignment, TfrMemoView(View).Angle);
1001 end;
1002 end;
1003
1004 procedure TlrPdfExportFilter.OnExported(x, y: Integer; View: TfrView);
1005 begin
1006 end;
1007
1008 initialization
1009 frRegisterExportFilter(TlrPdfExportFilter, 'PDF file (*.pdf)', '*.pdf');
1010 end.
1011
1012