How to get RadioButton index from Annot

Product: PdfTron.Net.x64

Product Version: 10.10.0

Please give a brief summary of your issue:
I don’t know how to get RadioButton Index from an Annot

Please describe your issue and provide steps to reproduce it:
(The more descriptive your answer, the faster we are able to help you)
I have a Pdf with 3 page.
On this Pdf there is a RadioGroup with 3 RadioButtons.
Every page contains 1 RadioButton.
The RadioButtons order is not equale to the page order.
So if I call RadioButtonGroup.GetButton(1), I get the RadioButton on the 3rd page.

While I’m iterating all the pages of a Pdf like said in this ticket
https://community.apryse.com/t/cannot-get-acrofieldpage/10421
I get one Annot per page, I can check that

annot.GetType() == Annot.Type.e_Widget

I can get the field and check its type

Field field = new Widget(annot).GetField();
bool isRadio = field.GetType() == Type.e_radio;

Is there a safe way to get the RadioButton index?

Please provide a link to a minimal sample where the issue is reproducible:
m29_l1.pdf (1.2 MB)

P.S. Incorrectly marked as spam

1 Like

Hi,

Thanks for reaching out to us.

The behavior you are seeing is happening due to how the buttons were encoded within the PDF. When you are calling RadioButtonGroup.GetButton(1), the SDK is returning the second indexed button in the array which in this case is not on page 1. For this PDF, the 0th place is page 2, 1 is page 3, and 2 is page 1. This listing is working as intended and GetButton() is returning correctly in this test case.

Examining your PDF shows that you have a single annotation of type Widget on each page. You can look into referencing your annotations differently. When iterating between annotations present in a PDF file, you’ll generally want to load a page and in your case then look for the widget annotation present on the page. This is because the annotation is saved within that single page.

You can use our sample as reference to this
Annot annot = page.GetAnnot(i);
annot.GetType();
Annotationtest | Apryse Documentation

Since you know that the annotation is saved per page, you can use this fundamental knowledge to help in referencing them. With each subsequent annotation that is added on a page, the index you can use to reference them using GetAnnot() is increased by 1:
Class Page

In summary, you can leverage GetAnnot() and search each page individually through a loop to reliably get access to your Widget annotations.

1 Like

With each subsequent annotation that is added on a page, the index you can use to reference them using GetAnnot() is increased by 1

I’m sorry but I’m not sure I understand how to proceed.

private static void MyMethod(PDFDoc doc)
{
for (PageIterator pitr = doc.GetPageIterator(); pitr.HasNext(); pitr.Next())
{
Page page = pitr.Current();
for (int i = page.GetNumAnnots() - 1; i >= 0; --i)
{
Annot annot = page.GetAnnot(i);
if (annot.GetType() == Annot.Type.e_Widget)
{
Widget widget = new(annot);
Field field = widget.GetField();
bool isRadio = field.GetType() == Field.Type.e_radio;
if (isRadio)
{
//TODO
}
}
}
}
}

The first time I reach the “//TODO” line, the instance of the variable “field” is referring to the RadioButton with index 2
How can I get this information starting from the page, annot, widget or field variables that I have available?

1 Like

The suggestion provided above shows that you can iterate through each PDF page, and then use the fact that you know you are on x page to specifically get access to a widget annotation located on that page. Due to how this specific PDF was encoded, you will not be able to reliably use the indexing returned when calling GetButton(1).

I understand that you have some additional confusion on how to properly reference these annotations. When iterating between pages, the Annot annot = page.GetAnnot(i); will provide you with the annotation on the page. You can further ensure the annotation is the one you’re looking for by checking the Annot type as the example shows. Can you please elaborate why this approach is currently not work for you?

You should have access to Annot object here which will allow you to manipulate the button as you would like. Can you please let me know given you are able to locate the correct button, what you are wanting to do with the annotation? Please let me know of your requirements, what are you wanting to do given you can locate these annotations?

Yeah, I may have some additional confusion
My use case is the following:
A user sends me a file indicating to me through a list of “acrofieldtags” the list of annotations that must be filled in.
Another user, at a later time, will receive the information relating to the annotations to be filled in, and will tell me what value to write in them

Since, when the second user tells me which button he has chosen, my way of indicating which button of a “RadioGroup” has been selected is via this code:

public PDFDoc MyMethod(PDFDoc doc, string acrofieldTag, uint selectedIndex)
{
Field foundField = doc.GetField(acrofieldTag);
if (foundField is not null && foundField.GetType() == Field.Type.e_radio)
{
var radioButtonGroup = new RadioButtonGroup(foundField);
uint numButtons = radioButtonGroup.GetNumButtons();
if (numButtons <= selectedIndex)
{
throw new Exception(“…”);
}
for (uint i = 0; i < numButtons; i++)
{
RadioButtonWidget radioButtonWidget = radioButtonGroup.GetButton(i);
Field radioButtonField = radioButtonWidget.GetField();
if (i == selectedIndex)
radioButtonField.SetValue(true);
radioButtonField.SetFlag(Field.Flag.e_read_only, true);
}
}
doc.RefreshFieldAppearances();
doc.RefreshAnnotAppearances();
return doc;
}

