Ghostscript Lite For Bullzip Pdf Printer

0 views
Skip to first unread message

Hollis Abdelkarim

unread,
Aug 3, 2024, 5:17:36 PM8/3/24
to jaechorule

You might want to break the code down to standalone parts, creating a reproducible project which just draws two lines.
With doing so you might find the problem yourself or it would at least be easier to track down the problem.

Using GDI+ to draw on the GDI canvas of the VCL is really not a good idea.
And I don't know which library you are using for GDI+ rendering, but usually it uses bitmap rendering over the VCL/GDI canvas handle.
So you loose most of the PDF vector benefits.

My guess is that it is more a problem of your GDI+ library, or how you use it, than a mormot.ui.pdf issue.
Or at least some confusion between how GDI, GDI+ and PDF are implemented and do interact.

There is no error there.
The solid line in the screenshot is an example for reference (correct), the problem is with the dashed line which, despite using width=1 the same as the solid line, it is drawn much bigger.

This same code is used to draw on screen, on PDF and even on a printer, just by feeding it a different canvas handle.
The drawing is correct on screen and on printer, but wrong on PDF. It works even if I use a PDF printer, like Bullzip etc.

Here is the main function that does the drawing.
It does not use any external library, except mormot.ui.pdf.
It draws two lines, one solid line for reference, one dashed line. Both lines are drawn with a width=1 but the dashed line is wider on PDF.

If you want to check, you can also draw on a form canvas, or even print the drawing (add Vcl.Printers in the uses) like this.
Both on the form and on printer, the drawing is correct (both lines have same width).

The GdiPlus directives are converted by the GdiPlus dll to regular GDI commands, in a way incompatible with what the PDF library can handle.
I am even surprised it even works. I expected the rendering to be at pixel level, not as vectorial calls.

Since everything seems to be working, except this, I am inclined to think that it could be fixed.
Do you think there are some intrinsic limitations within the pdf library itself which makes this impossible at the moment?

Increasing the width to 100 in second breakpoint-loop seems to increase the width of the dashed line.
But lowering it under 16 to 8 for example doesn't seem to be possible.
Minimum width dashed line seems to be that value.

1) Is the resolution set to maximum? If the resolution is higher it could be that there is a minimum width for a line (with taking rounding errors in account).
(for me fWorldFactorX and Canvas.fDevScaleX where not 1 so there could be some problems there. Canvas has a resolution.)

In my small example program, you can use the print button to print on PDF using a PDF printer (eg. change 'My Printer' with 'Microsoft Print on PDF', included in Windows).
The resulting PDF of the print will be perfect (both lines with width=1), so it is not a limitation of the PDF format, it must be something in the mormot pdf library.

When that is drawn on a canvas with 1 pixel resolution, you get the screen and printer result.
But when it is drawn to a canvas with much higher resolution, it's going to draw those circel thingies.

PS. I extracted the pdf with pdf2ps (from xpdf-tools) and looked at the resulting .ps file.
You can read the ps file afterwards with a postscript interpreter or with gimp (and setting a resolution of 1200 during import).

3) Third option is to hack mormot.ui.pdf and adjust the line width when there is a dashed line. But I looked at the TPdfEnum.NeedPen and when it's called, it's not called with any dash style because GDI+ takes the drawing of dash completely for itself. So it's difficult to know if there is a dash being drawn. You could put a global boolean switch and hack the TPdfEnum.NeedPen, to pass 0.1 if that boolean is set (and set the boolean yourself when you want to draw a dash).

I'm not sure why those curve calls are done in the synpdf version and not in the print to pdf one.
BUT, as I already mentioned... the print to pdf doesn't have smooth end-points. I think that's why there are so many "x l #10" lines for one section.
In synpdf those are smooth curves.

This is how it should be.
The [24 30] 0 d is the actual dashed line setup for pdf (as you could see in TPdfCanvas.SetDash()).
And the corresponding x l #10 after that prints the dashed line.

I think it has to do with the fact synpdf uses a EMR/enhanced meta canvas and gdi will pass the drawing different from passing it to the printerdriver via canvas. But I'm not sure (as I said, I'm no expert).

