Hello PoDoFo users and devs,

I've been quite busy rethinking the PdfPainter API in the last few
days. This is something I didn't really think about when I was working
on pdfmm, but I was feeling I would have needed at some point. The
upstream code has been like in a roller coaster (I am not proud of
this after the pdfmm reintegration) but the API should be quite in a
robust state now. First I would like to summarize why I thought the
painting API needed intervention. PdfPainter:
- contained a mix of stateless "draw at" and stateful "prolong to"
path constructing operations, without a consistent, easily recognizable
naming scheme;
- has some methods that were stroking and some that were not, with no
clear reason of the difference;
- contained a obscure internal state that included the last point and
other tracking coordinates that were relevant only for few SVG
emulation methods. This state was also poorly maintained in these SVG
emulation functions as well;
- provided no validation at all of the issued functions.

Designing a painting API really requires thinking that all these
functions will be called unpredictability and with lot of
misunderstandings (the same happened/is happening for me as well).
Best idea would be getting as much inspiration from existing API
designs but I also noticed the PDF standard has some uniqueness:
- The top level content stream is not a path itself and no operator
will implicitly open a sub-path (this is different for example from
CanvasRenderingContext2D[1]);
- The text operators need to be within text objects (the paired BT ... ET).

This led me to think that is better to separate path/continous text
operations from the user friendly API in PdfPainter. The new
PdfPainter API:
- Is inspired by both javascript CanvasRenderingContext2D[1] (which is
clearly derived from PostScript) and .NET Graphics class[2], with a
lot of "draw at" oriented API and many user friendly shape drawing
methods;
- Provides a very bold separations of contexts where one can use path
or continuous text operations, by the use of two context class
instances which can always be accessed as public members
PdfPainter::Path and PdfPainter::Text. In the end these two context
classes just pass-through all the control to PdfPainter, but this
separation allows to better grasp the API and PDF specificity;
- Provides validation of the method calling sequence (e.g. no text
operators while out of BT ET or path operators without a path being
opened);
- Provides an inspectable graphics/text state that now also include
the dynamically build last position of the pen. The current
graphics/text can be accessed for read and edit with respectively
public members PdfPainter::GraphicsState and PdfPainter::TextState.

Here is a short example of use:

    PdfPainter painter;
    painter.SetCanvas(page);
    painter.TextState.SetFont(font, 15);
    painter.Text.Begin();
    painter.Text.MoveTo(100, 500);
    painter.Text.AddText("Test");
    painter.Text.End();
    painter.DrawText("Test2", 100, 600, PdfDrawTextStyle::StrikeOut);
    painter.GraphicsState.SetLineWidth(1);
    painter.Path.Begin(20, 20);
    painter.Path.AddArcTo(150, 20, 150, 70, 50);
    painter.Path.AddLineTo(150, 120);
    painter.Path.Draw(PdfPathDrawMode::Stroke);
    painter.Path.Begin(40, 40);
    painter.Path.AddLineTo(100, 40);
    painter.Path.AddLineTo(70, 80);
    painter.Path.AddLineTo(40, 40);
    painter.Path.AddCircle(200, 200, 60);
    painter.Path.Draw(PdfPathDrawMode::Fill);
    painter.Save();
    const double SquareSize = 6;
    painter.GraphicsState.SetLineWidth(0.6);
    painter.DrawRectangle(150 - SquareSize / 2, 70 - SquareSize / 2,
SquareSize, SquareSize);
    painter.GraphicsState.SetLineWidth(0);
    painter.DrawLine(150, 70 - SquareSize / 2, 150, 70 + SquareSize / 2);
    painter.DrawLine(150 - SquareSize / 2, 70, 150 + SquareSize / 2, 70);
    painter.Restore();

We'll see with time if the validation is too much severe or we should
relax it in some parts. Also we could introduce a fail-safe mode in
the painter would allow for pass-through functionalities (still not
there). Still, the default should be to help users of the API to
produce clean streams.

There are some known bugs left:
- All the draw text multiline functions are still broken, at the
moment. Will be fixed before 0.10;
- I added an AddArcTo() path like method but still missing is
AddArc(x, y, radius, startAngle, endAngle, counterclockwise);
- The update of the last point when closing the path with "h" operator
is not done.

There are certainly tons of other unknown bugs and missing features.
Some more unit testing is introduced but we are not there yet.
Feedback and patches welcome, especially if you get idea of what the
new API is aiming to with these changes.

Cheers,
Francesco

[1] https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
[2] https://learn.microsoft.com/en-us/dotnet/api/system.drawing.graphics


_______________________________________________
Podofo-users mailing list
Podofo-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/podofo-users

Reply via email to