A Practical Guide to RadaeePDF APIs: Optimization, Annotations, and Cross-Platform UX

Analyzing the most frequent requests from our developer community, we noticed that most challenges revolve around two main areas: document loading performance and interactivity via annotations.

In this article, we will explore how to master these features using native RadaeePDF APIs in Java, Objective-C, and C#.

1. Optimizing Document Opening (Linearization)

When working with very heavy PDF documents, especially remotely (via HTTP stream), the wait for a full load can penalize the user experience. Linearization (or Fast Web View) solves this problem by allowing the first page to render before the entire file is downloaded.

The SetOpenFlag method allows you to instruct the RadaeePDF engine on how to behave during opening. Option 3 is often the best performing: it reads the linearized header, loads the first page, and assumes subsequent pages have the same dimensions, skipping time-consuming checks.

Implementation Examples:

Java (Android)

// Initialize the document and set the global flag
Document doc = new Document();
Document.SetOpenFlag(3); // 3 = Fast loading of linearized header

// Open the document (from stream or local file)
int ret = doc.OpenStream(m_http_stream, "password_if_present");
if (ret == 0) {
    // Get the status to verify if the PDF was actually linearized
    int status = doc.getLinearizedStatus();
    Log.d("PDF_STATUS", "Linearization status: " + status);
}

Objective-C (iOS)

// In iOS the flag is set via a global C function
Document_setOpenFlag(3);

PDFDoc *doc = [[PDFDoc alloc] init];
int error = [doc openStream:httpStream :@"password_if_present"];

if (error == 0) {
    // Check the status
    int status = [doc getLinearizedStatus];
    NSLog(@"Linearization status: %d", status);
}

C# (.NET / Xamarin / UWP)

// Setting the flag via the Global or Document static class
RadaeePDF.Document.SetOpenFlag(3);
RadaeePDF.Document doc = new RadaeePDF.Document();

int result = doc.Open(pdfPath, "password_if_present");
if (result == 0) {
    int status = doc.GetLinearizedStatus();
    Console.WriteLine($"Linearization status: {status}");
}

2. Managing Markup Annotations (Highlights, Underlines)

Making a PDF interactive means allowing the user to extract data and add notes. If you use our wrappers (like the Cordova plugin), you can extract all annotations in a convenient JSON format. If you work natively, you can add markup by calculating character indices.

Here is how to add a Markup annotation (e.g., Highlight = Type 0).

Java (Android – Core & Cordova Wrapper)

// Example using the manager (e.g., in Cordova)
// type: 0 = Highlight, 1 = Underline, 2 = StrikeOut
int type = 0;
// Get the character index starting from the touch coordinates (x, y)
int index1 = mPdfmanager.getCharIndex(pageNo, startX, startY);
int index2 = mPdfmanager.getCharIndex(pageNo, endX, endY);

// Add the annotation
mPdfmanager.addMarkupAnnotation(pageNo, type, index1, index2);

// JSON extraction (if supported by the wrapper)
String markupAnnotationsJson = mPdfManager.GetMarkupAnnotationDetails(pageNo);

Objective-C (iOS)

int type = 0; // Highlight

// Find the character indices using the touch coordinates
int index1 = [plugin GetCharIndex:page x:startX y:startY];
int index2 = [plugin GetCharIndex:page x:endX y:endY];

// Add the markup
[plugin AddMarkupAnnotation:page type:type index1:index1 index2:index2];

// Get details in JSON
NSString *json = [plugin GetMarkupAnnotationDetails:page];

C# (Native API equivalent)

// Working directly with the Page object in C#
RadaeePDF.Page page = doc.GetPage(pageNo);
page.ObjsStart();

// Find the character index on the page
int index1 = page.ObjsGetCharIndex(startX, startY);
int index2 = page.ObjsGetCharIndex(endX, endY);

