#1 Re: PDF Engine » VCLCanvasSize returns (0, 0) if VCLCanvas has not been initialised » 2017-06-16 09:43:09

Thanks, that's exactly what I was hoping for. I can now remove my workaround.

Thanks for you help.  I've not got my N pages per sheet PDF generation complete.

#2 PDF Engine » VCLCanvasSize returns (0, 0) if VCLCanvas has not been initialised » 2017-06-15 10:10:55

davidheffernan
Replies: 2

I found an oddity in code where I accessed VCLCanvasSize before VCLCanvas. Since the VCLCanvas is lazily created on demand, this scenario leads to GetVCLCanvasSize accessing fVCLCanvasSize before it has been initialised. I worked around this by making sure that I access VCLCanvas before VCLCanvasSize, but I think that this protection should be implemented inside SynPdf.

#3 Re: PDF Engine » Can I call RenderMetaFile multiple times on the same page » 2017-06-14 16:02:25

I'm actually mixing metafiles and raster images. For the former, I can, as you say, use TPdfDocumentGDI and render the metafile to the VCL canvas. That seems to have no problems with multiple metafiles.  For my raster images, I think it is better to use AddXObject and DrawXObject because that embeds the image in the document, which can be stretched appropriately by the PDF render process. A bit of a fankle, but I think I can make it work!

#4 Re: PDF Engine » Can I call RenderMetaFile multiple times on the same page » 2017-06-14 14:37:30

Isn't this a bug though. Why would it be possible to use RenderMetafile multiple times, apart from when there is text? It feels like the metafile enumeration code is failing to handle text properly.

#5 Re: PDF Engine » Can I call RenderMetaFile multiple times on the same page » 2017-06-14 12:44:18

OK, here's a simple reproduction:

program RenderMetafile;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.Classes,
  Winapi.Windows,
  Vcl.Graphics,
  SynCommons in 'SynCommons.pas',
  SynLZ in 'SynLZ.pas',
  SynPdf in 'SynPdf.pas';

var
  Doc: TPdfDocument;
  Page: TPdfPage;
  Metafile: TMetafile;
  Canvas: TMetafileCanvas;
  i: Integer;
begin
  Metafile := TMetafile.Create;
  Metafile.SetSize(200, 200);
  Canvas := TMetafileCanvas.Create(Metafile, GetDC(0));
  Canvas.TextOut(10, 10, 'SynPDF is the best!');
  Canvas.Free;

  Doc := TPdfDocument.Create;
  Doc.DefaultPaperSize := psA4;
  Page := Doc.AddPage;
  Page.PageLandscape := False;
  for i := 1 to 20 do begin
    Doc.Canvas.RenderMetaFile(Metafile, 1.0, 0.0, 20.0, i*20.0);
  end;
  Doc.SaveToFile('test.pdf');
  Doc.Free;
end.

There should be 20 instances of the text of the page, but there is just the first one.  If instead of the TextOut, I make a call to MoveTo/LineTo, then multiple instances of the line appear.

#6 Re: PDF Engine » Can I call RenderMetaFile multiple times on the same page » 2017-06-14 12:31:10

I'm not sure what you mean by "the main metafile".  Anyway, I'm working on a repro.  No point doing any more until I have something concrete.

#7 Re: PDF Engine » Can I call RenderMetaFile multiple times on the same page » 2017-06-14 10:41:58

Hmm, I think I'm going to have to make a small reproduction. The issue seems perhaps to be related to the inclusion of text in the metafile.  Without that, behaviour is fine.  Let me put together a reproduction.

#8 PDF Engine » Can I call RenderMetaFile multiple times on the same page » 2017-06-14 09:38:40

davidheffernan
Replies: 8

I'm trying to implement a "multiple pages per sheet" feature for my PDF output.  I'm currently rendering a single metafile to each page of the PDF document, calling TPdfCanvas.RenderMetaFile to achieve that.  It works a treat.

However, I'm not trying to call this function multiple times on the same page with no luck.  I'm seeing nothing at all in the generated PDF, or sometimes just a couple of parts of one of the metafiles.  But certainly not multiple metafile graphics around the page.

Before I carry on, is this something that I can expect to do, or do I need to find another approach?  I know that I can create my own metafile canvas, render my metafiles to that canvas, and finally render the composite metafile to the PDF document with a single call to TPdfCanvas.RenderMetaFile.  I was hoping to avoid having to use that extra metafile to prepare my pages.