I need the index of the selected RadioButton.
So when the first user tell me via AcrofieldTag wich RadioGroup should be filled, I should know for each radioButton the coordinates, page and index

I hope I was clearer.
Maybe there is another way that I don’t know of to indicate which button of a RadioGroup has been selected by recognizing it in a way that does not require knowing its index

1 Like

It looks like the fundamental confusion is that you are expecting the index provided to you by RadioButton to match the page order. This means that page 1 should contain the zero slot of the RadioButtonGroup array but because of how the PDF is encoded this will not work. Like I mentioned above this is instead pointing to button listed on page 2.

You won’t be able to rely on the RadioButtonGroup index here, but it looks like we’ll need to look at other options when it comes to interpreting the results from your users. Are you using our library to get both the acrofieldTag and selectIndex values used in your function? With our SDK you should be able to easily know which page an annotation is located to help focus on a specific button
https://sdk.apryse.com/api/PDFTronSDK/dotnet/pdftron.PDF.Annot.html#pdftron_PDF_Annot_GetPage
Can you send me the code which shows how you are getting these data point values? string acrofieldTag, uint selectedIndex
Please note, if the code is sensitive we can move to discussing your continued issue through email. Please let me know if that is your preference. You can also choose to email us at support@apryse.com and reference this post in your email.

1 Like

Maybe I’m explaining myself badly
I’m not expecting the index to match the page order. I know the index could not match the page order, this is thee reason I opened this ticket
I’m not using your SDK to get acrofieldTag and selectedIndex.
This is my business logic

A) User1 give me a Pdf file already containing the RadioGroup. I store it
B) User2 give me an acrofieldTag. I have to get the Page, Positions and Dimensions of the widget (if the widget is a RadioGroup, I need Page, Positions and Dimensions and SelectedIndex of every RadioButton) to store them.
C) I give AcrofieldTag, Page, Positions, Dimensions and indexes I got at point B to User3. User3 give me the value I have to write on the Pdf (if the Widget is a RadioGroup, User3 will give me the index of the button he choose)
D) I write the value User3 gave me on the Pdf I got on point A

So, to answer your question, I get both acrofieldTag and selectedIndex from the users

If I could call GetPage, I think I could solve my issue, but Ryan here

told me

is Optional for an Annotation to have a reference to its parent Page, and even if present, is not guaranteed to be correct. It really should be ignored

1 Like

If I could call GetPage, I think I could solve my issue, but Ryan here

For the PDF you provided, m29_l1.pdf the Widget’s do indeed have correct P mapping so you can Annot.GetPage reliably for this PDF file. If you are confident that other PDF files you will have to process are also like this (e.g. from the same author) then you could rely on this.

Otherwise, could you provide a specific example of what this acrofieldTag is that you get.

My assumption would be that for your PDF example, the acrofieldTag would be something like Group1.Three indicating the radio button on page one has been selected.

1 Like

Sadly I cannot be confident of that.
Users I still don’t know could (and will) upload any kind of Pdf

In the case in Example
User1 will upload the m29_l1.pdf file

User2 will give me the Group1 string as AcrofieldTag
Not Group1.Three, only Group1; targeting the entire RadioGroup and not a single RadioButton

User3 will see for each of the three buttons data (Page, Position and Dimensions) and will give me a SelectedIndex choosing between [0, 1, 2]

So, in the last code I posted, I can get the RadioButtonGroup via doc.GetField(acrofieldTag)
Then cycle the buttons, and set the Value of the correct button to true reading the selectedIndex

1 Like

It sounds then like you want to use FieldIterator and not PDFDoc.GetField.

It is useful to think of FieldIterator as actually a “Widget” iterator, so for your example PDF the FieldIterator will return Group1 three times, once for each Widget, but in order defined in the AcroForm, not the pages.

You can visualize the internals of a PDF using this site of ours https://cosedit.com/

See this sample below on how to use FieldIterator

1 Like

FieldIterator could be very useful to me, if there is a reliable way for each Field to get its respective page
As I was saying, my need is to get for each RadioButton the tuple (Page, Position, Dimensions, Index).
Once I have the Field I can use new Annot(field.GetSDFObj()).GetRect() to get the position and dimensions.
Using FieldIterator I can get the index, since as you wrote

will return Group1 three times […] in order defined in the AcroForm

If there is a reliable way to get the page, either through the FieldIterator alone or with the help of Page.GetAnnot, I will have all the information I need
At the moment it is not clear to me how to find out via FieldIterator the page where the single RadioButton is located

1 Like

To get Page Position and Dimensions you would want to follow our AnnotationTest sample, where you iterate each page, and each annotation, looking for e_widget type annots.

You would also store the object number annot.GetSDFObj().GetObjNum()

Then, to get the index you would use the FieldIterator and compare the object number field.GetSDFObj().GetObjNum() to what you found from the annotations, and set that as the index.

1 Like

Your solution of using GetSDFObj().GetObjNum() to match radioButtons works perfectly
Thank you very much

1 Like