// Add the annotation (0 = Highlight, color in ARGB format)
bool success = page.AddAnnotMarkup(index1, index2, 0, unchecked((int)0xFFFFFF00)); // Yellow
page.ObjsAlignWord(out index1, out index2);
page.Close();

3. Advanced UX: Adaptive Resizing of Free Text Annotations

A common UX issue is the “Free Text” annotation (Type 3) maintaining a fixed height regardless of the text entered. From SDK version 3.53.5 onwards, it’s possible to recalculate the annotation’s bounding box (Rect) before saving it, adapting it to the content.

The key concept (common to all platforms) is intercepting the moment the user closes the text editor (dismiss) and updating the “Rect” in the PDF engine.

Java (Android – UI Level)

// Inside your GLView, when the keyboard or text popup is dismissed
m_pEdit.setOnDismissListener(new PopupWindow.OnDismissListener() {
    @Override
    public void onDismiss() {
        if (m_annot != null && m_annot.GetType() == 3) { // 3 = Free Text
            // Get the original rectangle [left, top, right, bottom]
            float[] old_pdf_rect = m_annot.GetRect();
           
            // Calculate the new height based on the View divided by the page scale
            float new_height = m_pEdit.getContentHeight() / m_annot_page.GetScale();
           
            float[] new_pdf_rect = new float[4];
            new_pdf_rect[0] = old_pdf_rect[0]; // Left
            new_pdf_rect[2] = old_pdf_rect[2]; // Right
            new_pdf_rect[3] = old_pdf_rect[3]; // Bottom
            new_pdf_rect[1] = new_pdf_rect[3] - new_height; // Recalculate Top
           
            // Apply the new coordinates to the annotation
            m_annot.SetRect(new_pdf_rect[0], new_pdf_rect[1], new_pdf_rect[2], new_pdf_rect[3]);
        }
    }
});

Objective-C (iOS – Logical Concept)

// Inside your UITextView delegate (e.g., textViewDidEndEditing)
- (void)textViewDidEndEditing:(UITextView *)textView {
    if (m_annot != nil && [m_annot type] == 3) {
        PDF_RECT old_pdf_rect = [m_annot rect];
       
        // Calculate the new height based on the textView's contentSize and zoom scale
        float new_height = textView.contentSize.height / [m_annot_page scale];
       
        PDF_RECT new_pdf_rect;
        new_pdf_rect.left = old_pdf_rect.left;
        new_pdf_rect.right = old_pdf_rect.right;
        new_pdf_rect.bottom = old_pdf_rect.bottom;
        new_pdf_rect.top = new_pdf_rect.bottom - new_height; // Adapt the height
       
        [m_annot setRect:&new_pdf_rect];
    }
}

C# (Xamarin/UWP – Logical Concept)

// In the Unfocused or text changed event of your TextBox/Editor UI
private void OnEditorUnfocused(object sender, FocusEventArgs e)
{
    if (m_annot != null && m_annot.GetType() == 3)
    {
        float[] old_pdf_rect = m_annot.GetRect();
       
        // Simulate calculating the height needed for the text
        float new_height = CalculateTextHeight(myTextBox.Text) / m_annot_page.GetScale();
       
        float left = old_pdf_rect[0];
        float right = old_pdf_rect[2];
        float bottom = old_pdf_rect[3];
        float top = bottom - new_height;
       
        m_annot.SetRect(left, top, right, bottom);
    }
}

Conclusion

Mastering these three aspects — loading optimization (SetOpenFlag), annotation manipulation, and User Experience refinement (Auto-resize) — will allow you to leverage the full power of the RadaeePDF core engine.

For further details on these APIs or to explore advanced features like extracting Custom Page Labels, we invite you to consult our Knowledge Base or open a ticket in the support portal. Happy coding!

Utilizzato da

Need help?

For further information or clarifications regarding RadaeePDF licence plans, please do not hesitate to contact us, we will be more than happy to guide you towards the solution best suited to your development needs.