If I should be able to call TPdfCanvas.RenderMetaFile multiple times per page, and you'd like to dig into this, I'll prepare a reproduction of the issue.  I've not done that yet because it would take a little while to extract it from my complex application code.  And I didn't want to spend that time if the answer was a simple, "this can never work, do it a different way".

#9 mORMot 1 » x64 compiler warning » 2013-10-23 10:22:17

davidheffernan
Replies: 1

When compiling for x64 I see this warning:

    SynCommons.pas(28604): warning W1029: Duplicate constructor 'TFileBufferWriter.CreateInRawByteStringStream' with identical parameters will be inacessible from C++

I don't see the warning under x86.

I'm personally not concerned by this warning, but I expect that you'll find to find a way to keep the compiler happy so that code can be compiled warning free.

#10 Re: PDF Engine » Oddity when calling RenderMetaFile » 2013-10-17 18:59:38

Thanks Arnaud, that sorts the problem out and I can now remove my workaround.

#11 Re: PDF Engine » Oddity when calling RenderMetaFile » 2013-10-16 16:50:25

Thanks!  I'll check this all out tomorrow.

#12 PDF Engine » Oddity when calling RenderMetaFile » 2013-10-16 14:49:10

davidheffernan
Replies: 3

Consider the following program:

program PdfTest;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.Classes,
  Winapi.Windows,
  Vcl.Graphics,
  SynCommons in 'Synopse\SynCommons.pas',
  SynLZ in 'Synopse\SynLZ.pas',
  SynPdf in 'Synopse\SynPdf.pas';

var
  Doc: TPdfDocument;
  Page: TPdfPage;
  Metafile: TMetafile;
  Canvas: TMetafileCanvas;
begin
  // create test metafile
  Metafile := TMetafile.Create;
  Metafile.SetSize(700, 700);
  Canvas := TMetafileCanvas.Create(Metafile, GetDC(0));
  Canvas.MoveTo(0, 0);
  Canvas.LineTo(700, 700);
  Canvas.MoveTo(0, 700);
  Canvas.LineTo(700, 0);
  Canvas.Free;

  // create page in portrait orientation, and render metafile to it
  Doc := TPdfDocument.Create;
  Doc.DefaultPaperSize := psA4;
  Page := Doc.AddPage;
  Page.PageLandscape := False;
  Doc.Canvas.RenderMetaFile(Metafile);
  Doc.SaveToFile('_portrait.pdf');

  // same again, but with landscape orientation
  Doc := TPdfDocument.Create;
  Doc.DefaultPaperSize := psA4;
  Page := Doc.AddPage;
  Page.PageLandscape := True;
  Doc.Canvas.RenderMetaFile(Metafile);
  Doc.SaveToFile('_landscape.pdf');
end.

This emits two PDF files that are meant to contain a simple cross.  The portrait orientation version comes out correctly.  The landscape orientation does not.

I tracked this down to the fact that TPdfCanvas.SetPage is called from AddPage.  And this caches the height of the the page:

procedure TPdfCanvas.SetPage(APage: TPdfPage);
begin
  FPage := APage;
  FPageFontList := FPage.GetResources('Font');
  FContents := TPdfStream(FPage.ValueByName('Contents'));
  FHeight := FPage.GetPageHeight;  <-----  UH OH!
  FFactor := 72/FDoc.FScreenLogPixels; // PDF expect 72 pixels per inch
end;

Then when we subsequently change orientation, the page height is changed, but FHeight is not updated.

I guess I can solve my problem by throwing in a call to TPdfCanvas.SetPage immediately before I call RenderMetafile.  Is that what I am supposed to do?  Is there a better way to solve my problem?  Is the library behaving as designed?  Do you mean to cache FPage.GetPageHeight and then not update it later?

Thanks!

#13 Re: mORMot 1 » Synopse.inc incorrectly specifies $WEAKLINKRTTI and $RTTI » 2013-08-27 08:28:57

Yes, it is very weird.  I've not yet isolated the fault into an SSCCE so that a QC report can be logged.  Or perhaps there already is one.

Anyway, thanks for listening and understanding.  As for the naming of a conditional, I won't make a suggestion.  You know your users better than anyone and I'm sure you'll come up with a sensible name that follows your existing conventions and naming patterns.

