Plugin Apps Developer Guide
Plugin Apps Developer Guide
3
Adobe Acrobat SDK Contents
Developing Plug-ins and Applications 4
11
Adobe Acrobat SDK List of Examples
Developing Plug-ins and Applications 12
Developing Plug-ins and Applications is one of several resources available to help you learn about Adobe®
Acrobat® plug-in and Adobe® PDF Library application development.
This document assumes that you are familiar with the Acrobat product family and are an experienced user
of Acrobat products.
Related documentation
In addition to this guide, the resources in the table provide information about the Acrobat SDK.
A guide to the documentation in the Acrobat SDK. Acrobat SDK Documentation Roadmap
A guide to the sections of the Acrobat SDK that pertain to Developing for Adobe Reader
Adobe Reader.
A guide to the sample code included with the Acrobat SDK. Guide to SDK Samples
Prototyping code without the overhead of writing and Snippet Runner Cookbook
verifying a complete plug-in or application.
Detailed descriptions of JavaScript APIs for developing and JavaScript for Acrobat API Reference
enhancing workflows in Acrobat and Adobe Reader.
14
Adobe Acrobat SDK Preface
Developing Plug-ins and Applications Related documentation 15
Detailed descriptions of the APIs for Acrobat and Acrobat and PDF Library API Reference
Adobe Reader plug-ins, as well as for PDF Library
applications.
1 Introduction
You can use the Acrobat SDK to create plug-ins for Adobe Reader and Acrobat as well as standalone
applications that interact with and manipulate PDF documents. The Acrobat SDK contains two libraries:
the Acrobat core API and the PDF Library API.
The Acrobat core API contains a set of interfaces that enable you to develop plug-ins that integrate with
Acrobat and Adobe Reader. The PDF Library API enables you to develop applications that interact with and
manipulate PDF documents. It overlaps with the Acrobat core API (with the important exception of the
AV-layer, which is only part of the Acrobat core API); however, the PDF Library API also extends the Acrobat
core API with a small number of interfaces specific to the PDF Library API. This chapter introduces the
Acrobat core API and PDF Library API.
About plug-ins
A plug-in is an application that uses the resources of Acrobat or Adobe Reader as a host environment. This
means that a plug-in does not require complex user interface elements. However, it must perform certain
basic functions to let Adobe Reader or Acrobat know of its presence.
Plug-ins are dynamically-linked extensions to Acrobat or Adobe Reader and are written using the Acrobat
core API, which is an ANSI C/C++ library. Plug-ins add custom functionality and are equivalent to
dynamically-linked libraries (DLLs) on the Microsoft® Windows® platform; however, the plug-in file name
extension is .api, not .dll. On Mac OS, the file name extension of a plug-in is acroplugin.
After you develop a plug-in, you place it into the following directory:
\Program Files\Adobe\Acrobat\plug_ins
Acrobat or Adobe Reader must be restarted in order for the plug-in to be recognized. Three types of
plug-ins exist:
2. Reader-enabled plug-ins. Reader-enabled plug-ins access a limited set of APIs. These plug-ins are
developed with permission from Adobe and require special processing to load under Adobe Reader.
For information, see “Creating an Adobe Reader Plug-In” on page 245.
3. Certified plug-ins. Certified plug-ins have undergone extensive testing to ensure that they do not
compromise the integrity of the Acrobat security model. There is currently no way for third party
plug-ins to be certified by Adobe. There is a check box in the product user interface that can be used to
ensure that only certified plug-ins load (other plug-ins will not load). Certified plug-ins are reserved for
Adobe only.
16
Adobe Acrobat SDK Introduction
Developing Plug-ins and Applications About the Acrobat core API 17
The following diagram illustrates the hierarchy of the Acrobat core API.
Acrobat Viewer
layer
Acrobat
Portable Document
Support
layer
layer
PDFEdit PDSEdit
COS layer
Note: AV layer methods are not available through the PDF Library API.
Cos layer
The Cos Object System (Cos) layer provides access to the building blocks used to construct PDF
documents. Cos methods allow plug-ins and PDF Library applications to manipulate low-level data in a
PDF file, such as dictionary and data streams. For information, see “Working with Cos Objects” on
page 178.
Platform-specific methods
In addition to the method groups represented in the previous diagram, the Acrobat core API includes
platform-specific plug-in utilities to handle issues that are unique to Windows, Mac OS and Linux
platforms. For information about these methods, see the Acrobat and PDF Library API Reference.
The following table lists some common verbs that are used in method names and describes their meaning.
Verb Description
Acquire Obtains a shareable resource from a parent object or increments a reference counter
for an object. The shared object is not destroyed until all acquires have released it.
Example: AVMenuItemAcquire
Add Adds an object as a child to the current object.
Example: PDBookmarkAddChild
AddNew Creates a new object using the specified parameters and adds the new object to the
current object.
Example: PDBookmarkAddNewChild
Close Destroys an object that was opened and closes the underlying storage or stream.
Example: ASFileClose
Create Creates a new object of a given type.
Example: PDDocCreatePage.
Delete Removes the second object from the current object and destroys the second object.
Example: PDDocDeletePages
Destroy Destroys the specified object and releases its resources immediately.
Example: PDBookmarkDestroy
Enum Enumerates the specified descendant objects of the current object.
Example: PDDocEnumFonts
Get Retrieves a specific object attribute.
Example: AVWindowGetTitle
Is Retrieves a Boolean attribute of the object.
Example: PDBookmarkIsOpen
New Creates a new unattached object.
Example: AVMenuNew
Open Opens an object from storage or a stream.
Example: AVDocOpenFromFile
Release Releases a shared object.
Example: PDPageRelease
Adobe Acrobat SDK Introduction
Developing Plug-ins and Applications Data types 21
Verb Description
Remove Removes the second object from the current object but does not destroy it.
Example: AVMenuRemove
Set Sets an attribute of the object.
Example: PDAnnotSetFlags
Note: Cos methods uses the verb Put.
While many API method names follow the syntax specified in this section, there are exceptions. For
example, conversion methods conform to the following syntax:
<layer><object><source_object>to<dest_object>
An example is the AVPageViewPointToDevice method. For information about this method, see the
Acrobat and PDF Library API Reference.
Get and Set methods are used for getting and setting object attributes. Each object type has zero or more
attributes. For example, an annotation object (PDAnnot) contains attributes such as color and date. You
can obtain and modify attribute values by using methods such as PDAnnotGetColor and
PDAnnotSetDate.
In some cases, the return value of a Get method is another object. For example, the AVDocGetAVWindow
method returns an AVWindow object corresponding to the specified AVDoc object.
Other methods that return objects have the word Acquire in their name. These methods are always paired
with a corresponding Release method, and have the additional side effect of incrementing or
decrementing a reference count. The Acrobat core API uses Acquire and Release methods to perform
various tasks such as determining whether it is safe to free a memory structure representing an object.
Failure to match Acquire and Release method pairs can result in Acrobat complaining that a document
cannot be closed due to non-zero reference counts. For more information, see “Acquiring and releasing
objects” on page 35.
Data types
The Acrobat core API consists of the following data types:
● Scalar
● Simple
● Complex
● Opaque
● Cos
Scalar types
Scalar (non-pointer) types are based on underlying C language types, but have platform-independent bit
sizes. They are defined in the header file CoreExpT.h. All scalar types are AS layer types. For portability,
enumerated types are defined using a type of known size such as ASEnum16. For information, see
“Acrobat Support layer” on page 18.
Adobe Acrobat SDK Introduction
Developing Plug-ins and Applications Data types 22
Simple types
Simple types represent abstractions such as a rectangle or matrix. These objects have fields that do not
change. The following are examples of simple data types:
● ASFixedRect
● ASFixedMatrix
● AVRect32
Complex types
Complex types are structures that contain one or more fields. They are used in the following situations:
● To transfer a large number of parameters to or from a method. For example, the PDFontGetMetrics
method returns font metrics by filling out a complex structure (PDFontMetrics).
● To define a data handler or server. For example, your plug-in must provide a complex structure
populated with callback methods (AVAnnotHandlerRec) when it registers an annotation handler.
Opaque types
Many methods hide the concrete C-language representation of data structures. Most methods accept an
object and then perform an action on the object. Examples of opaque objects are PDDoc and
AVPageView objects.
Adobe Acrobat SDK Introduction
Developing Plug-ins and Applications About PDF Library and plug-in applications 23
Cos types
A Cos object refers to its corresponding Cos object in the PDF document. Cos objects are represented as
opaque 8-byte structures. They have subtypes of boolean, integer, real, name, string, array, dict, and
stream. For information, see “Working with Cos Objects” on page 178.
The following diagram shows the relationship between the PDF Library API and the Acrobat core API.
Public API
For information about creating an Acrobat core API or project or PDF Library API, see “Creating Plug-in and
PDF Library Applications” on page 39.
Note: The remaining parts of this section describe tasks that you can perform by using either the Acrobat
core API or the PDF Library API and refer you to the corresponding sections located in this guide.
Indexed searching
Indexed searching enables you to catalog, index, search, and highlight text in PDF files. Simple sequential
text searching may be too time consuming for long documents, and completely inadequate for searching
a large collection of documents. For information, see “Working with Words” on page 131.
Text retrieval systems overcome this problem by building a search index containing information on the
location of all words in each document in the collection. A search system uses this index to determine
which documents—and word locations within those documents—satisfy a given query. The search
system then allows a user to browse the found documents, optionally displaying or highlighting the
matching items.
The following features can be enabled in a PDF document by LiveCycle Reader Extensions:
● Basic form fill-in
● Dynamic form fields (add and delete form fields)
● Dynamic form pages (spawn template pages)
Adobe Acrobat SDK Introduction
Developing Plug-ins and Applications New Acrobat core APIs 25
● Digital signatures
● 2D barcode decoding
● Comments can be added, deleted, modified, copied, imported, exported, uploaded, downloaded, and
summarized
You may want your Reader-enabled plug-in to access APIs that are available when the plug-in is running
with Acrobat but not when running with Adobe Reader. Use the ASGetConfiguration method to
check whether Acrobat or Adobe Reader is running, and invoke these APIs only if your plug-in is running
with Acrobat. Failure to do so exposes the user to a variety of error messages. You can display a message to
the user by invoking the AVAlertNote method. For information, see the Acrobat and PDF Library API
Reference.
If such a plug-in is loaded under Adobe Reader, it notify the user that it cannot function fully, then proceed
in one of several ways:
● Not load.
● Omit toolbar buttons and menu items that enable editing.
● Display disabled (grayed-out) toolbar buttons and menu items that enable editing.
Plug-ins that need to check whether or not they are running under Adobe Reader should do so as early in
initialization as possible. Plug-ins that create and manipulate custom annotations should allow their
annotations to be displayed (they cannot be created, deleted, or edited) when running under Adobe
Reader.
AFPDFieldGetDefaultTextAppearanceEx AFPDFieldSetDefaultTextAppearanceEx
AFRegisterFormUIFrameworkHandler AFUnregisterFormUIFrameworkHandler
ASFileSysGetStorageFreeSpace64 ASFileSysIsLocal
ASGetDefaultFileSysForPath ASGetDefaultUnicodeFileSys
ASGetErrorStringASText ASRegisterErrorStringASText
AVAppGetAnnotAppearancePadding AVDocSaveOptimized
AVGetOptimizerPresets AVGetOptimizerParamsForPreset
AVMenuItemIsScriptable AVSysTrackMouse
CosSetExternalFilePermissionProc PDAnnotGetTitleASText
Adobe Acrobat SDK Introduction
Developing Plug-ins and Applications New Acrobat core APIs 26
PDAnnotSetTitleASText PDBookmarkAddNewChildASText
PDBookmarkAddNewSiblingASText PDBookmarkAddSubtreeASText
PDBookmarkGetByTitleASText PDBookmarkGetTitleASText
PDBookmarkSetTitleASText PDDocGetCryptHandler
PDDocGetInfoASText PDDocSetInfoAsASText
PDEColorSpaceCreateInCosDoc PDEFontCreateFromSysFontAndEncoding
InCosDoc
PDEFontCreateFromSysFontExInCosDoc PDEFontCreateFromSysFontInCosDoc
PDEFontCreateInCosDoc PDEFontCreateWithParamsInCosDoc
PDEFormGetBBox PDEFormGetMatrix
PDEImageCreateInCosDoc PDEScratchDocCleanup
PDFileSpecAcquireASPathEx PDFileSpecGetDIPathEx
PDFileSpecNewFromASPathEx PDFLibraryRegisterRNG
PDOCRegisterFindOutAutoStatePrefProc PDOCRegisterFindOutLanguageProc
PDOCRegisterFindOutUserProc PDOCRegisterFindOutZoomProc
PDPageHasOverprintExt PDPageLabelGetPrefixASText
PDPageLabelNewASText PDSElementExportUserProperties
PDSElementGetActualTextASText PDSElementGetAltASText
PDSElementGetTitleASText PDSElementSetActualTextASText
PDSElementSetAltASText PDSElementSetTitleASText
PDSysFontVerifyEncoding PDTextAnnotGetContentsASText
PDTextAnnotSetContentsASText PDThreadGetInfoASText
PDThreadSetInfoASText PDThumbGetImageData
PDThumbGetIndexedColorSpace PDXlateToASText
PDXlateToHostASText PSDataBufferReset
Note: For information about these APIs, see the Acrobat and PDF Library API Reference.
2 Understanding Plug-ins
This chapter provides an overview of how plug-ins are loaded, initialized, and unloaded as well as other
concepts related to plug-ins and PDF Library applications. It is recommended that you read this chapter
before you begin to develop plug-ins or PDF Library applications.
Using callback functions Describes callback functions and how they are used page 30
within the Acrobat SDK.
Handling events Describes event handling and the different event types, page 31
such as mouse clicks.
Using plug-in prefixes Describes how to use plug-in prefixes when creating page 31
plug-ins.
Modifying the Acrobat or Describes specific guidelines to keep in mind when page 33
Adobe Reader user interface modifying the Adobe Reader or Acrobat user interface.
Acquiring and releasing Describes how to work with memory allocation when page 35
objects creating plug-ins.
Page view layers Describes page views and how to work when them. page 36
Minimizing screen redrawing Describes how to avoid unnecessary screen redraws. page 36
Storing private data in PDF Describes working with private data in PDF files. page 37
files
Extracting data from PDF Describes exporting data from PDF document objects to page 37
document objects XML files.
27
Adobe Acrobat SDK Understanding Plug-ins
Developing Plug-ins and Applications Plug-in loading and initialization 28
Acrobat and Adobe Reader display a progress message in the bottom line of the splash screen at start-up.
As each plug-in is loaded, the progress message shows the plug-in name. No plug-ins are loaded if the
Shift key is held down while Acrobat or Adobe Reader launch. Also, if Acrobat or Adobe Reader are running
in certified mode, no third-party plug-ins are loaded.
1. Do not create a dialog box in your plug-in’s initialization or do anything else that might interfere with
the successful launching of Acrobat or Adobe Reader. The application may be started via an
interapplication communication (IAC) event in which case there would not be a user present to
respond to your dialog box.
2. Implement a PluginUnload procedure to free allocated memory. This routine is invoked if any of the
initialization routines returns false. Under normal conditions, this procedure is not invoked until the
user closes Acrobat or Adobe Reader.
During handshaking, the plug-in receives the hsData data structure (defined in the PIVersn.h file).
Acrobat and Adobe Reader convert all function pointers that are passed in this data structure into
callbacks using the ASCallbackCreateProto method. For information about this method, see the
Acrobat and PDF Library API Reference.
The DUCallbacks.h header file declares all callback methods that must be located in your plug-in. The
following shows the function signatures of these callback methods:
ACCB1 ASBool ACCB2 PluginExportHFTs(void);
ACCB1 ASBool ACCB2 PluginImportReplaceAndRegister(void);
ACCB1 ASBool ACCB2 PluginInit(void);
ACCB1 ASBool ACCB2 PluginUnload(void);
All callbacks return true if your plug-in’s procedure completes successfully or if the callbacks are optional
and are not implemented. If your plug-in’s procedure fails, false is returned. If either Acrobat, Adobe
Reader, or a plug-in aborts handshaking, then Acrobat or Adobe Reader displays an alert dialog box
showing a brief explanation before loading other plug-ins. At minimum, a plug-in must implement the
PluginInit callback.
Note: The handshaking function is located in the PIMain.c file. This source code located in this file is
functional and must not be modified.
Adobe Acrobat SDK Understanding Plug-ins
Developing Plug-ins and Applications Exporting HFTs 29
Exporting HFTs
A Host Function Table (HFT) is the mechanism through which plug-ins invoke methods in Adobe Reader or
Acrobat, as well as in other plug-ins. After Acrobat finishes handshaking with all the plug-ins, it invokes
each plug-in’s PluginExportHFTs callback procedure.
In the PluginExportHFTs procedure, a plug-in may export any HFTs it intends to make available to
other plug-ins. This callback should only export an HFT, not invoke other Acrobat core API methods. For
information, see “Working with Host Function Tables” on page 164.
Note: This is the only time that a plug-in can export an HFT.
2. Register for notifications by using the AVAppRegisterNotification method. Plug-ins also may
register and unregister for notifications while the plug-in is running. A plug-in may receive a
notification any time after it has registered for it, even if the plug-in's initialization callback has not yet
been called. This can occur if another plug-in initializes first and performs an operation, such as
creating a PDF document, which causes a notification to be sent. Plug-ins must be prepared to
correctly handle notifications as soon as they register for them.
3. Replace any of the Acrobat API’s replaceable HFT methods. For information, see “Replacing HFT
methods” on page 174.
Note: This is the only time a plug-in may import an HFT or replace a standard API method. Plug-ins may
register for notifications at this time or any time afterward.
Initialization
After Acrobat or Adobe Reader completes calling each plug-in’s PluginImportReplaceAndRegister
callback method, it invokes each plug-in’s PluginInit procedure. Plug-ins can use their initialization
procedures to hook into Acrobat’s user interface by adding menu items, toolbar buttons, windows, and so
on. It is also acceptable to modify Acrobat’s user interface later when the plug-in is running.
If your plug-in needs to carry out a task after all plug-ins have been initialized, it should register for the
AVAppDidInitialize notification. This notification is invoked when Acrobat has finished initializing
and is about to enter its event loop.
Unloading
A plug-in’s PluginUnload procedure should free any memory the plug-in allocated and remove any user
interface changes it made. Acrobat invokes this procedure when it terminates or when any of the other
handshaking callbacks return false. This function should perform the following tasks:
● Remove and release all menu items and other user interface elements, HFTs, and HFTServers.
● Release any memory or any other allocated resources.
Currently, plug-ins unload only when Acrobat exits.
Adobe Acrobat SDK Understanding Plug-ins
Developing Plug-ins and Applications Summarizing a plug-in’s life cycle 30
1. At startup, Adobe Reader or Acrobat searches its plug-in directory for plug-in files.
2. For each plug-in file, Adobe Reader or Acrobat attempts to load the file. If the plug-in is successfully
loaded, Adobe Reader or Acrobat invokes routines in PIMain.c which completes the handshaking
process.
This sequence establishes the linkages between the plug-in and Acrobat or Adobe Reader, and between
the plug-in and any other plug-ins. Once all plug-ins are loaded, Acrobat or Adobe Reader continues its
own loading and starts the user interface. It adds any plug-in provided tools to the toolbar and menu
items to the menu bar and starts the user session.
Type checking only occurs if the DEBUG macro is set to 1 at the time your plug-in is compiled. Be sure to set
it appropriately in your development environment and remove it when you build the shipping version of
your plug-in.
The following code example shows the syntax to create a callback function:
AVExecuteProc ExecProcPtr = NULL;
ExecProcPtr= ASCallbackCreateProto(AVExecuteProc, &ShowMessage);
The ASCallbackCreateProto macro returns a callback of the specified type that invokes the
user-defined function whose address is passed as the second argument. In this example, the
ShowMessage function is converted to a callback function (the ShowMessage function is a user-defined
function that is invoked when a specific action occurs).
The ASCallbackCreateProto macro returns a pointer to a function that can be invoked by a plug-in or
by Acrobat or Adobe Reader. Use the ASCallbackDestroy method to dispose of a callback that is no
longer required.
All callbacks must be declared with Pascal calling conventions. To make your code portable between
platforms, declare all your callback functions using the ACCB1 and ACCB2 macros:
static ACCB1 const char* ACCB2 ShowMessage(Thing* foo);
Adobe Acrobat SDK Understanding Plug-ins
Developing Plug-ins and Applications Notifications 31
Notifications
The Acrobat core API provides a notification mechanism so that plug-ins can synchronize their actions
with Acrobat or Adobe Reader. Notifications enable a plug-in to indicate that it has an interest in a
specified event (such as an annotation being modified) and provide a procedure that Acrobat invokes
each time that event occurs. For information, see “Registering for Event Notifications” on page 151.
Handling events
You can use the Acrobat core API to handle various types of events.
Mouse clicks
Mouse clicks are passed to any procedure registered using the AVAppRegisterForPageViewClicks
method. If all of those procedures return false, the click is passed to the active tool. If that returns false,
the click is passed to any annotation at the current location.
You can query the state of the mouse buttons in a manner appropriate for a click-drag operations by
invoking the AVSysTrackMouse method. For information, see the Acrobat and PDF Library API Reference.
Adjust cursor
Adjust cursor events are passed to any procedures registered using the
AVAppRegisterForPageViewAdjustCursor method. If all of those procedures return false, the
event is passed to the active tool. If that returns false, the event is passed to any annotation at the
current location.
Key presses
Key presses are first passed to the currently active selection server. If the selection server's
AVDocSelectionKeyDownProc callback returns false, Acrobat or Adobe Reader handles special keys
(Esc, Page Up, Page Down) or uses the key to select a tool from the toolbar.
Prevent spaces from being used in tokens you intend to use as names in a PDF file. This can happen, for
example, if you allow a user to type a name into the PDF file and your plug-in does not check the input
before writing it to the file.
Note: Registering a prefix with Acrobat Developer Support ensures that no other developer is assigned
the same prefix. It is up to you to ensure that names are unique among all plug-ins you or your
company write (for example, you must ensure that two of your plug-ins do not both use ADBE_save
as a menu item name).
Plug-in name
ExtensionName, used in plug-in handshaking, must use the following syntax: Prefix_PluginName.
hsData->extensionName = ASAtomFromString("ADBE_SuperCrop");
Menu prefixes
Menu names must use the following syntax: Prefix:MenuName.
SuperCropMenu = AVMenuNew(SuperCrop, "ADBE:SuperCropMenu", gExtensionID);
For information about invoking the AVMenuNew method, see “Adding menu commands to menus” on
page 90.
Tool prefixes
Tools names must use the following syntax: Prefix:Tool.
static ACCB1 ASAtom ACCB2 SuperCropToolGetType(AVTool tool)
{
return ASAtomFromString("ADBE:SuperCropTool");
}
For information about creating a toolbar button, see “Creating toolbar buttons” on page 100.
Adobe Acrobat SDK Understanding Plug-ins
Developing Plug-ins and Applications Modifying the Acrobat or Adobe Reader user interface 33
In the following example, the keys named First and Second cannot be referenced from any object in
the PDF file except the private key that uses an appropriate prefix, so there is no need to use a prefix for the
latter two keys.
/Prefix_PrivDataName << /First 2 /Second << /Third [ 2 3 ] >> >>
Please contact Acrobat Developer Support if you add private data to your plug-in that you believe is useful
to other plug-ins. Developer Support would like to know what types of private data plug-ins save in PDF
files so that similar data can be standardized with the same name and data format. In this way, developers
of different plug-ins using similar data can be assured that their plug-ins can exchange data. For more
information regarding private data in PDF files, see the PDF Reference.
Note: For information about Cos dictionaries, such as the one shown in the previous example, see
“Working with Cos dictionaries” on page 186.
Action prefixes
Actions must use the following syntax: Prefix_ActionName.
AVAppRegisterActionHandler(&BkmkHandler, NULL, "ADBE_HWAction", "HWAct");
Annotation prefixes
Annotation prefixes must use the following syntax: Prefix_AnnotType.
return(ASAtomFromString(“ADBE_MarkUpAnnot”);
HFT prefixes
When your plug-in exposes any HFTs of its own, it must use an HFT name that conforms to the following
syntax: Prefix_HFTName.
gDebuggWinHFTServer =
HFTServerNew("ADBE_DebugWin",provideDebugWinHFTCallback, NULL, NULL);
For information about HFTs, see “Working with Host Function Tables” on page 164.
Menu commands can have shortcuts (keyboard accelerators). Acrobat and Adobe Reader do not ensure
that plug-ins add unique shortcuts, but it is possible to programmatically check which shortcuts are
already in use before adding one.
You are encouraged to have your plug-in add its menu commands to the Tools menu. When it is launched,
Acrobat or Adobe Reader automatically add this menu, as well as the About Plug-ins and Plug-in Help
menus. After Acrobat or Adobe Reader loads all plug-ins, it checks these three menus and removes any
that are empty. For information, see “Creating Menus and Menu Commands” on page 88.
Modifying toolbars
You can add new buttons to the toolbar, although the size and resolution of the user’s monitor can limit
the number of tool buttons that are displayed. You can also remove buttons from an existing toolbar. For
information, see “Creating Toolbars and Buttons” on page 97.
About Adobe Plug-ins is a standard menu command in the Help menu. This menu command contains a
submenu. You are encouraged to have your plug-in add a menu command to the submenu to bring up its
own About box.
If you use an Acquire method to obtain an object, you must subsequently use a Release method to
correctly update the reference counter, as shown in the following example:
PDDoc doc;
PDPage page;
Notice that the PDPage object is acquired by invoking the PDDocAcquirePage method and is released
by invoking the PDPageRelease method. For information about working with pages, see “Working with
Page Views and Contents” on page 122.
Debugging plug-ins
When debugging your plug-in, consider the following points:
● Include the #define DEBUG 1 statement to ensure that parameter type checking is performed by
macros such as ASCallbackCreateProto and to enable the debug exception-handling macros.
● The AVSysBeep method provides a simple way to add an audible indication that a certain point has
been reached in a plug-in’s code. Likewise, the AVAlertNote method displays a message box that
indicates whether a certain point of code is reached.
● Creating a log file is very helpful when tracing large sections of code or checking values of a number of
variables. Use C library calls such as printf or platform-specific code to create a log file containing
whatever information is useful for the particular situation.
Adobe Acrobat SDK Understanding Plug-ins
Developing Plug-ins and Applications Page view layers 36
The following table shows the predefined layers used by Acrobat and Adobe Reader.
Layer Item
0 Page contents
LINK_LAYER (1) Links
NOTE_LAYER (3) Closed notes. Open notes are just above this.
Annotation handlers provided by plug-ins can reside in any layer. For example, a plug-in could choose for
its annotations to be between the page contents and links, such as in layer 0.5 (because layers are numbers
of type ASFixed).
Note: Acrobat and Adobe Reader do not invoke AVAnnotHandlerGetLayerProc callbacks for changes
in value, so be sure to invalidate the page rectangle of an annotation when its layer changes.
Node Name
nodeTag xyz_Node
nodeNameTag xyz_NodeName
propTag xyz_Property
propNameTag xyz_PropertyName
propValTag xyz_Value
After you export the data from this object into an XML file, the data would appear as shown in the
following diagram.
Adobe Acrobat SDK Understanding Plug-ins
Developing Plug-ins and Applications Exporting data from PDF document objects 38
To retrieve data from a PDF document object, invoke the PDDocExportUserProperties method and
pass the following arguments:
● A PDDoc object that represents a PDF document that contains the object from which data is extracted.
For information, see “Creating a PDDoc object” on page 83.
● A PDSElement instance that represents PDF structural elements.
● An ASStm object that represents XML content converted from information from labels.
● An ASBool value that specifies whether to save object data of the specified element (false) or the
whole subtree (true).
● An ASBool value that specifies whether to include hidden content of the element.
● An instance of the PDUserPropertiesXMLLabels data structure that specifies information for
converting object data to XML. For information about this data structure, see the Acrobat and PDF
Library API Reference.
3 Creating Plug-in and PDF Library Applications
This chapter discusses how to use the Acrobat SDK and the PDFL SDK to create plug-in applications as well
as standalone applications that interact with PDF documents. To develop a plug-in for the Windows
platform, you can use Microsoft Visual Studio 2003 or Microsoft Visual Studio 2005. To develop a plug-in
for the Mac OS platform, you can use the Xcode 2.2 or 2.3 development environment.
Supported environments Describes supported environments for plug-in and PDF page 39
Library application development.
Working with platform-specific Describes platform-specific techniques that you should be page 40
techniques familiar with before creating a plug-in or PDF Library
application.
Creating a sample plug-in Describes the process of creating a sample plug-in. page 47
Creating a sample PDF Library Describes the process of creating an application using the page 54
application PDF Library.
Upgrading existing plug-ins Describes how to upgrade an existing plug-in application. page 59
Supported environments
The following table specifies the supported platforms, operating systems, and compilers for Acrobat SDK
and PDFL SDK development.
Note: While it may be possible to use the Acrobat SDK and the PDFL SDK in other development
environments, such use is not supported. The project files for the sample applications are created
and supported only in the listed compiler versions.
39
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Working with platform-specific techniques 40
This chapter contains platform-specific development information for the Windows and Mac OS platforms
and provides guidelines that can help make plug-ins more portable among the various supported
platforms.
The following are platform-specific data types that do not appear explicitly in the API, but are used by
Acrobat, Adobe Reader or plug-ins:
Cursors: Data structures representing a cursor.
Toolbar button icons: Pixmaps that appear in the Acrobat or Adobe Reader toolbar.
Menu item icons: Icons that some platforms allow you to display adjacent to a menu item.
Menu items: Keep in mind that not all Acrobat or Adobe Reader implementations have the same menu
items. For example, on the UNIX platform Acrobat and Adobe Reader do not have a Window/Tile menu
item.
Portability techniques
The following techniques can improve your plug-in’s portability:
● Use predefined types instead of short and long.
● Use Acrobat API methods wherever possible instead of platform-specific APIs.
● Use #if around platform-specific code such as dialog boxes and use the predefined platform
constants (MAC_PLATFORM, UNIX_PLATFORM, WIN_PLATFORM, and so forth) to test what platform
you are compiling for.
● Place platform-specific code in separate files from the main portion of the plug-in, so that you can
easily recognize and rewrite platform-dependent sections.
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Windows techniques 41
Windows techniques
This section contains information necessary to implement plug-ins under Windows.
You are encouraged to use the plug-in samples BasicUI and Starter as a basis for developing plug-ins.
These samples have all of the appropriate project settings. The Starter sample only builds a loadable
plug-in while the BasicUI sample adds menu items.
LoadLibrary calls the DLLMain entry point of the plug-in with the parameter DLL_PROCESS_ATTACH
passed. It’s possible for a developer to run some initialization code in DLLMain (such as allocating memory)
before its PluginMain procedure is called by Acrobat or Adobe Reader. If you do this, it’s important to
deallocate the memory when DLLMain is called with DLL_PROCESS_DETACH.
If you rely on PluginUnload for deallocation of memory, it could fail if Acrobat or Adobe Reader unloads
the plug-in immediately without calling the plug-in’s handshaking callbacks. This would happen in the
following situations:
● If the plug-in is not Adobe-certified and the user has specified the Certified Plug-ins Only option in the
Preferences settings.
● If the plug-in is running under Adobe Reader, but it is not enabled for Adobe Reader. This could
potentially cause a crash when Acrobat or Adobe Reader quits.
For a plug-in to be loaded, it must export the symbol PlugInMain. This task can be accomplished by
including a .def file in the project for the plug-in or by including the line /EXPORT:PlugInMain in the
project settings for the plug-in. If you are developing an Adobe Reader plug-in, you also must define a
macro to access HFTs available to Adobe Reader. For information, see “Creating an Adobe Reader Plug-In”
on page 245.
Interapplication communication
Plug-ins can add their own DDE messages to those supported by Acrobat or Adobe Reader, by registering
to receive DDE messages directly. The DDEClnt sample in the Acrobat SDK shows how to do this.
It is not possible for a plug-in to implement OLE automation or be an ActiveX server through the use of
MFC. This is because Acrobat or Adobe Reader uses MFC to implement its OLE automation and there
cannot be two MFC-based OLE automation servers in the same process. OLE or ActiveX server plug-ins
must be implemented using the ActiveX Template Library. Plug-ins should use the DDEML library to
handle DDE messages. Problems may arise if they do not.
Debugging
Generally, the debugger built into Visual C++ is adequate to debug plug-ins. Debugging a Windows
plug-in compiled with Visual C++ is quite simple if you remember a few things:
● Specify the Acrobat plug-ins directory under the link | output tab in the Project settings dialog box.
● Specify the Acrobat or Adobe Reader executable under the executable for debug session in the Project
settings dialog box.
● The first time you build a plug-in, do a Rebuild All.
● Set breakpoints in your source code by selecting the line and clicking the hand icon or pressing the F9
key.
● After setting breakpoints, press the F5 key to have Microsoft Visual Studio launch Acrobat or Adobe
Reader.
The following information can help maximize the ability of Acrobat and Adobe Reader to load plug-ins.
When a process is created, an array of bit flags is allocated for the management of thread-specific data. In
the current Win32 implementation, this array is limited to 64 members or TLS slots. Every DLL/plug-in that
uses thread local storage is allocated at least one slot when loaded using LoadLibrary. This includes system
DLLs, plug-ins, and all the DLLs they load. When all of the TLS slots have been occupied for a process,
LoadLibrary will fail for any DLL requiring a TLS slot.
The following guidelines will minimize the TLS slots occupied by plug-ins:
● Plug-ins that are not multi-threaded should only link with the single-threaded runtime libraries that do
not occupy a TLS slot.
● If your plug-in is multi-threaded, you should consider linking it with the multi-threaded DLL runtime
library. Both the DLL and static versions of the runtime libraries occupy a TLS slot. However, many
plug-ins shipped with Acrobat or Adobe Reader use the DLL version so the runtime DLL will not occupy
another TLS slot after it has been loaded by the process.
Note: Acrobat and Adobe Reader do not currently raise an error when a plug-in fails to load due to the TLS
limit.
1. When you are creating your dialog box, get the parent HWND of the dialog box using the
WinAppGetModalParent method. Then use this HWND when creating the dialog box.
Make sure to get the mouse capture before putting up your dialog box so that Acrobat or Adobe
Reader does not receive the mouse clicks. After your dialog box returns, set the mouse capture back.
HWND CapturehWnd, hParent;
CapturehWnd = GetCapture();
if ( CapturehWnd != NULL )
ReleaseCapture();
hParent = WinAppGetModalParent(AVAppGetActiveDoc());
nRetVal = DialogBox(gHINSTANCE, MAKEINTRESOURCE(IDD_PROPS), hParent,
PropsDialogProc);
if ( CapturehWnd != NULL )
SetCapture( CapturehWnd );
2. As soon as you have an HWND for the dialog box itself, usually in response to the WM_INITDIALOG
message, you should acquire a new AVWindow using the AVWindowNewFromPlatformThing
method. Save this AVWindow in some place where you can access it when the dialog box is destroyed.
Then pass the AVWindow to the AVAppBeginModal method.
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Mac OS techniques 44
3. At the time the dialog box is destroyed, usually in response to a WM_DESTROY message, end the modal
operations using AVAppEndModal. If you are not using MFC, destroy the AVWindow for which you
saved the handle with AVWindowDestroy. Here is a section of code called in response to a
WM_DESTROY message:
AVAppEndModal();
AVWindowDestroy(sAVWin);
If you are using MFC to put up your dialog box, do not call AVWindowDestroy in the WM_DESTROY
message (MFC will cause Acrobat or Adobe Reader to destroy the AVWindow automatically).
Mac OS techniques
This section contains information necessary to implement plug-ins for Mac OS X. If you are upgrading your
plug-in, see “Upgrading plug-ins on Mac OS” on page 61.
Note: Acrobat SDK samples are built against the MacOSX10.4u.sdk as universal binaries.
The Info.plist file contains a list of properties used by the package. Adobe provides a common info.plist file.
It uses project settings to define properties appropriately for each plug-in.
Note: To prevent problems with older style event handling, plug-ins need to replace calls to
WaitNextEvent with calls to RunCurrentEventQueue or ReceiveNextEvent.
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Mac OS techniques 45
The configuration files and settings have a hierarchical structure modeled after Apple Developer
documentation located at the following URL:
http://developer.apple.com/documentation/DeveloperTools/Conceptual/XcodeUserGuide/Contents/
Resources/en.lproj/05_05_build_configs/chapter_33_section_6.html
Each project is based on a project-level build settings file(s) that includes SDK-level settings.
At the SDK level, there are separate configuration files for SDK plug-in settings (Default.xcconfig),
environmental variables (Environment.xcconfig) and resource settings (Resources.xcconfig). Global target
settings for _debug and _release targets are stored in Debug.xcconfig and Release.xcconfig, respectively.
Each project level configuration file includes the settings from its related (parent) SDK configuration file
(for example, ProjectDefault.xconfig includes Default.xcconfig and ProjectResources.xcconfig includes
Resources.xcconfig). Generally, SDK-level setting definitions are not included directly, but rather are
included through project-level configuration files.
Each SDK plug-in project includes a single (Default) configuration based on the ProjectDefault.xcconfig
build settings which include the SDK-level Default.xcconfig build settings. Each project has two targets: a
_debug target and a _release target. The targets’ build settings are based on Project_debug.xcconfig and
Project_release.xconfig, respectively. Similar to the project configuration files, each target configuration
settings include its parent SDK configuration file; for instance, Project_debug includes Debug.xcconfig
settings.
Project-level configuration files whose names begins with Project are the default project settings included
with most SDK plug-in samples. Project-level configuration files that are prefixed with a specific sample’s
name include settings specific to that sample. The build settings for most SDK projects are extremely
similar with most definitions residing in the SDK configuration files.
In all cases, you should pass GetMainDevice unless you have a particular device in mind or you are
restoring the GWorld to its original state. The following code is an example.
ACCB void ACCB2 foo(AVPageView pageView)
{
CGrafPtr oldGWorld, pagePort = NULL;
GDHandle oldDevice;
pagePort = (CGrafPtr)AVPageViewAcquireMachinePort(pageView);
if (pagePort){
GetGWorld(&oldGWorld, &oldDevice);
SetGWorld(pagePort, GetMainDevice());
//Draw to the port here
SetGWorld(oldGWorld, oldDevice);
AVPageViewReleaseMachinePort(pageView, pagePort);
}
}
Using memory
The Acrobat or Adobe Reader memory allocator gets its memory from the system and not from the
application's memory partition. For information, see “Acquiring and releasing objects” on page 35.
Memory allocation guidelines are particularly important in Mac OS to insure that memory is allocated from
the system rather than from the application partition. Otherwise your plug-in is very likely to cause
Acrobat or Adobe Reader to run out of memory.
Using SafeResources
The recommended way to access resources in the plug-in file is to use the functions declared in the header
file SafeResources.h in the SDK. These functions are direct replacements for each Toolbox function that
directly or indirectly calls GetResource. The replacement functions automatically place the plug-in file
on top of the resource chain before accessing the resource, and restore the old resource chain after
accessing the resource.
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Creating a sample plug-in 47
The global variable gResFile is automatically set up during handshaking and is declared in PICommon.h.
Macros
The following macros must be defined:
● POWER_PC must be defined
● PLATFORM must be defined as MacPlatform.h
● PRODUCT must be defined as Plugin.h
These macros are automatically defined correctly for the platform and development environment by the
header file PIPrefix.h. You are encouraged to use this header file.
Interapplication communication
Plug-ins can add their own Apple events to those supported by Acrobat or Adobe Reader, by hooking into
Acrobat or Adobe Reader’s Apple event handling loop. This is done by replacing the
AVAppHandleAppleEvent method in the API. If the plug-in receives an Apple event it does not want to
handle, it should invoke the implementation of the method it replaced, allowing other plug-ins or Acrobat
or Adobe Reader the opportunity to handle the Apple event.
However, to improve your understanding of creating plug-ins, the remaining parts of this section discuss
what tasks you must perform when creating a plug-in from a blank project. When using the Starter sample
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Including Acrobat SDK library files 48
plug-in, it is not necessary to perform some of the tasks discussed in this section. For example, you do not
need to start a new project, include header files, or add the PIMain source file. However, you still have to
add application logic, compile, and build your project.
➤ To create a plug-in:
1. Start a new C project.
The Acrobat SDK library files are separated into the following categories:
SDK: Header files that are common to most plug-ins and that are generally referenced from PIMain.c.
API: Mostly API header files specific to core and extended APIs.
After you add this file, you can add application logic to your project.
Note: As a plug-in developer, you will never have to create the application logic that is located in the
PIMain.c file or modify this file. However, you must include this file in your project.
You can copy the source code that is located in the StartInit.cpp file (located in the Starter plug-in) and
paste it. For information about these methods, see “About plug-in initialization” on page 27.
The entry point to a plug-in is the PluginInit method. For example, if you add the following line of code
to this method, an alert box is displayed when Adobe Reader or Acrobat is started.
AVAlertNote("This is your first plug-in");
You can add an application to the PluginInit method to meet your business requirements. You can
invoke other user-defined functions that you create or you can add application logic to this method that
performs a specific task. For example, you can add application logic to this method that adds a new menu
item to Adobe Reader or Acrobat. For information, see “Creating Menus and Menu Commands” on
page 88.
After you add the plug-in to this directory, you must restart Adobe Reader or Acrobat in order for the
plug-in to take affect.
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Creating a sample PDF Library application 54
This section helps you get started with development using the Adobe PDF Library Software Developers Kit
(SDK). It describes the contents of each directory in the PDF Library SDK installation, lists available code
samples, and provides platform-specific information on how to set up the development environment.
Note: For a detailed discussion about using the PDF Library API, see “Inserting Text into PDF Documents”
on page 62.
Sample code
Samples are provided for the Windows, Mac OS, and UNIX, platforms in two forms:
● Standalone sample programs
● The SnippetRunner, an environment and infrastructure for code snippets that illustrate specific
functions or techniques.
Sample code is intended to demonstrate the use of the PDF Library API and is not necessarily robust
enough for a final implementation. The sample code itself is platform-independent, as is the majority of
the PDF Library API; the only difference between the sample source code for different platforms is the
line-endings.
The Mac OS samples are provided as application packages. This format is normal for double-clickable
applications, but they can also be run from the command line. To run them from the command line, you
can either specify the command line arguments in the Xcode project file and execute within the IDE, or
you can target the actual executable, which is in the Contents/MacOS folder inside the package. For
example, from the Terminal window:
$ cd helowrld.app/Contents/MacOS/
$ helowrld
The MT (multithreading) samples require command line arguments (a default set is added to the project
files). Therefore, execution from within the IDE is preferred. Also, for those samples you must use absolute
paths for the command line arguments.
Standalone samples
The following table lists the standalone sample applications that accompany the PDF Library SDK.
SnippetRunner application
SnippetRunner allows you to quickly prototype code containing PDF Library API calls without the
overhead of writing and verifying a complete application. It provides an infrastructure and utility functions
to support execution and testing of code snippets, which are small but complete portions of PDF Library
application code.
For more information about SnippetRunner, see the Snippet Runner Cookbook.
This macro is used as a trigger for conditional compilation and allows the same headers to be used for
both the Acrobat core API and the Adobe PDF Library.
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Developing applications with the Adobe PDF Library 57
Windows
The following macros must also be defined in the IDE project settings for applications to compile correctly
on the Windows platform:
● WIN_ENV
● WIN32
● WIN_PLATFORM
The Adobe PDF Library is compiled with code generation set to Multithreaded. Applications linking with
the Adobe PDF Library must have code generation settings that match or there will be conflicts between
the Microsoft libraries MSVCRT and LIBCMT.
In Visual Studio, the Ignore Libraries settings (click Project Settings > Link > Input > Ignore libraries) should
not ignore LIBCMT (other versions of PDF Library do ignore it).
The Adobe PDF Library is distributed as an interface library (AdobePDFL.lib) and matching DLL
(AdobePDFL.dll). You should link the interface library into your application.
The operating system must be able to access the Adobe PDF Library at runtime. It does so by searching the
paths specified by the PATH environment variable, as well as the folder in which the application was
launched.
Mac OS
The Mac OS libraries use a precompiled header and prefix file to define the appropriate macros. See
Precompile.pch in the Samples:utils directory of the Adobe PDF Library SDK for the macros required to
successfully compile the samples.
UNIX
The following macros must be defined for the headers to compile correctly on the UNIX platform:
UNIX_ENV=1
UNIX_PLATFORM=1
Before you can compile the samples, you must point the makefiles to your gcc 3.2 or VisualAge XL 6.0
compiler. Make sure the permissions on all libraries are set so that the dynamic loader can find and load
the libraries.
chmod o+x libraryname
Shared objects are provided for AIX, Solaris and Linux. Alter the common makefile for each individual
platform/os (i.e., linux.mak) under the samples/utils directory to specify the gcc or g++ and static library
access path.
You will need to set the environment variable LD_LIBRARY_PATH to the location of the libraries so that
the application will find the shared object libraries at run time. This can be accomplished with the
command
setenv LD_LIBRARY_PATH path
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Initialization and termination 58
Before you run your application, set the PSRESOURCEPATH and ACRO_RES_PATH environment variables
to point to your fonts. For example, to set these environment variables manually before you run your
application:
setenv PSRESOURCEPATH /user/yourname/PSFont
setenv ACRO_RES_PATH /user/yourname/PSFont
Alternatively, you can define the environment variables within the application using the putenv system call.
Since the PDF Library supports thread-safety (since version 6.1.2), initialization and termination are
handled on a per-thread basis.
The PDFLInit function takes as a parameter a PDFLData structure, defined in the API header file
PDFInit.h. You must provide valid values for the following members of the structure before passing it to
PDFLInit:
● size denotes the size of the structure and can be obtained with sizeof(PDFLDataRec).
● listLen is the number of directories listed in dirList.
● dirList is an array of directories that contain font resources. The following discussion explains how to
use this member on each of the supported platforms.
In Windows and Mac OS, the PDF Library searches for fonts in the default system and in their
subdirectories (to 99 levels). You can specify additional font directories to search (also to 99 levels) in the
dirList array. (Note that this can affect performance.)
Here is an example showing how to pass the font paths to dirList for Windows:
pdflLibData.dirList[0]= strdup("C:\\Myfontfolder\\CMap");
pdflLibData.dirList[1]= strdup("C:\\Myfontfolder\\CIDFont");
pdflLibData.dirList[2]= strdup("C:\\Myfontfolder\\Font");
The paths can be either full paths or paths relative to the directory from which the executable linking in
the Adobe PDF Library was launched. You can set the value kPDFLInitIgnoreDefaultDirectories
in the flags field of the PDFLData structure to indicate that the default font directories should not be
searched but only the directories provided in dirList.
For more details, see the functions PDFLGetDirList_Win and PDFLGetDirList_Mac in the
MyPDFLibUtils.cpp file in the Samples/utils directory.
In UNIX, the PDF Library searches by default for fonts in the directory from which the application was
launched. Use dirList member to specify additional locations of font resources.
For more details, see the function PDFLGetDirList_Unx in the MyPDFLibUtils.cpp file in the
Samples/utils directory.
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Multithreading 59
Multithreading
When using the thread-safe PDF Library, initialization and termination now additionally need to be
performed for each thread that calls into the library, as well as at the process level. The interfaces for
per-thread initialization/termination are the same as before.
Since each thread acquires an independent PDF Library memory context, you should not share PDF
Library data and resources among threads. This includes sharing the same PDF file.
The Adobe PDF 8.0 libraries are thread-safe. To use threads, simply make the appropriate system call
(beginthreadex on Windows, and pthread_create on UNIX). Multiple threads cannot share PDF
Library data types. However, they share the same process heap; therefore, an application can share generic
data types between threads. Multiple threads can open the same file read-only; however, multiple threads
should not attempt to write to the same PDF document.
For Mac OS, plug-ins developed for earlier versions of Acrobat will not load in Acrobat 8. In Acrobat 7,
plug-ins could be built as frameworks or bundles. However, for Acrobat 8, all plug-ins must be built as
Carbon bundles against the Acrobat 8 SDK headers in order to be compatible with Mac OS X system
frameworks and libraries (rather than MSL), GCC 4.0, and Mach-O as supported by the Xcode development
environment. Therefore, for existing Mac OS plug-ins, a variety of code incompatibilities may exist.
Additionally, the Extended APIs provided by plug-ins will not work if an Acrobat product does not support the
use of those APIs. The HFTs will not load, so you need to check whether the HFT was successfully imported.
It is possible to determine in your code whether the HFT you are expecting is in fact the one that you are
importing, and whether it imported at all: simply check for a NULL return value. For example, a NULL will
be returned in the following call if AcroColorHFTNAME with the specified version is not available:
gAcroColorHFT = ASExtensionMgrGetHFT(ASAtomFromString(AcroColorHFTNAME),
PI_ACROCOLOR_VERSION);
Plug-ins that use new HFTs introduced with Acrobat 8.0 will not run on Acrobat versions prior to 8.0.
Whether or not an attempt to load these HFTs forces the plug-in to fail is controlled by flags in PIMain.c of
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Updates to ASCoord and AVRect 60
the form PI_HFT_OPTIONAL. By default these flags are undefined, so if your plug-in attempts to load
HFT and cannot, initialization will fail. If you define PI_HFT_OPTIONAL with some value (preferably 1) and
the load is not successful, initialization will continue.
Use the ASGetConfiguration method to determine the configuration on which the plug-in is running.
Use conditional logic in your code so that it makes calls only to APIs that are supported on that particular
configuration. In any case, your code should check for NULL HFTs so that it does not call APIs that are not
supported on the current configuration.
Under Adobe Reader, when a rights-enabled PDF file is opened, a flag is set that allows a plug-in to use APIs
that become enabled as a result of loading the rights-enabled PDF. Familiarize yourself with the features
available on the different configurations of Acrobat to ensure that you install plug-in menus and toolbars
appropriately at initialization. Ensure that you make calls only to APIs supported on the platform detected.
Though your existing plug-ins will continue to be backward-compatible, you should also change them
accordingly.
If you are currently using ASCoord for any coordinates other than those listed above, then you may be
using ASCoord inappropriately and it should be changed. You should also replace the AVRect datatype
with the more descriptive AVDevRect, AVWindowRect, and AVScreenRect datatypes.
Use Visual Studio .NET 2005 to automatically convert your project from previous versions of Visual Studio.
Once converted, you must also make the following changes to your plug-in’s project:
● Update the relative path of the header files.
● Files that are located in the header files folders and are source files of the project need to have their
paths updated. For each plug-in, you need to update the path for PIMain.c. To update these files, delete
the source file from your project and then add it from the correct path.
● Turn on the GS switch for each plug-in being upgraded. In Visual Studio 2005, click Project > Properties
> C/C++ > Code Generation and set the Buffer Security Check flag to Yes (/GS).
● Turn on incremental linking for each plug-in being upgraded. In Visual Studio 2005, click Project >
Properties > Linker > General, and set the Enable Incremental Linking flag to Yes.
Once you have upgraded your project to Visual Studio .NET 2005, recompile your plug-in using the
headers provided in the Acrobat 8 SDK. Be sure that the AcroSDKPIDir environment variable is set
correctly. Click My Computer > Control Panel > System > Advanced, set this environment variable to where
you want your compiled plug-ins to appear.
Adobe Acrobat SDK Creating Plug-in and PDF Library Applications
Developing Plug-ins and Applications Upgrading plug-ins on Mac OS 61
Specifically, Acrobat 8 SDK sample plug-ins have debug and release targets that are built against the
MacOSX10.4u.sdk SDK. These are universal binaries and use Z-strings. Acrobat is a Cocoa application whose
user interface uses NSViews, therefore, plug-ins must be built as Objective C++. Note that the linker main entry
point has changed from _main to _AcroPluginMain and is defined in the new Info.plist. Creator remains
CARO and type remains XTND. For a complete list of compatible plug-in build settings, please see the
MacSDKConfiguration Xcode configuration files and ProjectConfigurations files included in the Acrobat 8 SDK.
Note: As of Acrobat 8.0 SDK, CodeWarrior is no longer supported.
You can migrate a PDF Library application that was created using CodeWarrior to Xcode. As a starting point, it is
recommended that you read the information that is located at the following URL:
http://developer.apple.com/documentation/DeveloperTools/Conceptual/MovingProjectsToXcode/index.html.
The PDFL 8 SDK samples have debug and release targets that are built against the MacOSX10.4u.sdk SDK.
These are carbon applications that create universal binaries linked to universal Adobe libraries. For a
complete list of compatible application build settings, please see the MacSDKConfiguration Xcode
configuration files and ProjectConfigurations files included in the PDFL 8 SDK.
This chapter explains how to use the PDF Library API to insert text into a PDF document. As stated earlier in
this guide, the PDF Library API is a subset of the Acrobat core API that enables your application to interact
and manipulate PDF documents. The PDF Library API is not used to create plug-ins for Adobe Reader or
Acrobat nor is it used to modify the user interface of Adobe Reader or Acrobat such as adding a toolbar or
menu item.
Before reading this chapter, you should be familiar with creating a PDF Library application. For
information, see “Creating a sample PDF Library application” on page 54.
About inserting text into a PDF Describes the process of inserting text into a PDF page 62
document document.
Examining a PDF Library Examines a source file that contains application logic page 67
application’s source file that inserts text into a PDF document.
Note: The remaining parts of this chapter examine each step in detail. Assume that all code examples
specified in this chapter are located in an entry function named MainProc.
62
Adobe Acrobat SDK Inserting Text into PDF Documents
Developing Plug-ins and Applications Creating a new PDF document 63
Creating a container
To insert text into a PDF document, you must create a PDF container. A container contains the modifiable
contents of a PDF page. To create a PDF container, invoke the PDPageAcquirePDEContent method and
pass the following arguments:
● A PDPage object.
● An ASExtension object that represents the caller. If you invoke this method from a PDF Library
project, you can pass NULL. In contrast, if you invoke this method from a plug-in, you would pass the
gExtensionID extension.
Acquiring fonts
You must acquire the font that you will use to insert text into a PDF document. You can reference a font
that is installed on the host computer by creating a PDSysFont object and use this object to create a
PDEFont object, which represents the font that is used to draw text on a page. To acquire a font, perform
the following tasks:
2. Allocate the size of the PDEFontAttrs object’s buffer by using the memset method.
3. Set the PDEFontAttrs object’s name and type attributes. The name attribute defines the font name.
For example, you can specify CourierStd. The type attribute defines the font subtype. For example,
you can specify Type1, which is a Type 1 PostScript font. For information about valid font subtype
values, see the Acrobat and PDF Library API Reference.
4. Create a PDSysFont object by invoking the PDFindSysFont method and passing the following
arguments:
● The address of the PDEFontAttrs object.
● Size of the PDEFontAttrs object in bytes.
● A value that specifies a PDSysFontMatchFlags value. For information about this value, see the
Acrobat and PDF Library API Reference.
5. Create a PDEFont object that represents the font to use within a PDF document by invoking the
PDEFontCreateFromSysFont method and passing the following arguments:
● A PDSysFont object that references a system font.
● An ASUnit32 value that indicates whether to embed the font or whether to subset the font. You
can pass kPDEFontDoNotEmbed to this argument. For information about other values, see the
Acrobat and PDF Library API Reference.
The following code example acquires a font that is used to draw text on a page.
For more information about attributes that belong to this object, see the Acrobat and PDF Library API
Reference.
The following code example creates a PDEGraphicState object and sets it attributes.
Inserting text
You can insert text into the PDF document by performing the following tasks:
1. Create a PDEText object by invoking the PDETextCreate method. This method does not require
arguments.
Adobe Acrobat SDK Inserting Text into PDF Documents
Developing Plug-ins and Applications Inserting text 66
3. Insert text into the page content by invoking the PDEContentAddElem method and passing the
following arguments:
● The PDEContent object that you created. For information, see “Creating a container” on page 63.
● The location to where the text is added. Pass kPDEAfterLast to add the text to the end of the
PDEContent object.
● The PDEText object and cast this object to PDEElement.
4. Set the page's PDEContent back into the page by invoking the PDPageSetPDEContent method
and passing the following arguments:
● A PDPage object that you created. For information, see “Creating a new page” on page 63.
● An ASExtension object that represents the caller. If you invoke this method from a PDF Library
project, you can pass NULL. In contrast, if you invoke this method from a plug-in, you would pass
the gExtensionID extension.
The following code example saves the PDF document to the local directory as out.pdf.
The following image shows the PDF that is created when this source file is executed.
The following code example is a source file that inserts text into a PDF document.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "PDFInit.h"
#include "CosCalls.h"
#include "CorCalls.h"
#include "ASCalls.h"
#include "PDCalls.h"
#include "PSFCalls.h"
#include "PERCalls.h"
#include "PEWCalls.h"
#include "PIExcept.h"
Adobe Acrobat SDK Inserting Text into PDF Documents
Developing Plug-ins and Applications Examining a PDF Library application source file 69
#include "PagePDECntCalls.h"
#ifdef MAC_ENV
#include "macUtils.h"
#endif
void MainProc(void)
{
char buf[256];
ASInt32 i;
ASBool b;
PDDoc pdDoc; /* Reference to a PDF document */
PDPage pdPage; /* Reference to a page in doc */
PDEContent pdeContent; /* Container for page content */
ASFixedRect mediaBox; /* Dimensions of page */
PDSysFont sysFont; /* Used by PDEFont creation */
PDEFont pdeFont; /* Reference to a font used on a page */
PDEFontAttrs pdeFontAttrs; /* Font attributes */
PDEText pdeText; /* Container for text */
ASFixedMatrix textMatrix; /* Transformation matrix for text */
PDEColorSpace pdeColorSpace; /* ColorSpace */
PDEGraphicState gState; /* Graphic state to apply to operation */
char *HelloWorldStr = "Hello There"; // Text to write to the PDF
#ifdef MAC_ENV
ASPathName macPath;
#endif
/*==================================================================*\
Create the doc, page, and content container
\*==================================================================*/
DURING
//Create a page with those dimensions and insert it as the first page
pdPage = PDDocCreatePage(pdDoc, PDBeforeFirstPage, mediaBox);
/*==================================================================*\
Acquire a font, add text, and insert into page content container
\*==================================================================*/
pdeFontAttrs.type = ASAtomFromString("Type1");
/* The following code sets up the default graphics state. We do this so that
* we can free the PDEColorSpace objects
*/
/*==================================================================*\
Convert to objects, add to page, and release resources
\*==================================================================*/
HANDLER
ASGetErrorString(ERRORCODE, buf, sizeof(buf));
fprintf(stderr, "Error code: %ld, Error Message: %s\n", ERRORCODE, buf);
exit (-1);
END_HANDLER
}
#define INCLUDE_MYPDFLIBAPP_CPP1
#include "MyPDFLibApp.cpp"
#undef INCLUDE_MYPDFLIBAPP_CPP
5 Working with Documents and Files
This chapter explains how to use the Acrobat core API to perform operations on PDF documents and files,
such as opening a PDF document in an external window. When working with documents and files, you use
the following typedefs:
● An AVDoc typedef (from the AV layer) represents a document as a window in Acrobat or Adobe Reader.
A single AVDoc object exists for each displayed document. Operations on AVDoc objects are usually
visual modifications to the document’s view.
● A PDDoc typedef (from the PD layer) represents a document as a PDF file. You work with PDDoc objects
to make changes to a document’s contents. Using a PDDoc object, you can access components, such as
a PDPage object.
● An ASFile typedef (from the AS layer) represents a document as an open file.
Opening PDF documents Describes how to programmatically open a PDF document. page 72
Opening a PDF document in Describes how to open a PDF document from within an page 74
an external window external window.
Bridging core API layers Describes the Acrobat core API methods that enable you to page 83
work between different API layers.
As of Acrobat or Adobe Reader 8.0, you can open PDF documents that are based on Unicode-named files.
For information, see “Working with Unicode Paths” on page 160.
You can create an ASPathName object by using different techniques. This section describes how to create
an ASPathName object by invoking the ASFileSysCreatePathName method to convert a platform
specific path name to an ASPathName object. This method requires the following arguments:
● An ASFileSys object that represents the file system in which you are creating an ASPathName
object. For information, see “Creating an ASFileSys object” on page 162.
72
Adobe Acrobat SDK Working with Documents and Files
Developing Plug-ins and Applications Opening PDF documents 73
● An ASAtom object that specifies the data type of the third argument. You can specify Cstring, which
is accepted by the default file system on all platforms. In Windows, the path can be absolute
(C:\\folder\\file.pdf ) or relative (...\folder\file.pdf ). In Mac OS, it must be an absolute
path separated by colons (VolumeName:Folder:file.pdf ). In UNIX, the path can be absolute
(/folder/file.pdf ) or relative (.../folder/file.pdf ). For information about additional
supported values, see the ASFileSysCreatePathName method in the Acrobat and PDF Library API
Reference.
● A null- terminated character that specifies the PDF file on which the ASPathName object is based.
● A null- terminated character that specifies additional data that you can use. You can pass NULL. For
more information, see the ASFileSysCreatePathName method in the Acrobat and PDF Library API
Reference.
The ASFileSysCreatePathName method returns an ASPathName object. You can also create an
ASPathName object by displaying an open dialog box. For information, see “Displaying an open dialog
box” on page 76.
To programmatically open a PDF file in Acrobat or Adobe Reader, invoke the AVDocOpenFromFile
method and pass the following arguments:
● An ASPathName object that specifies the PDF file to open.
● An ASFileSys object that represents the file system in which the PDF file is located. For information,
see “Creating an ASFileSys object” on page 162.
● An ASText object that specifies a string value to display in the Adobe Reader or Acrobat title bar.
The following code example opens a PDF document that is based on a file named PurchaseOrder.pdf.
In addition to using the typedefs introduced in this chapter, you must also use the following typedefs to
open a PDF document in an external window:
● AVDocOpenParamsRec - defines required parameters for opening a PDF document in a window. This
typedef enables you to control the external window's size, location, and visibility.
● ExternalDocServerCreationDataRec - defines data that is used in conjunction with an AVDoc
object that is displayed in an external window.
4. Display an open dialog box to enable a user to retrieve a PDF file to open.
5. Display the PDF document that the user selected within a window.
Note: The remaining parts of this section describes these steps in detail.
Adobe Acrobat SDK Working with Documents and Files
Developing Plug-ins and Applications Creating a Window 75
Creating a Window
You must programmatically create the external window in which to display a PDF document. To create a
window, you invoke standard platform C functions and not the Acrobat core API. For example, if you are
creating your plug-in in Windows, you can use the Win32 API to create a window. In this situation, part of
the process of creating a window is to register the window class and define the window procedure. After
you perform these tasks, you can obtain a handle to the window by invoking the CreateWindow
function. For information about this function, see the MSDN online help at
http://msdn.microsoft.com/library/default.asp.
Note: Application logic that creates a window is shown in “Opening a PDF document in an external
window” on page 80.
● AVExternalView: Displays the page view of the document as well as scroll bars, toolbars,
bookmarks, and the thumbnails pane. Annotations, such as links, are active.
● AVEmbeddedView: Embeds the PDF file in an external document such as an HTML file. The first
page of the PDF document is displayed; however, user-interface component such as scroll bars,
toolbars, bookmarks, and the thumbnails pane are not displayed. Annotations, such as links, are
not displayed or active.
useReadOnly: An ASBool value that specifies whether the ReadOnly attribute is used.
readOnly: An ASBool value that opens the document in read-only mode if set to true.
useSourceDoc: An ASBool value that specifies whether the SourceDoc attribute is used.
sourceDoc: An AVDoc whose window is taken over by the new PDF document.
Note: Application logic that creates an AVDocOpenParamsRec object is shown in “Opening a PDF
document in an external window” on page 80.
The Acrobat core API has a typedef named AVOpenSaveDialogParamsRec that you use to display an
open dialog box. The AVOpenSaveDialogParamsRec typedef contains the following attributes that you
programmatically set:
size: The size of the AVOpenSaveDialogParamsRec object’s buffer.
flags: An AVOpenSaveDialogFlags value that specifies the dialog box’s appearance. The following
values are valid:
● kAVOpenSaveAllowAllFlag: Specifies All Files (*.*) for the dialog box. This value is only
applicable for an open dialog box.
● kAVOpenSaveAllowMultiple: Allows multiple files to be opened through the dialog box. This
value is only applicable for an open dialog box.
● kAVOpenSaveAllowForeignFileSystems: Allows file systems other than the default to be used
to open the files. You need to select this value to open Unicode-named files. This value is only
applicable for an open dialog box.
● kAVOpenSaveAllowSettingsButton: Adds a settings button to the dialog box. This value is
applicable to both open and save dialog boxes.
● kAVOpenSaveMergeTogetherPassedFilters: Meaningful only for open dialog boxes with
more than one filter.
parentWindow: An AVWindow object that specifies the parent window for the dialog box. This
attribute is ignored on Mac OS.
windowTitle: An ASText object that specifies the title for the dialog box. This attribute can be NULL,
in which case the default title is used.
actionButtonTitle: An ASText object that specifies the title of the action button. This attribute can be
NULL, in which case the default title is used.
cancelButtonTitle: An ASText object that specifies the title of the cancel button. This attribute can be
NULL, in which case the default title is used.
initialFileSys: An ASFileSys object that specifies the default file system. This value can be NULL if
the flags attribute does not contain kAVOpenSaveAllowForeignFileSystems.
initialPathName: An ASPathName object that specifies an initial path location. This value can be
NULL.
initialFileName: Specifies an initial file to save. This value is ignored for an open dialog box.
fileFilters: An array of pointers to addresses of AVFileFilterRec objects that act as a file filter (this
attribute is set in the example that is described in this section).
numFileFilters: Specifies the number of AVFileFilterRec pointers assigned to the fileFilters
attribute.
2. Create an AVFileFilterRec object used to store a series of file type descriptors that define a file
filter for an open or save dialog box. Secondly, create a pointer to an AVFileFilterRec.
AVFileFilterRec filterRec,*filterRecP;
3. Create an AVFileDescRec object used to store file extensions in an open dialog box.
AVFileDescRec descRec;
Adobe Acrobat SDK Working with Documents and Files
Developing Plug-ins and Applications Displaying an open dialog box 78
4. Set the AVFileDescRec object’s extension attribute with the value PDF.
strcpy (descRec.extension, "pdf");
5. Allocate the size of the AVFileFilterRec object’s buffer by using the memset method. Next, set the
AVFileFilterRec object’s fileDescs and numFileDescs attributes. The fileDescs attribute
defines file type and extension information. You can assign the address of the AVFileDescRec object
to the fileDescs attribute. The numFileDescs attribute specifies the number of
AVFileDescRecs objects assigned to the fileDescs attribute.
memset (&filterRec, 0, sizeof(AVFileFilterRec));
filterRec.fileDescs = &descRec;
filterRec.numFileDescs = 1;
6. Assign the AVFileFilterRec pointer with the address of the AVFileFilterRec object (this
pointer is used to set an attribute that belongs to the AVOpenSaveDialogParamsRec object).
filterRecP = &filterRec;
7. Set attributes that belong to the AVOpenSaveDialogParamsRec object. In this example, the size,
fileFilters, and numFileFilters attributes are set. Assign the fileFilters attribute with the
address of the pointer that points to AVFileFilterRec.
memset (&dialogParams, 0, sizeof (AVOpenSaveDialogParamsRec));
dialogParams.size = sizeof(AVOpenSaveDialogParamsRec);
dialogParams.fileFilters = &filterRecP;
dialogParams.numFileFilters = 1;
10. Display the open dialog box by invoking the AVAppOpenDialog method and passing the following
arguments:
● The address of an AVOpenSaveDialogParams object that represents the dialog box to open.
● The address of an ASFileSys object. This method will populate the ASFileSys object with the
file system in which the file that the user selects is located. This argument can be NULL if
kAVOpenSaveAllowForeignFileSystems is not set as the flags value.
● The address of a pointer that points to an ASPathName typedef. This argument is populated with
the file that was select by the user.
Adobe Acrobat SDK Working with Documents and Files
Developing Plug-ins and Applications Displaying a PDF document within a window 79
Note: This application logic is shown in “Opening a PDF document in an external window” on page 80.
To display a PDF document within an external window, perform the following tasks:
1. Open a PDF file by invoking the ASFileSysOpenFile method and passing the following arguments:
● An ASFileSys object that represents the file system in which the PDF file is located. For
information, see “Creating an ASFileSys object” on page 162.
● An ASPathName object that represents the path in which the PDF file is located.
● An ASFileMode object that represents the mode in which to open the file. For example, specify
ASFILE_READ to open the PDF document in read mode.
● The address of an ASFile object. This method populates this argument with the file that was
opened (file information is obtained from the ASPathName object).
If the ASFileSysOpenFile method is successful, then 0 is returned. Otherwise, an error value is
returned.
2. Display the PDF document within the window by invoking the AVDocOpenFromASFileWithParams
method and passing the following arguments:
● An ASFile object that specifies a PDF file to display (you can use the same ASFile object whose
address was passed to the ASFileSysOpenFile method).
● An ASText object that specifies the text to display in the window’s title bar. Create an ASText
object by invoking the ASTextFromScriptText method.
● The address of the AVDocOpenParamsRec object that you created. For information, see “Defining
the parameters for an external window” on page 75.
The following code example opens a PDF document in an external window. The application logic that is
located within the OpenExternalWindow user-defined function creates the window and displays a PDF
document within the window. A structure named gDocInfo that stores information such as the file to
open is also defined.
Adobe Acrobat SDK Working with Documents and Files
Developing Plug-ins and Applications Displaying a PDF document within a window 80
This code example contains a user-defined method named AVWndProc that acts as a window procedure
and another user-defined function named InitializeWindowHandler that registers the windows
class that is specified as an argument to CreateWindow.
Also shown in this code example is application logic that displays an open dialog box that enables a user
to select a PDF file to open. This application logic is located within a user-defined function named
OpenPDFFile. For information, see “Displaying an open dialog box” on page 76.
if (retVal ==0) {
//Create a ASText object used to display in the new window
ASText title = ASTextFromScriptText ("PDF Viewer", kASRomanScript);
wndClass.lpszMenuName = NULL;
wndClass.cbWndExtra = 0;
wndClass.lpszClassName = "ExternalWindow";
if (!RegisterClass(&wndClass))
return false;
return true;
}
//Display an open dialog box that enables a user to select a PDF file
ASPathName OpenPDFFile(ASFileSys * ASF)
{
//Declare an AVOpenSaveDialogParamsRec object
AVOpenSaveDialogParamsRec dialogParams;
DURING
//Set the AVFileFilterRec object’s filterDescription attribute
filterRec.filterDescription = ASTextNew();
ASTextSetEncoded (filterRec.filterDescription, "Adobe PDF Files",
ASScriptToHostEncoding(kASRomanScript));
//Display the Open dialog box - pass the address of the ASFileSys object
bSelected = AVAppOpenDialog(&dialogParams, &fileSys,
(ASPathName**)&pathName, NULL, NULL);
Adobe Acrobat SDK Working with Documents and Files
Developing Plug-ins and Applications Bridging core API layers 83
HANDLER
//Display an error message to the user
ASGetErrorString (ASGetExceptionErrorCode(), errorBuf, 256);
AVAlertNote (errorBuf);
END_HANDLER
You can create a PDDoc object by using an AVDoc object. To get a PDDoc object that corresponds to an
AVDoc object, invoke the AVDocGetPDDoc method. This method is referred to as a bridge method
because it allows your plug-in to access other layers from the AV layer. There are several bridge methods
which connect the different API layers (AV, PD, and Cos).
All AVDoc objects have an underlying PDDoc object. Operations on an AVDoc object usually result in
visible modifications to the document’s view. If you just want your plug-in to make changes to a
document’s contents, it can open a PDDoc object directly (that is, without going through an AVDoc object
to get the PDDoc object) and use PD layer methods.
The following code example creates a PDDoc object that is based on a PDF file named PurchaseOrder.pdf
and located in the root of the C drive. This code example is located within a user-defined function named
getDocument.
1. Create an AVDoc object by invoking the AVAppGetActiveDoc method. This method gets the
frontmost document located within Adobe Reader or Acrobat.
2. Create a PDDoc object by invoking the AVDocGetPDDoc method. This method requires an AVDoc
object and returns a PDDoc object.
Adobe Acrobat SDK Working with Documents and Files
Developing Plug-ins and Applications Accessing non-PDF files 85
The following code example creates a PDDoc object that is based on an open PDF document.
The following code example opens a file, writes data to it, and reads data from it. The following Acrobat
core API methods are invoked in this code example:
● AVAlertNote displays an error message if something goes wrong.
● ASFileSysOpenFile opens a file using the modes specified.
● ASFileWrite writes data to the file.
● ASFileClose closes the file.
● ASFileRead reads data from the file.
● ASFileGetEOF gets the current size of a file.
In the following code example, the CreateDataFile user-defined function creates a file and writes data
to it. The ReadDataFile user-defined function opens a file and reads data from it.
{
AVAlertNote ("Unable to open data file for writing.");
return false;
}
numBytes = ASFileWrite (TheFile, gDataBuf, strlen (gDataBuf));
if (path == NULL)
{
AVAlertNote ("Unable to gain access to data file.");
return;
}
err = ASFileSysOpenFile (NULL, path, mode, &TheFile);
Printing documents
You can use the Acrobat core API to print documents by using one of the following methods:
● AVDocPrintPages
● AVDocPrintPagesWithParams
The AVDocPrintPages method prints a document without displaying any user dialog boxes. The current
printer, page settings, and job settings are used. Printing is complete when this method returns.
The AVDocPrintPagesWithParams method prints a document with a full range of options. Printing is
complete when this method returns. It performs embedded printing; that is, it allows a PDF page to print
within a bounding rectangle on a page. It allows interactive printing to the specified printer.
To print a document with a range of options, invoke the AVDocPrintPagesWithParams method and
pass the following arguments:
● An AVDoc object that represents the PDF document from which to print page. For information about
creating an AVDoc object, see “Opening PDF documents” on page 72.
● An instance of the AVDocPrintParams data structure that defines printing parameters. For
information about this data structure, see the Acrobat and PDF Library API Reference.
6 Creating Menus and Menu Commands
This chapter explains how to use the Acrobat core API to create new menu commands and modify existing
menus. A menu command enables a user to interact with your plug-in by clicking a menu command that is
displayed within an Adobe Reader or Acrobat menu. When the user clicks the menu command, application
logic that is defined in the callback function associated with the menu command is executed. It is your
responsibility to define the application logic that is located in the callback function.
Adding menu commands to Describes how to add a menu command to a menu. page 90
menus
Creating menu callback Describes how to create callback functions for menus. page 93
functions
Determining if a menu item Describes how to determine if a menu item can be page 96
can be executed programmatically executed.
About menus
Adobe Reader and Acrobat have a standard menu bar and menu that enables user to invoke specific
functionality. You can, for example, click the Open command that is located on the File menu to open an
existing PDF file. Using the Acrobat core API, you can programmatically modify the menu bar. The
following illustration shows the menu bar located in Acrobat.
Letter Description
A The Acrobat menu bar.
B An Acrobat menu.
C A menu command.
88
Adobe Acrobat SDK Creating Menus and Menu Commands
Developing Plug-ins and Applications About AVmenubar typedefs 89
Submenus (also called pull right menus) are AVMenu objects that are attached to an AVMenuItem object
instead of to the menu bar.
Each menu has a title and a language-independent name. The title is the string that appears in the user
interface, while the language-independent name is the same regardless of the language used in the user
interface. Language-independent names enable a plug-in to locate a specific menu, such as the File menu,
without knowing, for example, that it is called Fichier in French.
You are strongly encouraged to begin your language-independent menu names with the plug-in name
(separated by a colon) to avoid name collisions when more than one plug-in is present. For example, if a
plug-in is named myPlug, it might add a menu whose name is myPlug:Options. For information, see
“Using plug-in prefixes” on page 31.
An AVMenuItem object can also serve as a separators between menu commands. You are encouraged to
position your plug-in menu commands relative to a separator. This helps ensure that if a block of menu
commands is moved in a future version of Acrobat, your plug-in menu commands also are moved.
A plug-in can simulate a user selecting a menu command by invoking the AVMenuItemExecute method. If
the menu command is disabled, the AVMenuItemExecute method returns without performing a task. The
AVMenuItemExecute method works even when the menu item is not displayed (for example, if it has not
been attached to a menu or if the menu bar is not visible). You can set the attributes of all menu commands
that you create; however, do not modify the Execute procedure of the Acrobat built-in menu commands.
Your plug-in can specify menu command names using either the names seen by a user, or
language-independent names. The latter allows your plug-in to locate a specific menu command without
knowing, for example, that it is called Imprimer in French.
You are strongly encouraged to avoid name collisions when naming menu commands by using your
plug-in name and a colon. For example, if a plug-in is named myPlug, you can name a menu command
myPlug:Open or myPlug:Find. For information, see “Using plug-in prefixes” on page 31.
Adobe Acrobat SDK Creating Menus and Menu Commands
Developing Plug-ins and Applications Adding menu commands to menus 90
1. Retrieve the Adobe Reader or Acrobat menu bar that is represented by an AVmenubar object by
invoking the AVAppGetMenubar method.
AVMenubar Themenubar = AVAppGetMenubar();
2. Retrieve the menu that will contain the new menu command by invoking the
AVMenubarAcquireMenuByName method and passing the following arguments:
● An AVmenubar object that represents the menu bar.
● The name of the menu. For example, to reference the File menu, specify File.
This method returns an AVMenu object that corresponds to the specified menu name.
AVMenu FileMenu = AVmenubarAcquireMenuByName (Themenubar, "File");
If the menu does not exist, you can programmatically create it (see the next step).
3. If necessary, programmatically create a new menu by invoking the AVMenuNew method and passing
the following arguments:
● A string value that represents the text displayed in Adobe Reader or Acrobat.
● A unique language-independent name of the menu to create. For information, see “Using plug-in
prefixes” on page 31.
● An ASExtension value that registers the menu. For information about an ASExtension value,
see the Acrobat and PDF Library API Reference.
The AVMenuNew method returns an instance of AVMenu.
AVMenu NewMenu = AVMenuNew ("Acrobat SDK", "ADBE:Acrobat_SDK",
gExtensionID);
After you create a new menu, you must attach it to the menu bar. For information, see “Adding a menu
command to a new menu” on page 92.
4. Create a new menu command by invoking the AVMenuItemNew method and passing the following
arguments:
● A string value that represents the menu command’s text. On Windows only, you can specify a
keyboard shortcut by including an ampersand (&) character in the title. Within Acrobat or Adobe
Reader, an underscore character (_) is placed under the character following the ampersand (char).
This allows the user to press alt+<char> to select the item.
● The language-independent name of the menu command to create. For information, see “Using
plug-in prefixes” on page 31.
● An AVMenu object that represents a submenu for which this menu command is the parent. Pass
null if this menu item does not have a submenu.
● A Boolean value. If true, the menu item is visible only when the user selects Full Menus. If false,
the menu item is visible for both Full Menus and Short Menus modes (this value is ignored in Adobe
Reader or Acrobat 3.0 or later).
● The key to use as a shortcut for the menu command (an ASCII character). Use NO_SHORTCUT if the
menu command does not have a shortcut.
Adobe Acrobat SDK Creating Menus and Menu Commands
Developing Plug-ins and Applications Adding a menu command to an existing menu 91
● Modifier keys, if any, that are used as part of the shortcut. Must be an OR of the Modifier Keys values,
except that AV_COMMAND cannot be specified.
● An AVIcon object that represents the icon to show in the menu command, or null if no icon is
shown. In Windows, a valid icon is a 24x24 sample monochrome HBITMAP. In Mac OS, an icon is a
handle to a standard SICN resource. For information about creating an AVIcon object, see
“Creating toolbar buttons” on page 100.
● An ASExtension value that registers this menu command. For information about an
ASExtension value, see the Acrobat and PDF Library API Reference.
The AVMenuItemNew method returns an AVMenuItem object.
AVMenuItem menuItem = AVMenuItemNew ("Show Message", "ADBE:ExternWin",
NULL, true, NO_SHORTCUT, 0, NULL, gExtensionID);
5. Attach the menu command to a menu by invoking the AVMenuAddMenuItem method and passing
the following arguments:
● An AVMenu object to which a menu command is attached.
● An AVMenuItem object that is attached.
● The location in the menu that specifies where the command is added. You can specify
APPEND_MENUITEM to append the menu command to the end of the menu.
If this method is successful, the menu command is added to the specified menu.
AVMenuAddMenuItem (FileMenu, menuItem, APPEND_MENUITEM);
6. Release the typedef instances to free memory. To release an AVMenu instance, invoke the
AVMenuRelease method and pass the AVMenu instance. To release an AVMenuItem instance, invoke
the AVMenuItemRelease method and pass the AVMenuItem instance.
{
AVAlertNote ("Unable to create the menu command");
AVMenuItemRelease(NewMenuCommand);
return;
}
Note: This code example creates a new menu command that displays Show Message in the File menu.
However, before the menu command performs an action, you have to create a callback menu
function. For information, see “Creating menu callback functions” on page 93.
Tip: To see how the global gEntensionID variable is declared, see the plug-in samples that accompany
the Acrobat SDK.
Note: If you plan to add a submenu to a menu command, you must create the submenu before creating
the menu command.
For the purpose of this discussion, a simplistic user-defined function named ShowMessage is introduced.
This method displays a message box by invoking the AVAlertNote method. The following code example
shows the body of the ShowMessage function.
ACCB1 void ACCB2 ShowMessage (void* data)
{
AVAlertNote ("A menu command was selected.");
}
The data parameter (for this and the other callbacks) can be used to maintain private data for the menu
command. Notice that this user-defined function is declared using the ACCB1 and ACCB2 macros. For
information, see “Using callback functions” on page 30.
For each callback that you create, you declare pointers to callbacks that are defined in the Acrobat core
API:
AVExecuteProc ExecProcPtr = NULL;
AVComputeEnabledProc CompEnabledProcPtr = NULL;
AVComputeMarkedProc CompMarkedProcPtr = NULL;
AVExecuteProc is a callback that you can create that is invoked by Acrobat or Adobe Reader when a user
selects a menu item. AVComputeEnabledProc is a callback that you can create that is invoked by Adobe
Reader or Acrobat when determining whether or not to enable the menu command.
AVComputeMarkedProc is a callback that you can create that is invoked by Adobe Reader or Acrobat
when determining whether or not the menu command should be checked.
Adobe Acrobat SDK Creating Menus and Menu Commands
Developing Plug-ins and Applications Creating menu callback functions 94
After you create a pointer, such as a pointer that points to AVExecuteProc, you can invoke the
ASCallbackCreateProto macro that is defined in the Acrobat core API to convert a user-defined
function to an Acrobat callback function. For example, you can invoke ASCallbackCreateProto to
convert ShowMessage to a callback function. The ASCallbackCreateProto macro requires the
following arguments:
● The callback type. For example, you can pass AVExecuteProc.
● The address of the user-defined function to convert to a callback function.
The ASCallbackCreateProto macro returns a callback of the specified type that invokes the
user-defined function whose address was passed as the second argument. The following code example
shows the ASCallbackCreateProto macro converting the ShowMessage user-defined function to a
AVExecuteProc callback.
AVExecuteProc ExecProcPtr = NULL;
ExecProcPtr = ASCallbackCreateProto(AVExecuteProc, &ShowMessage);
When you are done with a menu callback, you can invoke the ASCallbackDestroy method to release
memory that it consumes. The following code example creates callback functions for menu commands.
Note: Notice that the application logic that creates a menu command is located within the PluginInit
procedure. For information, see “About plug-in initialization” on page 27.
Adobe Acrobat SDK Creating Menus and Menu Commands
Developing Plug-ins and Applications Determining if a menu item can be executed 96
Acrobat and Adobe Reader 8.0 contain a list of menu items which can be executed using ExecMenu. Any
menu item not on the list cannot be programmatically executed.
You can determine if a menu item can be programmatically executed by invoking the
AVMenuItemIsScriptable method and passing an AVMenuItem. This method returns a Boolean
value. That is, if the menu item that corresponds to the AVMenuItem argument can be executed, True is
returned; otherwise, False is returned.
7 Creating Toolbars and Buttons
This chapter explains how to use the Acrobat core API to create new toolbars and toolbar buttons and to
modify existing ones. For example, you can create a new button, attach it to an existing toolbar, and
associate the button with a specified callback function that is executed when the user clicks the button.
Retrieving toolbars Describes how to retrieve toolbars from Adobe Reader or page 98
Acrobat.
Creating toolbar buttons Describes how to create toolbar buttons. page 100
Retrieving existing toolbar Describes how to retrieve existing toolbar buttons. page 102
buttons
Exposing a button in a web Describes how to expose a button in a web browser. page 104
browser
Removing a button from a Describes how to remove a button from a toolbar. page 105
toolbar
Creating toolbar callback Describes how to create callback functions for toolbar page 105
functions buttons.
About toolbars
Adobe Reader and Acrobat consists of various toolbars that enable a user to invoke specific functionality.
For example, you can click the Open button that is located on the File toolbar to open an existing PDF
document. The following illustration shows two toolbars located in Acrobat.
97
Adobe Acrobat SDK Creating Toolbars and Buttons
Developing Plug-ins and Applications About AVToolBar typedefs 98
Letter Description
Tip: You can obtain the display name of the toolbar by pointing the mouse to the left portion of a toolbar.
Note: The display name is the name that is displayed in Acrobat or Adobe Reader. However, toolbars also
have internal names that may differ. That is, in some cases, the internal name and display name of a
toolbar are different and in other cases they are the same. For example, consider the Help toolbar.
The display name is Help and the internal name is HowTo. An internal name is used to
programmatically retrieve a toolbar. For information, see “Retrieving toolbars” on page 98.
You can add a button to a toolbar by specifying the relative position of the button (before or after) to an
existing button. A plug-in controls the toolbar upon which a button will appear by placing the button next
to an existing one already in the appropriate location.
A plug-in can invoke a button as if a user clicked it. Buttons can be enabled (selectable) or disabled (grayed
out), and can be marked (selected). Each button also has an icon that appears in the toolbar. Normally, all
tools are persistent and remain selected indefinitely. The Control key (Windows) or Option key (Mac OS)
can be used to select a tool for one-shot use. Plug-ins should follow this convention to add buttons.
Separators between groups of buttons are themselves buttons, although they are neither selectable nor
executable. Because they are buttons, however, they do have names, allowing other buttons to be
positioned relative to them.
You are encouraged to position tool buttons relative to separators. Doing this increases the likelihood that
tool buttons will be correctly placed if future versions of Acrobat move groups of tool buttons around.
Retrieving toolbars
You can use the Acrobat core API to retrieve an existing toolbar that appears in Adobe Reader or Acrobat.
After you retrieve a toolbar, you can perform additional tasks such as attaching a button. For information,
see “Attaching a button to a toolbar” on page 103.
You retrieve a specific toolbar by invoking the AVAppGetToolBarByName method. This method requires
a constant character pointer that specifies the internal name of a toolbar and returns an AVToolBar
object that corresponds to the toolbar. If the name cannot be found, this method returns NULL.
Adobe Acrobat SDK Creating Toolbars and Buttons
Developing Plug-ins and Applications Retrieving toolbars 99
The following table lists toolbar names that appear in Acrobat and Adobe Reader (Adobe Reader does not
contain all the toolbars that Acrobat does). The Display Name column specifies the toolbar name that
appears in Acrobat or Adobe Reader. The Internal Name column specifies the value that you must pass to
the AVAppGetToolBarByName method to retrieve the toolbar.
Note: You can invoke the AVAppGetToolBar method to return an AVToolbar object that is based on
the Advanced Editing toolbar.
Adobe Acrobat SDK Creating Toolbars and Buttons
Developing Plug-ins and Applications Creating toolbar buttons 100
The AVToolButtonNew method returns an AVToolButton object. You must attach this button to a
toolbar in order to view it. For information, see “Attaching a button to a toolbar” on page 103.
It is strongly recommended that you create an AVIcon object when creating a new button. To create an
AVIcon object, you must invoke platform specific APIs. That is, you do not invoke methods that belong to
the Acrobat core API. If, for example, you are working on Windows, you can invoke a Win32 API method
named LoadBitmap. Likewise, if you are working on Mac OS, you can invoke SafeGetResource.
The following code example shows how to create an AVIcon object that is based on a bitmap resource
named IDB_BITMAP1.
AVIcon myIcon = (AVCursor)LoadBitmap(gHINSTANCE,
MAKEINTRESOURCE(IDB_BITMAP1));
The gHINSTANCE object is an instance of HINSTANCE and is declared in the PIMain.c file. In addition to
creating a new icon, you can also retrieve an existing icon appearing on a toolbar button. For information,
see “Retrieving existing toolbar buttons” on page 103.
Once you create an AVIcon object, you can create a new toolbar button. The following code example
creates a new toolbar button.
Tip: To view an example of a sub-menu, click the Help button that appears on the Help toolbar.
To retrieve an existing toolbar button, invoke the AVToolBarGetButtonByName method and pass the
following arguments:
● An AVToolBar object that represents the toolbar from which the button is retrieved.
● An ASAtom object that represents the button name. For information about button names, see the
Acrobat and PDF Library API Reference.
The following code example retrieves the SecureTask button located on the Tasks toolbar and gets its icon.
if (mySecureButton == NULL)
{
AVAlertNote ("The button was not successfully retrieved");
return;
}
Before a button has functionality, you must create a callback function. For information, see “Creating
toolbar button callback functions” on page 105.
The following code example attaches a newly created button to the File toolbar.
Adobe Acrobat SDK Creating Toolbars and Buttons
Developing Plug-ins and Applications Exposing a button in a web browser 104
After you remove the button, invoke the AVToolBarUpdateButtonStates method to update the
toolbar. This method requires an AVToolBar object that represents the toolbar to update. The following
code example removes the SecureTask button located on the Tasks toolbar.
if (mySecureButton == NULL)
{
AVAlertNote ("The button was not successfully retrieved");
return;
}
The data parameter (for this and the other callbacks) can be used to maintain private data that is used by
the callback. Notice that this user-defined function is declared using the ACCB1 and ACCB2 macros. For
information, see “Using callback functions” on page 30.
AVExecuteProc is a callback that you can create that is invoked by Acrobat or Adobe Reader when a user
clicks a button. After you create an AVExecuteProc object, you can invoke the
ASCallbackCreateProto macro that is defined in the Acrobat core API to convert a user-defined
function to an Acrobat callback. For example, you can invoke ASCallbackCreateProto to convert
ShowButtonMessage to a callback function. The ASCallbackCreateProto macro requires the
following arguments:
● The callback type. For example, you can pass AVExecuteProc.
● The address of the user-defined function to convert to a callback.
The ASCallbackCreateProto macro returns a callback of the specified type that invokes the
user-defined function whose address was passed as the second argument. The following lines of code
shows the ASCallbackCreateProto macro converting the ShowButtonMessage user-defined
function to a AVExecuteProc callback.
AVExecuteProc ExecProcPtr = NULL;
ExecProcPtr= ASCallbackCreateProto(AVExecuteProc, &ShowButtonMessage);
After you create an AVExecuteProc callback, you can invoke the AVToolButtonSetExecuteProc
method to associate a button with a callback. That is, when a user clicks a button, Acrobat or Adobe Reader
will invoke the user-defined function whose address was passed to the ASCallbackCreateProto
macro. The AVToolButtonSetExecuteProc method requires the following parameters:
● An AVToolButton object that represents the button to associate with the callback
● An AVExecuteProc object that represents the callback function
● The address of a user-defined data structure that can be passed to the user-defined function
When you are done with a button callback, invoke the ASCallbackDestroy method to release the
memory that it consumes.
return true;
}
ACCB1 ASBool ACCB2 PluginUnload (void)
{
ASCallbackDestroy (ExecProcPtr);
ASCallbackDestroy (CompEnabledProcPtr);
ASCallbackDestroy (CompMarkedProcPtr);
return true;
}
Note: Notice that the application logic that creates a toolbar button is located within the PluginInit
procedure. For information, see “About plug-in initialization” on page 27.
8 Creating Annotations
This chapter explains how to create new annotations and modify existing ones. Annotations are tools that
let you electronically collaborate within Adobe Reader or Acrobat, similar to the way people traditionally
collaborate using paper by adding comments, highlights, sticky notes, and so on. For example, the note
annotation enables Adobe Reader or Acrobat users to add notes within a PDF document that other
viewers can read.
Creating text annotations Describes how to create text annotations. page 108
Retrieving existing annotations Describes how to retrieve existing text annotations. page 110
Modifying text annotations Describes how to modify existing annotations. page 111
About annotations
The Acrobat core API provides methods for working with annotations in PDF documents. Annotations are
represented by a PDAnnot typedef, which is the abstract superclass for all annotations.
Several annotation types exist, which are identified by their subtype. Each subtype can have additional
properties that extend the basic ones. The subtype for text annotations (also called notes) is text. The
subtype for link annotations is link. The Acrobat core API contains two built-in annotation typedefs
PDTextAnnot and PDLinkAnnot. A PDTextAnnot object corresponds to a text annotation and a
PDLinkAnnot object corresponds to a link annotation.
You can use PDAnnot methods to get and set various annotation properties, such as color, date, title, location,
and subtype. For example, you can invoke the PDAnnotSetColor method to set the color of an annotation.
Note: This chapter does not discuss how to create 3D annotations. For information, see “Creating 3D
Annotations” on page 203.
1. Create a rectangle region that specifies the annotation’s location. To create a rectangle region, create
an ASFixedRect object.
2. Define the rectangle’s borders by setting the ASFixedRect object’s left, top, right, and bottom attributes.
3. Create an ASPage object that represents the page that will contain the new annotation by invoking
the PDDocAcquirePage method. This method requires a PDDoc object and the ASInt32 object that
represents the page number. This method returns an ASPage object.
108
Adobe Acrobat SDK Creating Annotations
Developing Plug-ins and Applications Creating text annotations 109
4. Create a PDAnnot object by invoking the PDPageCreateAnnot method and passing the following
arguments:
● An ASPage object that represents the page that will contain the new annotation.
● An ASAtom object that represents the annotation’s subtype. Because a text annotation is created,
specify Text as the annotation’s subtype. For information about an annotation’s subtype, see the
Acrobat and PDF Library API Reference.
● The address of the ASFixedRect object.
5. Cast the PDAnnot object to a PDTextAnnot object by invoking the CastToPDTextAnnot method.
This method requires a PDAnnot object and returns a PDTextAnnot object.
6. Open the text annotation by invoking the PDTextAnnotSetOpen method. Opening an annotation
enables you to set its content. This method requires a PDTextAnnot object and an ASBool value that
specifies true.
7. Set the text of the annotation by invoking the PDTextAnnotSetContents method and passing the
following arguments:
● A PDTextAnnot object that represents the annotation for which text is set.
● A character pointer that specifies the text to set.
● An ASInt32 object that specifies the length of the character pointer.
8. Add the text annotation to the page by invoking the PDPageAddAnnot method and passing the
following arguments:
● An ASPage object that represents the page that will contain the new annotation.
● An ASInt32 object that specifies the index that controls where the annotation is added. The first
annotation in the array has an index of zero. Passing a value of -2 adds the annotation to the end of
the array.
● A PDTextAnnot object that represents the annotation.
The following code example adds a text annotation to a PDF document page. In this code example, a
PDDoc object named myPDDoc exists. For information, see “Creating a PDDoc object” on page 83.
1. Create a PDDoc object that represents the PDF document that contains annotations. For information,
see “Creating a PDDoc object” on page 83.
2. Search for existing annotations by iterating through the PDF document page by page. One way to
perform this task is to create a for loop structure and invoke the PDDocGetNumPages method. This
method requires a PDDoc object as an argument and returns the number of pages within the
document.
3. For each page within the PDF document, obtain a PDPage object by invoking the
PDDocAcquirePage method and passing the following arguments:
● A PDDoc object that represents the PDF document that contains the page.
● An ASInt32 object that represents the page number.
4. After you obtain a PDPage object, get the number of annotations located on the page by invoking the
PDPageGetNumAnnots method. This method requires a PDPage object as an argument and returns
an ASInt32 object representing the number of annotations located on the page.
5. For each annotation on a page, invoke the PDPageGetAnnot method. This method requires a PDPage
object and an ASInt32 object that represents the index of the annotation. This method returns a
PDAnnot object.
The following code example retrieves existing annotations located within a PDF document. After an
annotation is retrieved, information about the annotation is displayed within an alert box. Information
about the annotation is retrieved by invoking the PDAnnotGetSubtype method. This method returns an
ASAtom object representing the annotation’s subtype. For example, if the annotation is a stamp, then an
ASAtom object storing the value Stamp is returned. You can get the string value from an ASAtom object
by invoking the ASAtomGetString method and passing the ASAtom object.
Note: In the previous code example, assume a PDDoc object named myPDDoc exists. For information, see
“Creating a PDDoc object” on page 83.
Before you modify an annotation, determine whether the annotation is the correct subtype. That is, before
modifying a text annotation, ensure that the annotation is a Text annotation. You can determine whether
an annotation is the correct subtype by invoking the PDAnnotGetSubtype method. This method
requires a PDAnnot object and returns an ASAtom object that specifies the annotation’s subtype.
When modifying a text annotation, it is recommended that you check its contents. For example, you can
retrieve all text annotations in a PDF document, retrieve the annotation’s text, and modify annotations
that contain specific text. To retrieve the text of an annotation, invoke the PDTextAnnotGetContents
method and pass the following arguments:
● A PDTextAnnot object that contains text to retrieve.
● A character pointer that is populated with the annotation’s text.
● An ASInt32 object that represents the size of the character pointer.
The following code example iterates through all annotations located in a PDF document. Each valid
annotation is checked to determine whether it is a Text annotation. This task is performed by invoking
the PDAnnotGetSubtype method. If the annotations is a Text annotation, then the annotation’s text is
retrieved by invoking the PDTextAnnotGetContents method.
Because the size of the annotation’s text is unknown, the PDTextAnnotGetContents is invoked twice.
The first time it is invoked, NULL is passed as the buffer address (second argument) and 0 is specified as
the buffer size (third argument). The text length is returned to an ASInt32 object named bufSize. The
ASmalloc method is invoked which allocates bufSize bytes to the character pointer.
Adobe Acrobat SDK Creating Annotations
Developing Plug-ins and Applications Modifying text annotations 112
The second time PDTextAnnotGetContents is invoked, the allocated character pointer is passed as
well as the ASInt32 object named bufSize. The character pointer is populated with the annotation’s
text.
Next the strcmp method is invoked to compare the annotation’s text with a specific string value. If the
annotation’s text matches the string value, then the PDTextAnnotSetContents method is invoked,
which replaces the annotation’s text with new text.
Note: In the previous code example, assume a PDDoc object named myPDDoc exists. For information, see
“Creating a PDDoc object” on page 83.
9 Working with Bookmarks
This chapter explains how to use the Acrobat core API to create new bookmarks and search for existing
ones. A bookmark is a link with representative text on the Bookmarks tab in the navigation pane. Each
bookmark navigates to a different view or page within a PDF document. You can also use a bookmark to
navigate to a specific destination within a PDF document, to another document (PDF or other), or to a web
page. Bookmarks can also perform actions, such as executing a menu item or displaying a graphic file.
About bookmarks
Bookmarks are represented by a PDBookmark object. All bookmarks have the following attributes:
● A title that appears in Adobe Reader or Acrobat.
● An action that specifies what happens when a user clicks on the bookmark. The typical action for a
bookmark is to move to another location in the current document, although other actions can be
specified.
Every document has a root bookmark. The root bookmark does not represent a physical bookmark that
appears in Adobe Reader or Acrobat, but is the root from which all bookmarks in the tree are descended.
Bookmarks are organized in a tree structure in which each bookmark has zero or more children that
appear indented, and zero or more siblings that appear at the same indentation level. All bookmarks
except the bookmark at the top level of the hierarchy have a parent, the bookmark under which it is
indented. A bookmark is open if its children are visible on screen, and closed if they are not.
The following image shows how bookmarks appear in Adobe Reader or Acrobat.
Parent bookmark
Child bookmark
Sibling bookmark
113
Adobe Acrobat SDK Working with Bookmarks
Developing Plug-ins and Applications Creating bookmarks 114
The Acrobat core API contains methods that operate on bookmarks. Using these methods, you can
perform the following tasks:
● Create new bookmarks
● Get and set various attributes of a bookmark (such as its title or action or whether it is open)
● Search for a bookmark
Creating bookmarks
You can use the Acrobat core API to create a new bookmark that appears in a PDF document. Before you
can create a bookmark, you must create a PDDoc object that represents the PDF document to which the
bookmark is added. For information, see “Creating a PDDoc object” on page 83.
1. Get the root of the PDF document's bookmark tree by invoking the PDDocGetBookmarkRoot method.
This method requires a PDDoc object and returns a PDBookmark object that represents the document's
root bookmark. The document’s root bookmark does not appear in Adobe Reader or Acrobat.
2. Create another PDBookmark object that represents the bookmark to add to the document’s root
bookmark by invoking the PDBookmarkAddNewChild method. This method requires a PDBookmark
object that represents the parent bookmark (in this case the parent bookmark is also the document’s
root bookmark) and an ASAtom object that represents the bookmark’s title.
3. Create a PDBookmark object that represents a sibling bookmark to the bookmark that was added to
the document’s root bookmark (the sibling bookmark is also a child of the document’s root bookmark).
You can perform this task by invoking the PDBookmarkAddNewSibling method. This method
requires a PDBookmark object that represents the new bookmark’s sibling bookmark and an ASAtom
object that represents the bookmark’s title.
The following code example adds two new bookmarks to a PDF document. After each bookmark is created, the
PDBookmarkIsValid method is invoked to determine whether the bookmark is valid. The name of the PDDoc
object used in this code example is myPDDoc. For information, see “Creating a PDDoc object” on page 83.
if (PDBookmarkIsValid(rootBookmark)){
if (PDBookmarkIsValid(childBookmark)){
To create an action for a bookmark, you must create a PDAction object that represents the action that
occurs when a user clicks on a bookmark. Once you create a PDAction object, you can assign it to a
bookmark. For information, see “Assigning an action to a bookmark” on page 116.
As specified earlier in this chapter, a typical bookmark action is to move to another location in the current
document. To illustrate how to create a bookmark action, this section defines a bookmark action that
displays a specific page in a PDF document when a user clicks the bookmark.
To define a bookmark action that generates a specific view of a PDF document, you create a PDAction
object by invoking the PDActionNewFromDest method. This method creates a new action that directs
the user to the specified destination view and requires the following arguments:
● A PDDoc that represents the PDF document for which the action is created.
● A PDViewDestination object that represents a specific view in the PDF document. For information,
see “Creating a PDViewDestination object” on page 115.
● A PDDoc that represents the destination document. This object is the same object that is specified as
the first parameter.
Value Description
XYZ Destination specified as upper-left corner point and a zoom factor.
Fit Fits the page into the window, corresponding to the Acrobat viewer’s FitPage menu item.
FitH Fits the width of the page into the window, corresponding to the Acrobat viewer’s Fit Width
menu item.
FitV Fits the height of the page into a window.
FitR Fits the rectangle specified by its upper-left and lower-right corner points into the window.
FitB Fits the rectangle containing all visible elements on the page (known as the bounding box) into
the window (corresponds to the Acrobat viewer’s Fit Visible menu item).
Adobe Acrobat SDK Working with Bookmarks
Developing Plug-ins and Applications Defining bookmark actions 116
Value Description
FitBH Fits the width of the bounding box into the window.
FitBV Fits the height of the bounding box into the window.
You can create an AVDoc object that is based on the PDDoc object that already exists by invoking the
AVDocFromPDDoc method and passing the PDDoc object. You can invoke this method as an argument for
the AVDocGetPageView method.
AVPageView myPageView = AVDocGetPageView(AVDocFromPDDoc(myPDDoc));
Once you create an AVPageView object, you can specify a specific PDF document page number by
invoking the AVPageViewGoTo method and passing the AVPageView object and an ASInt32 object
that represents the page number:
ASInt32 pNum = 2;
AVPageViewGoTo(myPageView,pNum);
The following code example creates a PDAction object and assigns it to a bookmark that is represented
by a PDBookmark object named childBookmark.
Caution: When running this code example, you must have the PDF document on which the PDDoc object
is based open. Otherwise, a run-time error occurs. Also, you must create a PDBookmark object
named childBookmark. For information, see “Creating bookmarks” on page 114.
Before you invoke the PDBookmarkSetOpen method, it is recommended that you invoke the
PDBookmarkIsOpen method to determine whether the bookmark is open. This method requires a
PDBookmark object and returns an ASBool value. If the bookmark is open, then true is returned.
The following code example retrieves and opens a bookmark whose title is Samples. For information about
retrieving a specific bookmark, see “Retrieving a specific bookmark” on page 118.
Retrieving bookmarks
You can use the Acrobat core API to retrieve bookmarks located within a PDF document. You can retrieve
the root bookmark, retrieve a specific bookmark, or retrieve all bookmarks that are located within a PDF
document.
The following code example shows how to get a PDF document’s root bookmark by creating application
logic within a user-defined function named GetFirstBookmark. First, the PDDocGetBookmarkRoot
method is invoked to get the bookmark root. This method requires a PDDoc object that represents the
PDF document from which the root bookmark is retrieved and returns a PDBookmark object that
represents the root bookmark. For information, see “Creating a PDDoc object” on page 83.
Next, the PDBookmarkGetFirstChild method is invoked to get the first child of the root. If there are no
bookmarks, PDBookmarkGetFirstChild returns NULL.
Note: In the previous code example, a PDDoc object named myPDDoc is passed to the
PDDocGetBookmarkRoot method. For information about creating this object, see “Creating a
PDDoc object” on page 83.
The following code example creates a recursive user-defined function named VisitAllBookmarks. First
it invokes the PDBookmarkIsValid method to ensure that the bookmark that is passed is valid (the root
bookmark is always valid.)
Second, this user-defined function retrieves the title of the bookmark by invoking the
PDBookmarkGetTitle method. This method requires the following arguments:
● A PDBookmark object that contains the title to retrieve.
● A character pointer that is populated with the bookmarks title.
● An ASInt32 object that represents the size of the character pointer.
Because the size of the bookmark’s title is unknown, the PDBookmarkGetTitle is invoked twice. The
first time it is invoked, NULL is passed as the buffer address (second argument) and 0 is specified as the
buffer size (third argument). The text length is returned to an ASInt32 object named bufSize. The
ASmalloc method is invoked which allocates bufSize bytes to the character pointer.
The second time PDBookmarkGetTitle is invoked, the allocated character pointer is passed as well as
the ASInt32 object named bufSize. The character pointer is populated with the bookmark’s title. The
AVAlertNote method is invoked and the character pointer is passed as an argument that results in the
bookmark’s title being displayed within a message box.
The PDBookmarkHasChildren method is invoked to determine whether there are any child bookmarks
under the current bookmark. If there are child bookmarks, the PDBookmarkGetFirstChild method is
invoked to retrieve the first child bookmark. A recursive call is made to VisitAllBookmarks (that is, the
user-defined method is invoking itself ) until there are no more children bookmarks. Then the
PDBookmarkGetNext method is invoked to get a sibling bookmark and the process continues until there
are no more bookmarks within the PDF document.
if (!PDBookmarkIsValid(aBookmark))
E_RTRN_VOID
END_HANDLER
}
Deleting bookmarks
You can use the Acrobat core API to delete an existing bookmark. Deleting a bookmark deletes child
bookmarks; however, PDF document content is not affected. To delete a bookmark, you must invoke the
PDBookmarkDestroy method and pass a PDBookmark object that represents the bookmark to delete.
For example, consider the bookmark structure shown in the following diagram.
Assume, for example, that you want to delete the bookmark titled Copying LiveCycle Print files. Once you
delete this bookmark, the API files and XDC files bookmarks are also deleted. To delete the Copying
LiveCycle Print files bookmark, you must create a PDBookmark object that represents this bookmark and
pass this object to the PDBookmarkDestroy method.
The following code example deletes a bookmark. Included in this code example is application logic that
retrieves a specific bookmark. For information, see “Retrieving a specific bookmark” on page 118.
Adobe Acrobat SDK Working with Bookmarks
Developing Plug-ins and Applications Deleting bookmarks 121
Note: In the previous code example, a PDDoc object named myPDDoc is passed to the
PDDocGetBookmarkRoot method. For information about creating this object, see “Creating a
PDDoc object” on page 83.
10 Working with Page Views and Contents
This chapter explains how to display page views and modify page contents. A page view is the area of the
Acrobat or Adobe Reader window that displays the visible content of a document page. An example of a
page view is a PDF document page displayed within Adobe Reader or Acrobat at a 120% magnification.
About page coordinates Describes the characteristics of page coordinates. page 122
About page views Describes the characteristics of page views. page 124
Displaying page views Describes how to display a page view. page 124
Modifying page contents Describes how to modify page contents. page 125
User space is the coordinate system used within PDF documents. It specifies coordinates for most objects
in the PD layer. For information, see “Portable Document layer” on page 17.
When working with the user space coordinate system, you use an ASFixedRect object to represent a
rectangle. For example, to place an annotation on a page, create an ASFixedRect object and specify its
coordinates. To specify a ASFixedRect object’s coordinates, you must define its top, right, bottom,
and left attributes. For information, see “Creating text annotations” on page 108.
122
Adobe Acrobat SDK Working with Page Views and Contents
Developing Plug-ins and Applications About page coordinates 123
Media Box
Crop Box
(0,0)
Device space specifies coordinates in screen pixels and is used in the AV layer to specify screen coordinates
of windows. In device space, you use an AVRect object to represent a specific coordinate. The following
diagram shows a device space coordinate system.
Aperture
(0,0)
Crop Box
Media Box
The AVPageViewRectToDevice method can transform a rectangle’s coordinates from user space to
device space. For example, you can use PD methods to determine user space coordinates of a rectangle.
However, to display an outline around the rectangle, you must convert user space coordinates to device
space coordinates. For information, see “Modifying page contents” on page 125.
Adobe Acrobat SDK Working with Page Views and Contents
Developing Plug-ins and Applications About page views 124
Using AVPageView methods, you can perform page-view tasks such as:
● Displaying a page.
● Selecting a zoom factor.
● Scrolling the displayed page.
● Highlighting one or more words.
● Controlling screen redrawing.
● Traversing the view stack that records where users have been in a document.
Note: To control the size of the page view, you can invoke the AVWindowSetFrame and
AVDocSetSplitterPosition methods. For information about these methods, see the Acrobat
and PDF Library API Reference.
1. Create an AVDoc object that represents the PDF document that contains the page on which the page
view is based. For information, see “Opening PDF documents” on page 72.
2. If desired, ensure that the specified page number does not exceed the number of pages located in the
document. Convert the AVDoc object to a PDDoc object by invoking the AVDocGetPDDoc method.
This method requires an AVDoc and returns a PDDoc object. Get the total number of pages located
within the document by invoking the PDDocGetNumPages method. This method requires a PDDoc
object and returns an ASInt32 object representing the number of pages within the document.
3. Create an AVPageView object that represents the page view by invoking the AVDocGetPageView
method. This method requires an AVDoc object and returns an AVPageView object.
4. Specify the page view’s page number by invoking the AVPageViewGoTo method. This method
requires an AVPageView object that represents the page view and an ASInt32 object that specifies
the page number. The page number uses a zero-based index value. Therefore the value of the first page
is 0.
5. Display the page view by invoking the AVPageViewDrawNow method and passing the AVPageView
object. When you invoke a method that affects a page view, you must invoke this method to redraw the
page and display the page view. Otherwise, changes to a page view are not displayed.
The following code example displays a page view that is based on an AVDoc object named myDocument.
The specified page of the page view is 40 (which displays page 41). For information about creating an
AVDoc object, see “Opening PDF documents” on page 72.
Adobe Acrobat SDK Working with Page Views and Contents
Developing Plug-ins and Applications Modifying page contents 125
To access a PDPage object, you must obtain the applicable PDDoc object, either directly or by invoking
the AVDocGetPDDoc method. You can then invoke the PDDocAcquirePage method to acquire the
page (the PDPage object).
To access the contents of PDF pages, you use PD layer methods. In addition, the Acrobat core API provides
the PDFEdit typedef, which provides an easy way to access to the contents of a PDF page. PDFEdit
methods are useful when working with page items such as images, paths, graphics, and text objects. This
API treats the contents of a page as a list of objects whose values and attributes can be modified.
Each PDFEdit object encapsulates all the relevant information about itself. A PDEText object, for
example, contains text and its attributes such as font and position on the page. It can access single
characters or multiple character strings, but not words. To access words, you need to use PD layer
methods. For information see “Portable Document layer” on page 17.
1. Create an AVDoc object by invoking the AVAppGetActiveDoc method. This method gets the
frontmost document located within Adobe Reader or Acrobat.
Adobe Acrobat SDK Working with Page Views and Contents
Developing Plug-ins and Applications Accessing page contents 126
2. Create an AVPageView object by invoking the AVDocGetPageView method. This method requires
an AVDoc object and returns an AVPageView object.
3. Get the current page number of the PDF document by invoking the AVPageViewGetPageNum
method. This method requires an AVPageView object and returns a PDPageNumber object that
represents the current page number.
4. Create a PDDoc object by invoking the AVDocGetPDDoc method. This method requires an AVDoc
object and returns a PDDoc object.
5. Create a PDPage object by invoking the PDDocAcquirePage method. This method requires a PDDoc
object and a PDPageNumber object as arguments and returns a PDPage object.
1. Create a PDEContent object. For information, see “Creating a PDEContent object” on page 125.
2. Invoke the PDEContentGetNumElems method to retrieve the number of elements located within the
PDEContent object. This method requires a PDEContent object and returns an ASInt32 object that
specifies the number of elements.
3. Iterate through the PDEContent object and retrieve each element by invoking the
PDEContentGetElem method. This method requires a PDEContent object and an ASInt32 object
that specifies the element index (this is a zero-based value) and returns a PDEElement object that
represents a specific page property.
Adobe Acrobat SDK Working with Page Views and Contents
Developing Plug-ins and Applications Determining page element types 127
The following code example accesses each element located in a PDEContent object.
The following code example determines the element type by adding application logic to the application
logic introduced in “Accessing page contents” on page 127.
//Perform an action
}
Adobe Acrobat SDK Working with Page Views and Contents
Developing Plug-ins and Applications Modifying text elements 128
After you create a PDColorValueRec object, you can attach it to an AVPageView object by invoking the
AVPageViewSetColor method. This method requires an AVPageView object and a
PDVColorValueRec object. Once set, this color is used in drawing operations.
A text element is represented by a PDEText object, which is a container of text runs. A text run can be a
single character or multiple characters having the same attributes in a PDF file. You can get the number of
text runs located within a PDEElement object by invoking the PDETextGetNumRuns method and
passing the PDEElement object and casting it as a PDEText object.
int numRuns = PDETextGetNumRuns((PDEText) pdeElement);
You can draw a red border around each PDEText object by performing the following tasks:
1. Get the bounding box of the PDEText object by invoking the PDETextGetBBox method and passing
the following arguments:
● A PDEText object that represents the text element whose bounding box is obtained.
● A PDETextFlags value that specifies whether index refers to the character offset from the
beginning of the text object or the index of the text run. Must be either kPDETextChar for a text
character or kPDETextRun for a text run.
● An ASInt32 value that specifies the index of the character or text run.
● The address of an ASFixedRect object that is populated with the coordinates of the bounding
box of a specified character or text run.
2. Transform the bounding box's coordinates from user space to device space by invoking the
AVPageViewRectToDevice method and passing the following arguments:
● An AVPageView object that represents the page view for which the coordinates are transformed.
Use the same AVPageView object that was used to create a PDEContent object. For information,
see “Creating a PDEContent object” on page 125.
● The address of the ASFixedRect object that was passed to the PDETextGetBBox method. This
object contains coordinate data that is transformed.
● The address of an AVRect object that is populated with device space coordinates.
3. Draw a stroked, but not filled, rectangle by invoking the AVPageViewDrawRectOutline method
and passing the following arguments:
● An AVPageView object that represents the page view in which the rectangle is drawn.
● The address of the AVRect object that specifies device space coordinates. You can pass the address
of the same AVRect object that was passed to the AVPageViewRectToDevice method.
● An AVDevSize object that specifies the border width in pixels.
Adobe Acrobat SDK Working with Page Views and Contents
Developing Plug-ins and Applications Modifying text elements 129
● The address of an ASFixed object whose elements specify the length of dashes and gaps. You can
specify NULL to draw a solid outline.
● An AVTArraySize object that specifies the number of elements in the ASFixed object. This value
is ignored if you specified Null as the previous argument. As a result, you can specify 0 for this
argument. The maximum allowed number of elements is currently 10.
The following code example modifies page contents by placing a red border around text elements and
places a blue border around other elements that are located within a PDEContent object.
//Define red
red.space = PDDeviceRGB;
red.value[0] = ASInt32ToFixed(1);
red.value[1] = 0;
red.value[2] = 0;
//Define blue
blue.space = PDDeviceRGB;
blue.value[0] = 0;
blue.value[1] = 0;
blue.value[2] = ASInt32ToFixed(1);
//Release objects
PDPageRelease(pdPage);
PDPageReleasePDEContent (pdPage, gExtensionID);
11 Working with Words
This chapter explains how to use the Acrobat core API to search for words, extract and display words, and
highlight words. Using the Acrobat core API, you can, for example, create application logic that extracts
words from a PDF document and places each word in a repository.
About searching for words Describes searching for words. page 131
Creating a PDWordFinder object Describes how to create a PDWordFinder object. page 132
Extracting and displaying words Describes how to extract and display words. page 134
Each character in a word has a character type. Character types include: control code, lowercase letter,
uppercase letter, digit, punctuation mark, hyphen, soft hyphen, ligature, white space, comma, period,
unmapped glyph, end-of-phrase glyph, wildcard, word break, and glyphs that cannot be represented in
the destination font encoding. For information about character types, see the Acrobat and PDF Library API
Reference.
The PDWordGetCharacterTypes method can get the character type for each character in a word. The
PDWordGetAttr method returns a mask containing information on the types of characters in a word. The
mask is the logical OR of several flags, including the following:
● One or more characters in the word cannot be represented in the output encoding.
● One or more characters in the word are punctuation marks.
● The first character in the word is a punctuation mark.
● The last character in the word is a punctuation mark.
131
Adobe Acrobat SDK Working with Words
Developing Plug-ins and Applications About PDWordFinder typedefs 132
● The word contains a ligature (a special typographic symbol consisting of two or more characters such
as the English ligature used to replace the two-character sequence, f followed by i). Ligatures are used
to improve the appearance of a word.
● One or more characters in the word are digits.
● There is a hyphen in the word.
● There is a soft hyphen in the word.
A word’s location is specified by the offset of its first character from the beginning of the page (known as
the character offset). The characters are enumerated in the order in which they appear in page’s content
stream in the PDF file (which is not necessarily the order in which the characters are read when displayed
or printed).
A word also has a character delta, which is the difference between the number of characters representing
the word in the PDF file and the number of characters in the word. The character delta is non-zero, for
example, when a word contains a ligature.
Optionally, you can create a PDWordFinderConfigRec object when creating a PDWordFinder object.
A PDWordFinderConfigRec object enables you to customize how text is extracted. After you create an
PDWordFinderConfigRec object, allocate its buffer size and set the following attributes:
recsize: The size of the data structure. This attribute must be set to
sizeof(PDWordFinderConfigRec).
ignoreCharGaps: If true, this attribute disables the conversion of large character gaps to space
characters, so that the word finder reports a character space only when a space character appears in
the PDF content.
Adobe Acrobat SDK Working with Words
Developing Plug-ins and Applications Creating a PDWordFinder object 133
ignoreLineGaps: If true, this attribute disables the handling of vertical movements as line breaks, so
that the word finder determines a line break only when a line break character or special tag information
appears in the PDF content.
noAnnots: If true, this attribute disables the extraction of text from text annotations. Normally, the
word finder extracts text from the normal appearances of text annotations that are inside the page
crop box.
noEncodingGuess: If true, disables the guessing of the encoding of fonts that have unknown or
custom encoding, when there is no ToUnicode table. Inappropriate encoding conversions can cause
the word finder to mistakenly recognize non-Roman single-byte fonts as Standard Roman encoding
fonts and extract the text in an unusable format. When this option is selected, the word finder avoids
such unreliable encoding conversions and tries to provide the original characters without any
encoding conversion for a client with its own encoding handling.
Note: For a complete list of attributes that belong to an PDWordFinderConfigRec object, see the
Acrobat and PDF Library API Reference.
Create a PDWordFinder object that is based on an active document by performing the following tasks:
1. Create an AVDoc object by invoking the AVAppGetActiveDoc method. For information, see
“Opening PDF documents” on page 72.
2. Create a PDDoc object by invoking the AVDocGetPDDoc method and passing the AVDoc object.
Example 11.1 Creating a PDWordFinder object that is based on the current PDF document
//Get the current PDF document
AVDoc currentAVDoc = AVAppGetActiveDoc();
PDDoc currentPDDoc = AVDocGetPDDoc(currentAVDoc);
pConfig.ignoreCharGaps = true;
pConfig.ignoreLineGaps = true;
pConfig.noAnnots = true;
pConfig.noEncodingGuess = true;
PDWordProc is a callback that is invoked when a word is located. After you create a PDWordProc object,
you can invoke the ASCallbackCreateProto macro to convert a user-defined function to an Acrobat
callback. For example, you can invoke ASCallbackCreateProto to convert a user-defined function
named wordEnumerator to a callback function. The ASCallbackCreateProto macro requires the
following arguments:
● The callback type. In this situation, specify PDWordProc.
● The address of the user-defined function to convert to a callback function.
The ASCallbackCreateProto macro returns a callback of the specified type that invokes the
user-defined function whose address was passed as the second argument. The following lines of code
shows the ASCallbackCreateProto macro converting the wordEnumerator user-defined function
to a PDWordProc callback.
PDWordProc wordProc;
wordProc= ASCallbackCreateProto(PDWordProc, &wordEnumerator);
After you create a callback function, invoke the PDWordFinderEnumWords method to extract all words
from the specified page and pass the following arguments:
● A PDWordFinder object that is responsible for finding and extracting words.
● An ASInt32 value that represents the page number from which to extract words.
● A PDWordProc object that represents the callback function to invoke when a word is located.
● A pointer to user-supplied data to pass to the callback function. Pass NULL if you do not want to pass
user-supplied data.
To illustrate how to display words that are located on a page, this section contains a code example that
creates a callback function named wordEnumerator that performs the following tasks:
● Removes punctuation characters from the word by invoking the PDWordFilterWord method. The
encoding information passed to the PDDocCreateWordFinderEx method determines which
characters are removed.
● Invokes the PDWordGetString method to get the word as a string.
● Displays the string in an alert box by invoking the AVAlertConfirm method. If the user clicks OK, the
next word is displayed until all words for the document page have been displayed. If the user clicks
Cancel, this callback function returns false.
Adobe Acrobat SDK Working with Words
Developing Plug-ins and Applications Extracting and displaying words 135
The following code example extracts and displays all words that are located on the current PDF document
page. Included in this code example is application logic that creates a PDWordFinder object. For
information, see “Creating a PDWordFinder object” on page 132.
//Remove punctuation
PDWordFilterWord(wInfo, stringBuffer, 99, &wordLength);
stringBuffer[wordLength] = 0;
//Populate the char array with text that represents the word
PDWordGetString (wInfo, stringBuffer, 99);
return AVAlertConfirm(stringBuffer);
}
Note: In the previous code example, assume that the DisplayWords function was invoked from a menu
item. For information, see “Creating Menus and Menu Commands” on page 88.
Adobe Acrobat SDK Working with Words
Developing Plug-ins and Applications Highlighting words 136
Caution: If you pass true as the PDDocCreateWordFinderEx method’s third argument, then the word
finder encodes the extracted text in Unicode format. As a result, words will not be displayed
within the alert box. Notice in this code example, the value false is passed as the
PDDocCreateWordFinderEx method’s third argument.
Highlighting words
You can use the Acrobat core API to highlight a word or a group of words located within a PDF document.
By highlighting a word, you can make a specific word or group of words stand out. The following
illustration shows the word Adobe highlighted.
To highlight a word you must create a HiliteEntry object and set its offset and length attributes.
The offset attribute specifies the location of the word from the beginning of the document. For
example, if you specify 1, then the second word in the document is highlighted (this value is a 0-based
index). The length attribute specifies the number of words that are highlighted. If you specify 1, then a
single word is highlighted.
You can highlight a word that is located in the current page by performing the following tasks:
1. Create a HiliteEntry object and set its offset and length attributes.
2. Create an AVDoc object by invoking the AVAppGetActiveDoc method. For information, see
“Opening PDF documents” on page 72.
3. Create a PDDoc object by invoking the AVDocGetPDDoc method and passing the AVDoc object.
4. Get the page view by invoking the AVDocGetPageView method and passing the AVDoc object. This
method returns an AVPageView object. For information, see “Displaying page views” on page 124.
5. Get the current page number by invoking the AVPageViewGetPageNum method and passing the
AVPageView object. This method returns the page number of the current page view, which is required
to highlight a word or group of words.
Adobe Acrobat SDK Working with Words
Developing Plug-ins and Applications Highlighting words 137
6. Create a PDPage object by invoking the PDDocAcquirePage method and passing the following
arguments:
● A PDDoc object.
● The page number of the current page view.
The PDDocAcquirePage method returns a PDPage object.
8. Set the PDF document's text selection type by invoking the AVDocSetSelection method. This
method does not have a return value and requires the following arguments:
● An AVDoc object that represents the PDF document in which the highlighted words appear.
● An ASAtom object that specifies the selection type. Because words are highlighted, you can specify
text.
● A PDTextSelect object that represents the text selection. Cast the PDTextSelect object as a
void pointer.
● An ASBool object that specifies whether to highlight the selection. Pass the value true to
highlight the specified word(s).
9. Display the current selection by invoking the AVDocShowSelection method and passing the AVDoc
that represents the PDF document that contains the highlighted word(s).
10. Release the PDPage object by invoking the PDPageRelease method and passing the PDPage object.
The following code example highlights the tenth word that is located in the page of the current PDF document.
Adobe Reader and Acrobat plug-ins and PDF Library applications can add new types of tools, annotations,
actions, file systems, and so on, thereby expanding the number of supported object types. To accomplish
this task, the Acrobat core API provides a collection of callback routines called handlers that support
objects. Handlers perform operations, such as creating and destroy objects, handling mouse clicks,
handling keyboard events, and so on.
File format conversion Describes the characteristics of file format conversion page 145
handlers handlers.
File specification handlers Describes the characteristics of file specification handlers. page 146
Selection servers Describes the characteristics of selection server handlers. page 146
Adding message handlers Describes how to add Apple events and DDE messages. page 150
About handlers
To add a new handler, you must write callback functions, create the appropriate data structure containing
the callbacks and other data, and pass the structure to Acrobat by invoking the appropriate method.
Subsequently, Acrobat automatically invokes the correct callback when it encounters an object of the type
handled by the handler.
138
Adobe Acrobat SDK Creating Handlers
Developing Plug-ins and Applications Action handlers 139
It is possible to subclass existing handlers or to create entirely new handler types. For example, a plug-in
can subclass the built-in text annotation handler by adding the ability to hide annotations. To accomplish
this task, perform the following tasks:
1. Obtain the built-in text annotation handler structure by invoke the AVAppGetAnnotHandlerByName
method.
3. Replace the handler’s Draw callback with one that invokes the built-in Draw callback (obtained from
the structure) if annotations are visible, or simply return without drawing anything if annotations are
hidden.
4. Register the new handler by invoking the AVAppRegisterAnnotHandler method with a new type.
If a handler requires more data than provided in the predefined structures that are described in this
section, you can append additional data to the predefined structures. To do this, create a new structure
type with the predefined structure as its first member and the additional data as subsequent members.
Before passing the expanded structure to an Acrobat method, cast the structure to the predefined
structure type. Upon return of the structure from Acrobat, re-cast the structure to its expanded type to
access the appended data.
Each handler data structure contains a size field, which specifies the structure’s size. This field provides
future compatibility. Different versions of the structure have different sizes, allowing Acrobat to determine
which version your plug-in was written to use.
Note: Regardless of whether your plug-in adds data to the predefined structures, it must pass the size of
the predefined structure (rather than the size of its expanded structure) in the size field.
Action handlers
Support for action types can be added by defining and registering an action handler. For example, the
Acrobat Weblink plug-in uses this ability to add support for URL links.
To add a new action type, you must provide a set of callbacks. Specify them in the
AVActionHandlerProcs structure, and invoke the AVAppRegisterActionHandler method to
register them.
Annotation handlers
Support for annotation types in Acrobat can be added by defining and registering an annotation handler.
For example, the Acrobat movie plug-in uses an annotation handler to support video annotations.
To add an annotation type, you must provide a set of callbacks, specify them in the AVAnnotHandler
structure, and register them with AVAppRegisterAnnotHandler.
Note: For information about working with annotations, see “Creating Annotations” on page 108.
AVCommand handlers
An AVCommand represents an action that a user can perform on the current document or the current
selection in the current document. AVCommands are exposed to Adobe Reader or Acrobat through
AVCommand handlers. You can add new command types by defining and registering an AVCommand
handler. Commands can be executed interactively, programmatically, or through batch processing.
Invoking AVCommands
To programmatically invoke AVCommands using AVCommand methods, perform the following tasks:
1. Instantiate the command by invoking the AVCommandNew method, providing the registered name of
the command:
ASAtom cmdName;
AVCommand cmd;
cmdName = ASAtomFromString ("MinimalCommand");
cmd = AVCommandNew(cmdName);
Configuring AVCommands
Prior to executing an AVCommand, you configure three categories of properties:
● Input parameters (required)
● Configuration parameters (optional - initialized to defaults)
● AVCommand parameters (optional - initialized to defaults)
// Handle error
Note: For more information about the AVCommandSetInputs method, see the Acrobat and PDF Library
API Reference.
You can create an ASCab object to store the appropriate parameters; then create empty ASText objects
to hold the parameter values and place these values into the ASCabs object. The following example uses
this approach to set the Document Summary Title and Subject values.
Running commands
The following code example shows an entire example of creating an AVCommand and running it.
ASTextSetEncoded(text, docTitleValue,(ASHostEncoding)PDGetHostEncoding());
ASCabPutText (params, docTitleValue, text);
Although this step can be performed at any time once the command handler is registered, handlers
commonly register commands from within the AVCommandRegisterCommandsProc callback (of the
AVCommandHandlerRec structure).
Supporting properties
When building a list of batchable commands, Adobe Reader or Acrobat iterates through its internal
command list, querying each command for the CanBatch and GroupTitle properties. To be exposed
through the batch framework user interface, a command must support these properties (that is, return
true and a valid ASText object, respectively). The AVCommand handler must implement the GetProps
callback of the AVCommandHandlerRec structure.
If an AVCommand supports these properties, Adobe Reader or Acrobat queries a number of additional
properties as the user interacts with the batch framework. Of these additional properties, only two are
required: Title and Generic Title. A command must provide the title strings that will be displayed in
the Batch Sequences and Batch Edit Sequence dialog boxes.
Adobe Acrobat SDK Creating Handlers
Developing Plug-ins and Applications File format conversion handlers 145
Note: The params object was declared in “Running an AVCommand” on page 143.
To add a new file conversion handler, you provide a set of callback functions, specify them in the
AVConversionToPDFHandler or AVConversionFromPDFHandler structures, and invoke the
AVAppRegisterToPDFHandler or AVAppRegisterFromPDFHandler methods to register them.
Specify the file types that the plug-in can convert and whether it can perform synchronous conversion
(required for the handler to be accessible from the batch framework). Upon registration, the conversion
handlers are automatically added to the respective Open and Save As dialog boxes.
Adobe Acrobat SDK Creating Handlers
Developing Plug-ins and Applications File specification handlers 146
By using a file format conversion handler, you can perform the following tasks:
● Provide default settings for the conversion by using the AVConversionDefaultSettingsProc
callback method.
● Provide conversion parameter information by using the AVConversionParamDescProc callback
method.
● Display a settings dialog box by using the AVConversionSettingsDialogProc callback method.
● Convert a non-PDF file to or from a PDF file by invoking either the
AVConversionConvertToPDFProc or AVConversionConvertFromPDFProc callback methods.
To create a new file specification handler, a plug-in or application must provide callbacks that:
● Convert an ASPathName to a PDFileSpec. It is called by PDFileSpecNewFromASPath.
● Convert a PDFileSpec to an ASPathName.
Selection servers
A selection server enables the selection of specific data types such as annotations, text, or graphics. You
can also create selection servers to enable the selection of data types not already supported. To add a new
selection server, you must provide a set of callbacks, specify them in the AVDocSelectionServer data
structure, and register them using an AVDocRegisterSelectionServer object.
For a complete list of the callbacks in a selection server, see the description of AVDocSelectionServer
in the Acrobat and PDF Library API Reference.
Note: The SelectionServer sample plug-in that is located in the Acrobat SDK shows an example of a
selection server.
Tool callbacks
To add a new tool, you must provide a set of callbacks, specify them in the AVTool data structure, and
register them using AVAppRegisterTool. By using tool callbacks, you can perform the following tasks:
● Activate the tool when the tool is selected by using the ActivateProcType callback method.
● Deactivate the tool when another tool is selected by using the DeactivateProcType callback
method.
● Handle mouse clicks by using the DoClickProcType callback method.
● Handle key presses by using the DoKeyDownProcType callback method.
● Control the cursor shape by using the AdjustCursorProcType callback method.
● Return the tool’s name by using the GetTypeProcType callback method.
● Indicate whether the tool stays active after it is used by using the IsPersistentProcType callback
method.
● Determine whether the tool is enabled by using the AVComputeEnabledProc callback method. For
example, if a tool is meant to be used within documents, but there are no documents open, it does not
make sense to activate the tool.
Note: For a complete list of callbacks, see the description of AVTool in the Acrobat and PDF Library API
Reference.
Window handlers
When a plug-in creates a window, it can register the window, so that it behaves like other windows in
Acrobat; for example, when Adobe Reader or Acrobat is minimized or hidden. For each window that a
plug-in provides, a window handler must be provided. Window handlers are used only in the Mac OS
version of Adobe Reader or Acrobat. Windows and UNIX versions of Acrobat instead use the platform’s
native window handling mechanisms. For information, see “Opening a PDF document in an external
window” on page 74.
To define a window handler, you must provide a set of callbacks, specify them in an AVWindowHandler
structure, and pass the structure to AVWindowNew or AVWindowNewFromPlatformThing. The window
handler’s callbacks are automatically called by Acrobat. Default behavior is used for any missing callbacks.
● Do anything that must be done when the window is activated or deactivated by using the following
callback methods: AVWindowDidActivateProc or AVWindowWillDeactivateProc.
● Permit or constrain window size changes by using the AVWindowWillBeResizedProc callback
method.
● Determine whether the Cut, Copy, Paste, Clear, SelectAll, and Undo menu items are enabled by using
the AVWindowCanPerformEditOpProc callback method.
● Perform Cut, Copy, Paste, Clear, SelectAll, and Undo operations by using the
AVWindowPerformEditOpProc callback method.
● Control the shape of the cursor when it is within the window by using the
AVWindowAdjustCursorProc callback method.
For a complete list of callbacks in a window handler, see the description of AVWindowHandler in the
Acrobat and PDF Library API Reference.
File systems
Plug-ins can add new file systems to Acrobat or Adobe Reader, to access files on a device that cannot be
accessed as a local hard disk, such as a socket or a modem line.
To add a new file system, you must provide a set of callbacks and specify them in the ASFileSysRec
structure. This structure is passed as a parameter to calls that require a file system. A file system handler
does not require explicit registration.
By using a file system handler, you can perform the following tasks:
● Open a file by using the ASFileSysOpenProc callback method.
● Close a file by using the ASFileSysCloseProc callback method.
● Flush a file’s buffered data to disk by using the ASFileSysFlushProc callback method.
● Get or set the current position in a file by using one of the following callback methods:
ASFileSysSetPosProc or ASFileSysGetPosProc.
● Get or set a file’s logical size by using one of the following callback methods: ASFileSysGetEofProc
or ASFileSysSetEofProc.
● Read data from a file by using the ASFileSysReadProc callback method.
● Write data to a file by using the ASFileSysWriteProc callback method.
● Delete a file by using the ASFileSysRemoveProc callback method.
● Rename a file by using the ASFileSysRenameProc callback method.
● Get a file’s name by using the ASFileSysGetNameProc callback method.
● Get a file system’s name by using the ASFileSysGetFileSysNameProc callback method.
● Determine whether two files are the same by using the ASFileSysIsSameFileProc callback
method.
● Get a path to a temporary file by using the ASFileSysGetTempPathNameProc callback method.
● Copy a path (not the underlying file) by using the ASFileSysCopyPathNameProc callback method.
● Convert between device-independent and device-dependent path by using the
ASFileSysDiPathFromPathProc callback method.
Adobe Acrobat SDK Creating Handlers
Developing Plug-ins and Applications Progress monitors 149
● Dispose of a path (not the underlying file) by using the ASFileSysDisposePathNameProc callback
method.
● Flush data on a volume by using the ASFileSysFlushVolumeProc callback method.
● Handle asynchronous I/O operations by using the following callback methods:
ASFileSysAsyncReadProc or ASFileSysAsyncWriteProc.
● Handle multiple read requests by using the ASFileSysMReadRequestProc callback method.
For details on each of the callbacks in a file system, see the description of ASFileSysRec in the Acrobat
and PDF Library API Reference.
Progress monitors
Progress monitors provide feedback to a user on the progress of a time-consuming operation. Some
potentially time-consuming methods in the Acrobat core API require a progress monitor as a parameter.
Acrobat has a default progress monitor, which generally is sufficient for plug-ins to use. The built-in
progress monitor can be obtained by using the AVAppGetDocProgressMonitor method.
Plug-ins can use the default progress monitor or implement their own by providing a set of callbacks,
specifying them in the ASProgressMonitorRec data structure, and passing a pointer to the structure to
the methods that require a progress monitor (there is no explicit registration method).
For details, see the description of ASProgressMonitorRec in the Acrobat and PDF Library API Reference.
Transition handlers
Transitions allow effects such as dissolves or wipe-downs when displaying a new page. New transition
types can be added by defining and registering a transition handler.
To add a new transition, you must provide a set of callbacks, specify them in the AVTransHandler data
structure, and register them by invoking the AVAppRegisterTransHandler method.
● Fill in the transition dictionary in the PDF file by using either the
AVTransHandlerInitTransDictProc or AVTransHandlerCompleteTransDictProc
methods.
● Provide information for the user interface that sets the attributes of the transition by invoking the
AVTransHandlerGetUINameProc method.
If a plug-in receives an Apple event it does not want to handle, it should invoke the implementation of the
method it replaced, allowing other plug-ins or Acrobat or Adobe Reader the opportunity to handle the
Apple event. Acrobat and Adobe Reader on UNIX do not currently provide built-in IAC support, but
plug-ins can add IAC support via RPC or other mechanisms.
Note: Plug-ins should use the DDEML library to handle DDE messages. Problems may arise if they do not.
13 Registering for Event Notifications
This chapter explains how to register for notification of a specific event. The Acrobat core API provides a
notification mechanism so that plug-ins can synchronize their actions with Acrobat or Adobe Reader.
Notifications enable plug-ins to indicate that they are interested in a specified event (such as the
initialization of Adobe Reader or Acrobat) and to provide a callback function that is invoked by Adobe
Reader or Acrobat each time an event occurs.
The order in which notifications occur may vary depending on the platform. For example, after opening a
PDF document on the Windows platform, notifications occur in this order:
1. AVPageViewDidChange
2. AVDocDidOpen
3. AVDocDidActivate
4. AVPageViewDidChange
In contrast, after opening a PDF document in Mac OS, notifications occur in this order:
1. AVPageViewDidChange
2. AVDocDidActivate
3. AVPageViewDidChange
4. AVDocDidOpen
Registering event notifications Describes how to register for event notifications. page 151
Unregistering event notifications Describes how to unregister event notifications. page 153
151
Adobe Acrobat SDK Registering for Event Notifications
Developing Plug-ins and Applications Registering event notifications 152
You can register for an event notification by performing the following tasks:
The following code example registers for the event that occurs when Adobe Reader or Acrobat is finished
initializing. The name of the callback function is myNotificationCallback. This function simply
displays an alert box. Note that AVAppRegisterNotification is invoked within the PluginInit
method. For information about this method, see “Handshaking and Initialization” on page 28.
The following example unregisters the event notification that occurs when Adobe Reader or Acrobat has
initialized.
Note: Pass the same arguments that you specified when you registered for the event notification. For
information, see “Registering event notifications” on page 151.
14 Working with Document Security
This chapter describes the document security features of the Acrobat core API. This chapter contains the
following information.
About security handlers Describes the characteristics of security handlers. page 154
Setting security for a document Describes how to set security for a document. page 159
Each stream or string object in a PDF file is individually encrypted. This level of encryption improves
performance because objects can be individually decrypted as needed rather than decrypting an entire
file. All objects, except for the encryption dictionary (which contains the security handler’s private data),
are encrypted using the RC4 algorithm Adobe licenses from RSA Data Security, Inc. A plug-in may not
substitute another encryption scheme for RC4.
A plug-in that implements a security handler is responsible for encrypting the values it places into the
encryption dictionary, and it may use any encryption scheme. If the security handler does not encrypt the
values it places into the encryption dictionary, the values are in plain text.
The core API provides two Cos layer methods to encrypt and decrypt data using the RC4 algorithm. These
methods are CosEncryptData and CosDecryptData. For information about these methods, see the
Acrobat and PDF Library API Reference.
Security handlers may use these methods to encrypt data they want to put into the PDF file’s encryption
dictionary and decrypt data when it is read from the dictionary. Security handlers may instead choose to
ignore these methods and use their own encryption algorithms.
Note: In addition, Acrobat provides other ways to secure a PDF document such as public key security and
policies that are created by Adobe LiveCycle® Policy Server. For information, see the Acrobat and PDF
Library API Reference.
154
Adobe Acrobat SDK Working with Document Security
Developing Plug-ins and Applications Adding a security handler 155
You can use the Acrobat core API’s built-in security handler or write your own security handlers to perform
user authorization (for example, by the presence of a specific hardware key or file, or by reading a
magnetic card reader).
A document may have zero, one, or two security handlers associated with it. A document has zero security
handlers if no security is used on the file. When security is applied to a file, or the user selects a different
security handler for a secured file, the newly-chosen security handler is not put in place immediately.
Instead this new security handler is simply associated with the document; it is a pending security handler
until the document is saved.
The new security handler is not put in place immediately because it is responsible for decrypting the
contents of the document’s encryption dictionary, and that dictionary is re-encrypted in the correct
format for the new security handler only when the document is saved. As a result, a document may have
both a current and a new security handler associated with it.
A security handler has two names: one that is placed in each PDF file that is saved by the handler (for
example, ADBE_Crypt), and another name that Acrobat can use in any user interface items in which the
security handler appears (for example, Acrobat Developer Technologies default encryption). This is similar
to the two-name scheme used for menu items: a language-independent name that the application logic
can refer to regardless of the user interface language, and another name that appears in the user interface.
For information, see “Adding menu commands to menus” on page 90.
With Acrobat 5.0 and later, a finer granularity of permissions has been predefined for objects supported by
a PDF document. Plug-ins can invoke the PDDocPermRequest method to request whether a particular
operation is authorized to be performed on a specified object in a document.
To support the PDDocPermRequest method, there are two new callback methods:
PDCryptAuthorizeExProc and PDCryptGetAuthDataExProc. Acrobat 5.0 and later also includes
optional security handling for batch operations (operations on one or more files). There are a number of
callbacks (indicated by PDCryptBatch... ) that a security handler must provide to support batch processing.
These callbacks are part of a PDCryptBatchHandler structure. The PDCryptHandlerRec structure
contains a new member CryptBatchHandler, which points to this structure.
To support batch processing, a security handler should provide a non-NULL value for
CryptBatchHandler and implement the batch callbacks. Prior to Acrobat 5.0, the maximum length of
the encryption key that Acrobat accepted was 40 bits. Acrobat version 5.0 or later accommodates an
encryption key length of 128 bits. These length limitations are imposed to comply with export restrictions.
Adobe Acrobat SDK Working with Document Security
Developing Plug-ins and Applications Opening a secured file 157
2. If the authorize callback returns true, the file is opened. Otherwise, the authorization procedure
executes the following steps up to three times, to give the user three chances to enter a password, or
whatever authorization the security handler uses.
● It calls the security handler’s get authorization data callback (PDCryptGetAuthDataExProc or
the older PDCryptGetAuthDataProc). This callback should obtain the authorization data using
whatever user interface (for example, a dialog box used to obtain a password) or other means
necessary, and then creates and fills the authorization data structure.
● It calls the security handler’s authorize callback, passing the authorization data returned by the get
authorization data callback. If the authorization succeeds, the authorize callback returns the
permissions granted to the user, and the authorization procedure returns.
The authorize callback can access the encrypted PDF document, allowing it to encrypt the authorization
data using a mechanism that depends on the document’s contents. By doing this, someone who knows a
document’s password cannot easily find out which other documents use the same password. The
authorize callback can return permissions that depend on the password as well as the permissions
specified when encryption was set up. This allows, for example, more rights to be granted to someone
who knows a document’s owner password than to someone who knows the document’s user password.
The authorization procedure must implement the authorization strategy, such as giving the user three
chances to enter a password. The PDAuthProc is not part of a security handler, but it must call the
security handler’s methods to authorize the user (for example, to get the password from the user and to
check whether or not the password is valid).
1. Searches for an Encrypt key in the PDF document’s trailer, to determine whether or not the document is
encrypted. If there is no Encrypt key, Acrobat opens the document immediately.
2. If there is an Encrypt key, its value is an encryption dictionary. Acrobat gets the value of the Filter key in
the dictionary to determine which security handler was used when the file was saved. It looks in the list
of registered security handlers (which contains Acrobat’s built-in handler and any handlers that
plug-ins or applications have registered) for one whose name matches the name found in the PDF file.
For information about a dictionary, see “Working with Cos dictionaries” on page 186.
Adobe Acrobat SDK Working with Document Security
Developing Plug-ins and Applications Saving a secured file 158
3. If Acrobat finds no match, indicating that the necessary handler could not be found, it does not open
the document. If it finds a matching security handler, it invokes that handler’s
PDCryptNewSecurityDataProc callback to extract and decrypt information from the PDF file’s
encryption dictionary.
4. Acrobat invokes the security handler’s authorize callback (PDCryptAuthorizeExProc) with NULL
authorization data, and with the requested permissions set to PDPermReqOprOpen or pdPermOpen
(requesting that the user be allowed to open the file). This allows support for authorization schemes
that do not need authorization data.
5. If authorization succeeds, the handler’s authorization callback must return the PDPermReqStatus
(when the callback is PDCryptAuthorizeExProc) or pdPermOpen (when the callback is
PDCryptAuthorizeProc) indicating that the user is permitted to open the file.
6. If authorization fails, the authorization procedure passed in the call to open the PDDoc is called.
When security is set, the security handler obtains the permissions and authorization data (such as
passwords) to be used for the file. The settings do not take effect until the file is saved, as described in the
previous section.
3. PDCryptFillEncryptDictProc writes data from the security data structure into the encryption
dictionary. When Acrobat is done with the security data structure, it invokes the
PDCryptFreeSecurityDataProc method.
2. PDCryptAuthorizeExProc is invoked and returns NULL since the authorization permissions have
not been determined. This callback should not present a user interface.
3. The plug-in does not use the authorization data structure, but instead only the security data structure.
It calls an internal authorization procedure that determines the authorization level of the logged-in
user. This authorization procedure is the same procedure as is called by
PDCryptUpdateSecurityDataProc in the previous section.
This chapter explains how to work with Acrobat or Adobe Reader’s support of Unicode paths. Using this
feature, you can programmatically open and save Unicode-named files and select Unicode-named folders.
You can, for example, enable a user to open a Unicode-named file and view the corresponding PDF
document in Acrobat or Adobe Reader.
Creating Unicode file path Describes how to create application logic to work with page 160
application logic Unicode paths.
Retrieving Unicode path values Describes how to retrieve Unicode path values. page 161
You can programmatically use this feature by obtaining a pointer to the Unicode file system fileSys
argument and then invoking a method that accepts the fileSys argument. The Windows Unicode file
system can be obtained by either invoking the ASGetDefaultUnicodeFileSys method or by invoking
the ASFileGetFileSysByName method and passing either ASAtomFromString("Win").
Never assume that the ASPathName argument is a character pointer. Do not typecast any character value
to an ASPathName, and do not typecast a returned ASPathName value to a character pointer. If you are
passing an ASPathName argument without a file system argument, then ensure that you add the file
system argument.
Never assume that path and file names can be stored and passed as character pointers (char * values). If
you have limited code that passes file names, then change them to an ASText value or to something that
is capable of storing a full Unicode path. If you have a lot of code that passes character pointer values as
file names, then consider changing the internal representation of those character pointer values to UTF-8
encoded file names.
160
Adobe Acrobat SDK Working with Unicode Paths
Developing Plug-ins and Applications Retrieving Unicode path values 161
The following table lists Acrobat core API methods that should be replaced by newer methods in order to
work with Unicode paths.
ASPathFromPlatformPath ASFileSysCreatePathName
ASPathFromPlatformPathEx ASFileSysCreatePathName
ASFileSysCreatePathName("Cstring") ASFileSysCreatePathName("ASTextPath")
ASFileSysCreatePathName("Folder ASFileSysCreatePathName("FolderPathName
PathName") WithASText")
ASFileSysCreatePathName("DIPath") ASFileSysCreatePathName("DIPathWithAS
Text")
ASFileSysGetNameFromPath ASFileSysGetNameFromPathAsASText
ASFileSysDisplayStringFromPath ASFileSysDisplayASTextFromPath
ASFileSysDIPathFromPath ASFileSysDIPathFromPathEx
ASFileSysPathFromDIPath ASFileSysPathFromDIPathEx
If you have Windows-specific application logic that uses ASPlatformPathGetCstringPtr to get the
native path name, invoke the ASFileSysAcquirePlatformPath method and pass WinUnicodePath
as the platformPathType argument. The ASPlatformPathGetCstringPtr method will return an
ASUTF16 path.
You can create an ASPathName object by using one of the following methods:
● ASFileSysCreatePathName
● ASFileSysPathFromDIPathEx
When you invoke either one of these methods, you must create an ASFileSys object to use as an
argument.
Adobe Acrobat SDK Working with Unicode Paths
Developing Plug-ins and Applications Creating an ASFileSys object 162
To create an ASFileSys object, invoke the ASGetDefaultFileSysForPath method and specify the
following arguments:
● An ASAtom object that defines the format of the pathSpec argument (second argument). To create an
ASAtom object, invoke the ASAtomFromString method and pass one of the following values:
● DIPathWithASText if the pathSpec is a DIPath being passed to
ASFileSysPathFromDIPathEx.
● ASTextPath for Windows
● FSRef, CFURLRef, POSIXPath, FSSpec or Cstring for Mac OS
● Cstring for UNIX
● A void pointer that specifies the location of the file.
On Windows, the ASGetDefaultFileSysForPath method checks the specified path values and
decides if the classic default file system is used works or if the Unicode file system is used. On Mac OS and
UNIX, the default file system is always returned (because neither has a separate Unicode file system; Mac
OS already supports Unicode-named paths).
The following code example creates an ASFileSys object as part of the process of opening a PDF file. For
information, see “Opening PDF documents” on page 72.
A Unicode file system can be retrieved by using the ASFileGetFileSysByName method if you pass Win
(or ASAtomFromString(“Win”)) for the ASAtom name argument.
Note: The classic Windows file system supports both Cstring and WinUnicodePath in its
implementation of the ASFileSysAcquirePlatformPath and
ASPlatformPathGetCstringPtr methods.
The following code example retrieves the host encoded platform path on Windows.
In contrast, the following code example retrieves a Unicode platform path on Windows.
Note that the ASPlatformPathGetCstringPtr method is still called to get the path string, but that a
wide-char string is returned since WinUnicodePath was passed to the
ASFileSysAcquirePlatformPath method.
16 Working with Host Function Tables
A host function table (HFT) is the mechanism through which plug-ins and PDF lLibrary applications invoke
methods in Adobe Reader and Acrobat, as well as other plug-ins. Acrobat and Adobe Reader have HFTs
containing pointers to all Acrobat core API methods. In addition, a plug-in may create its own HFT to
export its methods to other plug-ins. This chapter illustrates how to export and import HFTs.
About host function tables Describes host table functions. page 164
Exporting host table functions Describes how to export host table functions to other plug-ins. page 165
Importing an existing HFT Describes how to import host table functions. page 173
Invoking HFT methods Describes how to invoke HFT methods. page 174
Replacing HFT methods Describes how to replace methods that are located in page 174
existing HFTs.
Migrating non-HFT PDF Library Describes how to migrate non-HFT PDF Library page 176
applications to HFT applications applications to HFT applications
Each entry represents a single method that a plug-in can invoke, and is defined as a linked list of function
pointers. Adobe Reader or Acrobat uses linked lists because some HFT entries may be marked so that they
can be replaced by a plug-in. Also, it is useful to keep a list of each implementation of a method that has
been replaced (to allow methods to call the implementations they replaced).
164
Adobe Acrobat SDK Working with Host Function Tables
Developing Plug-ins and Applications Exporting host function tables 165
The following diagram shows the relationship between Adobe Reader or Acrobat, other plug-ins, and HFTs.
Plug-in
Acrobat
HFTs
application
HFTs
Plug-in
Plug-ins must use the ASExtensionMgrGetHFT method to import each HFT they intend to use. A
plug-in requests an HFT by its name and version number. An HFT is imported during plug-in initialization.
For information, see “Importing HFTs and registering for notifications” on page 29.
When a plug-in invokes a method in Adobe Reader, Acrobat, or another plug-in, the function pointer at the
appropriate location in the appropriate HFT is dereferenced and executed. Macros in the Acrobat SDK’s
header files hide this functionality, so that plug-ins contain only what appear to be normal function calls.
Each HFT is serviced by an HFT server. The HFT server is responsible for handling requests to obtain or
destroy its HFT. As part of its responsibility to handle requests, an HFT server can choose to support
multiple versions of the HFT. These versions generally correspond to versions of Acrobat, Adobe Reader or
the plug-in that exposes the HFT.
The ability to provide more than one version of an HFT improves backward-compatibility by allowing
existing plug-ins to continue to work when new versions of Acrobat or Adobe Reader (or other plug-ins
whose HFTs they use) become available. It is expected that HFT versions typically will differ only in the
number, not the order, of methods they contain.
1. Create the HFT methods that you want to make available to other plug-ins.
Note: The remaining parts of this section examine each step in detail.
Adobe Acrobat SDK Working with Host Function Tables
Developing Plug-ins and Applications Creating HFT methods 166
The indexes are called selectors, hence the SEL at the end of the method names. BeepOnce is at index 1;
BeepTwice, at index 2; and BeepNTimes, at index 3. You can specify the number of indexes in the HFT by
defining the following statement:
#define NUMSELECTORS (NUMSELECTORSPlusOne - 1);
For example, to define an HFT method name, you must specify an HFT object. For information, see
“Defining an HFT method name” on page 167.
Adobe Acrobat SDK Working with Host Function Tables
Developing Plug-ins and Applications Creating HFT method definitions 167
For example, to define a function pointer to the BeepNTimes method, specify the following syntax:
typedef ACCBPROTO1 void (ACCBPROTO2 *BeepNTimesSELPROTO)(ASInt32 numtimes);
ACCBPROTO1 and ACCBPROTO2 are macros whose definitions are platform-specific (for example, in Mac
OS, ACCBPROTO1 is defined as pascal). BeepNTimesSELPROTO specifies a pointer to the BeepNTimes
method. Without using these macros, you would have to use the following syntax:
typedef void (*func)(ASInt32 numtimes);
method_name The name of the HFT method that is used to invoke the method from external
plug-ins.
HFTname The name of the HFT object.
For example, to define a method name for the BeepNTimesImplementation method, specify the
following:
#define BeepNTimes (*((BeepNTimesSELPROTO)(gMyHFT[BeepNTimesSEL])))
This macro defines the symbol BeepNTimes, which is the HFT method name.
gMyHFT[BeepNTimesSEL] is the function pointer obtained by indexing the HFT and
BeepNTimesSELPROTO casts the pointer to the right type. The end result is that the method can be
invoked by specifying the HFT method name:
BeepNTimes(3);
HFT method names and the implementation method names must be different to avoid conflict between
the #define statement and the corresponding method name.
Adobe Acrobat SDK Working with Host Function Tables
Developing Plug-ins and Applications Creating HFT callback functions 168
To create an HFT callback function, declare an HFT ServerProvideHFTProc object that represents the
callback:
HFTServerProvideHFTProc provideMyHFTCallback
The ASCallbackCreateProto macro returns a callback of the specified type that invokes the
user-defined function whose address was passed as the second argument. The following lines of code
show the ASCallbackCreateProto macro converting the ProvideMyHFT user-defined function to a
PDWordProc callback.
HFTServerProvideHFTProc provideMyHFTCallback =
ASCallbackCreateProto(HFTServerProvideHFTProc, &ProvideMyHFT);
The callback function is invoked when another plug-in attempts to use the HFT. After you create an HFT
callback function, you can invoke the HFTServerNew method to obtain an HFT Server object, which is
responsible for handling requests to obtain or destroy its HFT. An HFTServer object is required in order to
create a new HFT object.
The following code example creates an HFT callback function within the PluginExportHFTs method.
After the HFTServerProvideHFTProc object is created, the HFTServerNew method is invoked which
creates an HFTServer object.
DURING
//Create an HFT callback function
provideMyHFTCallback = ASCallbackCreateProto(HFTServerProvideHFTProc,
&ProvideMyHFT);
Note: In the previous code example, the gMyHFT, gMyHFTServer, and gSomethingWentWrong
variables are declared as global variables. To view the complete code example, including the
location of where these global variables are declared, see “Examining HFT header and source files”
on page 170.
1. Create an HFT object by invoking the HFTNew method. This method requires an HFTServer object
and the number of entries in the new HFT as arguments. The number of entries determines how many
methods that the HFT contains. Each method occupies one entry.
2. Invoke the HFTReplaceEntry method to populate the entries in the HFT object with pointers to the
HFT methods. This method requires the following arguments:
● An HFT object that you want to populate.
● The entry in the HFT object to replace. You can specify an index value that is specified in the
enumeration that you created. For example, you can specify BeepTwiceSEL. For information, see
“Creating HFT method definitions” on page 166.
● An HFTEntry object that represents a method that will become available through the HFT. You
can, for example, reference the BeepTwiceImplementation method by passing the
ASCallbackCreateReplacement method, as shown in the following example:
ASCallbackCreateReplacement(BeepTwiceSEL,&BeepTwiceImplementation)
● The new entry's properties. Currently, only HFTEntryReplaceable is defined.
You must invoke the HFTReplaceEntry method for each method that you expose through the HFT. For
example, if you expose three methods through the HFT, then you invoke the HFTReplaceEntry method
three times.
The following code example shows the syntax of the ProvideMyHFT method, which is the HFT callback
function defined in the previous section. Within this method, a new HFT is created. For information about
HFT callback methods, see “Creating HFT callback functions” on page 168.
Adobe Acrobat SDK Working with Host Function Tables
Developing Plug-ins and Applications Examining HFT header and source files 170
DURING
/*
** Replace the entries in the HFT
** with the methods that you want to make available.
*/
HFTReplaceEntry (gMyHFT,
BeepOnceSEL,ASCallbackCreateReplacement(BeepOnceSEL,&BeepOnce
Implementation), 0);
HFTReplaceEntry (gMyHFT,
BeepTwiceSEL,ASCallbackCreateReplacement(BeepTwiceSEL,&BeepTwice
Implementation), 0);
HFTReplaceEntry (gMyHFT,
BeepNTimesSEL,ASCallbackCreateReplacement(BeepNTimesSEL,&BeepNTimes
Implementation), 0);
HANDLER
return NULL;
END_HANDLER
return gMyHFT;
}
enum
{
DUMMYBLANKSELECTOR,
BeepOnceSEL,
BeepTwiceSEL,
BeepNTimesSEL,
NUMSELECTORSPlusOne
};
extern HFT gMyHFT;
AVSysBeep (0);
AVAlertNote ("In BeepOnceImplementation function.");
}
/* The implementation for the BeepTwice() function. Note it has a
** different name than the #define for the function in MyHFT.h
*/
ACCB1 void ACCB2 BeepTwiceImplementation()
{
AVSysBeep (0);
AVSysBeep (0);
AVAlertNote ("In BeepTwiceImplementation function.");
}
/* The implementation for the BeepNTimes() function. Note it has a
** different name than the #define for the function in MyHFT.h
*/
ACCB1 void ACCB2 BeepNTimesImplementation (ASInt32 numtimes)
{
ASInt32 i;
for (i=0; i < numtimes; i++)
AVSysBeep (0);
AVAlertNote ("In BeepNTimesImplementation function.");
}
/*
** Create a new HFT of NUMSELECTORS entries
** Then put the methods into the table via HFTReplaceEntry
*/
ACCB1 HFT ACCB2 ProvideMyHFT(HFTServer server, ASUns32 version,void *rock)
{
ACCB1 HFT ACCB2 ProvideMyHFT(HFTServer server, ASUns32 version,void *rock)
{
//Ensure version is 1
if (version != 1)
return NULL;
DURING
/*
** Replace the entries in the HFT
** with the methods that you want to make available.
*/
HFTReplaceEntry (gMyHFT,
BeepOnceSEL,ASCallbackCreateReplacement(BeepOnceSEL,&BeepOnceImplementation)
, 0);
HFTReplaceEntry (gMyHFT,
BeepTwiceSEL,ASCallbackCreateReplacement(BeepTwiceSEL,&BeepTwice
Implementation), 0);
HFTReplaceEntry (gMyHFT,
BeepNTimesSEL,ASCallbackCreateReplacement(BeepNTimesSEL,&BeepNTimes
Implementation), 0);
HANDLER
return NULL;
Adobe Acrobat SDK Working with Host Function Tables
Developing Plug-ins and Applications Importing an existing HFT 173
END_HANDLER
return gMyHFT;
}
/*
** Called by viewer to set up for exporting an HFT. This method
** creates a new HFT server and provides a callback that
** provides the HFT.
*/
ACCB1 ASBool ACCB2 PluginExportHFTs(void)
{
gMyHFTServer = NULL;
DURING
HANDLER
return false;
END_HANDLER
return true;
}
The ASExtensionMgrGetHFT method returns an HFT object. The following code example shows the
PluginImportReplaceAndRegister handshaking method that contains application logic that
imports the MyHFT HFT.
Note: Both the exporting and importing plug-ins must be located in Acrobat or Adobe Reader’s plug-ins
directory. If the exporting plug-in is not located in this directory, the importing plug-in cannot
successfully import an HFT.
Adobe Acrobat SDK Working with Host Function Tables
Developing Plug-ins and Applications Invoking HFT methods 174
However, you must include the header file that defines the HFT method name in the source file in which an
HFT method is invoked. Because the above methods are declared in a header file named myhft.h, you
must specify the following statement to successfully invoke these methods:
#include "myhft.h"
If you do not include the appropriate header file, you will receive a compile error.
The following table lists all the replaceable Acrobat and Adobe Reader methods.
AVAlert AVAppCanQuit
AVAppHandleAppleEvent AVDocClose
AVDocDoPrint AVDocDoSave
AVDocDoSaveAs AVDocDoSaveAsWithParams
(not replaceable in Adobe Reader) (not replaceable in Adobe Reader)
AVDocOpenFromASFileWithParams AVDocPrintPages
AVDocPrintPagesWithParams AVPageViewGetNextView
PDDocSave PDDocSaveWithParams
(not replaceable in Adobe Reader) (not replaceable in Adobe Reader)
PDImageSelectAlternate
To replace one of these methods, a plug-in invokes the HFTReplaceEntry method. In some cases, when
the replacement method is finished executing, it should invoke the previous implementation of the
method, using the CALL_REPLACED_PROC macro, to allow previously-registered implementations of the
method (including Acrobat and Adobe Reader’s built-in implementation) to execute. Previous
implementations of the method are not invoked automatically; it is up to the replacement
implementation to invoke them.
When you replace an Acrobat HFT method, the replaced method is available from other plug-ins. For
example, assume you replace the AVAlert method. When other plug-ins invoke the AVAlert method,
the replacement version of AVAlert is invoked.
Adobe Acrobat SDK Working with Host Function Tables
Developing Plug-ins and Applications Replacing HFT methods 175
When an HFT entry is replaced, the entry’s linked list is updated so that the newly-added implementation
is at the head of the linked list. Previous implementations, if any, follow in order, as shown in the following
diagram.
The following example shows how to replace the AVAppCanQuit method with a custom method named
MyAvAppCanQuit. The MyAVAppCanQuit method’s arguments and return value are identical to those of
the AVAppCanQuit method. Replaceable methods must be replaced with methods that have the same
arguments and return type.
The first statement in the following code example initializes a global pointer named
gMyAVAppCanQuitPtr to your replacement method. You can use this pointer to invoke the original
method. For example, you can invoke your replacement method to exhibit custom functionality and then
invoke the original method. To invoke the original method, use the CALL_REPLACED_PROC macro and
pass the pointer to your replacement method. For more information about this macro, see the Acrobat and
PDF Library API Reference.
}
void ReplaceAVAppCanQuit ()
{
DURING
//Create the callback
gMyAVAppCanQuitPtr =
ASCallbackCreateReplacement (AVAppCanQuitSEL,
&MyAVAppCanQuit);
HANDLER
AVAlertNote("Trying to replace AVAppCanQuit");
END_HANDLER
}
Note: In the previous code example, an HFT object named gMyHTF is passed to the REPLACE macro. To
execute this example, you must create this object. For information, see “Exporting host function
tables” on page 165.
You can migrate existing non-HFT PDF Library applications to HFT PDF Library applications by performing
the following tasks:
1. Change your project settings from PRODUCT = Library.h to PRODUCT = HFTLibrary.h (the header
files include the necessary code to translate from direct calls into calls though HFTs).
2. Add the following files to your PDF Library application: PDFLInitHFT.c and PDFLInitCommon.c.
3. Compile and link your project with the new source files (PDFLInitHFT.c and PDFLInitCommon.c).
4. Invoke the PDFLInitHFT method instead of the PDFLInit to initialize the HFT mechanism and the
PDF Library. The PDFLInitHFT method is defined in PDFLInitHFT.c file and the prototype for this
function is defined in PDFInit.h along with the prototype for the PDFLInit method. The
PDFLInitHFT method can be called more than once and a count of the initializations will be
maintained by PDF Library.
5. Invoke the PDFLTermHFT method instead of the PDFLTerm method to shutdown the HFT mechanism
and PDF Library. The PDFLTermHFT method is defined in the PDFLInitHFT.c file. The prototype for this
function is defined in the PDFInit.h file along with the prototype of the PDFLTerm method. In case of
multiple initializations, the library shuts down after the number of terminations matches the number of
initializations.
Adobe Acrobat SDK Working with Host Function Tables
Developing Plug-ins and Applications Migrating non-HFT PDF Library applications to HFT applications 177
The following table lists PDF Library API methods that should be changed to newer methods when
working with HFTs.
ASPushExceptionFrame ACPushExceptionFrame
ASPopExceptionFrame ACPopExceptionFrame
ASGetExceptionErrorCode ACGetExceptionErrorCode
Note: Other PDF Library API methods will work as is without any code change.
17 Working with Cos Objects
A PDF file is structured as a tree of low-level objects, called Cos objects. Cos objects form all PDF document
components, such as bookmarks, pages, fonts, images, and annotations. The Acrobat core API contains
methods (the Cos layer) that enable you to operate directly on these low-level objects. You may encounter
a situation where you want to perform a task that is not supported by using AV and PD layer methods. In
such a situation, it is necessary to use Cos methods.
For example, the Creating Annotations chapter explains how to set text annotations properties by using
PDTextAnnot methods. Some newer types of annotations, such as 3D annotations, have properties that
cannot be accessed directly by PD layer methods. As a result, you must use Cos layer methods to access
the PDF dictionary representing the annotation. For information, see “Creating 3D Annotations” on
page 203.
About Cos objects Describes the characteristics of Cos objects. page 178
Working with Cos strings Describes how to work with Cos strings. page 183
Working with Cos arrays Describes how to work with Cos arrays. page 184
Working with Cos dictionaries Working with Cos dictionaries. page 186
Working with Cos names Working with Cos names. page 188
Working with Cos streams Working with Cos streams page 190
Caution: Care is required when working with Cos objects. Unlike using AV and PD objects, Cos objects can
produce invalid PDF files. Before working with Cos objects, it is strongly recommended that you
be familiar with concepts such as resource dictionaries, that are discussed in the PDF Reference.
178
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications About direct and indirect objects 179
This reference is equivalent to the direct object represented by the indirect object.
This example shows indirect object 6, followed by a reference to it in indirect object 7.
6 0 obj
(This is a string)
endobj
7 0 obj
[ 6 0 R ] %An array with one element that is indirect object 6
endobj
If you were to retrieve the zeroth element in the array represented by object 7, you would get the Cos
object that represents this string value:
This is a string
On the other hand, in the following definition of indirect object 8, the elements of the array are all direct
objects (the integer objects, 1, 2, and 3).
8 0 obj
[1 2 3]
endobj
Cos strings
A string object consists of a series of bytes—unsigned integer values in the range 0 to 255. The string
elements are not integer objects, but are stored in a more compact format. String objects can be written in
the following ways:
● As a sequence of literal characters enclosed in parentheses
● As hexadecimal data enclosed in angle brackets
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications About Cos object types 180
Literal strings
A literal string is written as an arbitrary number of characters enclosed in parentheses. Any characters may
appear in a string except unbalanced parentheses and the backslashes, which must be treated specially.
Balanced pairs of parentheses within a string require no special treatment.
Within a literal string, the backslash (\) is used as an escape character for various purposes, such as
including newline characters, nonprinting ASCII characters, unbalanced parentheses, or the backslash
character itself in the string. The character immediately following the backslash determines its precise
interpretation. If the character following the backslash is not one of those shown in the following table, the
backslash is ignored. The following table shows valid literal string escape sequences.
\b Backspace (BS)
\( Left parenthesis
\) Right parenthesis
\\ Backslash
If a string is too long to be conveniently placed on a single line, it may be split across multiple lines by
using the backslash character at the end of a line to indicate that the string continues on the following line.
The backslash and the end-of-line marker following it are not considered part of the string. For example,
the following strings examples are equivalent:
(These \
two strings \
are the same.)
(These two strings are the same.)
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications About Cos object types 181
Hexadecimal strings
Strings may also be written in hexadecimal form, which is useful for including arbitrary binary data in a
PDF file. A hexadecimal string is written as a sequence of hexadecimal digits (0–9 and either A–F or a–f )
enclosed within angle brackets (< and >). Consider the following example:
<4E6F762073686D6F7A206B6120706F702E >
Each pair of hexadecimal digits defines one byte of the string. White-space characters (such as space, tab,
carriage return, line feed, and form feed) are ignored. If the final digit of a hexadecimal string is missing,
that is, if there is an odd number of digits, the final digit is assumed to be 0. Consider the following
example:
<901FA3>
This is a 3-byte string consisting of the characters whose hexadecimal codes are 90, 1F, and A3, but
<901FA> is a 3-byte string containing the characters whose hexadecimal codes are 90, 1F, and A0.
Cos arrays
Arrays are one-dimensional collections of objects accessed by a numeric index. Array indexes are
zero-based and may be any combination of the Cos data types. The following array has seven elements:
three integers, a string, a Boolean value, a dictionary (containing one key-value pair), and an indirect
object reference.
[ 1 2 3 (This is a string) true << /Key (The value) >> 6 0 R ]
Cos names
A name object is an atomic symbol uniquely defined by a sequence of characters. Uniquely defined means
that any two name objects made up of the same sequence of characters are identically the same object.
Atomic means that a name has no internal structure; although it is defined by a sequence of characters,
those characters are not considered elements of the name.
/AName
A slash character (/) introduces a name. The slash is not part of the name but is a prefix indicating that the
following sequence of characters constitutes a name. There can be no white-space characters between the
slash and the first character in the name. The name may include any regular characters, but not delimiter
or white-space characters. Uppercase and lowercase letters are considered distinct: /A and /a are different
names. The following examples are valid literal names:
/Name1
/ASomewhatLongerName
/A;Name_With-Various***Characters?
/1.2
/$$
/@pattern
/.notdef
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications About Cos object types 182
Beginning with PDF 1.2, any character except null (character code 0) may be included in a name by writing
its 2-digit hexadecimal code, preceded by the number sign character (#). This syntax is required to
represent any of the delimiter or white-space characters or the number sign character itself; it is
recommended but not required for characters whose codes are outside the range 33 (!) to 126 (~). The
examples shown in the following table are valid literal names in PDF 1.2 and later.
The length of a name is subject to an implementation limit. The limit applies to the number of characters
in the name’s internal representation. For example, the name /A#20B has four characters (/, A, space, B), not
six.
Name objects are treated as atomic symbols within a PDF file. Ordinarily, the bytes making up the name
are never treated as text to be presented to a user. However, occasionally the need arises to treat a name
object as text, such as one that represents a font name.
In such situations, it is recommended that the sequence of bytes (after expansion of # sequences, if any) be
interpreted according to UTF-8, a variable-length byte-encoded representation of Unicode in which the
printable ASCII characters have the same representations as in ASCII. This enables a name object to
represent text in any natural language, subject to the implementation limit on the length of a name.
Cos dictionaries
A dictionary object is an associative table containing pairs of objects, known as the dictionary’s entries.
The first element of each entry is the key and the second element is the value. The key must be a name.
The value can be any kind of object, including other dictionaries and streams. A dictionary entry whose
value is null is equivalent to an absent entry.
The value associated with the Name key is the value John. The value for the Age key is 27. And the value
for the AnArray key is an array with the values 1, 2, and 3. For information about creating a Cos
dictionary, see “Creating Cos dictionaries” on page 186.
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications Working with Cos strings 183
Cos streams
A stream is a sequence of bytes that can be read a portion at a time. For this reason, objects with
potentially large amounts of data, such as images and page descriptions, are represented as streams. A
stream consists of a dictionary followed by zero or more bytes bracketed between the keywords stream
and endstream. The following example shows the basic syntax of a stream:
dictionary
stream
…Zero or more bytes…
endstream
The stream keyword should be followed by an end-of-line marker consisting of either a carriage return
and a line feed or just a line feed, and not by a carriage return alone. The sequence of bytes that make up a
stream is located between the stream and endstream keywords. Streams must be indirect objects and
the stream dictionary must be a direct object. For information, see “About direct and indirect objects” on
page 179.
Note: For more information about streams, see the PDF Reference.
1. Create a CosDoc object that represents a PDF file by invoking the PDDocGetCosDoc method and
passing a PDDoc object.
2. Create a CosObj object that is based on a Cos string by invoking the CosNewString method and
passing the following arguments:
● A CosDoc object.
● An ASBool object that specifies whether the CosObj object is an indirect or direct object. If true,
the string is an indirect object. If false, the string is a direct object. For information, see “About
direct and indirect objects” on page 179.
● A character pointer that specifies the string. Cos strings can contain NULL characters.
● The length of the character pointer.
The following code example creates a CosObj that is based on a Cos string. A PDDoc object named
myPDDoc is passed to the PDDocGetCosDoc method. For information, see “Creating a PDDoc object” on
page 83.
An exception is thrown if the CosObj object that is passed to the CosStringValue method is not based
on a Cos string. The following code example expands the previous code example by retrieving the string
value by invoking the PDDocGetCosDoc method.
1. Create a CosDoc object that represents a PDF file by invoking the PDDocGetCosDoc method and
passing a PDDoc object.
2. Create a CosObj object that is based on a Cos array by invoking the CosNewArray method and
passing the following arguments:
● A CosDoc object.
● An ASBool object that specifies whether the CosObj object is an indirect or direct object. If true,
the string is an indirect object. If false, the string is a direct object. For information, see “About
direct and indirect objects” on page 179.
● An ASTArraySize object that specifies the number of elements.
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications Retrieving Cos array values 185
3. Create a CosObj object that stores a value to add to the Cos array. For example, to create a CosObj
object that is based on an integer value, invoke the CosNewInteger method and pass the following
arguments:
● A CosDoc object.
● An ASBool object that specifies whether the CosObj object is an indirect or direct object. If true,
the string is an indirect object. If false, the string is a direct object. For information, see “About
direct and indirect objects” on page 179.
● An ASInt32 value that specifies the integer value.
4. Add the value to the Cos array by invoking the CosArrayPut method and passing the following
arguments:
● A CosObj object that represents a Cos array.
● An ASTArraySize object that specifies a 0-based index value.
● A CosObj object that stores the value to add to the array.
The following code example creates a Cos array and adds the values 1, 2, 3, 4, and 5 to it. A PDDoc object
named myPDDoc is passed to the PDDocGetCosDoc method. For information, see “Creating a PDDoc
object” on page 83.
The following code illustrates a user-defined function named GetArrayValues that retrieves the value
of each element and displays it in an alert box. Notice that a CosObj that represents a Cos array is passed
to the GetArrayValues as its only parameter.
3. Create a CosObj object that represents a dictionary value. You must invoke a method that corresponds
to the value’s data type. For example, to add an integer value, invoke the CosNewInteger method
and pass the following arguments:
● A CosDoc object.
● An ASBool object that specifies whether the CosObj object is an indirect or direct object. If true,
the string is an indirect object. If false, the string is a direct object. For information, see “About
direct and indirect objects” on page 179.
● An ASInt32 value that specifies the integer value.
4. Place the CosObj object that represents a dictionary value into the dictionary by invoking the
CosDictPut method and passing the following arguments:
● A CosObj that represents the dictionary
● An ASAtom object that specifies the key name
● A CosObj object that specifies the dictionary value
5. Repeat steps 3 and 4 for each dictionary entry that you want to add.
The following code example creates a Cos dictionary with the following entries: /Key1 1 /Key2. A
PDDoc object named myPDDoc is passed to the PDDocGetCosDoc method. For information, see
“Creating a PDDoc object” on page 83.
1. Get a dictionary key value by invoking the CosDictGet method and passing the following arguments:
● A CosObj object that represents the dictionary.
● An ASAtom object that represents the key name.
The CosDictGet method returns a CosObj object that represents the dictionary value.
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications Querying a Cos dictionary for a key 188
2. Get the element value. However, you must invoke the method that corresponds to the CosObj object’s
data type. If, for example, the Cos array stores integer values, invoke the CosIntegerValue method
to obtain the dictionary entry value. Pass the CosObj object that represents the dictionary entry. This
method returns the corresponding value. If the CosIntegerValue method is invoked, then an
ASInt32 value is returned.
The following code example retrieves the value of a dictionary element whose key is named Key1. The
element value is displayed within an alert box.
Note: The Dict object is a CosObj that represents the dictionary. For information, see “Creating Cos
dictionaries” on page 186.
This method returns an ASBool value that specifies whether the key-value pair exists. If this method
returns true, then the key-value pair exists. The following code example queries a dictionary to determine
whether a key named Key1 exists.
1. Create a CosDoc object that represents a PDF file by invoking the PDDocGetCosDoc method and
passing a PDDoc object.
2. Create a CosObj object that represents the name by invoking the CosNewName method and passing
the following arguments:
● A CosDoc object.
● An ASBool object that specifies whether the CosObj object is an indirect or direct object. If true,
the string is an indirect object. If false, the string is a direct object. For information, see “About
direct and indirect objects” on page 179.
● An ASAtom object that represent the name to create.
The CosNewName method returns a CosObj object that represents the new Cos name.
The following code example creates a Cos name with the value Name1. A PDDoc object named myPDDoc
is passed to the PDDocGetCosDoc method. For information, see “Creating a PDDoc object” on page 83.
1. Invoke the CosNameValue method and pass the CosObj that represents the Cos name. This method
returns an ASAtom object that represents the name value.
2. Invoke the ASAtomGetString method to get a constant character pointer that specifies the Cos
name value. Pass the ASAtom object that is returned from the CosNameValue method.
A stream is represented by an ASStm object definition. A data stream can be a buffer in memory, a file, or
an arbitrary user-written procedure. When writing or extracting data streams, an ASStm object must be
converted to a Cos stream.
Note: Before reading this section, it is strongly recommended that you are familiar with concepts
discussed earlier in this chapter such as Cos arrays and Cos dictionaries.
The following example shows the syntax of a stream that creates a thin line segment:
150 250 m 150 350 l S
In contrast, the following example shows the syntax of a stream that inserts the text Hello There into a
PDF document:
BT /F0 1 Tf 24 0 0 24 36 756 Tm 0 Tr 0 g 0 Tc 0 Tw \(Hello There) Tj ET
Note: For information about stream syntax, see the PDF Reference.
In addition, most filters are defined so that the data is self-limiting; that is, they use an encoding scheme in
which an explicit end-of-data (EOD) marker delimits the extent of the data. Finally, streams are used to
represent many objects from whose length attributes can be inferred. All of these constraints must be
consistent.
For example, an image with 10 rows and 20 columns, using a single color component and 8 bits per
component, requires exactly 200 bytes of image data. If the stream uses a filter, there must be enough
bytes of encoded data in the PDF file to produce those 200 bytes. An error occurs if the Length entry is
too small, if an explicit EOD marker occurs too soon, or if the decoded data does not contain 200 bytes. It is
also an error if the stream contains too much data, with the exception that there may be an extra
end-of-line marker in the PDF file before the endstream keyword. All streams created in this section have
a stream dictionary defined.
For each stream that you want to insert into a PDF document, create a stream dictionary that contains at
least the Length entry, as shown in the following example:
<</Length 100>>
To create a stream dictionary with the Length entry defined, perform the following tasks:
1. Create a CosDoc object that represents a PDF file by invoking the PDDocGetCosDoc method.
3. Create a CosObj object that represents the length of the stream by invoking the CosNewInteger
method and passing the following arguments:
● A CosDoc object that you created in step 1.
● An ASBool object that specifies whether the CosObj object is an indirect or direct object. If true,
the string is an indirect object. If false, the string is a direct object. For information, see “About
direct and indirect objects” on page 179.
● The ASUns32 object created in step 2 that represents the stream length.
The CosNewInteger method returns a CosObj object that represents the stream length.
4. Create a CosObj object that represents the Cos dictionary. For information, see “Creating Cos
dictionaries” on page 186.
5. Set the stream dictionary key and value by invoking the CosDictPutKeyString method and
passing the following arguments:
● The CosObj object that you created in step 4 that represents the dictionary.
● A character pointer that specifies the name of the key, which in this situation is Length.
● The CosObj object created in step 3 that specifies the length of the stream.
The following code example creates a stream dictionary. The first part of this code example creates a
PDPage object by using an AVDoc object. For information about this application logic, see “Creating a
PDEContent object” on page 125.
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications Creating Cos streams 192
Note: This code example creates a CosObj object named AttrDict that represents a stream dictionary.
1. Create a PDPage object that represents the current PDF page. For information, see “Creating a
PDEContent object” on page 125.
2. Create a CosDoc object that represents a PDF file by invoking the PDDocGetCosDoc method.
3. Define the stream that draws a thin black line segment. You can populate a character array with a
stream by invoking the sprintf method.
5. Create a CosObj object that represents the stream dictionary. For information, see “Creating a stream
dictionary” on page 190.
6. Read the stream into memory by invoking the ASMemStmRdOpen method and passing the following
arguments:
● A character pointer that contains the data stream
● An ASUns32 object that specifies the stream length
This method returns an ASStm object that represents an in-memory data stream.
7. Create a new Cos stream that is based on data located in the ASStm object by invoking the
CosNewStream method and passing the following arguments:
● A CosDoc object that specifies the PDF document in which the Cos stream is inserted (pass the
CosDoc object created in step 2).
● An ASBool object that specifies whether the Cos stream is an indirect object. Because all streams
are indirect objects, this argument must be set to true.
● An ASStm object that contains the stream data (pass the ASStm object created in step 6).
● A CosStreamStartAndCode object that specifies the byte offset from which data reading starts.
You can pass 0 to ensure that data reading starts at the beginning of the stream.
● An ASBool object that specifies whether the data is encoded using filters specified in the stream
dictionary before it is written to the Cos stream.
● A CosObj object that represents the stream dictionary (pass the CosObj object created in step 5).
● A CosObj object that represents the parameters that are used by the encoding filter if the source
data is encoded before it is written to the file. If encoding parameters are not required, this value is
ignored. For information about encoding filters, see the PDF Reference.
● A CosByteMax object that specifies the amount of data read from the source. If this value is -1,
data is read from the source until it reaches the end of the stream.
The CosNewStream method returns a CosObj object that represents the Cos stream.
8. Replace the contents of the specified page with the Cos stream by invoking the
PDPageAddCosContents method and passing the following arguments:
● A PDPage object that represents the current page of the PDF document (pass the PDPage object
created in step 1).
● A CosObj object that contains the Cos stream.
The following code example creates a Cos stream and inserts it into the current page of a PDF document.
DURING
//Create a new Cos stream using data from the ASStm object
PageStrm = CosNewStream(cd, true, OpenedStream, 0,
false, // StmDataIsNotDecoded
AttrDict, //The stream dictionary
EncodeParms, -1);
HANDLER
AVAlertNote ("Trying to create new CosStream");
CosObjDestroy (AttrDict);
ASStmClose (OpenedStream);
return;
END_HANDLER
Caution: If you execute this code example without having a PDF document open, you will cause an
Adobe Reader or Acrobat run-time error. The run-time error occurs because this code example
creates a PDPage object that is based on the current PDF document page.
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications Populating a PDF document with a content stream 195
The following example shows the resource dictionary that is created in this section:
4 0 obj
<<
/Font << /F0 5 0 R >>
/ProcSet 6 0 R
>>
endobj
The following example shows the font descriptor that is created in this section:
5 0 obj
<<
/Type /Font
/Subtype /Type1
/Name /F0
/BaseFont /Courier
/Encoding /WinAnsiEncoding
>>
endobj
The following example shows the page dictionary that is created in this section.
This is the page dictionary.
7 0 obj
<<
/Type /Page
/MediaBox [ 0 0 612 792 ]
/Parent 2 0 R
/Resources 4 0 R
/Contents 8 0 R
>>
endobj
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications Populating a PDF document with a content stream 196
The following diagram shows the PDF document that is created in this section.
To create a PDF document and populate it with a Cos content stream, perform the following tasks:
1. Define the media box rectangle used in the PDF document’s page.
ASFixedRect MedBox;
MedBox.left = ASInt32ToFixed (0);
MedBox.top = ASInt32ToFixed (792);
MedBox.right = ASInt32ToFixed (612);
MedBox.bottom = ASInt32ToFixed (0);
2. Define the stream that is written to the PDF document page, as shown in the following example.
char* StreamBuf = (char*)"BT /F0 1 Tf 24 0 0 24 36 756 Tm 0 Tr 0 g 0 Tc 0 Tw \
(Hello There) Tj ET";
3. Create a PDDoc object that represents the new document by invoking the PDDocCreate method.
After the document is created, at least one page must be added before Acrobat or Adobe Reader can
display the document.
PDDoc NewDoc = PDDocCreate ();
4. Create a PDPage object that represents the page by invoking the PDDocCreatePage method and
passing the following arguments:
● The PDDoc object that you created.
● The PDBeforeFirstPage enum value that specifies where to place the page.
● The ASFixedRect object that defines the media box rectangle.
This method returns a PDPage object that represents the new page.
5. Create a CosObj object that represents a resource dictionary. In the following code example, a
resource dictionary is created in a user-defined function named SetResourceForPage.
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications Populating a PDF document with a content stream 197
6. Set the page’s resource key. In the following code example, the page’s resource’s key is set in a
user-defined function named CreateResourceDicts.
7. Add a Cos stream to the page. In the following code example, a Cos stream is added to the page in a
user-defined function named AddStreamToPage.
8. Open the PDF document in Adobe Reader or Acrobat. In the following code example, this task occurs in
the user-defined function named MakeTheFile.
9. Save the PDF document. In the following code example, this task occurs in the user-defined function
named MakeTheFile.
The following code example represents an entire C source file that creates a PDF document and populates
it with a Cos content stream. This source file is made up by various user-defined functions. To make it
easier to view these functions, all function signatures are bolded. The entry point to this source file is the
MakeTheFile function. You can invoke the MakeTheFile function from a menu item or toolbar button
to execute this code example.
Example 17.12 Creating a PDF document and populating it with a Cos content stream
#include "ascalls.h"
#include "avcalls.h"
#include "avcalls.h"
#include "coscalls.h"
#include "pdcalls.h"
#include "ascalls.h"
#include "corcalls.h"
#include "dos.h"
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
** Set the page’s resource key. Return true if everything is valid,
** else false.
*/
ASBool SetResourceForPage (PDPage page)
{
CosObj PageCosObj;
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications Populating a PDF document with a content stream 198
DURING
//Get a CosDoc object by using the PDPage page passed to this object
PageCosObj = PDPageGetCosObj(page);
/*
** Create the font’s resources. Return true if all is valid, else false.
** Creates the required font and proc set dictionaries; then creates the
** global resource dictionary for the PDF page
*/
ASBool CreateResourceDicts (CosDoc cd)
{
DURING
ResDict = CosNewDict (cd, true, 10);
HANDLER
AVAlertNote("Trying to create the resource dictionary.");
return false;
END_HANDLER
DURING
FontDictObj = CosNewDict (cd, true, 5);
HANDLER
AVAlertNote ("Trying to create the font’s dictionary.");
CosObjDestroy (ResDict);
return false;
END_HANDLER
DURING
CosArrayPut (procArray, 0, CosNewName (cd, false, ASAtomFromString ("PDF")));
Adobe Acrobat SDK Working with Cos Objects
Developing Plug-ins and Applications Populating a PDF document with a content stream 200
// Create and return the stream’s dictionary that defines the Length attribute
CosObj CreateAttribsDict(CosDoc Doc, ASInt32 Len)
{
//Declare local variables
CosObj Dict; /* Holds newly created dictionary */
ASAtom Key; /* Key used to retrieve CosObj in dictionary */
CosObj Value; /* Assigned, then added to dictionary */
CosObj DecodeArray;
DURING
//Create the CosDoc object
cd = PDDocGetCosDoc (PDPageGetDoc (page));
HANDLER
AVAlertNote("Unable to get CosDoc");
return false;
END_HANDLER
return false;
}
//Read the stream into memory by invoking the ASMemStmRdOpen method
Stm = ASMemStmRdOpen (StreamBuf, StreamBufLen);
if (!Stm){
AVAlertNote ("Unable to open data stream to create content stream.");
return false;
}
DURING
//Creates a new Cos stream using data from the ASStm object
PageStrm = CosNewStream(cd, true, Stm, -1,
false,
AttrDict, /* attributesDict */
EncodeParms,
-1);
ASStmClose (Stm);
HANDLER
AVAlertNote ("Trying to create new CosStream.");
CosObjDestroy (AttrDict);
ASStmClose (Stm);
return false;
END_HANDLER
//Define a stream to set the text matrix and write out the text
StreamBuf = (char*)"BT /F0 1 Tf 24 0 0 24 36 756 Tm 0 Tr 0 g 0 Tc 0 Tw \(Hello
There) Tj ET";
DURING
//Create a PDDoc object
NewDoc = PDDocCreate();
if (NewDoc){
//Invoke the PDDocCreatePage method
NewPage = PDDocCreatePage(NewDoc, PDBeforeFirstPage, MedBox);
if (!NewPage)
ASRaise (0);
//Invoke CreateResourceDicts
if (CreateResourceDicts(PDDocGetCosDoc(NewDoc)) == false)
ASRaise (0);
// Invoke AddStreamToPage
result = AddStreamToPage (NewPage, StreamBuf, StreamBufLen);
if (result == false)
ASRaise (0);
PDPageRelease (NewPage);
}
HANDLER
AVAlertNote ("Problem creating document.");
if (NewPage) PDPageRelease (NewPage);
if (NewDoc) PDDocClose (NewDoc);
return;
END_HANDLER
DURING
HANDLER
AVAlertNote ("Cannot open new document.");
END_HANDLER
}
18 Creating 3D Annotations
The underlying 3D object data in a 3D annotation must conform to the Universal 3D (U3D) format
developed by the 3D Industry Forum (http://www.3dif.org). Acrobat supports a subset of U3D, as
described in the document U3D Elements.
Adding 3D data to an annotation Describes how to add 3D data to an annotation. page 204
Creating annotations
Before you can add three-dimensional data to an annotation, you must create it. Annotations are
represented by an annotation dictionary. A dictionary is a data structure with one or more entries, which
are key-value pairs:
● The key is a name object.
● The value is some type of PDF object. Section 3.2 in the PDF Reference describes all the PDF object
types. If the value is a dictionary, that dictionary has its own key-value pairs. Therefore, dictionaries can
be nested within other dictionaries (as you will see with the 3D structures).
General annotation dictionary entries are described in Table 8.11 in the PDF Reference. Those specific to 3D
annotations are described in Table 9.33.
The following code example creates a 3D annotation with corners (1, 9.5) and (7,4) using the
PDPageAddNewAnnot method:
ASFixedRect annotRect;
annotRect.left = Int16ToFixed(1*72);
annotRect.top = Int16ToFixed(9.5*72);
annotRect.right = Int16ToFixed(7.0*72);
annotRect.bottom = Int16ToFixed(4*72);
203
Adobe Acrobat SDK Creating 3D Annotations
Developing Plug-ins and Applications Adding 3D data to an annotation 204
● The type of the annotation, which in this case is 3D. This sets the value of the annotation dictionary’s
Subtype entry. It is important to note that in PDF this is a name object, not a string. In the API, the
ASAtom type is frequently used to represent names; the ASAtomFromString method converts a
string to a name.
● The rectangle in which the annotation appears on the page. This sets the value of the annotation
dictionary’s Rect entry.
After the annotation has been created, you must complete the other entries in the annotation dictionary.
The F (flags) entry is set here:
PDAnnotSetFlags(newAnnot, pdAnnotPrint | pdAnnotReadOnly);
The annotation’s initial appearance (the AP entry) can be set as described in “Setting the annotation
appearance” on page 210.
Other entries are set as described in Adding 3D data to an annotation using the EmbedDataIn3Dannot
function.
If necessary, you can determine the type of a CosObj by calling the CosObjGetType method, which
returns a constant (CosNull, CosInteger, CosFixed, CosReal, CosBoolean, CosName, CosString,
CosDict, CosArray, or CosStream).
Adobe Acrobat SDK Creating 3D Annotations
Developing Plug-ins and Applications Creating the 3D annotation dictionary entries 205
Most of the code described here involves setting the entries of dictionaries (CosObjs of type CosDict).
Dictionaries contain a number of key-value pairs, where the key is a name object and the value is any type
of CosObj.
There are several common methods that can be used, which differ only in how the keys are specified. The
CosDictPutKeyString method (available in Acrobat 7.0 or later) allows the key to be specified as a
string and is the recommended method, as in the following example:
CosDictPutKeyString(theDict, // The dictionary
"TheKey", // The key: a string
theCosValue); // The value: a CosObj
CosDictPut requires the key to be specified as an ASAtom. CosDictPutKey requires the key to be a
name object (a CosObj of type CosName).
Next, get the CosDoc object corresponding to the document by invoking the CosObjGetDoc method
and passing the CosObj object, as shown in the following example:
CosDoc cosDoc = CosObjGetDoc(cosAnnot);
Two additional dictionary entries (which are not specific to 3D annotations)—the P (page) and Contents
entries—can be set as follows:
CosDictPutKeyString(cosAnnot, "P", PDPageGetCosObj(pdPage));
CosDictPutKeyString(cosAnnot, "Contents",
CosNewString(cosDoc, false, "3D Model", strlen("3D Model")));
The following sections show how to set the dictionary entries that are specific to 3D annotations (see Table
9.33 in the PDF Reference):
3DD: A 3D stream specifying the 3D content. (See “Specifying the 3D stream” on page 205.)
3DV: The initial view of the 3D content. (See “Setting the default view” on page 209.)
3DA: The activation dictionary. (See “Setting the activation dictionary” on page 213.)
Other entries are unique to 3D streams (see Table 9.35 in the PDF Reference). They include:
● Type (optional): Must be 3D if present.
● Subtype (required): Must be U3D.
● OnInstantiate (optional): A JavaScript script to be executed when the 3D stream is read. For
information, see “Specifying JavaScript code” on page 208.
1. Create an ASPathName object that represents the file containing the U3D data by invoking the
ASPathFromPlatformPath method and passing a character pointer that specifies the location of
the file containing U3D data. If you are working on the Mac OS platform, then invoke the GetMacPath
method and pass a character pointer that specifies the file location.
3. Populate the ASFile object with the file containing the U3D data by invoking the
ASFileSysOpenFile method and passing the following arguments:
● An ASFileSys object that represents the file system in which the PDF file is located. Invoke the
ASGetDefaultFileSys method to get the default file system.
● An ASPathName object that represents the path in which the file containing the U3D data is
located (pass the ASPathName object created in step 1).
● An ASFileMode object that represents the mode in which to open the file. For example, specify
ASFILE_READ to open the file in read mode.
● The address of an ASFile object. This method populates this argument with the file that was
opened (file information is obtained from the ASPathName object).
4. Create an ASStm object by invoking the ASFileStmRdOpen method and passing the following
arguments:
● The ASFile object with the file containing the U3D data.
● Length of data buffer, in bytes. If you specify 0, then the default buffer size (currently 4kB) is used.
5. Invoke the CosNewStream method to create a Cos stream containing the data that is located within
the ASStm object. This Cos stream will become the value of the 3DD entry of the 3D annotation. Pass
the following arguments to this method:
● A CosDoc object that specifies the PDF document in which the Cos stream is inserted.
● An ASBool object that specifies whether the Cos stream is an indirect object. Because all streams
are indirect objects, this argument must be set to true.
● An ASStm object that contains the stream data (pass the ASStm object created in step 4).
● A CosStreamStartAndCode object that specifies the byte offset from which data reading starts.
You can pass 0 to ensure that data reading starts at the beginning of the stream.
● An ASBool object that specifies whether the data is encoded using filters specified in the stream
dictionary before it is written to the Cos stream.
Adobe Acrobat SDK Creating 3D Annotations
Developing Plug-ins and Applications Specifying the 3D stream 207
● A CosObj object that represents the stream dictionary. You can invoke the CosNewNull method.
● A CosObj object that represents the parameters that are used by the encoding filter if the source
data is encoded before it is written to the file. If encoding parameters are not required, this value is
ignored. For information about encoding filters, see the PDF Reference.
● A CosByteMax object that specifies the amount of data read from the source. If this value is -1,
data is read from the source until it reaches the end of the stream.
The CosNewStream method returns a CosObj object that represents the Cos stream. The following code
example creates a Cos stream.
//Create an ASPathName that specifies the location of the.U3D file
//u3dFileName is a character pointer that specifies the path to this file
ASPathName u3DPathName = ASPathFromPlatformPath((void*) u3dFileName);
if (asFile == NULL)
AVAlertNote("Error opening 3D data file.");
//Create a new Cos stream and set it under 3DD key in the annot dictionary
CosObj stm3D = CosNewStream(cosDoc, true, fileStm, 0, false, CosNewNull(),
CosNewNull(), -1);
Next, entries can be added to the dictionary. The Type and Subtype entries both take name objects as
values. Therefore, strings specified in the code must be explicitly converted to names:
//Set the stream's dictionary
CosDictPutKeyString(attrObj, "Subtype", CosNewName(cosDoc, false,
ASAtomFromString("U3D")));
CosDictPutKeyString(attrObj, "Type", CosNewNameFromString(cosDoc, false,
"3D"));
Adobe Acrobat SDK Creating 3D Annotations
Developing Plug-ins and Applications Specifying the 3D stream 208
The following code example creates an ASFile object and populates it with the JavaScript file. The
JsFileName variable is a character pointer that specifies the location of the JavaScript file.
//Create a char pointer that specifies the location of the JavaScript file
char*JsFileName = "C:\\3DJavaScript.js"
In the following code, an entry is added to the stream dictionary in the process of creating the stream,
rather than afterwards as in the previous code. First, the CosNewDict method is used to create a new
dictionary:
CosObj dictJsStm = CosNewDict(cosDoc, false, 1);
Next, the value of the Filter entry is set to FlateDecode using the CosDictPutKeyString method.
This means that the stream will be compressed using Flate (ZIP) compression.
CosDictPutKeyString(dictJsStm, "Filter",
CosNewNameFromString(cosDoc, false, "FlateDecode"));
Next, the Cos stream is created, using the stream data and attributes dictionary already created:
stm3Djscode = CosNewStream(cosDoc, true,
JsFileStm, //The stream
0, true,
dictJsStm, // The stream dictionary
CosNewNull(), -1);
Adobe Acrobat SDK Creating 3D Annotations
Developing Plug-ins and Applications Setting the default view 209
Set it as the value of the OnInstantiate entry of the 3D stream dictionary. The following code example
specifies a JavaScript script as the value of the OnInstantiate entry of the 3D stream dictionary.
CosDictPutKeyString(attrObj, "OnInstantiate", stm3Djscode);
U3D data typically contains a default initial view. This view is used by default if not otherwise specified. In
addition, views can be specified by the entries in a view dictionary.
The VA entry in the 3D stream dictionary is an array of view dictionaries. One of the views can be chosen as
the default by means of the 3DV entry in the 3D annotation dictionary or the DV entry in a 3D stream
dictionary.
The following code creates a view dictionary and specifies its entries. The code assumes the Cos objects
cosAnnot for the annotation and cosDoc for the document have already been obtained. First, a view
dictionary is created by invoking the CosNewDict method:
CosObj cosView = CosNewDict (cosDoc, true, 8);
Next, the code sets the following entries (see Table 9.37 in the PDF Reference for more detailed
information):
Type (optional): If present, must be the name 3DView.
XN (required): The name of the view, a string that can be displayed in the user interface.
IN (optional): The internal name of the view, a string that can be used to refer to the view from other
objects, such as in JavaScript code.
C2W (optional): A transformation matrix specifying the camera position. To use this, it is also necessary
to set the value of the MS entry to M.
CO (optional): A number indicating the distance to the center of orbit for this view.
The following code creates an array of type double and specifies values for views:
char* externalViewName = "Default View";
char* internalViewName = "Sample3dView";
double gMatrixVals[12] =
{1.0, 0.0, 0.0, 0.0, 0.0000000000000000612303, -1.0,
0.0, 1.0, 0.0000000000000000612303, 82.9517, -883.324, 115.166};
float gCOvalue = (float) 725.305;
externalViewName, strlen(externalViewName)));
CosDictPutKeyString(cosView, "MS",
CosNewNameFromString(cosDoc, false, "M"));
Last, the dictionary is set as the value of the 3DV key in the annotation dictionary:
CosDictPutKeyString(cosAnnot, "3DV", cosView);
There are several ways to get the poster. The function described below, GetFormXObjectFromFile,
illustrates one method. The appearance is generated from a separate PDF file containing an image or other
content. You call this function as follows:
CosObj formXObject = GetFormXObjectFromFile
(gsPosterFilePath, //The external file
pdDoc);
The function returns a Cos object, formXObject, which is the form XObject to be used as the appearance.
CosObj cosAnnot = PDAnnotGetCosObj(newAnnot);
CosDoc cosDoc = CosObjGetDoc(cosAnnot);
and set its N (normal) entry to the appearance stream obtained above.
CosDictPutKeyString(apprDict, "N", formXObject);
CosDictPutKeyString(cosAnnot, "AP", apprDict);
Adobe Acrobat SDK Creating 3D Annotations
Developing Plug-ins and Applications Setting the annotation appearance 211
The content to be used is expected to be on the first page of the PDF file. The PDDocAcquirePage
method returns a PDPage object for the first page.
pdPageImage = PDDocAcquirePage(posterPDFDoc, 0);
The code then uses PDE-layer (PDFEdit) methods that work with the content streams on the PDF page.
(See the Overview guide for more information on how these methods work.)
The PDEContentToCosObj method converts the PDEContent to a form XObject Cos object.
PDEContentToCosObj (pdeContent,
kPDEContentToForm, // To Form XObject
&pdeContentAttrs, // PDEContentAttrsP
sizeof(pdeContentAttrs), // attrsSize,
pdDocCos, // The CosDoc
NULL, // PDEFilterArrayP
&contentFormXObject, // Resulting form Cos object
&contentResources); // Resulting resource Cos object
Adobe Acrobat SDK Creating 3D Annotations
Developing Plug-ins and Applications Setting the annotation appearance 212
The returned resources must be put into the form XObject’s Resources dictionary:
CosDictPutKeyString(contentFormXObject, "Resources",
contentResources);
The BBox entry of the form XObject is required and is set to the value of the page’s media box:
ASFixedRect boundingBox;
PDPageGetMediaBox(pdPageImage, &boundingBox);
CosObj BBoxArray = CosNewArray(pdDocCos, 4, false);
CosArrayPut(BBoxArray,0, CosNewInteger(pdDocCos, false,
ASFixedRoundToInt16(boundingBox.left)));
CosArrayPut(BBoxArray,1, CosNewInteger(pdDocCos, false,
ASFixedRoundToInt16(boundingBox.bottom)));
CosArrayPut(BBoxArray,2, CosNewInteger(pdDocCos, false,
ASFixedRoundToInt16(boundingBox.right)));
CosArrayPut(BBoxArray,3, CosNewInteger(pdDocCos, false,
ASFixedRoundToInt16(boundingBox.top)));
CosDictPutKeyString(contentFormXObject, "BBox", BBoxArray);
// Set matrix key in form object
The Matrix entry of the form XObject is set to the values obtained from the page by means of the
PDPageGetDefaultMatrix method:
ASFixedMatrix defaultMatrix;
PDPageGetDefaultMatrix(pdPageImage, &defaultMatrix);
CosObj MatrixArray = CosNewArray(pdDocCos, 6, false);
CosArrayPut(MatrixArray,0, CosNewFixed(
pdDocCos, false, defaultMatrix.a));
CosArrayPut(MatrixArray,1, CosNewFixed
(pdDocCos, false, defaultMatrix.b));
CosArrayPut(MatrixArray,2, CosNewFixed
(pdDocCos, false, defaultMatrix.c));
CosArrayPut(MatrixArray,3, CosNewFixed
(pdDocCos, false, defaultMatrix.d));
CosArrayPut(MatrixArray,4, CosNewFixed
(pdDocCos, false, defaultMatrix.h));
CosArrayPut(MatrixArray,5, CosNewFixed
(pdDocCos, false, defaultMatrix.v));
Adobe Acrobat SDK Creating 3D Annotations
Developing Plug-ins and Applications Setting the activation dictionary 213
Finally, the CosObjCopy method is used to copy the Cos object contentFormXObject into the current
PDF document. The parameters to this method are:
● The CosObj to copy.
● The CosDoc for the document in which to copy it.
● A Boolean value: true means that all indirectly referenced objects from the source should be copied to
the destination.
formXObject = CosObjCopy (contentFormXObject,
PDDocGetCosDoc(TargetPdDoc), true);
When an annotation is inactive, it displays its normal appearance. (See “Setting the annotation
appearance” on page 210.) When it is activated, one of its views (specified by the 3DV entry) is displayed.
First the dictionary is created and set as the 3DA entry of the 3D annotation:
CosObj activationDict = CosNewDict(CosObjGetDoc(cosAnnot), false, 1);
CosDictPutKeyString (cosAnnot, "3DA", activationDict);
It is not necessary to set any entries whose default values are acceptable. Here the non-default entries are
set.
The DIS entry of the activation dictionary specifies the state of the 3D content when it is deactivated. In
this case, it is set to I, meaning that it should be instantiated. (The default is U for uninstantiated.)
CosDictPutKeyString (activationDict, "DIS",
CosNewNameFromString (cosDoc, false, "I"));
The code provides a variable to determine the value of the A entry. The default value is XA, meaning that
the annotation needs to be explicitly activated. PO means that the annotation should be activated as soon
as the page containing the annotation is opened:
// Optional activation choice
if(gbShowDefaultViewWhenOpenPage == true)
CosDictPutKeyString(activationDict, "A",
CosNewNameFromString (cosDoc, false, "PO"));
19 Handling Exceptions
This chapter explains how to handle exceptions that are raised by Acrobat core API methods. Acrobat core
API methods generally do not return error codes; instead, they raise exceptions when errors occur.
Exceptions are handled by exception handlers. It is recommended that you create your own exception
handlers to trap and handle exceptions.
Creating exception handlers Describes how to create exception handlers. page 214
Returning a value from an Describes how to return a value from an exception page 215
exception handler handler.
Exception handling scenarios Describes scenarios related to exception handling. page 215
You use the DURING, HANDLER, and END_HANDLER macros to define exception handlers. Application
logic that may raise an exception appears between the DURING and HANDLER macros. Application logic
that handles exceptions appears between the HANDLER and END_HANDLER macros.
If the method raises an exception, the handler code is executed; otherwise, it is not executed. When an
exception occurs, your handler can access the exception error code by using the ERRORCODE macro. The
value returned by the ERRORCODE macro does not change until another exception is raised. For
information about the ERRORCODE macro, see the Acrobat and PDF Library API Reference.
The following code example declares an error handler that is active during a call to the
AVDocOpenFromFile method. If an exception occurs, an error message is displayed to the user. For
information about opening a PDF document by using the AVDocOpenFromFile method, see “Opening
PDF documents” on page 72.
Note: For code brevity, most of the code examples located within this guide do not include DURING,
HANDLER, and END_HANDLER macros to handle exceptions. You should include these macros in
your own custom code.
214
Adobe Acrobat SDK Handling Exceptions
Developing Plug-ins and Applications Returning a value from an exception handler 215
The E_RETURN(x) macro must not invoke a function that might raise an exception, because the macro
pops an exception frame off the stack before evaluating the expression to return. If this evaluation raises
an exception, it does not call your handler, but instead calls the next handler up the stack. For example,
consider the following application logic:
E_RETURN(myfn());
This is not recommended if there is any possibility that myfn could raise an exception. If you need to
invoke a function, it is best to do it this way:
result = myfn();
E_RETURN(result);
Raising exceptions
Although many Acrobat core API methods raise exceptions, some methods do return error codes or NULL
if something goes wrong. Inside a DURING HANDLER block, if your plug-in detects one of these cases, it
can invoke the ASRaise method, which generates an exception. This has the effect of causing the
HANDLER END_HANDLER code to execute, just as if the original method raised an exception.
You can also use the RERAISE macro when you do not want your exception handler to handle an
exception, but want to pass the exception to the next exception handler on the stack.
Note: Your plug-in should use the ASRegisterErrorString method to define its own exceptions.
This action leads to unpredictable results because the top stack frame has not been removed. As a result,
the frame is incorrect. Instead, use the ASRaise method and then use the goto statement within the
HANDLER END_HANDLE block, as shown in the following example:
DURING ...
ASRaise(myspecialerrorcode);
HANDLER
if ERRORCODE == myspecialerrorcode
goto error;
END_HANDLER
error:
Note: For information about the goto statement, see the Acrobat and PDF Library API Reference.
If you insist on nesting exception handlers in a single function, do not return from the inner exception
handler (either through a call to return in a handler or E_RETURN from body code). This action leaves the
exception stack out of sync with the call stack. Any errors raised in body code surrounded by the outer
Adobe Acrobat SDK Handling Exceptions
Developing Plug-ins and Applications Using register variables 217
exception handler will restore the incorrect calling environment and lead to unpredictable results, as
shown in the following example:
{
DURING /* Places one frame on the exception stack */
pdoc = AVDocGetPDDoc(avdoc);
DURING /* Places a second frame on the stack */
rootBm = PDDocGetBookmarkRot(pdDoc);
if (!PDBookmarkIsValid(rootBm)){
E_RTRN_VOID
/*
Returning here interferes with the exception stack
because two frames have been placed on the stack
and E_RTRN_VOID only clears one of them before
returning
*/
}
pdAction = PDBookMarkGetAction(parentBm);
HANDLER
AVAlertNote("Bad AVDoc");
return (1);
/*
Returning here interferes with the exception stack
because there is still a frame on the stack from
the outer DURING macro and it will not be cleared
before the function returns
*/
END_HANDLER
HANDLER
AVAlertNote("Bad PDDoc");
END_HANDLER
}
As a result, the state of local variables that have been optimized into registers is unpredictable when the
exception handler is invoked. To avoid this situation, declare all variables that are set in the main body of
the code and used in the exception handler or beyond (if the handler lets execution continue) as volatile.
This ensures that they are never optimized into register variables, but are always referenced from memory.
When using the volatile statement, be sure to place the keyword in the correct location, for example:
volatile myStruct* p = 0;
declares the pointer itself to be volatile. In general, the second version is the one to use.
20 Working with Acrobat Extended APIs
Some of Acrobat’s default plug-ins expose their APIs for use by third parties. These are Acrobat’s extended
APIs. The AcroColor extended API is the only extended API that is not in a plug-in: it is part of the Acrobat
core, but is considered an extended API because it does not cleanly fit into the layered structure of the
core. Although the APIs are documented in the Acrobat and PDF Library API Reference, this chapter provides
an overview.
About Acrobat extended APIs Describes the characteristics of Acrobat extended APIs. page 218
Search extended API Describes the Search extended API. page 219
Catalog extended API Describes the Catalog extended API. page 219
PDF Consultant and Accessibility Describes the PDF Consultant and Accessibility Checker page 219
Checker extended API extended API
Digital signature extended API Describes the digital signature extended API. page 229
Forms extended API Describes the forms extended API. page 235
Weblink extended API Describes the weblink extended API. page 236
Spelling extended API Describes the spelling extended API. page 237
AcroColor extended API Describes the AcroColor extended API. page 238
PDF Optimizer API] Describes the PDF Optimizer API page 244
218
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications Search extended API 219
The Search plug-in exports a host function table (HFT) that contains methods that can be used by other
plug-ins. The HFT’s name is Search, and its version number is 0. To use the Search plug-in’s HFT, a plug-in
must include the header file SrchClls.h. The plug-in must also import the HFT using the
ASExtensionMgrGetHFT method and assign the HFT returned by this call to a plug-in-defined global
variable named gSearchHFT. For information, see “Working with Host Function Tables” on page 164.
Acrobat 6.0 and later has two versions of the Search plug-in:
● The Search plug-in uses a search engine licensed from Lextek International. Lextek can be contacted at
http://www.lextek.com.
● The Search5 plug-in uses a search engine licensed from Verity, Inc. Verity can be contacted at
http://www.verity.com.
You can perform the following tasks with either version of the Search plug-in:
● Create or delete indexes
● Determine what indexes are available
● Send queries to an existing index
You cannot use either version of the Search plug-in to directly obtain the results of a search, for
manipulation or for display in an application other than Adobe Acrobat. For information about the
methods included in the Search extended API, see the Acrobat and PDF Library API Reference.
The Catalog plug-in has an HFT consisting of several methods that plug-in developers can import and use.
In addition, Catalog supports DDE, and broadcasts several Windows messages. For information about the
methods included in the Catalog extended API, see the Acrobat and PDF Library API Reference.
The consultant visits the objects in a PDF document according to instructional flags you pass to it. After
the consultant visits an object, the object may be different. The consultant reclassifies modified objects
before moving on to the next object.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications PDF Consultant and Accessibility Checker extended API 220
As the consultant traverses a PDF document, gathering objects of interest, it can perform the following
tasks:
● Walk a given hierarchy
● Keep track of cycles
● Ensure that objects are only visited once, if desired
● Recognize object types
● Keep a traversal stack list
Acrobat agents
The consultant accomplishes its task by using agents, which are pieces of code you design to gather the
statistics and recommend to the consultant the necessary repairs of the document. Separate agents
handle each area of analysis and repair. The agents inform the consultant of the particular types of objects
in which they are interested by registering with the consultant. When the consultant has one or more
agents registered, it hands each object of the requested type(s) in the current document to each of the
agents that requested that type. The consultant gives objects to each agent in turn, depending on the
order in which they registered.
The consultant must intelligently determine the type of each object it comes across (both direct and
indirect), so it can pass appropriate objects to the agents, or replace or remove ones that it has been
instructed to handle itself. The consultant communicates directly with agents, keeping lists of which
agents are interested in which objects, and obtaining instructions from the agent as to an object’s
visitation status.
Agents can perform their own repairs and modifications to the PDF document, and can return a corrected
object to serve as a replacement for the object the consultant originally passed to it. Agents can also
modify the Cos graph themselves (including adding or removing Cos objects or modifying the contents
such as keys or array elements).
The consultant keeps a list of each object (starting with the object which began the traversal) that it visits
on its way to any given object. Agents must be careful not to make any modifications that would affect any
of the objects in the list, which is referred to as the traversal stack. For this reason, agents can specify a
post-processing callback that the consultant invokes once it has finished traversing the entire document.
Agents also pass visitation flags to the consultant that determine how object types should be visited.
Limiting the traversal is important, as PDF documents are graphs, arbitrarily complex, and often there are
many ways to visit a single object. If the consultant reclassifies an object, it may also change the way that
object is revisited. You must keep this in mind as you develop your agents.
Agent architecture
Your agent code will primarily consist of a structure, as defined in the ConsExpt.h header file. Acrobat
provides a C++ wrapper class to facilitate writing agents; you can derive an agent class from this base class.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications How the consultant works 221
Reclassifying objects
In general, the consultant reclassifies an object after an agent is finished performing operations on it. It is
possible that, in the process of modifying the object, the agent may actually change the type of the object.
This could mean that agents originally interested in the object may not be interested in it. So the
consultant must reclassify an object after each agent has finished with it. Because the default behavior in
the revisit upon reclassification mode is to revisit objects when they are reclassified, new objects added in
this mode will actually be visited again if they are reclassified as the traversal continues.
Determining the higher-level type (the PDFObjType, as the consultant code calls it) of a given Cos object
is not always easy. The consultant not only looks at the construction of objects (what keys are present in
the object) but also at how the object was reached (through what particular object type and via what
keys). Objects that are interpreted differently depending on how they are traversed can be properly
identified.
Consultant process
The following steps describe the consultant process:
3. Register your agent with the consultant, with information as to which object types are of interest.
5. The consultant creates a traversal stack to keep track of where it is in walking through the PDF document.
6. The consultant begins traversing the PDF document. If agents have instructed the consultant to modify
or remove the object, it does so, returning the appropriate replacement.
7. The consultant pushes the object onto the traversal stack and sends a message to the agent that the
object was found.
8. The agent sends messages to the consultant about what to do to objects: replace them, remove them,
revisit them later or not.
9. When the entire PDF document has been traversed, the consultant calls the agent back to perform any
post-processing repairs it might want to do.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications Important issues for consultant development 222
If you do decide to use the consultant, there are a number of issues that are important to keep in mind
when you are developing your agent. You should make your decisions about all of these issues before you
write your code, so you will know exactly what to expect.
● Agents must not modify objects on the traversal stack while the consultant is still walking through the
document, otherwise infinite loops and other problems can occur.
● Decide which piece of code is actually going to do the work (the consultant or the agent) in order to
optimize your plug-in.
● The order in which agents interact with the consultant is very important, as agents can modify objects
that other agents want to see.
You should make your decisions about all of these issues before you write your code. Some of these issues
lead to errors that are difficult to debug, so it is best to understand them all while creating your plug-in.
It is extremely important that the integrity of the traversal stack remain undamaged. You must design your
agent carefully so as to avoid this problem. You can use the postprocessing step of your agent to handle
many repair tasks, thereby avoiding dealing with objects still on the traversal stack.
For example, suppose an agent wants to remove annotations while there are form widgets present in the
document. There are a few ways the agent can remove the annotations while the consultant is working,
but they all have problems:
● Invoking the agent for all annotations and removing them at the Cos level does not clean up the forms
tree if there are Widget Annots in the document.
● Invoking the agent for all annotations and using the PDPageAnnotRemove method modifies the page
object, which might still be in the traversal stack.
The best solution in this case is to enumerate all of the Annot objects by having the consultant look for
Annot objects and keep a list of them, then let the agent invoke PDPageAnnotRemove on them in the
postprocessing step.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications Importing the consultant HFTs into a plug-in 223
A rarer problem could occur with self-referential objects. For example, if DictA contains a reference to
itself and the first agent replaces DictA with DictB (which would still contain a reference to DictA),
another agent cannot work with DictB until the internal reference is changed. But if you are running the
agents concurrently, there will be a collision. This would be a case best handled by the consultant.
To access the HFT, you must include the ConsHFT.h file into your project. In a plug-in, the
PluginImportReplaceAndRegister method should contain the code that imports the HFT.
Because there is some memory overhead in creating a consultant, you should only create a Consultant
object when it is required, not before. If your target application is a plug-in, the most logical place to
perform all operations is in the menu item execute procedure. Whether or not it makes sense to destroy
the Consultant object after each execution of the menu item depends on your project.
The consultant HFT provides the functions ConsultantCreate and ConsultantDestroy, for creating
and destroying Consultant objects. It also provides the Consultant data type, an opaque type for
passing handles to Consultant objects. The ConsultantCreate method returns variables of that type
and requires them as parameters to all other HFT functions having the Consultant prefix.
After each run the consultant unregisters all the agents that were registered with it; however the memory
for the Consultant object itself remains, and the object must be explicitly destroyed to free the memory.
Depending on the duties you assign your consultant, you may want to destroy it after each execution of
the menu item that launches it, or you may wish to keep it running.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications Registering agents with consultants 225
Once the agent is registered with the consultant, it remains registered until a call to
ConsultantTraverseFrom is made. You must re-register agents before each successive call to
ConsultantTraverseFrom.
When you register an agent, you supply a rule (one of the RegAgentFlag values) for revisitation of
objects as the consultant runs through the document from the starting object. The following code
example registers an agent with a consultant.
DURING
AVDoc hAVDoc = AVAppGetActiveDoc();
miAssert(hAVDoc != ( AVDoc )NULL );
if( hAVDoc != ( AVDoc )NULL )
{
//Create a Consultant object
hConsultant = ConsultantCreate(
DumpAllObjectsAgentPercentDone );
miAssert( hConsultant != ( Consultant )NULL );
if((gDumpAllObjectsAgent == (DumpAllObjectsAgent*)NULL)
|| (gDumpAllObjectsAgent->IsValid() == false))
{
ASRaise(GenError(genErrNoMemory) );
}
else
{
ConsultantRegisterAgent(hConsultant,*gDumpAllObjectsAgent,
REG_REVISITRECLASS_ALL );
Each Cos object has a simple Cos type and attributes, in the scheme of the document as a whole each
object serves a particular purpose. The PDF object type assigned to each object represents that object's
role in the PDF document.
Some PDF object types represent higher-level, conceptually-familiar objects like PT_PAGE (which
indicates that the object is a page in the document), while others (like PT_AADICTIONARY ) are a bit more
obscure, particularly to those who are not familiar with the PDF document format. PDF object types are
represented using the enumerated type PDFObjType, which is defined in ConsObTp.h. A good way to see
all of the various PDF object types that the consultant can identify is to look at the constants defined in
that file.
Some object types (in particular many simpler objects such as strings and numbers) are not assigned a
particular type. The consultant can identify those objects that are of most use to you. If the consultant
cannot identify a specific object, it assigns the identity of PT_UNKNOWN to the object. Just because the
consultant assigns this value to an object does not mean the object is foreign or invalid (although it can
potentially mean that), it may simply mean that the object type is not particularly significant in the realm
of the PDF document format, and thus the consultant does not know about it.
To allow for greater agent flexibility, the consultant understands PDF object type subclasses and
superclasses. Certain PDF object types are members of more generic classes of PDF object type. Agents
can often make use of this information, so the consultant assigns object types that are actually arrays of
types.
The consultant assigns to an object the most specific classification as well as the more generic classes of
which the object is a member. Agent structures include a field called WantSubclasses that indicates
whether or not the agent wants to be called for all the interesting objects’ subclasses as well as their
directly interesting types.
For example, the PT_ANNOTATION object type has a number of more specific subclasses such as
PT_LINKANNOTATION, PT_LINEANNOTATION, and so on. If an agent requests only objects of type
PT_ANNOTATION, and its WantSubclasses member is false, it may not be called back for very many
objects. If the WantSubclasses member is true, then the consultant will invoke the agent back for
objects of all specific types of annotations as well as those classified only as PT_ANNOTATION. This also
means that when an agent retrieves the type of an object, it must specify which type it wants. The types in
the array that is the classification of the object always go from the most specific (at index 0) to the least
specific (the last index in the array).
//Constructor / destructor
DumpAllObjectsAgent(PDDoc hPDDoc);
virtual ~DumpAllObjectsAgent(void);
//Required methods
virtual void ConsAgentPostProcess(void);
virtual ASInt32 ObjFound(CosObj Obj, const PDFObjType*
pObjTypeHierarchy,
const ASUns32 SizeObjHierarchy,
TraversalStack Stack,CosObj* pObjToReturn);
};
The following example shows an example constructor. In the Agent example the array types and array
length are static data members of the Agent class. In larger-scale systems it is better to create a host
object for the agent that is responsible for determining the proper objects to include in the array and for
passing them on to the Agent constructor. The list of object types is passed on to the consultant when
ConsultantRegisterAgent is invoked.
In the Creating agent constructors example, an Agent constructor simply gathers information about each
object encountered and outputs it to a file. It does not need to have the consultant make any
modifications to the document. Therefore, in the definition of the ObjFound callback function, the return
value is always OD_NOCHANGE and the object returned in pObjToReturn is simply the same object that
was found. In many cases it makes the most sense for an agent to make all document modifications itself,
without the consultant’s replace and remove facilities. In these cases you must take special care not to
modify objects that are currently on the consultant’s traversal stack.
The DumpAllObjects plug-in demonstrates that PDFConsultant agents can access any Cos object
from any point in the document. The plug-in writes information about certain Cos objects to an output file,
called AllObjects.txt.
The ObjFound callback function of the DumpAllObjects agent writes to a file the Cos object traversal
path that it took to reach a specific Cos object. The function calls GetTraversalString, which
describes, with respect to other objects, where a given object lives in the document. For example, the
following shows the format of a traversal path of a text annotation:
18 0 obj PT_TEXTANNOTATION | PT_ANNOTATION | ->AcroForm->Fields->[0]->
P->Annots->[1]
The consultant looks at all Cos objects. To simplify the output, the DumpAllObjects agent only involves
the most common Cos objects—CosString, CosDict, CosArray, and CosStream.
The PostProcess callback function is the place to perform any operations that might otherwise damage
the consultant’s traversal by modifying objects up the consultant’s current traversal stack.
A single document may be signed more than once, and changes may occur between signings. Acrobat’s
digital signatures link each signature with a particular state of the document. All changes append the PDF
changes to the fully-preserved base PDF document. The ability to do serial signatures of protected
documents is unique to Acrobat, and draws heavily on the PDF file design for an appended save.
Adobe Acrobat implements digital signatures using plug-ins that can handle both generic functions
common to all digital signatures, and also specific kinds of signatures (signing methods), such as
public-private key (PPK), handwriting, retinal scans, fingerprints, and so on.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications The PubSec layer 230
Note: For information about the APIs that make up the Digital signature extended API, see the Acrobat
and PDF Library API Reference.
Handlers can call back into the PubSec HFT for various services. Most calls to PubSec pass an opaque state
object called a PSEngine. You specify a default engine upon registering the handler, and the default
engine can make use of the security UI dialog boxes provided by PubSec and DigSig.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications Digital signature components 231
1. Implement the callbacks you need to provide customized functionality. Many of the callbacks for
PubSec can be specified as NULL, in which case PubSec provides default behavior. It is recommended
that you use the default behavior when possible.
2. Fill in the handler structure with pointers to your callback implementations (PubSecHandler).
Acrobat’s digital signature plug-in creates these two parts when the user chooses to sign a document. Your
plug-ins do not have to handle deleting the signature, as the DigSig plug-in does that transparently.
1. If the user creates a signature field and does not specify a default signing method, DigSig handles that
case with no communication to your plug-ins:
● DigSig creates the signature field dictionary.
● DigSig creates the signature annotation dictionary.
● DigSig creates the (blank) signature appearance dictionary.
2. The Forms plug-in also creates Signature fields. If the user creates a signature field and specifies a
default method, Forms calls DigSig to fill in default values:
● DigSig creates the signature field dictionary, the signature annotation dictionary, and the (blank)
signature appearance dictionary.
● DigSig calls the DSDefaultValueProc callback that your plug-in provides. This callback must
create the default signature value dictionary and create the /DV key in the signature field
dictionary to point to it.
3. If the user asks to sign a specific signature field using the plug-in, DigSig invokes callbacks into your
plug-in during a four-step sequence. Your plug-in must register these callbacks during the plug-in
initialization phase. The four callbacks required for this scenario are:
● dsNewSigData
● dsCommitSign
● dsFinshSign
● dsFreeSigData
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications Initializing the digital signature plug-in 232
1. The DigSig plug-in exports its HFT under the name DigSigHFT.
2. To work with DigSig, your plug-in must import the DigSig HFT.
3. To work with DigSig, your plug-in must create a DigSigHandlerRec structure, assign the relevant
methods, and then invoke the DigSigRegisterFilter method to register the structure.
When the user opens a document, the digital signature plug-in notifies your plug-in of the new document
by invoking the DSDocOpenProc method. You can allocate some storage or choose to automatically
validate any of their respective signatures in the document.
Auto-validation may produce significant delays if it must read all of a large document from a CD-ROM or
over a network, or if it must access a signature registry or authority over a network. Therefore, Adobe
software only accesses signatures at user request.
When the user closes a document, the digital signature plug-in invokes DSDocCloseProc.
Saving a document
The following steps describe how the digital signature plug-in saves a document:
1. The digital signature plug-in invokes your DSCommitSignProc callback method to update the
document with the actual signature. Your DSCommitSignProc callback must perform the following
tasks:
● Create the signature dictionary, possibly using information in the signature field /DV dictionary,
perhaps using the /ByteRange and /Contents keys.
● Point /V in the signature field dictionary to this. Then create the /AP /N value in the signature
annotation dictionary, using a method-specific visible representation of the signature, including
a symbol signifying “unvalidated signature.”
● Optionally allocate dynamic storage for a marked array, an array of marked COS objects that it
cares about.
● Return a marked array that includes at least the /ByteRange and /Contents value objects.
2. The digital signature plug-in inserts the /Changes array from step 1.
3. The digital signature plug-in saves the PDF document to a file. For each Cos object in the marked array,
DigSig records the object’s byte offset and length in the file as written. The saved file may have objects
encrypted by the Acrobat standard encryption handler, if the user so chooses.
4. The first time a document is signed, the digital signature plug-in may rename the file and may invoke
the Optimizer, Linearizer, and Garbage Collector. Upon return from the save, all Cos objects are invalid,
including those in the marked array.
All PD-level objects except the PDDoc are invalid. Signing methods must not depend on saving any
such state between dsCommitSign and dsFinishSign. In particular, the byte offsets and lengths in
the marked array are valid upon entry to doSign, but the Cos objects are not. The order of entries is
unchanged, however, these Cos objects will be rewritten as CosNull before invoking dsFinishSign.
1. Invokes dsFinishSign, passing back in the marked array. Your DSFinishSignProc callback
method must perform the following tasks:
● Calculate the /ByteRange that it desires, using the byte offsets and lengths in the marked
array.
● Overwrite the marked /ByteRange value in the saved file, using the
DigSigOverwriteIntArray or DigSigOverwriteBytes callback.
● Overwrite any other marked Cos objects it wants to.
● Calculate any document digest that it desires, using the DigSigFileGetEOF,
DigSigFileSetPos, and DigSigFileRead callbacks; or it may use the
DigSigMD5ByteRange callback.
● Obscure or encrypt this digest in a method-specific way.
● Overwrite the marked /Contents value in the saved file, using
DigSigOverwriteHexstring or DigSigOverwriteBytes.
● Optionally delete dynamic storage for the marked array returned by the plug-in.
Revalidating signatures
If the user reopens the file, the signatures must be validated. If the user asks to validate one or more
signature fields, the digital signature plug-in sequences through them one at a time. Your
DSValidateSignProc callback method must perform the following tasks:
● Recalculate any document digest that it desires, using the DigSigFileGetEOF,
DigSigFileSetPos, and DigSigFileRead callbacks; or it may use the DigSigMD5ByteRange
callback.
● Compare this result to the stored one, and do any other method-specific checks it desires.
● Optionally do a validation against some stored (network) registry.
● Update the /AP /N value in the signature annotation dictionary to show doublechecked/pass/fail
symbol.
● Return doublechecked/pass/fail.
The user may open more than one document at a time, and may switch between open documents.
1. CLOSED displays a doublechecked/pass/fail/unknown/blank icon and a line of text for each signature
field in the document. The default text is the name of the person signing and the date and time of
signing, displayed in a language-independent way.
2. The digital signature plug-in calls dsGetValidState to choose which icon to show.
3. OPEN displays an icon and line of text for each signature, then indented lines of further text, currently
consisting of the name of the signer, date and time of signing, location of signing, reason for signing,
and signing method.
5. Your plug-in may update the signature panel for a document asynchronously (it might be doing
validation as a background or idle-loop task). To do this, use the DigSigUpdatePanel callback.
To avoid saving a signature to a file with an appearance of valid (rather than unvalidated), just before each
file save, DigSig loops through all the signature fields and calls the specific method’s dsUnValidateSig
entry. This routine restores the signature’s appearance to the unvalidated state.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications Forms extended API 235
The AcroForms Widget Annot handler calls into DigSig using four entries. These calls all reflect user actions
taken in the document view, not the Signatures panel view.
When the user selects an annotation by tabbing to it or by clicking it with the mouse, and that annotation
is for a signature field, AcroForms calls DigSigDraw. If the annotation is selected, then bIsSelected is
true. When the user tabs to a signature annotation and activates it by hitting the spacebar or enter key, this
is equivalent to a left mouse click.
When the user right-clicks inside a signature annotation, AcroForms calls DigSigRightClick.
Rollback support
There is a constraint on the values in the /ByteRange array. This constraint allows DigSig to implement
rollbacks prior to signatures.
The largest offset + length value in the /ByteRange array for a given signature must be equal to the length
of the PDF file containing that signature; that is, it must equal offset + 1 of the "F" in the %%EOF at the end
of the file.
Data may be imported and exported into Acrobat Forms in forms data format (FDF). FDF is used to submit
form data to a server, as well as to receive the response and incorporate it into a form. FDF is based on PDF
and uses the same syntax and set of basic object types as PDF. It also has the same file structure, except
that the cross-reference table is optional. See the PDF Reference for more information about the structure
of a PDF document.
Note: For information about the APIs included in the Forms extended API, see the Acrobat and PDF Library
API Reference.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications Weblink extended API 236
The Acrobat Weblink plug-in exports its own Host Function Table (HFT), whose methods can be used by
other plug-ins. The HFT’s name is defined in the WLHFTNAME macro, and its version number is
WEB_LINK_HFT_LATEST_VERSION.
To use the Weblink plug-in’s HFT, a plug-in must include the header file WeblinkHFT.h. The plug-in must
also import the HFT using ASExtensionMgrGetHFT and assign the HFT returned by this call to a
plug-in-defined global variable named gWLHFT. The easiest way to do this is to use the Init_gWLHFT
macro defined in the header files.
Note: For information about the APIs included in the Weblink extended API, see the Acrobat and PDF
Library API Reference.
Weblink services
The Weblink plug-in provides the following services:
● Maintenance of links (editing and storage of URLs associated with links, and so on)
● Manipulation of links (appropriate cursor changes and dynamic display of URL destinations)
● Selection of the external web browser
● Manipulation of the Adobe standard web driver
● Basic progress status services (progress monitor, wait cursor, and so on)
The Weblink plug-in includes a standard driver, known as the Adobe Standard Web Driver. It allows
support for transport mechanisms or web browsers to be added at a later time.
The Standard Web Driver uses DDE messages and Apple events to communicate with a web browser. It
supports a protocol that consists of a suite of verbs—some going to and some coming from—the web
browser. These verb definitions are provided so that web browsers can implement this protocol to be
compatible with the Adobe standard web driver. Each verb is specified in terms of the platform-specific
implementation: DDE for Windows and Apple events for Mac OS. The standard driver’s use of each verb is
also described. Browsers that wish to use their own protocol may do so by writing a custom driver.
The Weblink plug-in communications software in the Weblink driver is independent of the Acrobat
mechanism for handling links (the PDF implementation of URLs). This separation improves portability by
isolating the highly platform-specific interapplication communication messages. Even on a given
platform, there is no standard among web browsers for handling interapplication communication, and the
actual transport mechanism may vary over time. By separating out the transport code, the Weblink plug-in
remains portable across platforms, across different vendors’ implementations of web browsers, and across
different versions of web browsers from the same vendor.
2. The user opens a PDF document with Weblinks and clicks a Weblink.
● The Weblink plug-in extracts the URL from the link and passes it to the driver.
● The driver packages the URL into an interapplication communication (IAC) message and sends it to
an external web browser (launching the browser application, if necessary).
● The external web browser brings itself to the foreground unless the URL’s MIME type is
application/pdf.
3. The web browser retrieves the document and packages an IAC message.
● The driver accepts the IAC message from the browser and opens the PDF document by using the
AVDocOpenFromFile method. The driver should associate the URL with the document.
● To resolve relative links, Weblink prepends either a base URL with the document, or if there is no
base URL, the appropriate portion of the URL of the document the link is in.
To use the spelling HFT, a plug-in must include the header file SpellerHFT.h, which includes Speller_Sel.h.
The following is a typical sequence of calls made by a plug-in using the Spelling HFT. During its
importReplaceAndRegister callback, the plug-in should:
● Import the HFT, using ASExtensionMgrGetHFT, and assign the HFT returned by this call to a
plug-in-defined global variable named gSpellerHFT. The easiest way to do this is to use the
Init_SpellerHFT macro defined in SpellerHFT.h.
● Allocate and initialize one SpellCheckParam block for each spelling domain the client will add.
● Add zero or more domains using the SpellAddDomain call.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications AcroColor extended API 238
2. The client may call other Spelling HFT services during execution even if it did not add a domain.
1. Remove all spelling domains added during initialization using the SpellRemoveDomain method.
2. Free all memory associated with SpellCheckParam block(s) (scInBuffer, scOutBuffer, and
scClientData).
Several of the Spelling API methods (SpellCheck, SpellCheckText, and SpellCheckWord) take
input strings as parameters, and several methods return strings as output parameters.
Input strings are either big-endian Unicode strings with the bytes 0xFE 0xFF prepended, or strings with
PDFDocEncoding. In either case a string is expected to have the appropriate null-termination. If a string
is UCS-2 it may have embedded language and country information.
Output text is in big-endian UCS-2 format with the bytes 0xFE 0xFF prepended. This string can be
converted to a host encoded string by using the ASTextFromPDText and ASTextGetEncodedCopy
methods:
char **altArray = NULL;
ASInt32 altCount = 0;
ASBool status = SpellCheckWord(acd, cWord, NULL, 0, &altArray, &altCount);
if (altCount) {
ASText ast = ASTextFromPDText(altArray[1]);
char* altWord = ASTextGetEncodedCopy(ast, (ASHostEncoding)
PDGetHostEncoding() );
}
While not, strictly speaking, an “extended API” (since the API is not exposed from a plug-in) the AcroColor
API is included here with the extended APIs since it doesn’t fit into the “layered” structure of the Acrobat
core API. The AcroColor APIs, unlike the other extended APIs, can be used by the PDF Library.
The AcroColor HFT encapsulates color management into a set of convenient objects and functions. The
objects represent basic color-management entities:
● The color management engine, or ACE, which is used by the underlying software to control a color
management session.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications AcroColor extended API 239
● Device-specific ICC color profiles, which provide specific mapping between standard color
specifications and specific values for particular output devices that produce those colors. Additional
support objects include profile lists.
● Color spaces for the different kinds of color production (such as grayscale, RGB, and CMYK). Additional
support objects include calibrated color spaces for standard color specifications.
● Transformations between profiles or color spaces.
● Color settings, as listed in the Acrobat Preferences. Color settings files contain, for instance, references
to color profiles, and apply across Adobe products. Additional support objects include a string object
and preset lists of settings.
You can create an ICC color profile from available data (ACMakeBufferProfile), or use profiles that are
installed on the system (ACGetWorkingSpaceProfile), or stored in color settings files
(ACGetSettingsProfile).
You can extract information directly from profiles, such as a string to use in the UI
(ACProfileDescription). However, the most important thing you do with color profiles is use them to
make transformations (ACMakeColorTransform). You can then apply it (ACApplyTransform) to
transform a set of image data from one profile to another, so that it appears with the same colors on a
different display device.
AcroColor objects are reference-counted. Each object type has an unreference method (such as
ACUnReferenceProfile). Whenever you create one of these objects, you are responsible for using the
corresponding unreference method to release it when you are finished with it.
The list of conversion actions is evaluated in order. For example, a list could contain the following actions:
Object attributes
An object located within a PDF document can contain the following attributes:
● Image (for example, JPEG/JPEG2K, lossless)
● Line art (for example, fill or stroke)
● Text
● Smooth shade
● Transparency
● Overprinting
Conversion actions
The following is a list of conversion actions:
● Convert to a color space
● Preserve the object as it is
● Alias a separation to a different one
● Decalibrate the object, if possible (for example, replace calibrated spaces with device). This does not
work with Lab color spaces.
● Downconvert from NChannel to DeviceN
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications AcroColor extended API 241
Action modifiers
The following action modifiers apply if the action converts the object:
● Render Intent:
● Override the color conversion with one of the ICC intents
● Use document intent
● Preserve black
● Black point compensation: on or off
● Embed or do not embed the target profile if the object was converted
Ink aliasing
Along with the list of actions, there is a list of inks, such as specific colorants, which can control whether a
particular ink is converted to process or aliased to another colorant.
Data structures
The AcroColor extended API contains methods, such as PDDocColorConvertPage, that accept data
structure instances as arguments. These data structures consist of a list of action records and a list of inks.
Each action record specifies attributes, color spaces, and rendering intent, along with an action. That is,
what to do with the particular object if a match is located. The ink list defines ink aliasing or conversion to
process for particular named colorants.
The following list specifies the data structures that you use to work with the AcroColor extended API:
PDColorConvertAction: Defines a color conversion action for a combination of attributes, color space,
and rendering intent.
PDColorConvertParams: Represents a list of actions that will be performed.
Note: For information about these data structures and their data members, see the Acrobat and PDF
Library API Reference.
For information about these enum values, see the Acrobat and PDF Library API Reference.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications AcroColor extended API 242
2. Create an AC_Profile object. This object is used to assign a value to the mConvertProfile data
member that belongs to the PDColorConvertAction data structure. When you are done with this
object, invoke the ACUnReferenceProfile method to release it from memory.
5. Create an instance of the PDColorConvertAction data structure and assign the following values to
its data members:
mMatchAttributesAny: Assign -1
mMatchSpaceTypeAny: Assign -1
mMatchIntent: Assign AC_UseProfileIntent (an AC_RenderIntent value)
mConvertProfile: Assign the AC_Profile object
mEmbed: Assign true
mPreserveBlack: Assign false
mUseBlackPointCompensation: Assign true
mAction: Assign the PDColorConvertActionType variable
● The data element to pass to the progress monitor callback. You can pass NULL if you do not want to
provide a progress monitor callback.
● A PDColorConvertReportProc object that represents the reporting callback. You can pass 0 to
indicate that there is no reporting callback.
● The data element to pass to the reporting callback. You can pass NULL if you do not want to provide
a reporting callback.
● The address of an ASBool variable. If a conversion is made to the specified page, true is assigned.
The following code example converts a page in a PDF document to Apple RGB.
For information about the APIs included in the AcroColor extended API, see the Acrobat and PDF Library API
Reference.
Adobe Acrobat SDK Working with Acrobat Extended APIs
Developing Plug-ins and Applications PDF Optimizer API 244
Using this API, you can reduce the size of bulky PDF files and run Distiller optimizations on PDF files
without having to print them. Avoiding the print route enables you to retain bookmarks, tags, links, and so
on. You can also make PDF files compatible with specific versions of Acrobat.
You can invoke the AVDocSaveOptimized method to run the PDF Optimizer tool on a specified PDF
document. An optimized document is created using the settings specified in the PDFOptParams
structure. The optimized document is saved to disk at the location specified in the parameter's structure. If
the operation is successful, the active document is closed and the optimized document is opened for
viewing. If the operation fails, the active document remains open.
The AVDoc object passed to the proc should not be dirty. PDF Optimizer is unavailable in external
windows like those of a web browser, so the AVDoc object should not be from a document open in an
external window. The document should not be of a version greater than the default PDF version of the
Acrobat application.
When you invoke the AVDocSaveOptimized method, pass the following arguments:
● An AVDoc object that represents the PDF document to optimize.
● An instance of a PDFOptParams data structure. For information about this data structure, see the
Acrobat and PDF Library API Reference.
21 Creating an Adobe Reader Plug-In
This chapter describes the steps required to enable a plug-in to be loaded by Adobe Reader. Both technical
and licensing restrictions exist on what an Adobe Reader plug-in can accomplish.
A common cause of difficulty when Reader-enabling a plug-in is that the plug-in attempts to acquire one
or more HFTs during startup that are not available within Adobe Reader. To avoid this problem on
Windows and Mac OS, make sure that the READER_PLUGIN symbol is defined. On the Windows platform,
this can be achieved by placing READER_PLUGIN in the preprocessor definitions section of the project
settings. On the Mac OS platform, this can be achieved by placing #define READER_PLUGIN in
PIRequir.h. With this symbol defined, only those HFTs available in Adobe Reader are acquired. On the UNIX
platform, only those HFTs available within Adobe Reader are acquired by default. For information about an
HFT, see “Working with Host Function Tables” on page 164.
Enabling an Adobe Reader plug-in Describes how to enable an Adobe Reader plug-in. page 245
Creating resource files on the Describes how to create resource files on the Mac OS page 246
Mac OS platform platform.
Creating resource files on the Describes how to create resource files on the page 247
Windows platform Windows platform.
Troubleshooting Describes how to solve problems that may occur with page 249
an Adobe Reader plug-in.
1. Write the code for your plug-in. When possible, ensure that the plug-in works correctly in the full
Acrobat viewer (Standard or Professional) before trying to Reader-enable it.
2. Visit the Adobe web site and fill out an Adobe Reader Integration Key License Agreement. There is a fee
involved. The Adobe Reader Integration Key Licensing Agreement can only be submitted as a web
form. Information can be found at http://www.adobe.com/go/acrobat_developer.
Once your Adobe Reader Integration Key Licensing Agreement is approved, you will receive a contract
package that includes your contract number and other information that is unique to you.
3. Create the public/private key pair and public key files (see the platform-specific instructions below)
using the MakeKey utility provided in the Acrobat SDK.
245
Adobe Acrobat SDK Creating an Adobe Reader Plug-In
Developing Plug-ins and Applications Creating resource files on the Mac OS platform 246
4. Return to the Adobe web site (the exact URL will be provided to you in your contract package), and
upload only the public key as a ZIP, HQX, or TAR archive. You must submit your public key via the
Internet. There is no other method available. The same web form is used for all geographic locations.
Your public key will be used to generate an encrypted digital certificate which will be returned in an
HQX, ZIP, or TAR file. The certificate can then be used to enable any plug-in you create which meets the
criteria established by the Adobe Reader Integration Key Licensing Agreement. If you have a digital
certificate that you created for a plug-in for a previous version of Acrobat, you do not need to have a
new certificate generated. Be sure to state if your key is for a Windows, Mac OS, or Unix platform. The
encrypted digital certificate that you receive back from Adobe will be named using your contract
number. You are free to rename it.
5. After receiving the digital certificate, generate an encrypted key and add it to the plug-in as described
for each platform in the following sections. The plug-in should now be enabled for loading by Adobe
Reader.
To enable your Acrobat 7 or later plug-in for Adobe Reader, use the enabling tool supplied with the
Acrobat 7 SDK. For Acrobat 6, use the tool supplied with Acrobat 6. The same digital certificate that you
received from the Adobe Support Network (ASN) is used for both enablings.
1. Run the MakeKey utility. MakeKey must be passed two parameters—the name of the file in which to
store the key pair, and the name of the file in which to store the public key. Neither name can exceed
the platform limitations on filename lengths.
MakeKey keypair.rsrc publickey.rsrc
Enter a random seed value at the prompt. This can be any string of alphanumeric characters, up to 126
characters in length. This process can take from 30 seconds to a minute in length, and there is no user
interaction during this time. The size of the public key should be 415 bytes. The size of the
public/private key pair should be 796 bytes. The size of the returned encrypted key should be 458
bytes.
2. Send an HQX archive containing the public key to Adobe using the instructions given in step 4 of
Enabling an Adobe Reader plug-in.
Adobe Acrobat SDK Creating an Adobe Reader Plug-In
Developing Plug-ins and Applications Enabling the plug-in for Adobe Reader 247
2. Run the ReaderEnable tool using the command line options shown in the sample invocation below.
Pass the key pair resource file, the digital certificate resource file, and the plug-in as arguments. The
following sample invocation enables plug-in Plug-in.acroplugin located at
/Volumes/dev/Plugin/build.
./ReaderEnable -kf ./keypair.rsrc -cf ./digitalcertificate.rsrc
/Volumes/dev/Plugin/build/Plug-in.acroplugin
If successful, you will receive the message: “Plug-in.acroplugin successfully Reader Enabled”. (Tip: to
easily copy paths to the command line, drag files from the Finder window to the Terminal window.) The
plug-in can now be loaded by Adobe Reader.
Note: Steps 1 and 2 must be repeated each time the plug-in is built. The public and private key pair and
digital certificate files may be used.
2. Upload a ZIP file containing the public key using the instructions given in step 4 of Enabling an Adobe
Reader plug-in.
2. Open your plug-in project in Visual Studio. Make sure you are in Resource View.
Adobe Acrobat SDK Creating an Adobe Reader Plug-In
Developing Plug-ins and Applications Creating resource files on the UNIX platform 248
3. Open dummy.rc from your project directory. Copy the API_ENCRYPTED_DIGEST data segment (a
dummy encrypted digest) to the resource portion of your plug-in.
4. Open the digital certificate file returned to you by Adobe. Copy the API_DIGITAL_CERTIFICATE
data segment (your digital certificate) to the resource portion of your plug-in.
5. Rebuild your plug-in. The plug-in will be created with the correct API_DIGITAL_CERTIFICATE data
segment and a dummy API_ENCRYPTED_DIGEST data segment, which will be replaced with real data
in the next steps.
6. Run Makemd32.exe.
● Type the path to the plug-in.
● Type the path to the keypair file generated above.
● Type the path of the file to store the encrypted message digest. It is recommended that you save
this as msgdig.rc.
7. Within Visual Studio .NET, delete the dummy API_ENCRYPTED_DIGEST data segment from your
plug-in project. Open the msgdig.rc file that Makemd32.exe created. Copy the
API_ENCRYPTED_DIGEST data segment from msgdig.rc to the resource portion of your plug-in.
8. Build your plug-in again, doing a build only (not a rebuild-all). This will create a plug-in that has the
correct API_DIGITAL_CERTIFICATE and API_ENCRYPTED_DIGEST resources.
The plug-in can now be loaded by Adobe Reader. If you encounter any difficulties refer to
“Troubleshooting” on page 249.
Note: Steps 6-8 must be repeated each time the plug-in is built. The same public/private key pair and
digital certificate files may be used.
2. Upload a TAR file containing the public key using the instructions given in step 4 of “Enabling an Adobe
Reader plug-in” on page 245.
Adobe Acrobat SDK Creating an Adobe Reader Plug-In
Developing Plug-ins and Applications Enabling the plug-in for Adobe Reader 249
The plug-in can now be loaded by Adobe Reader. If you encounter any difficulties, refer to
“Troubleshooting” on page 249.
Troubleshooting
There are a number of issues that can cause a plug-in not to load in Adobe Reader. The most common
issues are documented here. If the problem persists, contact Acrobat Developer Support.
The first error will be displayed if the plug-in returns false from the PISetupSDK method (defined in
PIMain). The method will return false if the plug-in attempts to acquire an HFT that is not available. For
information, see “Working with Host Function Tables” on page 164.
Index
250
Adobe Acrobat SDK Index
Developing Plug-ins and Applications 251
M
E memory usage 46
enabling for Adobe Reader 25 menus and menu items 34
errorcode macro 214 methods
event handling 31 ASAtomGetString 110
events 31 ASExtensionMgrGetHFT 165
exception handler ASFileClose 85
creating 214 ASFileGetEOF 85
returning values 215 ASFileRead 85
exporting ASFileSysCreatePathName 72
host function tables 165 ASFileSysOpenFile 79, 85
exporting HFTs 29 ASFileWrite 85
external window ASGetDefaultFileSys 72, 83
creating 75 ASMemStmRdOpen 193
creating handler 76 AVAlertNote 85
defining parameters 75 AVAppGetActiveDoc 84, 125, 136
displaying a PDF document 74 AVAppGetToolBarByName 98
ExternalDocServerCreationDataRec typedef 74 AVAppRegisterCommandHandler 140
extracting words 134 AVDocFromPDDoc 116
Adobe Acrobat SDK Index
Developing Plug-ins and Applications 252