Last post for tonight. The problem is indeed the GDI+ to EnhancedMetaCanvas interface.
For example... if you change the FormButtom method to create a TMetaFileCanvas and use that and save it you see that the dashed line is also bigger.
(emf file can be opened in Paint)

I think you are on the right track with this.
The MetaFile (emf) is just a list of GDI commands.
After a bit of googling, apparently, there is a different format (emf+) for GDI+, so here is where probably the incompatibility arises.
I had read that mormot.ui.pdf uses MetaFiles internally, but wasn't aware of the incompatibility.

There is an option with POSTSCRIPT_IDENTIFY to set PSIDENT_GDICENTRIC or PSIDENT_PSCENTRIC for GDI centric or Postscript centric but that's for the device driver I think. (I don't even know if that would help)

GDI+ does have the dash stored as real dash-structure (like passed to it). It gives it correctly to the printer driver (via the canvas) on Draw() command.
But for the TEnhancedMetaCanvas this is translated to ellipsed (which contain a bug that it draws the line length which is too big).

You confirmed that in the "print as pdf" file that I posted, the dashed line is still created as many segments (ellipses) and not as a real dashed line.
How does it display correctly then? What does it do differently?

Yes, that's from the Microsoft Print to PDF. That driver is really bad. It also creates very large PDF's and isn't optimized.
I usually avoid that printer.
(But I don't know why those segments are printed/interpreted correctly)

I have my own printer for my application. It creates a Postscript printer from which a catch the output to a .ps file and I throw that through ghostscript.
Somehow the .ps file from that Postscript printer is very small and the dashed line doesn't contain segments.

BTW. Both drivers use the same base driver (PScript5.dll) so it must be something that the ghostscript.ppd is setting (because that's the only difference).
(Edit: actually, the print to pdf from Microsoft now uses some other driver I see)

In my setup I installed Ghostscript and then I create a 'Postscript' printer with the ghostscript.ppd as main driver-description.
ghostscript.ppd uses the standard PScript5.dll from Windows.
For Windows 7+ I created my own version of the PDD-package because it needed to be signed, and the version from Ghostscript back then wasn't signed (I think now it is).

In my application I set the output for the print-job to a file (instead of the installed port LPT1: or NULL:) and print to the 'Postscript' printer.
That creates a .ps file which a can throw through ghostscript.exe (gswinc32.exe or gswin64c.exe). You could also use the gsdll64.dll.
That will result in a pdf (without background).
Then you could use pdftk to merge a background.pdf with your just created pdf.

I recently switched to SynPdf for creating a pdf. For this I also use TGdiPages (essentially the same as TPdfDocumentGDI).
(That way you would only have one code-base for the actual printing, PDF or real printer doesn't matter)

There is only one downside in SynPdf, I recently discovered. In the Postscript driver from Windows I could print a transparent bitmap (hand signature on stationery).
When merging with a background (with background colors and images) the bitmap kept it's transparency.
In SynPdf it's only transparent for the current PDF/job (so over your own text in the same job).
But when merging the resulting PDF with a background.pdf (full lightgreen.pdf for example, the background of the bitmap is white).

As I understand it now... the Microsoft Print to PDF uses a complete different method of using the GDI+ for printing.
You have GDI-based printing and XPS-based printing. Microsoft Print to PDF does the latter.

That's probably also the reason the dashed line is a path instead of actual dashed line.
I think XPS-based printing always uses the ellipse version which is badly rounded.
But they did fixed the bug that the TEnhancedMetaFile has (i.e. the bigger line width which the ellipses are drawn).
So we can forget about that one.

You also have several flavors of GDI-printing. You can print via the print spooler (which uses EMF format) or directly to the printer.
I'm not sure how I can force the EMF method to see if my printer then also has the same problem (setting the processor didn't hold).
I think the printer version prints directly (via the dll's) but I'm not sure about that and how.

But there might be other drawings which need EMR_POLYBEZIERTO16 to be drawn with a pen with of > 0.
(I'm also sure this 'fix' can be improved upon, for example by setting the pen correctly so other drawings will reset the pen if needed.)

c80f0f1006
Reply all
Reply to author
Forward
0 new messages