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