[Lazarus] [ISSUE] FCL-Web and LazReport
Leonardo M. Ramé
l.rame at griensu.com
Thu Jan 17 12:18:07 CET 2013
On 2013-01-17 09:07:09 -0200, silvioprog wrote:
> 2013/1/17 Leonardo M. Ramé <[1]l.rame at griensu.com>
>
> On 2013-01-17 08:52:11 +0100, Michael Van Canneyt wrote:
> >
> > On Wed, 16 Jan 2013, silvioprog wrote:
> >
> > >Hello,
> > >Please see in:
> > >
> > >[2]http://bugs.freepascal.org/view.php?id=23664
> >
> > This cannot be fixed. Lazreport is not suitable for use in
> webapplications.
> >
> > Some time ago, I started a new reporting engine exactly for this
> reason.
> >
> > A well-designed reporting engine is independent of any widget set.
> > (see e.g. jasperreports in Java)
> >
> > Michael.
> >
>
> I had a similar issue some time ago with, TAChart. It needed TCanvas to
> draw charts, but that was fixed by Alexander, if I remember correctly.
>
> That's why I stopped looking for a report generator for my cgi apps. Now
> I rely on libHaru ([3]http://libharu.org/), which is a C shared library
> with Pascal bindings that allows creation of PDF files.
>
> The problem with libHaru is you don't create reports out of markup, but
> by code. In my case that's not a problem, because I'm the only one in
> charge of creating reports, a different story will be when the final
> user wants to create their own reports.
> --
> Leonardo M. Ramé
> [4]http://leonardorame.blogspot.com
>
> Very nice.
> You could send a small example with this library to take a look? Thank
> you.
> --
Yes, te attached file generates a report based on a TCollection
containing the data for each page, it has a header, body (with many
lines) and a footer. I also attached a small jpg showing the final
report.
--
Leonardo M. Ramé
http://leonardorame.blogspot.com
-------------- next part --------------
unit resumen_cuenta;
{$mode delphi}{$H+}
interface
uses
SysUtils, hpdf, hpdf_types, hpdf_consts,
Math, Classes,
datos_resumen;
type
{ TResumenCta }
TResumenCta = class(TCollectionItem)
private
FDatosResumen: TDatosResumen;
page: HPDF_Page;
pageWidth: Double;
pageHeight: Double;
leftMargin: Double;
rightMargin: Double;
topMargin: Double;
x: double;
y: double;
angle1: double;
rad1: double;
image: HPDF_Image;
iw: double;
ih: double;
pdf: HPDF_Doc;
FFont: HPDF_Font;
FBold: HPDF_Font;
FBolditalic: HPDF_Font;
FLogoGS: HPDF_Image;
FLogoBW: HPDF_Image;
procedure WriteText(page: HPDF_Page; x,y: double; Text: string; font: HPDF_Font);
procedure WriteCenteredText(page: HPDF_Page; x,w,y: double; Text: string; font: HPDF_Font);
procedure WriteRightAlignedText(page: HPDF_Page; x,w,y: double; Text: string; font: HPDF_Font);
procedure DrawCoupon(page: HPDF_Page; x, y: double; font, bold: HPDF_Font; pdf: HPDF_Doc);
procedure ImprimirDetalle(font, bold: HPDF_Font);
public
constructor Create(ACollection: TCollection); override;
procedure Draw;
property bold: HPDF_Font read FBold write FBold;
property font: HPDF_Font read FFont write FFont;
property boldItalic: HPDF_Font read FBoldItalic write FBoldItalic;
property DatosResumen: TDatosResumen read FDatosResumen write FDatosResumen;
property LogoGS: HPDF_Image read FLogoGS write FLogoGS;
property LogoBW: HPDF_Image read FLogoBW write FLogoBW;
end;
{ TResumenesCta }
TResumenesCta = class(TCollection)
private
FDatosResumenes: TDatosResumenes;
FPdf: HPDF_Doc;
font: HPDF_Font;
bold: HPDF_Font;
bolditalic: HPDF_Font;
FLogoGS: HPDF_Image;
FLogoBW: HPDF_Image;
function GetItem(AIndex: Integer): TResumenCta;
public
constructor Create(ADatosResumenes: TDatosResumenes);
destructor Destroy; override;
function Add: TResumenCta;
procedure Save;
procedure SaveToStream(AStream: TStream);
procedure Draw;
property Items[AIndex: Integer]: TResumenCta read GetItem; default;
property pdf: HPDF_Doc read FPdf;
property DatosResumenes: TDatosResumenes read FDatosResumenes;
end;
implementation
const
cLineHeight = 12;
fname: string = 'Test.pdf';
DASH_MODE1: array[0..0] of HPDF_UINT16 = (5);
procedure error_handler (error_no: HPDF_STATUS; detail_no: HPDF_STATUS;
user_data: Pointer); stdcall;
var
message: string;
begin
message := 'ERROR: ' + IntToStr(error_no) + '-' + IntToStr(detail_no);
raise Exception.Create(message);
end;
{ TResumenesCta }
constructor TResumenesCta.Create(ADatosResumenes: TDatosResumenes);
begin
inherited Create(TResumenCta);
Fpdf := HPDF_New(@error_handler, nil);
HPDF_SetCompressionMode(Fpdf, HPDF_COMP_ALL);
{* create default-font *}
bold := HPDF_GetFont(Fpdf, 'Courier-Bold', 'WinAnsiEncoding');
font := HPDF_GetFont(Fpdf, 'Courier', 'WinAnsiEncoding');
bolditalic := HPDF_GetFont(Fpdf, 'Courier-BoldOblique', 'WinAnsiEncoding');
FDatosResumenes := ADatosResumenes;
if not fileExists('logo-gs.png') then
raise Exception.Create('file logo-gs.png does not exists.');
FLogoGS := HPDF_LoadPngImageFromFile (pdf, 'logo-gs.png');
if not fileExists('logo-bw.png') then
raise Exception.Create('file logo-bw.png does not exists.');
FLogoBW := HPDF_LoadPngImageFromFile (pdf, 'logo-bw.png');
end;
destructor TResumenesCta.Destroy;
begin
HPDF_Free (pdf);
end;
function TResumenesCta.Add: TResumenCta;
begin
Result := TResumenCta(inherited Add);
Result.pdf := FPdf;
Result.font := font;
Result.bold := bold;
Result.boldItalic:= bolditalic;
end;
procedure TResumenesCta.Save;
begin
(* save the document to a file *)
HPDF_SaveToFile (Fpdf, PChar(fname));
end;
procedure TResumenesCta.SaveToStream(AStream: TStream);
var
lSize: HPDF_UINT32;
buf: array[0..4096] of HPDF_BYTE;
begin
HPDF_SaveToStream(pdf);
HPDF_ResetStream(pdf);
while true do
begin
lSize := 4096;
HPDF_ReadFromStream(pdf, buf, @lSize);
if(lSize = 0) then
break;
AStream.Write(buf, lSize);
end;
AStream.Position := 0;
end;
procedure TResumenesCta.Draw;
var
I: Integer;
lResumenCta: TResumenCta;
begin
Clear;
for I := 0 to FDatosResumenes.Count - 1 do
begin
lResumenCta := Add;
lResumenCta.LogoBW:= FLogoBW;
lResumenCta.LogoGS:= FLogoGS;
lResumenCta.DatosResumen := FDatosResumenes[I];
lResumenCta.Draw;
end;
end;
function TResumenesCta.GetItem(AIndex: Integer): TResumenCta;
begin
Result := TResumenCta(inherited GetItem(AIndex));
end;
{ TResumenCta }
constructor TResumenCta.Create(ACollection: TCollection);
begin
page := HPDF_AddPage((ACollection as TResumenesCta).pdf);
(* tamaño de página *)
pageWidth := HPDF_Page_GetWidth(page);
pageHeight := HPDF_Page_GetHeight(page);
leftMargin := 10;
rightMargin := pageWidth - leftMargin;
topMargin := pageHeight - 10;
x := leftMargin + 4;
y := topMargin;
end;
procedure TResumenCta.WriteText(page: HPDF_Page; x,y: double; Text: string; font: HPDF_Font);
begin
HPDF_Page_BeginText(page);
HPDF_Page_MoveTextPos(page, x, y);
HPDF_Page_SetFontAndSize(page, font, 10);
HPDF_Page_ShowText(page, PAnsiChar(UTF8ToAnsi(Text)));
HPDF_Page_EndText(page);
end;
procedure TResumenCta.WriteCenteredText(page: HPDF_Page; x,w,y: double; Text: string; font: HPDF_Font);
var
lText: PAnsiChar;
begin
lText := PAnsiChar(UTF8ToAnsi(Text));
HPDF_Page_BeginText(page);
HPDF_Page_MoveTextPos(page, x, y);
HPDF_Page_SetFontAndSize(page, font, 10);
HPDF_Page_TextRect(page, x, y, x + w, y, lText, HPDF_TALIGN_CENTER, nil);
HPDF_Page_EndText(page);
end;
procedure TResumenCta.WriteRightAlignedText(page: HPDF_Page; x,w,y: double; Text: string; font: HPDF_Font);
var
lText: PAnsiChar;
begin
lText := PAnsiChar(UTF8ToAnsi(Text));
HPDF_Page_BeginText(page);
HPDF_Page_MoveTextPos(page, x, y);
HPDF_Page_SetFontAndSize(page, font, 10);
HPDF_Page_TextRect(page, x, y, x + w, y, lText, HPDF_TALIGN_RIGHT, nil);
HPDF_Page_EndText(page);
end;
procedure TResumenCta.DrawCoupon(page: HPDF_Page; x, y: double; font, bold: HPDF_Font; pdf: HPDF_Doc);
var
image: HPDF_Image;
iw: double;
ih: double;
begin
iw := HPDF_Image_GetWidth(FLogoBW) / 6;
ih := HPDF_Image_GetHeight(FLogoBW) / 6;
HPDF_Page_DrawImage(page, FLogoBW, x + 43, y, iw, ih);
y := y - (cLineHeight * 0.5);
WriteCenteredText(page, x, 210, y, 'Vencimiento', font);
y := y - cLineHeight;
WriteCenteredText(page, x, 210, y, FormatDateTime('DD/MM/YYYY', FDatosResumen.Vto), font);
y := y - (cLineHeight * 1.5);
WriteCenteredText(page, x, 210, y, FDatosResumen.Cliente, bold);
y := y - cLineHeight;
WriteCenteredText(page, x, 210, y, 'Cta. Nº ' + FDatosResumen.TarjetaNro, bold);
y := y - (cLineHeight * 1.5);
WriteCenteredText(page, x, 210, y, 'Importe: $ ' + Format('%.2f', [FDatosResumen.Importe]), font);
y := y - cLineHeight;
WriteCenteredText(page, x, 210, y, Format('Nº Resumen: %d', [FDatosResumen.ResumenNro]), font);
end;
function compare(Item1, Item2: TCollectionItem): Integer;
var
lItem1: TItemDetalle;
lItem2: TItemDetalle;
begin
lItem1 := Item1 as TItemDetalle;
lItem2 := Item2 as TItemDetalle;
if lItem1.Tipo < lItem2.Tipo then
Result := -1
else if lItem1.Tipo > lItem2.Tipo then
Result := 1
else
Result := 0;
end;
procedure TResumenCta.ImprimirDetalle(font, bold: HPDF_Font);
var
I: Integer;
y: Integer;
lDetalle: TItemDetalle;
lFont: HPDF_Font;
lTipo: Integer;
begin
y := 694;
x := leftMargin + 5;
lTipo := 1; // el tipo 1 no se muestra, para mostrarlo comenzar con tipo -1.
//FDatosResumen.Detalle.Sort(compare);
for I := 0 to FDatosResumen.Detalle.Count - 1 do
begin
lDetalle := FDatosResumen.Detalle[I];
if lDetalle.Tipo <> lTipo then
begin
lTipo := lDetalle.Tipo;
lFont := bold;
lDetalle := FDatosResumen.Detalle[I];
case lTipo of
2: WriteText(page, x + 120, y, 'CONSUMO DEL MES', lFont);
3: WriteText(page, x + 120, y, 'CONSUMO DE LOS ADICIONALES', lFont);
4: WriteText(page, x + 120, y, 'CARGOS FIJOS', lFont);
5: WriteText(page, x + 120, y, 'OTROS CARGOS (5)', lFont);
7: WriteText(page, x + 120, y, 'OTROS CARGOS', lFont);
else
WriteText(page, x + 120, y, Format('Tipo: %d', [lTipo]), lFont);
end;
y := y - cLineHeight;
end;
lFont := font;
WriteText(page, x, y, FormatDateTime('DD/MM/YYYY', lDetalle.Fecha), lFont);
WriteRightAlignedText(page, x + 60, 50, (y - 4) + cLineHeight, lDetalle.Cupon, lFont);
WriteText(page, x + 120, y, lDetalle.Concepto, lFont);
WriteRightAlignedText(page, x + 495, 70, (y - 4) + cLineHeight, Format('$ %.2f', [lDetalle.Importe]), lFont);
y := y - cLineHeight;
end;
end;
procedure TResumenCta.Draw;
begin
{* encabezado *}
HPDF_Page_SetGrayFill (page, 0.8);
HPDF_Page_Rectangle(page, leftMargin, topMargin, rightMargin - leftMargin, -54);
HPDF_Page_Fill(page);
HPDF_Page_SetGrayFill (page, 0);
HPDF_Page_SetFontAndSize(page, bold, 10);
y := y - cLineHeight;
WriteText(page, x, y, 'Señores', bold);
y := y - cLineHeight;
WriteText(page, x, y, FDatosResumen.Cliente, bold);
y := y - cLineHeight;
WriteText(page, x, y, FDatosResumen.GetDomicilio, bold);
y := y - cLineHeight;
WriteText(page, x, y, FDatosResumen.GetBarrio, bold);
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 1);
HPDF_Page_SetGrayStroke(page, 0);
HPDF_Page_Rectangle(page, 360, topMargin - 2, 110, -50);
HPDF_Page_Rectangle(page, 473, topMargin - 2, 110, -50);
HPDF_Page_FillStroke(page);
DefaultFormatSettings.DateSeparator := '/';
HPDF_Page_SetGrayFill (page, 0);
y := topMargin - 4;
x := 360;
WriteCenteredText(page, x, 110, y, 'Período desde', bold);
y := y - cLineHeight;
WriteCenteredText(page, x, 110, y, FormatDateTime('DD/MM/YYYY', FDatosResumen.Desde), font);
y := y - cLineHeight;
WriteCenteredText(page, x, 110, y, 'Período hasta', bold);
y := y - cLineHeight;
WriteCenteredText(page, x, 110, y, FormatDateTime('DD/MM/YYYY', FDatosResumen.Hasta), font);
y := topMargin - 4;
x := 473;
WriteCenteredText(page, x, 110, y, 'Fecha emisión', bold);
y := y - cLineHeight;
WriteCenteredText(page, x, 110, y, FormatDateTime('DD/MM/YYYY', FDatosResumen.Emision), font);
y := y - cLineHeight;
WriteCenteredText(page, x, 110, y, 'Fecha vto.', bold);
y := y - cLineHeight;
WriteCenteredText(page, x, 110, y, FormatDateTime('DD/MM/YYYY', FDatosResumen.Vto), font);
x := leftMargin;
y := (y + 4) - (cLineHeight * 2.5);
WriteText(page, x, y, 'CUIL / CUIT: ' + FDatosResumen.CUIL + ' ' + FDatosResumen.CondIVA + ' PESOS (Arg.)', bold);
y := y - cLineHeight;
WriteText(page, x, y, 'Tarjeta Nro.: ' + FDatosResumen.TarjetaNro + ' - Alta/Renovación: ' + FormatDateTime('DD/MM/YYYY', FDatosResumen.Renovacion), bold);
y := y - cLineHeight;
(* Tabla *)
// borde general
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 1);
HPDF_Page_SetGrayStroke(page, 0);
HPDF_Page_Rectangle(page, leftMargin, y, pageWidth - (leftMargin * 2), -550);
HPDF_Page_FillStroke(page);
// primera linea
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 0.75);
HPDF_Page_SetGrayStroke(page, 0);
HPDF_Page_Rectangle(page, leftMargin, y, pageWidth - (leftMargin * 2), -(cLineHeight + 5));
HPDF_Page_FillStroke(page);
HPDF_Page_SetGrayFill (page, 0);
WriteCenteredText(page, x, pageWidth, y - 3, 'DETALLE RESUMEN DE CUENTA', bold);
// segunda linea
y := y - (cLineHeight + 5);
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 1);
HPDF_Page_SetGrayStroke(page, 0);
HPDF_Page_Rectangle(page, leftMargin, y, pageWidth - (leftMargin * 2), -(cLineHeight + 5));
HPDF_Page_FillStroke(page);
HPDF_Page_SetGrayFill (page, 0);
y := y - 3;
WriteCenteredText(page, x, 70, y, 'FECHA', font);
WriteCenteredText(page, x + 70, 50, y, 'CUPON', font);
WriteCenteredText(page, x + 130, 380, y, 'CONCEPTO', font);
WriteCenteredText(page, x + 498, 80, y, 'IMPORTE', font);
// divisores de columna linea continua
y := y - cLineHeight;
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 1);
HPDF_Page_SetGrayStroke(page, 0);
x := 80;
HPDF_Page_MoveTo(page, x, 724);
HPDF_Page_LineTo(page, x, 707);
x := 130;
HPDF_Page_MoveTo(page, x, 724);
HPDF_Page_LineTo(page, x, 707);
x := 510;
HPDF_Page_MoveTo(page, x, 724);
HPDF_Page_LineTo(page, x, 707);
HPDF_Page_FillStroke(page);
(* Se incluye filigrama *)
iw := HPDF_Image_GetWidth(FLogoGS) / 2.5;
ih := HPDF_Image_GetHeight(FLogoGS) / 2.5;
x := (pageWidth / 2) - (iw / 2);
y := (pageHeight / 2);
HPDF_Page_DrawImage(page, FLogoGS, x, y, iw, ih);
// divisores de columna linea discontinua
y := y - cLineHeight;
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 1);
HPDF_Page_SetGrayStroke(page, 0.75);
HPDF_Page_SetDash(page, @DASH_MODE1, 1, 1);
x := 80;
HPDF_Page_MoveTo(page, x, 704);
HPDF_Page_LineTo(page, x, 200);
x := 130;
HPDF_Page_MoveTo(page, x, 704);
HPDF_Page_LineTo(page, x, 200);
x := 510;
HPDF_Page_MoveTo(page, x, 704);
HPDF_Page_LineTo(page, x, 200);
HPDF_Page_FillStroke(page);
// pie de la tabla
y := 200;
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 1);
HPDF_Page_SetGrayStroke(page, 0);
HPDF_Page_SetDash(page, nil, 0, 0);
HPDF_Page_Rectangle(page, leftMargin, y, pageWidth - (leftMargin * 2), -(cLineHeight + 5));
HPDF_Page_FillStroke(page);
x := 510;
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 0.75);
HPDF_Page_SetGrayStroke(page, 0);
HPDF_Page_SetDash(page, nil, 0, 0);
HPDF_Page_Rectangle(page, x, y, 75, -(cLineHeight + 5));
HPDF_Page_FillStroke(page);
x := 350;
HPDF_Page_SetGrayFill (page, 0);
y := y - 3;
WriteRightAlignedText(page, x, 150, y, 'Saldo al ' + FormatDateTime('DD/MM/YYYY', FDatosResumen.Desde), FBold);
HPDF_Page_SetGrayFill (page, 0);
x := 510;
WriteRightAlignedText(page, x, 70, y, '$ ' + Format('%.2f', [FDatosResumen.Importe]), FBold);
(* Recuadro lugares de pago *)
y := y - 28;
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 0);
HPDF_Page_SetGrayStroke(page, 0);
HPDF_Page_Rectangle(page, leftMargin + 8, y, pageWidth - ((leftMargin + 5) * 2), -(cLineHeight + 5));
HPDF_Page_FillStroke(page);
y := y + 3;
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 1);
HPDF_Page_SetGrayStroke(page, 0);
HPDF_Page_Rectangle(page, leftMargin + 5, y, pageWidth - ((leftMargin + 5) * 2), -(cLineHeight + 5));
HPDF_Page_FillStroke(page);
HPDF_Page_SetGrayFill (page, 0);
x := leftMargin + 5;
y := y - 2;
WriteCenteredText(page, x, pageWidth - ((leftMargin + 5) * 2), y - 1, 'Este resumen podrá ser abonado en Farmacias Del Milagro y Del Norte, o por Débito Automático', FBolditalic);
(* linea discontinua horizontal*)
y := y - 30;
HPDF_Page_SetLineWidth (page, 0.5);
HPDF_Page_SetGrayFill (page, 1);
HPDF_Page_SetGrayStroke(page, 0.75);
HPDF_Page_SetDash(page, @DASH_MODE1, 1, 1);
x := leftMargin;
HPDF_Page_MoveTo(page, x, y);
HPDF_Page_LineTo(page, x + (pageWidth - (leftMargin * 2)), y);
(* 1ra linea discontinua vertical *)
x := (leftMargin + (pageWidth - (leftMargin * 2))) / 3;
HPDF_Page_MoveTo(page, x, y);
HPDF_Page_LineTo(page, x, y - 140);
(* 2da linea discontinua vertical *)
x := x + ((leftMargin + (pageWidth - (leftMargin * 2))) / 3);
HPDF_Page_MoveTo(page, x, y);
HPDF_Page_LineTo(page, x, y - 140);
HPDF_Page_FillStroke(page);
(* Pié *)
angle1 := 90;
HPDF_Page_SetFontAndSize(page, font, 10);
rad1 := DegToRad(angle1);
HPDF_Page_SetGrayFill (page, 0);
HPDF_Page_BeginText (page);
HPDF_Page_SetTextMatrix (page,
cos(rad1),
sin(rad1),
-sin(rad1),
cos(rad1),
leftMargin + 5,
y - 94);
HPDF_Page_ShowText (page, 'Para el cliente');
x := (leftMargin + (pageWidth - (leftMargin * 2))) / 3;
HPDF_Page_SetTextMatrix (page,
cos(rad1),
sin(rad1),
-sin(rad1),
cos(rad1),
x + 10,
y - 82);
HPDF_Page_ShowText (page, 'Para el banco');
x := x + (leftMargin + (pageWidth - (leftMargin * 2))) / 3;
HPDF_Page_SetTextMatrix (page,
cos(rad1),
sin(rad1),
-sin(rad1),
cos(rad1),
x + 10,
y - 112);
HPDF_Page_ShowText (page, 'Para Tarjeta Salud');
HPDF_Page_EndText (page);
HPDF_Page_SetGrayFill (page, 0);
x := leftMargin;
y := y - (cLineHeight * 3);
DrawCoupon(page, x, y, font, bold, pdf);
x := (leftMargin + (pageWidth - (leftMargin * 2))) / 3;
DrawCoupon(page, x, y, font, bold, pdf);
x := x + (leftMargin + (pageWidth - (leftMargin * 2))) / 3;
DrawCoupon(page, x, y, font, bold, pdf);
(* Detalle *)
HPDF_Page_SetGrayFill (page, 0);
ImprimirDetalle(font, bold);
end;
end.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: report.jpg
Type: image/jpeg
Size: 30006 bytes
Desc: not available
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20130117/d0d98709/attachment-0003.jpg>
More information about the Lazarus
mailing list