With PDFBox 2, It was possible to construct a PDPageContentStream that issues (drawing) instructions to one of the following:

 * A PDPage (root <svg> in SVG terms)
 * A PDAppearanceStream (<symbol> in SVG terms)
 * A PDTilingPatten (<pattern> in SVG terms)

In PDFBox 3, it is no longer possible to construct a PDPageContentStream that issues (drawing) instructions to a PDTilingPattern. Which would mean I can no longer use the same code to convert different pieces from an SVG input to PDF through PDFBox. (With 60+ instruction primitives, circumventing the limitation with a wrapper class would be tedious.)

Now, the three content stream classes that draw on PDPage,PDAppearanceStream,PDTilingPattern all inherit from PDAbstractContentStream. But PDAbstractContentStream is a package local class. Probably to prevent people from subclassing it. (Do not worry Andreas, I am not mad, I do not want to subclass PDAbstractContentStream). Luckily, in PDAbstractContentStream, the 60+ methods to issue (drawing) instructions to the stream are public.

Without making PDAbstractContentStream a public class, the methods to issue (drawing) instructions to a content stream can be captured in a public interface. Consuming code, like mine, can be written in terms of the interface. The nice thing about this is that the actual implementations are unchanged. That means that you open extra possibilities while maintaining full binary compatibility.

So let me give an example. Suppose I want to draw a diagonal line on a page and on a pattern. I might do the following:

PDPageContentStream pgContentStream=new 
PDPageContentStream(document,page,PDPageContentStream.AppendMode.APPEND,true,true
 );
pgContentStream.moveTo( 0f, 0f);
pgContentStream.lineTo( 1f, 1f);

PDPatternContentStreamptContentStream=new PDPatternContentStream(tilingPattern 
);
ptContentStream.moveTo( 0f, 0f);
ptContentStream.lineTo( 1f, 1f);

Now with the interface, I can use the same code to draw on the page and on the pattern. E.G.

private void drawDiagonal(PDContentOutputStream outStream ) { outStream.moveTo( 
0f, 0f);
outStrean.lineTo( 1f, 1f);
}

PDPageContentStream pgContentStream=new 
PDPageContentStream(document,page,PDPageContentStream.AppendMode.APPEND,true,true
 );
drawDiagonal( pgContentStream);

PDPatternContentStreamptContentStream=new PDPatternContentStream(tilingPattern 
);
drawDiagonal( ptContentStream);

With code that is more elaborate than drawing a simple diagonal, that is quite an advantage.

--
Mark de Does, Magdalenastraat 6, 3512 NH Utrecht, the Netherlands,
http://maps.google.nl/?q=52.08692,5.1271,
e:m...@mdedoes.xs4all.nl t: 030 2314150

On 04-03-2025 08:13, Andreas Lehmkühler wrote:
Hi,

I don't understand your issue.

AFAIKT there is no api using a PDPageContentStream as parameter, so that you shouldn't be bound to use any of our classes. Your proposal to introduce an interface indicates that you are reimplementing the whole class. Why is a change on our side necessary?

Maybe it is just me, but I didn't get your point. Can you give as some sample code how you are using that content stream of yours?

Andreas


Am 28.02.25 um 14:22 schrieb Mark de Does:
In one of my projects, I convert (a subset of) SVG to PDF, using PdfBox.

In SVG, the contents of the main <svg> element, the <marker>, <symbol> and <pattern> definitions have the same syntax and structure. With PdfBox 2, I use a PDPageContentStream to record the content of all three. With PdfBox 3, that no longer works because I must use a PDPatternContentStream to record a pattern. Because the different kinds of content stream do not share a visible (public) ancestor, I cannot use the same code to record SVG content to a content stream.

This morning, I captured the public methods of PDAbstractContentStream in an interface and declared PDAbstractContentStream to implement that interface. I adapted my code to use the interface and everything works fine. (As expected).

Before I make a PR, I need some guidance.

  * Do you think introducing an interface is overkill? Simply making
    PDAbstractContentStream public would achieve the same thing for me.
    (The class, not the constructor)
  * I chose the name PDContentStream for the interface. Later on, I
    discovered that is an infortunate name: A different interface with
    that name already exists. What would be a better name?
  * I moved the JavaDoc comments from the abstract class to the
    interface. You agree? Or shall I also leave them in place?
  * On which branch must I base my PR? (I see that the trunk already has
    a 4.0 version number)

Thanks and Greetings.. Mark



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@pdfbox.apache.org
For additional commands, e-mail: users-h...@pdfbox.apache.org

Reply via email to