Accessibility โ
Foxit PDF SDK provides PDF accessibility capabilities for creating and maintaining structure tags, checking compliance rules, fixing common issues, and editing reading order and the tag tree so assistive technologies (such as screen readers) can interpret documents correctly.
Auto tagging is supported from version 8.4. From version 12.0, APIs for checking, fixing, navigation, reading order, and tag-tree editing are public, and auto tagging has improved structure recognition (such as heading levels H1/H2).
System Requirements โ
- Platforms: Windows, Mac, Linux
- Languages: C, C++, Java, C#, Python, Objective-C, Node.js, Go
- License: A license key that includes the
Accessibilitymodule
Auto tagging โ
Use TaggedPDF to automatically tag a PDF. Supported from version 8.4 (Node.js requires 10.0+, Go requires 11.0+). From version 12.0, auto tagging improves structure recognition such as heading levels, making the tag tree easier to navigate by outline. Header path, SetCallback deprecation, and StartTagDocument parameter changes are in Release notes ยท TaggedPDF. A complete runnable sample is in the product package under examples/simple_demo/taggedpdf.
StartTagDocument can take:
pause: progressive pause callback (may beNULL)report_callback: tagging report output stream (may beNULL)callback:AutoTagProviderCallbackfor custom report text (may beNULL). ImplementGetReportText(AutoTagResultDataType type)only when custom text is required
c++
#include "include/common/fs_common.h"
#include "include/pdf/fs_pdfdoc.h"
#include "include/addon/accessibility/fs_taggedpdf.h"
using namespace foxit;
using namespace foxit::common;
using namespace pdf;
using namespace foxit::addon::accessibility;
// Assume Library::Initialize has been called, and the license includes the Accessibility module.
PDFDoc pdf_doc(input_file);
pdf_doc.Load();
TaggedPDF tagged_pdf(pdf_doc, false);
Progressive progressive = tagged_pdf.StartTagDocument(NULL, NULL, NULL);
Progressive::State state = Progressive::e_ToBeContinued;
while (Progressive::e_ToBeContinued == state) {
state = progressive.Continue();
}
pdf_doc.SaveAs(output_file_path);C
#include "include/fs_basictypes_c.h"
#include "include/fs_common_c.h"
#include "include/fs_pdfdoc_c.h"
#include "include/fs_taggedpdf_c.h"
...
FS_PDFDOC_HANDLE pdf_doc = NULL;
FSDK_PDFDoc_Create0(input_file, &pdf_doc);
FSDK_PDFDoc_Load(pdf_doc, NULL, NULL);
FS_TAGGEDPDF_HANDLE tagged_pdf = NULL;
FSDK_TaggedPDF_Create(pdf_doc, FALSE, &tagged_pdf);
FS_PROGRESSIVE_HANDLE progressive = NULL;
FSDK_TaggedPDF_StartTagDocument(tagged_pdf, NULL, NULL, NULL, &progressive);
FS_PROGRESSIVESTATE progressive_state = e_FSToBeContinued;
while (progressive_state == e_FSToBeContinued) {
FSDK_Progressive_Continue(progressive, &progressive_state);
}
FS_BOOL return_value = FALSE;
FSDK_PDFDoc_SaveAs(pdf_doc, output_file, 0, &return_value);
FSDK_TaggedPDF_Release(tagged_pdf);
FSDK_PDFDoc_Release(pdf_doc);java
import com.foxit.sdk.common.Progressive;
import com.foxit.sdk.pdf.PDFDoc;
import com.foxit.sdk.addon.accessibility.TaggedPDF;
PDFDoc pdfDoc = new PDFDoc(input_file);
pdfDoc.load(null);
TaggedPDF taggedpdf = new TaggedPDF(pdfDoc, false);
Progressive progressive = taggedpdf.startTagDocument(null, null, null);
int progressState = Progressive.e_ToBeContinued;
while (Progressive.e_ToBeContinued == progressState) {
progressState = progressive.resume();
}
pdfDoc.saveAs(output_file_path, 0);py
pdfDoc = PDFDoc(input_file)
pdfDoc.Load("")
taggedpdf = TaggedPDF(pdfDoc, False)
progressive = taggedpdf.StartTagDocument(None, None, None)
progressState = Progressive.e_ToBeContinued
while Progressive.e_ToBeContinued == progressState:
progressState = progressive.Continue()
pdfDoc.SaveAs(output_file_path, PDFDoc.e_SaveFlagNoOriginal)objc
FSPDFDoc* doc = [[FSPDFDoc alloc] initWithPath:inputFile];
FSErrorCode errorCode = [doc load:nil];
FSTaggedPDF* taggedpdf = [[FSTaggedPDF alloc] initWithDoc:doc];
FSProgressive* progressive = [taggedpdf startTagDocument:nil report_callback:nil callback:nil];
while ([progressive resume] == FSProgressiveToBeContinued) {
}
[doc saveAs:outputFile save_flags:FSPDFDocSaveFlagNoOriginal];js
let pdfDoc = new FSDK.PDFDoc(input_file);
pdfDoc.Load("");
let taggedpdf = new FSDK.TaggedPDF(pdfDoc, false);
let progressive = taggedpdf.StartTagDocument(null, null, null);
let progressState = FSDK.Progressive.e_ToBeContinued;
while (FSDK.Progressive.e_ToBeContinued == progressState) {
progressState = progressive.Continue();
}
pdfDoc.SaveAs(output_file_path, FSDK.PDFDoc.e_SaveFlagNormal);csharp
using (PDFDoc pdf_doc = new PDFDoc(input_file))
{
pdf_doc.Load(null);
using (TaggedPDF taggedpdf = new TaggedPDF(pdf_doc, false))
{
Progressive progressive = taggedpdf.StartTagDocument(null, null, null);
Progressive.State state = Progressive.State.e_ToBeContinued;
while (state == Progressive.State.e_ToBeContinued)
{
state = progressive.Continue();
}
}
pdf_doc.SaveAs(output_file, 0);
}go
pdfDoc := NewPDFDoc(input_file)
pdfDoc.Load("")
taggedpdf := NewTaggedPDF(pdfDoc, false)
progressive := taggedpdf.StartTagDocument()
progressState := ProgressiveE_ToBeContinued
for ProgressiveE_ToBeContinued == progressState {
progressState = progressive.Continue()
}
pdfDoc.SaveAs(output_file_path, uint(PDFDocE_SaveFlagNoOriginal))A complete sample for custom report text is in the product package under examples/simple_demo/taggedpdf.
Accessibility checking โ
From version 12.0, use AccessibilityChecker to run accessibility rule checks on a document.
Typical workflow:
- Construct
AccessibilityChecker(pdf_doc). UseCanCheck()to determine whether a full check is possible. - Configure
AccessibilityCheckOptions(check_rule_arrayfor the rule list,page_rangefor the page range; an empty page range means all pages). Rule values are defined byAccessibilityCheckOptions::e_CheckValidateRuleType*. - Implement
AccessibilityCheckResultsCallbackand receive the result tree inReportCheckResult. - Call
StartCheckand poll with the usualProgressivepattern until complete.
c++
using namespace foxit::addon::accessibility;
class MyCheckResultsCallback : public AccessibilityCheckResultsCallback {
public:
virtual WString GetIdentityName() override { return L""; }
virtual WString GetIdentityOrganization() override { return L""; }
virtual WString GetURL(const WString& link_info) override { return L""; }
virtual WString GetTextName(const WString& string_id) override { return L""; }
virtual void ReportCheckResult(const AccessibilityCheckResultItemDataArray& item_array) override {
// Iterate item_array and handle check results.
}
};
// Assume PDFDoc pdf_doc has been loaded.
AccessibilityChecker checker(pdf_doc);
if (!checker.CanCheck()) {
// The current document does not meet full check prerequisites.
}
AccessibilityCheckOptions options;
UInt32Array rules;
rules.Add(AccessibilityCheckOptions::e_CheckValidateRuleTypeDocTagged);
rules.Add(AccessibilityCheckOptions::e_CheckValidateRuleTypeDocLanguageSpecified);
options.check_rule_array = rules;
// An empty options.page_range means all pages.
MyCheckResultsCallback results_callback;
Progressive progressive = checker.StartCheck(options, NULL, &results_callback, NULL);
Progressive::State state = Progressive::e_ToBeContinued;
while (Progressive::e_ToBeContinued == state) {
state = progressive.Continue();
}C
FS_WSTR gGetIdentityName(void* user_data) {
FS_WSTR result = {0};
return result;
}
FS_WSTR gGetIdentityOrganization(void* user_data) {
FS_WSTR result = {0};
return result;
}
FS_WSTR gGetURL(void* user_data, FS_WSTR link_info) {
FS_WSTR result = {0};
return result;
}
FS_WSTR gGetTextName(void* user_data, FS_WSTR string_id) {
FS_WSTR result = {0};
return result;
}
void gReportCheckResult(void* user_data, FSAccessibilityCheckResultItemData* item_array, int count) {
// Iterate item_array and handle check results.
}
// Assume pdf_doc has been loaded.
FS_ACCESSIBILITYCHECKER_HANDLE checker = NULL;
FSDK_AccessibilityChecker_Create(pdf_doc, &checker);
FS_BOOL can_check = FALSE;
FSDK_AccessibilityChecker_CanCheck(checker, &can_check);
FSAccessibilityCheckOptions options = {0};
FS_UINT32ARRAY_HANDLE rules = NULL;
FSDK_UInt32Array_Create(&rules);
FSDK_UInt32Array_Add(rules, e_FSCheckValidateRuleTypeDocTagged);
FSDK_UInt32Array_Add(rules, e_FSCheckValidateRuleTypeDocLanguageSpecified);
options.check_rule_array = rules;
FSAccessibilityCheckResultsCallback* results_callback =
(FSAccessibilityCheckResultsCallback*)malloc(sizeof(FSAccessibilityCheckResultsCallback));
results_callback->user_data = results_callback;
results_callback->GetIdentityName = gGetIdentityName;
results_callback->GetIdentityOrganization = gGetIdentityOrganization;
results_callback->GetURL = gGetURL;
results_callback->GetTextName = gGetTextName;
results_callback->ReportCheckResult = gReportCheckResult;
FS_PROGRESSIVE_HANDLE progressive = NULL;
FSDK_AccessibilityChecker_StartCheck(checker, options, NULL, results_callback, NULL, &progressive);
FS_PROGRESSIVESTATE state = e_FSToBeContinued;
while (state == e_FSToBeContinued) {
FSDK_Progressive_Continue(progressive, &state);
}java
class MyCheckResultsCallback extends AccessibilityCheckResultsCallback {
@Override public String getIdentityName() { return ""; }
@Override public String getIdentityOrganization() { return ""; }
@Override public String getURL(String linkInfo) { return ""; }
@Override public String getTextName(String stringID) { return ""; }
@Override
public void reportCheckResult(AccessibilityCheckResultItemDataArray itemArray) {
// Iterate itemArray and handle check results.
}
}
AccessibilityChecker checker = new AccessibilityChecker(pdfDoc);
if (!checker.canCheck()) {
// The current document does not meet full check prerequisites.
}
AccessibilityCheckOptions options = new AccessibilityCheckOptions();
Uint32Array rules = new Uint32Array();
rules.add(AccessibilityCheckOptions.e_CheckValidateRuleTypeDocTagged);
rules.add(AccessibilityCheckOptions.e_CheckValidateRuleTypeDocLanguageSpecified);
options.setCheck_rule_array(rules);
MyCheckResultsCallback resultsCallback = new MyCheckResultsCallback();
Progressive progressive = checker.startCheck(options, null, resultsCallback, null);
int state = Progressive.e_ToBeContinued;
while (Progressive.e_ToBeContinued == state) {
state = progressive.resume();
}py
class MyCheckResultsCallback(AccessibilityCheckResultsCallback):
def GetIdentityName(self, *args):
return ""
def GetIdentityOrganization(self, *args):
return ""
def GetURL(self, *args):
return ""
def GetTextName(self, *args):
return ""
def ReportCheckResult(self, *args):
# Handle check results.
pass
checker = AccessibilityChecker(pdfDoc)
if not checker.CanCheck():
pass # The current document does not meet full check prerequisites.
options = AccessibilityCheckOptions()
rules = UInt32Array()
rules.Add(AccessibilityCheckOptions.e_CheckValidateRuleTypeDocTagged)
rules.Add(AccessibilityCheckOptions.e_CheckValidateRuleTypeDocLanguageSpecified)
options.check_rule_array = rules
results_callback = MyCheckResultsCallback()
progressive = checker.StartCheck(options, None, results_callback, None)
state = Progressive.e_ToBeContinued
while Progressive.e_ToBeContinued == state:
state = progressive.Continue()objc
@interface MyCheckResultsCallback : NSObject<FSAccessibilityCheckResultsCallback>
@end
@implementation MyCheckResultsCallback
- (NSString *)getIdentityName { return @""; }
- (NSString *)getIdentityOrganization { return @""; }
- (NSString *)getURL:(NSString *)linkInfo { return @""; }
- (NSString *)getTextName:(NSString *)stringID { return @""; }
- (void)reportCheckResult:(FSAccessibilityCheckResultItemDataArray *)item_array {
// Iterate item_array and handle check results.
}
@end
FSAccessibilityChecker* checker = [[FSAccessibilityChecker alloc] initWithPdf_doc:pdfDoc];
if (![checker canCheck]) {
// The current document does not meet full check prerequisites.
}
FSAccessibilityCheckOptions* options = [[FSAccessibilityCheckOptions alloc] init];
FSUint32Array* rules = [[FSUint32Array alloc] init];
[rules add:FSAccessibilityCheckOptionsCheckValidateRuleTypeDocTagged];
[rules add:FSAccessibilityCheckOptionsCheckValidateRuleTypeDocLanguageSpecified];
options.check_rule_array = rules;
MyCheckResultsCallback* resultsCallback = [[MyCheckResultsCallback alloc] init];
FSProgressive* progressive = [checker startCheck:options report_callback:nil provider:resultsCallback pause:nil];
while ([progressive resume] == FSProgressiveToBeContinued) {
}js
class MyCheckResultsCallback {
GetIdentityName() { return ""; }
GetIdentityOrganization() { return ""; }
GetURL(linkInfo) { return ""; }
GetTextName(stringID) { return ""; }
ReportCheckResult(itemArray) {
// Iterate itemArray and handle check results.
}
}
let checker = new FSDK.AccessibilityChecker(pdfDoc);
if (!checker.CanCheck()) {
// The current document does not meet full check prerequisites.
}
let options = new FSDK.AccessibilityCheckOptions();
let rules = new FSDK.UInt32Array();
rules.Add(FSDK.AccessibilityCheckOptions.e_CheckValidateRuleTypeDocTagged);
rules.Add(FSDK.AccessibilityCheckOptions.e_CheckValidateRuleTypeDocLanguageSpecified);
options.check_rule_array = rules;
let results_callback = new FSDK.AccessibilityCheckResultsCallback(new MyCheckResultsCallback());
let progressive = checker.StartCheck(options, null, results_callback, null);
let state = FSDK.Progressive.e_ToBeContinued;
while (FSDK.Progressive.e_ToBeContinued == state) {
state = progressive.Continue();
}csharp
public class MyCheckResultsCallback : AccessibilityCheckResultsCallback
{
public override string GetIdentityName() { return ""; }
public override string GetIdentityOrganization() { return ""; }
public override string GetURL(string linkInfo) { return ""; }
public override string GetTextName(string stringID) { return ""; }
public override void ReportCheckResult(AccessibilityCheckResultItemDataArray item_array)
{
// Iterate item_array and handle check results.
}
}
using (AccessibilityChecker checker = new AccessibilityChecker(pdf_doc))
{
if (!checker.CanCheck())
{
// The current document does not meet full check prerequisites.
}
AccessibilityCheckOptions options = new AccessibilityCheckOptions();
using (UInt32Array rules = new UInt32Array())
{
rules.Add((uint)AccessibilityCheckOptions.CheckValidateRuleType.e_CheckValidateRuleTypeDocTagged);
rules.Add((uint)AccessibilityCheckOptions.CheckValidateRuleType.e_CheckValidateRuleTypeDocLanguageSpecified);
options.check_rule_array = rules;
using (MyCheckResultsCallback results_callback = new MyCheckResultsCallback())
{
Progressive progressive = checker.StartCheck(options, null, results_callback, null);
Progressive.State state = Progressive.State.e_ToBeContinued;
while (state == Progressive.State.e_ToBeContinued)
{
state = progressive.Continue();
}
}
}
}go
type MyCheckResultsCallback struct {
fsdk.AccessibilityCheckResultsCallback
}
func (cb MyCheckResultsCallback) GetIdentityName() string { return "" }
func (cb MyCheckResultsCallback) GetIdentityOrganization() string { return "" }
func (cb MyCheckResultsCallback) GetURL(linkInfo string) string { return "" }
func (cb MyCheckResultsCallback) GetTextName(stringID string) string { return "" }
func (cb MyCheckResultsCallback) ReportCheckResult(itemArray fsdk.AccessibilityCheckResultItemDataArray) {
// Iterate itemArray and handle check results.
}
checker := fsdk.NewAccessibilityChecker(pdfDoc)
if !checker.CanCheck() {
// The current document does not meet full check prerequisites.
}
options := fsdk.NewAccessibilityCheckOptions()
rules := fsdk.NewUInt32Array()
rules.Add(uint(fsdk.AccessibilityCheckOptionsE_CheckValidateRuleTypeDocTagged))
rules.Add(uint(fsdk.AccessibilityCheckOptionsE_CheckValidateRuleTypeDocLanguageSpecified))
options.SetCheck_rule_array(rules)
resultsCallback := fsdk.NewDirectorAccessibilityCheckResultsCallback(MyCheckResultsCallback{})
progressive := checker.StartCheck(options, nil, resultsCallback, nil)
state := fsdk.ProgressiveE_ToBeContinued
for fsdk.ProgressiveE_ToBeContinued == state {
state = progressive.Continue()
}After the check completes, you can also use APIs such as RecheckResult / ChangeCheckStateInResultTree for partial rechecks or status updates on the result tree.
Accessibility fix-up โ
From version 12.0, use AccessibilityFixer to fix common accessibility issues. Before fixing, use CanFixRules / CanFixPermissionRules to determine whether a rule can be fixed under the current check state.
c++
AccessibilityFixer fixer(pdf_doc);
fixer.FixDocumentLanguage(L"en-US");
fixer.FixDocumentTitle(L"Document Title", L"Subject", L"Author", L"keywords");
fixer.FixDocumentPermission();
fixer.FixDocumentTag();
fixer.FixPageTabOrder();
fixer.FixFormFieldTagged();
fixer.FixFormFieldDescriptions();
// FixFigureAltText requires the detail data array from the check results.
// fixer.FixFigureAltText(detail_data_array);C
FS_ACCESSIBILITYFIXER_HANDLE fixer = NULL;
FSDK_AccessibilityFixer_Create(pdf_doc, &fixer);
FSDK_AccessibilityFixer_FixDocumentLanguage(fixer, L"en-US");
FSDK_AccessibilityFixer_FixDocumentTitle(fixer, L"Document Title", L"Subject", L"Author", L"keywords");
FSDK_AccessibilityFixer_FixDocumentPermission(fixer);
FSDK_AccessibilityFixer_FixDocumentTag(fixer);
FSDK_AccessibilityFixer_FixPageTabOrder(fixer);
FSDK_AccessibilityFixer_FixFormFieldTagged(fixer);
FSDK_AccessibilityFixer_FixFormFieldDescriptions(fixer);java
AccessibilityFixer fixer = new AccessibilityFixer(pdfDoc);
fixer.fixDocumentLanguage("en-US");
fixer.fixDocumentTitle("Document Title", "Subject", "Author", "keywords");
fixer.fixDocumentPermission();
fixer.fixDocumentTag();
fixer.fixPageTabOrder();
fixer.fixFormFieldTagged();
fixer.fixFormFieldDescriptions();py
fixer = AccessibilityFixer(pdfDoc)
fixer.FixDocumentLanguage("en-US")
fixer.FixDocumentTitle("Document Title", "Subject", "Author", "keywords")
fixer.FixDocumentPermission()
fixer.FixDocumentTag()
fixer.FixPageTabOrder()
fixer.FixFormFieldTagged()
fixer.FixFormFieldDescriptions()objc
FSAccessibilityFixer* fixer = [[FSAccessibilityFixer alloc] initWithPdf_doc:pdfDoc];
[fixer fixDocumentLanguage:@"en-US"];
[fixer fixDocumentTitle:@"Document Title" subject:@"Subject" author:@"Author" keywords:@"keywords"];
[fixer fixDocumentPermission];
[fixer fixDocumentTag];
[fixer fixPageTabOrder];
[fixer fixFormFieldTagged];
[fixer fixFormFieldDescriptions];js
let fixer = new FSDK.AccessibilityFixer(pdfDoc);
fixer.FixDocumentLanguage("en-US");
fixer.FixDocumentTitle("Document Title", "Subject", "Author", "keywords");
fixer.FixDocumentPermission();
fixer.FixDocumentTag();
fixer.FixPageTabOrder();
fixer.FixFormFieldTagged();
fixer.FixFormFieldDescriptions();csharp
using (AccessibilityFixer fixer = new AccessibilityFixer(pdf_doc))
{
fixer.FixDocumentLanguage("en-US");
fixer.FixDocumentTitle("Document Title", "Subject", "Author", "keywords");
fixer.FixDocumentPermission();
fixer.FixDocumentTag();
fixer.FixPageTabOrder();
fixer.FixFormFieldTagged();
fixer.FixFormFieldDescriptions();
}go
fixer := fsdk.NewAccessibilityFixer(pdfDoc)
fixer.FixDocumentLanguage("en-US")
fixer.FixDocumentTitle("Document Title", "Subject", "Author", "keywords")
fixer.FixDocumentPermission()
fixer.FixDocumentTag()
fixer.FixPageTabOrder()
fixer.FixFormFieldTagged()
fixer.FixFormFieldDescriptions()Navigation search โ
From version 12.0, AccessibilityNavigator can find unmarked content, unmarked comments/links, Artifacts, OCR suspects, and similar items on a page by type.
c++
AccessibilityNavigator navigator(pdf_doc);
navigator.StartFindNextElement();
AccessibilityFindResult result = navigator.FindNextElement(
0, AccessibilityNavigator::e_FinderTypeUnmarkedContent, true);
// Handle hits from result; you may keep calling FindNextElement, then when finished:
navigator.StopFindNextElement();C
FS_ACCESSIBILITYNAVIGATOR_HANDLE navigator = NULL;
FSDK_AccessibilityNavigator_Create(pdf_doc, &navigator);
FSDK_AccessibilityNavigator_StartFindNextElement(navigator);
FSAccessibilityFindResult result;
FSDK_AccessibilityNavigator_FindNextElement(
navigator, 0, e_FSFinderTypeUnmarkedContent, TRUE, &result);
FSDK_AccessibilityNavigator_StopFindNextElement(navigator);java
AccessibilityNavigator navigator = new AccessibilityNavigator(pdfDoc);
navigator.startFindNextElement();
AccessibilityFindResult result = navigator.findNextElement(
0, AccessibilityNavigator.e_FinderTypeUnmarkedContent, true);
navigator.stopFindNextElement();py
navigator = AccessibilityNavigator(pdfDoc)
navigator.StartFindNextElement()
result = navigator.FindNextElement(
0, AccessibilityNavigator.e_FinderTypeUnmarkedContent, True)
navigator.StopFindNextElement()objc
FSAccessibilityNavigator* navigator = [[FSAccessibilityNavigator alloc] initWithPdf_doc:pdfDoc];
[navigator startFindNextElement];
FSAccessibilityFindResult* result = [navigator findNextElement:0
find_type:FSAccessibilityNavigatorFinderTypeUnmarkedContent
is_search_page:YES];
[navigator stopFindNextElement];js
let navigator = new FSDK.AccessibilityNavigator(pdfDoc);
navigator.StartFindNextElement();
let result = navigator.FindNextElement(
0, FSDK.AccessibilityNavigator.e_FinderTypeUnmarkedContent, true);
navigator.StopFindNextElement();csharp
using (AccessibilityNavigator navigator = new AccessibilityNavigator(pdf_doc))
{
navigator.StartFindNextElement();
AccessibilityFindResult result = navigator.FindNextElement(
0, AccessibilityNavigator.FinderType.e_FinderTypeUnmarkedContent, true);
navigator.StopFindNextElement();
}go
navigator := fsdk.NewAccessibilityNavigator(pdfDoc)
navigator.StartFindNextElement()
result := navigator.FindNextElement(
0, fsdk.AccessibilityNavigatorE_FinderTypeUnmarkedContent, true)
navigator.StopFindNextElement()Common FinderType values include: e_FinderTypeArtifacts, e_FinderTypeUnmarkedComments, e_FinderTypeUnmarkedLinks, e_FinderTypeUnmarkedAnnots, e_FinderTypeUnmarkedContent, e_FinderTypeOcrSuspects, and others.
Reading order โ
From version 12.0, ReadingOrder supports reading-order operations: configure display options, draw reading-order items on a page, set structure types for selected content, and more.
c++
ReadingOrder reading_order(pdf_doc);
ReadingOrderOptions options;
options.reading_order_show_type = ReadingOrderOptions::e_ReadingOrderShowTypeStruct;
options.is_show_table_figure = true;
options.is_display_like_element = true;
options.is_show_table_cells = true;
reading_order.SetReadingOrderOptions(options);
reading_order.DrawReadingOrderItems(0); // Draw by page (typically with a Provider callback for presentation)C
FS_READINGORDER_HANDLE reading_order = NULL;
FSDK_ReadingOrder_Create(pdf_doc, &reading_order);
FSReadingOrderOptions options = {0};
options.reading_order_show_type = e_FSReadingOrderShowTypeStruct;
options.is_show_table_figure = TRUE;
options.is_display_like_element = TRUE;
options.is_show_table_cells = TRUE;
FSDK_ReadingOrder_SetReadingOrderOptions(reading_order, options);
FS_BOOL return_value = FALSE;
FSDK_ReadingOrder_DrawReadingOrderItems(reading_order, 0, &return_value);java
ReadingOrder readingOrder = new ReadingOrder(pdfDoc);
ReadingOrderOptions options = new ReadingOrderOptions();
options.setReading_order_show_type(ReadingOrderOptions.e_ReadingOrderShowTypeStruct);
options.setIs_show_table_figure(true);
options.setIs_display_like_element(true);
options.setIs_show_table_cells(true);
readingOrder.setReadingOrderOptions(options);
readingOrder.drawReadingOrderItems(0);py
reading_order = ReadingOrder(pdfDoc)
options = ReadingOrderOptions()
options.reading_order_show_type = ReadingOrderOptions.e_ReadingOrderShowTypeStruct
options.is_show_table_figure = True
options.is_display_like_element = True
options.is_show_table_cells = True
reading_order.SetReadingOrderOptions(options)
reading_order.DrawReadingOrderItems(0)objc
FSReadingOrder* readingOrder = [[FSReadingOrder alloc] initWithPdf_doc:pdfDoc];
FSReadingOrderOptions* options = [[FSReadingOrderOptions alloc] init];
options.reading_order_show_type = FSReadingOrderOptionsReadingOrderShowTypeStruct;
options.is_show_table_figure = YES;
options.is_display_like_element = YES;
options.is_show_table_cells = YES;
[readingOrder setReadingOrderOptions:options];
[readingOrder drawReadingOrderItems:0];js
let reading_order = new FSDK.ReadingOrder(pdfDoc);
let options = new FSDK.ReadingOrderOptions();
options.reading_order_show_type = FSDK.ReadingOrderOptions.e_ReadingOrderShowTypeStruct;
options.is_show_table_figure = true;
options.is_display_like_element = true;
options.is_show_table_cells = true;
reading_order.SetReadingOrderOptions(options);
reading_order.DrawReadingOrderItems(0);csharp
using (ReadingOrder reading_order = new ReadingOrder(pdf_doc))
{
ReadingOrderOptions options = new ReadingOrderOptions();
options.reading_order_show_type = ReadingOrderOptions.ReadingOrderShowType.e_ReadingOrderShowTypeStruct;
options.is_show_table_figure = true;
options.is_display_like_element = true;
options.is_show_table_cells = true;
reading_order.SetReadingOrderOptions(options);
reading_order.DrawReadingOrderItems(0);
}go
readingOrder := fsdk.NewReadingOrder(pdfDoc)
options := fsdk.NewReadingOrderOptions()
options.SetReading_order_show_type(fsdk.ReadingOrderOptionsE_ReadingOrderShowTypeStruct)
options.SetIs_show_table_figure(true)
options.SetIs_display_like_element(true)
options.SetIs_show_table_cells(true)
readingOrder.SetReadingOrderOptions(options)
readingOrder.DrawReadingOrderItems(0)Structure types are specified with ReadingOrder::StructureType (text, figure, table, H1โH6, background/Artifact, and so on). When UI drawing is involved, register AccessibilityProviderCallback (see the next section).
Tag tree editing โ
From version 12.0, TagTreeEditor can read and edit the document structure tree.
c++
TagTreeEditor editor(pdf_doc);
TagTreeItemArray tree = editor.GetTagTree();
// Iterate TagTreeItem / TagTreeItemData entries in the tree.
editor.SetTagPropertyType(item_id, L"P");
editor.SetTagPropertyTitle(item_id, L"Title");
editor.SetTagPropertyActualText(item_id, L"Actual text");
editor.SetTagPropertyAlternateText(item_id, L"Alternate text");
editor.SetTagPropertyLanguage(item_id, L"en-US");C
FS_TAGTREEEDITOR_HANDLE editor = NULL;
FSDK_TagTreeEditor_Create(pdf_doc, &editor);
FS_TAGTREEITEMARRAY_HANDLE tree = NULL;
FSDK_TagTreeEditor_GetTagTree(editor, &tree);
FSDK_TagTreeEditor_SetTagPropertyType(editor, item_id, L"P");
FSDK_TagTreeEditor_SetTagPropertyTitle(editor, item_id, L"Title");
FSDK_TagTreeEditor_SetTagPropertyActualText(editor, item_id, L"Actual text");
FSDK_TagTreeEditor_SetTagPropertyAlternateText(editor, item_id, L"Alternate text");
FSDK_TagTreeEditor_SetTagPropertyLanguage(editor, item_id, L"en-US");java
TagTreeEditor editor = new TagTreeEditor(pdfDoc);
TagTreeItemArray tree = editor.getTagTree();
editor.setTagPropertyType(itemId, "P");
editor.setTagPropertyTitle(itemId, "Title");
editor.setTagPropertyActualText(itemId, "Actual text");
editor.setTagPropertyAlternateText(itemId, "Alternate text");
editor.setTagPropertyLanguage(itemId, "en-US");py
editor = TagTreeEditor(pdfDoc)
tree = editor.GetTagTree()
editor.SetTagPropertyType(item_id, "P")
editor.SetTagPropertyTitle(item_id, "Title")
editor.SetTagPropertyActualText(item_id, "Actual text")
editor.SetTagPropertyAlternateText(item_id, "Alternate text")
editor.SetTagPropertyLanguage(item_id, "en-US")objc
FSTagTreeEditor* editor = [[FSTagTreeEditor alloc] initWithPdf_doc:pdfDoc];
FSTagTreeItemArray* tree = [editor getTagTree];
[editor setTagPropertyType:itemId type:@"P"];
[editor setTagPropertyTitle:itemId title:@"Title"];
[editor setTagPropertyActualText:itemId actual_text:@"Actual text"];
[editor setTagPropertyAlternateText:itemId alternate_text:@"Alternate text"];
[editor setTagPropertyLanguage:itemId language:@"en-US"];js
let editor = new FSDK.TagTreeEditor(pdfDoc);
let tree = editor.GetTagTree();
editor.SetTagPropertyType(item_id, "P");
editor.SetTagPropertyTitle(item_id, "Title");
editor.SetTagPropertyActualText(item_id, "Actual text");
editor.SetTagPropertyAlternateText(item_id, "Alternate text");
editor.SetTagPropertyLanguage(item_id, "en-US");csharp
using (TagTreeEditor editor = new TagTreeEditor(pdf_doc))
{
TagTreeItemArray tree = editor.GetTagTree();
editor.SetTagPropertyType(item_id, "P");
editor.SetTagPropertyTitle(item_id, "Title");
editor.SetTagPropertyActualText(item_id, "Actual text");
editor.SetTagPropertyAlternateText(item_id, "Alternate text");
editor.SetTagPropertyLanguage(item_id, "en-US");
}go
editor := fsdk.NewTagTreeEditor(pdfDoc)
tree := editor.GetTagTree()
editor.SetTagPropertyType(itemID, "P")
editor.SetTagPropertyTitle(itemID, "Title")
editor.SetTagPropertyActualText(itemID, "Actual text")
editor.SetTagPropertyAlternateText(itemID, "Alternate text")
editor.SetTagPropertyLanguage(itemID, "en-US")APIs are also available to create tags from a selection/content, add tags for annotations, get context-menu items, and more. See TagTreeEditor in the API Reference.
Host Provider callback โ
Some check / reading-order / tag-editing flows need the host to provide page content generation and drawing. From version 12.0, register AccessibilityProviderCallback with Library::RegisterAccessibilityProviderCallback.
Interfaces to implement include Release, GenerateContent, OnContentChanged, DrawRect, DrawLine, DrawText, and others (full list in the API Reference). The following shows only the registration entry point:
c++
Library::RegisterAccessibilityProviderCallback(provider_callback);C
FSDK_Library_RegisterAccessibilityProviderCallback(provider_callback);java
Library.registerAccessibilityProviderCallback(providerCallback);py
Library.RegisterAccessibilityProviderCallback(provider_callback)objc
[FSLibrary registerAccessibilityProviderCallback:providerCallback];js
FSDK.Library.RegisterAccessibilityProviderCallback(provider_callback);csharp
Library.RegisterAccessibilityProviderCallback(provider_callback);go
fsdk.LibraryRegisterAccessibilityProviderCallback(providerCallback)If the Provider is not implemented or not registered, some APIs that rely on drawing feedback may not present as expected; pure check / fix / auto-tagging flows can still be used as described above.