hexapdf icon indicating copy to clipboard operation
hexapdf copied to clipboard

[Proposal] Make at: more flexible, by adding a top-left-at (starting at the top left of a page).

Open rubyFeedback opened this issue 6 months ago • 1 comments

Sers Thomas,

Right now the recommended, or only way possible, way to add text, it seems, via at: goes like this:

canvas.text(this_text, at: [150, 150])

An example for this can be found in the excellent documentation here:

https://hexapdf.gettalong.org/documentation/basics/creating-a-pdf-from-scratch.html

It is explained here:

"The coordinate system of a PDF page has its origin at the lower-left corner"

Now, while that may be the mathematically correct way (lower-left corner is typically the place where 0 is), when I work on an existing .pdf file, I often want to "append" to an existing page, and I then actually think from "top-left to bottom-left". So, still on the left side, but rather than starting from bottom, I would like to start from the top.

Would it be possible to add a keyword here that would allow us to do so? The default behaviour is still via at:, but perhaps we could add an API such as:

top_left_at:
top:
top_at:
from_top:

Just showing a few examples how this could be.

The first line is counted from the top, so 5 pixels (px) would count from top-to-bottom.

The logic used for at: can be re-used here, just that we would do an "inverse count", e. g. we calculate from the top place. So we could re-use the code that governs at:, with the sole difference that we would count from top.

I am not sure how many users would like this; perhaps it was already suggested before (I admittedly had this as spontaneous idea, actually as my current task is to append to an existing .pdf file; I may suggest something for this too, but for now this is just for top-to-bottom counting.)

At any rate thank you for reading this suggestion.

rubyFeedback avatar May 28 '25 11:05 rubyFeedback

Thanks for the suggestions!

So, first, I will have to update that documentation page to mention the newer canvas.composer method that provides the ability to use the high-level layout functionality on a single canvas. With that the layout of text (and everything else) flows - as expected - from top to bottom.

As for amending the canvas.text method I'm not sure if that would be a good idea. Everything in the canvas works under the assumption that we have a coordinate system with the origin (0,0) at the bottom-left corner of the page. So making the #text method special in that in could act in two ways would complicate matters - I think.

You could do something like this:

require 'hexapdf'

doc = HexaPDF::Document.new
canvas = doc.pages.add.canvas
canvas.translate(0, canvas.context.box.height)
canvas.font('Helvetica', size: 10)
canvas.text('Hello world', at: [100, -150])
canvas.circle(100, -150, 3).stroke
doc.write('/tmp/out.pdf')

This would set the origin to the top-left corner but then you would need to use negative y-coordinates.

gettalong avatar May 28 '25 20:05 gettalong

I have updated the linked page so that it mentions the HexaPDF::Composer class and added a link to the composer tutorial.

gettalong avatar Aug 04 '25 14:08 gettalong