Looking at the low level acroform spec, we should be able to get dimensions / positions of fields.
A good use case for this is knowing where and what size to stamp an image. We can leave a blank readOnly field in our form, and effectively "fill" it with an image.
const form = doc.getForm();
const field = doc.getField('somefield');
// This would be useful
const fieldDimensions = field.getDimensions(); // {x: number, y: number, width: number, height: number}
I'd like this feature as well
Hello @jamesmfriedman!
Happy to accept PRs for this. The information is certainly accessible. The main thing to be aware of when designing such an API is that form fields do not necessarily have just one single location on a page. The same field can actually be rendered in multiple locations on different pages. So, effectively, a single field can have multiple coordinates and dimensions. See https://pdf-lib.js.org/docs/api/classes/pdffield for a bit more detail about this.
Here's an example of how you can access the information with the current APIs:
import { PDFDocument } from 'pdf-lib';
(async () => {
const url = 'https://pdf-lib.js.org/assets/dod_character.pdf';
const fancyFields = await fetch(url).then((res) => res.arrayBuffer());
const pdfDoc = await PDFDocument.load(fancyFields);
const form = pdfDoc.getForm();
const textField = form.getTextField('CharacterName 2');
const widgets = textField.acroField.getWidgets();
widgets.forEach((w) => {
const rect = w.getRectangle();
console.log(rect);
});
})();
// Output:
// { x: 47.52, y: 705.92, width: 208.44, height: 20.879999999999995 }
Note also that if you're specifically looking to stamp images on fields, pdf-lib provides a PDFButton.setImage method that does exactly this. Though it currently only exists for button fields.
Thanks @Hopding, that little bit of guidance went a long way. I'll see if I can get it in there.
Hello @jamesmfriedman!
Happy to accept PRs for this. The information is certainly accessible. The main thing to be aware of when designing such an API is that form fields do not necessarily have just one single location on a page. The same field can actually be rendered in multiple locations on different pages. So, effectively, a single field can have multiple coordinates and dimensions. See https://pdf-lib.js.org/docs/api/classes/pdffield for a bit more detail about this.
Here's an example of how you can access the information with the current APIs:
import { PDFDocument } from 'pdf-lib'; (async () => { const url = 'https://pdf-lib.js.org/assets/dod_character.pdf'; const fancyFields = await fetch(url).then((res) => res.arrayBuffer()); const pdfDoc = await PDFDocument.load(fancyFields); const form = pdfDoc.getForm(); const textField = form.getTextField('CharacterName 2'); const widgets = textField.acroField.getWidgets(); widgets.forEach((w) => { const rect = w.getRectangle(); console.log(rect); }); })(); // Output: // { x: 47.52, y: 705.92, width: 208.44, height: 20.879999999999995 }Note also that if you're specifically looking to stamp images on fields,
pdf-libprovides aPDFButton.setImagemethod that does exactly this. Though it currently only exists for button fields.
Thanks @Hopding
How about text rotate? How can I get the angle of the text field?
Hello @jamesmfriedman!
Happy to accept PRs for this. The information is certainly accessible. The main thing to be aware of when designing such an API is that form fields do not necessarily have just one single location on a page. The same field can actually be rendered in multiple locations on different pages. So, effectively, a single field can have multiple coordinates and dimensions. See https://pdf-lib.js.org/docs/api/classes/pdffield for a bit more detail about this.
Here's an example of how you can access the information with the current APIs:
import { PDFDocument } from 'pdf-lib'; (async () => { const url = 'https://pdf-lib.js.org/assets/dod_character.pdf'; const fancyFields = await fetch(url).then((res) => res.arrayBuffer()); const pdfDoc = await PDFDocument.load(fancyFields); const form = pdfDoc.getForm(); const textField = form.getTextField('CharacterName 2'); const widgets = textField.acroField.getWidgets(); widgets.forEach((w) => { const rect = w.getRectangle(); console.log(rect); }); })(); // Output: // { x: 47.52, y: 705.92, width: 208.44, height: 20.879999999999995 }Note also that if you're specifically looking to stamp images on fields,
pdf-libprovides aPDFButton.setImagemethod that does exactly this. Though it currently only exists for button fields.
I'm sorry if it's kinda naive quiestion, but how can I distinguish page number of a field or a widget?
@Hopding can you please take a look?
@chislin @jamesmfriedman Considering an element can have multiple widgets, what do you expect the return to be?
Imagine having a FirstName TextField both at the top and the bottom of the page.
Would you want something like this?
const textField = form.getTextField('FirstName');
const coordinates = textField.getCoordinates();
/* coordinates: [
* { x: 23, y: 44, width: 100, height: 20 },
* { x: 23, y: 844, width 75, height: 14 }
/* ];
Something else?
@chislin @jamesmfriedman Considering an element can have multiple widgets, what do you expect the return to be?
Imagine having a _FirstName_
TextFieldboth at the top and the bottom of the page.
Would you want something like this?const textField = form.getTextField('FirstName'); const coordinates = textField.getCoordinates(); /* coordinates: [ * { x: 23, y: 44, width: 100, height: 20 }, * { x: 23, y: 844, width 75, height: 14 } /* ];Something else?
I'd love to see page number along with coordinates
I'm not sure it makes sense to mix the page with the coordinates.
Once #695 gets merged, you would be able to find the page or page number of a widget:
let page = document.getPages().find(x => x.ref === widget.P());
let pageNumber = document.getPages().findIndex(x => x.ref === widget.P());
element.getCoordinates() is trivial to implement, if we just want the coordinates.
@Hopding is the plan to keep acroField private? We could document it, along with widget.
Otherwise, we could implement a getCoordinates() on the element.
I'm not sure it makes sense to mix the page with the coordinates.
Once #695 gets merged, you would be able to find the page or page number of a widget:let page = document.getPages().find(x => x.ref === widget.P());let pageNumber = document.getPages().findIndex(x => x.ref === widget.P());
element.getCoordinates()is trivial to implement, if we just want the coordinates.
@Hopding is the plan to keepacroFieldprivate? We could document it, along withwidget.
Otherwise, we could implement agetCoordinates()on the element.
This is even better, thanks for reply!