#14 Re: mORMot 1 » Synopse.inc incorrectly specifies $WEAKLINKRTTI and $RTTI » 2013-08-26 14:45:18

Yes, I know I can comment this out. But if Synopse.inc breaks RTTI in my project, for sure it will affect others. Anyway, I can work around it, but you may wish to dig a bit deeper for the benefit of your other users.

#15 mORMot 1 » Synopse.inc incorrectly specifies $WEAKLINKRTTI and $RTTI » 2013-08-26 11:12:00

davidheffernan
Replies: 7

I recently discovered that Synopse.inc has this code:

{$WEAKLINKRTTI ON}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}

I don't understand why, but for 64 bit targets only, this means that any DUnit projects that include a unit that includes Synopse.inc, fail to enumerate test methods.  I'm building with XE3.

It seems to me that these options should not be specified in the Synopse.inc file.  The appropriate place for them is in the .dpr file.  Since they have an impact on the entire project, it feels wrong that they appear in Synopse.inc.

#17 Re: PDF Engine » SaveToStreamDirectBegin and metafiles/VCLCanvas » 2013-07-15 12:58:50

Thank you very much for that. Much appreciated.

My next step is to try drawing a metafile onto a PDF doc that is using SaveToStreamDirectBegin.  I'm hoping that will work.  I'll get back to you if I have problems, but since I'm moving house at the moment, it may be a little while.

#18 Re: PDF Engine » SaveToStreamDirectBegin and metafiles/VCLCanvas » 2013-07-12 15:45:13

OK, that does a lovely job solving my problem.  Thank you kindly.

But the SynPdf unit does not compile at the moment when USE_PDFSECURITY is not defined.

#19 PDF Engine » SaveToStreamDirectBegin and metafiles/VCLCanvas » 2013-07-12 13:39:35

davidheffernan
Replies: 6

I'm having problems trying to use SaveToStreamDirectBegin etc. with VCLCanvas and metafiles.  For example, here's a simple demo program that produces an empty PDF file.  You'll recognise the code since I took it from here: http://blog.synopse.info/post/2010/05/0 … PDF-engine

If I switch from SaveToStreamDirectBegin to SaveToFile then the generated PDF file is as expected.

I'm using your code from this revision: http://synopse.info/fossil/vinfo?name=d … 0ec68b709b

Can I expect SaveToStreamDirectBegin to work in this setting, or should I give up on it?

program SaveToStreamDirectBeginQuery;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, Graphics, SynPdf;

procedure MakePDF(const FileName: string);
var
  i: Integer;
  Stream: TStream;
begin
  with TPdfDocumentGDI.Create do
    try
      Stream := TFileStream.Create(FileName, fmCreate);
      try
        SaveToStreamDirectBegin(Stream);
        for i := 1 to 9 do
        begin
          AddPage;
          with VCLCanvas do
          begin
            Font.Name := 'Times new roman';
            Font.Size := 150;
            Font.Style := [fsBold, fsItalic];
            Font.Color := clNavy;
            TextOut(100, 100, 'Page ' + IntToStr(i));
          end;
          SaveToStreamDirectPageFlush;
        end;
        SaveToStreamDirectEnd;
      finally
        Stream.Free;
      end;
    finally
      Free;
    end;
end;

begin
  MakePDF('C:\desktop\test.pdf');
end.

#20 Re: PDF Engine » Two hints when compiling SynPdf » 2013-05-16 14:43:48

Thanks for that.  I fully understand.

If your policy is to enable assertions in all builds, then shouldn't that be enforced in your Synopse.inc file?  That would then mean you could avoid the messy $ifopt.

#21 PDF Engine » Two hints when compiling SynPdf » 2013-05-16 13:55:37

davidheffernan
Replies: 3

I'm trying out SynPdf which on the face of it is truly wonderful.  Very well done indeed!

The compiler spits out a couple of hints when I compile SynPdf.  These hints only appear when compiling with assertions disabled, i.e. $C- mode.

[dcc32 Hint] SynLZ.pas(1087): H2077 Value assigned to 'dst_beg' never used
[dcc32 Hint] SynCommons.pas(8491): H2077 Value assigned to 'PW' never used

The hints are produced in each case because a value assigned to these variables is only referred to in an assertion.  I checked out revision 59eb20700d.

Board footer

Powered by FluxBB