0

Is there any way with iTextSharp to retrieve the action contained in a button field contained in a pdf?

I want to know what action that button field will do when clicked on (on MouseUp).

Thanks in advance

Senick
  • 101
  • 15
  • I don't know why the vote down, even on the Acrobat forum there is no real post on the internet about this except mine here and on Adobe Forum... – Senick Jul 29 '11 at 14:10

1 Answers1

1

Button information is stored as Annotations within the PDF. I wrote some code recently here that enumerated hyperlinks within a PDF (also annotations) and I'll re-purpose it here for you.

The action of a button can be a bunch of different things, from JavaScript to menu items to playing a movie and more. The code below handles JavaScript, Named Actions and Destination Actions, I'll leave the others up to you. Named Actions are application-specific and I don't know if Adobe has a list of what they all are. See my post above for how to resolved a Destination Action (InDirect Reference).

    Dim WorkingFolder As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    Dim WorkingFile As String = Path.Combine(WorkingFolder, "Services.pdf")

    ''//Setup some variables to be used later
    Dim R As PdfReader
    Dim PageCount As Integer
    Dim PageDictionary As PdfDictionary
    Dim Annots As PdfArray
    Dim ActionObject, NamedAction As PdfObject
    Dim DestinationAction As PdfArray
    Dim ActionOjbectID As PdfObject
    Dim ActionDictionary As PdfDictionary

    ''//Open our reader
    R = New PdfReader(WorkingFile)
    ''//Get the page cont
    PageCount = R.NumberOfPages

    ''//Loop through each page
    For I = 1 To PageCount
        ''//Get the current page
        PageDictionary = R.GetPageN(I)

        ''//Get all of the annotations for the current page
        Annots = PageDictionary.GetAsArray(PdfName.ANNOTS)

        ''//Make sure we have something
        If (Annots Is Nothing) OrElse (Annots.Length = 0) Then Continue For

        ''//Loop through each annotation
        For Each A In Annots.ArrayList

            ''//Convert the itext-specific object as a generic PDF object
            Dim AnnotationDictionary = DirectCast(PdfReader.GetPdfObject(A), PdfDictionary)

            ''//Make sure this annotation is a button
            If Not AnnotationDictionary.Get(PdfName.FT).Equals(PdfName.BTN) Then Continue For

            ''//Make sure this annotation has an ACTION
            If AnnotationDictionary.Get(PdfName.A) Is Nothing Then Continue For

            ActionObject = AnnotationDictionary.Get(PdfName.A)

            If ActionObject.IsIndirect Then
                ActionOjbectID = PdfReader.GetPdfObject(AnnotationDictionary.Get(PdfName.A))
                If ActionOjbectID.IsDictionary Then
                    ActionDictionary = DirectCast(ActionOjbectID, PdfDictionary)
                    If ActionDictionary.Get(PdfName.JS) IsNot Nothing Then
                        Trace.WriteLine("JavaScript Action  : " & ActionDictionary.GetAsString(PdfName.JS).ToUnicodeString())
                    ElseIf ActionDictionary.Get(PdfName.N) IsNot Nothing Then
                        NamedAction = ActionDictionary.Get(PdfName.N)
                        Trace.WriteLine("Named Action       : " & NamedAction.ToString())
                    ElseIf ActionDictionary.Get(PdfName.D) IsNot Nothing Then
                        DestinationAction = ActionDictionary.GetAsArray(PdfName.D)
                        Trace.WriteLine("Destination Action : " & DestinationAction.ToString())
                    Else
                        ''//Add a bunch more 
                        Trace.WriteLine("Some other action  : ")
                        For Each K In ActionDictionary.Keys
                            Trace.WriteLine("                   : " & K.ToString())
                        Next
                    End If
                Else
                    ''//Not a dictionary, do something else here, should never reach this
                End If
            Else
                ''//Non InDirect reference, should never reach this
            End If
        Next
    Next

I should note that this pulls the "default action" for a button but its possible to have multiple actions on a button for the various states. To get those, instead of looking at PdfName.A you need to look at PdfName.AA which will give you an InDirectReference that you'll need to resolve.

Community
  • 1
  • 1
Chris Haas
  • 53,986
  • 12
  • 141
  • 274
  • I have a question though, I am trying to get the code you provided working (thanks for it btw). My problem is that I don't know where the Trace.WriteLine will write and for some reason when i try to put it in a textbox the ToString return the name of the class in string. I don't know if I'm clear and thanks in advance – Senick Jul 29 '11 at 19:03
  • I'll have to finish testing this on Monday, hope I can make it work and give you a correct answer! – Senick Jul 29 '11 at 19:24
  • `Trace.WriteLine` writes to the "Immediate Window" which you can get to by going to the "Debug", then "Windows" and then "Immediate Window". I use that over the Output window because you can inspect objects from within the Immediate Window. Just a personal preference, however. – Chris Haas Jul 29 '11 at 19:28
  • Good answer, still not able to get the action as it is (like in a setAction) but it is a great start! thanks – Senick Aug 01 '11 at 12:42
  • If you put a breakpoint on `If ActionObject.IsIndirect Then` does it get hit at least? – Chris Haas Aug 01 '11 at 12:53
  • yeah, no problem your code is really good. I'm jsut having problem interpreting the objects past ... Get(PdfName.D) IsNot Nothing Then. I see the item but I can't quite get what it means or anything for now. – Senick Aug 01 '11 at 12:59
  • @Senick, I understand. The iText model takes a little while to get used to. A `PdfDictionary` object is basically a name/value collection but instead of strings for names it takes `PdfName` objects (which map directly to strings anyway). `ActionDictionary` is a `PdfDictionary` so when we say `ActionDictionary.Get(PdfName.D) IsNot Nothing` we're checking to see if that has that key. As to the names within `PdfName` they're mapped directly to the PDF spec which is (painfully) terse in syntax. Here's the spec: http://www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf – Chris Haas Aug 01 '11 at 13:07