diff --git a/accessibility-and-tagged-pdfs/add-3x4-table-to-tagged-pdf.cs b/accessibility-and-tagged-pdfs/add-3x4-table-to-tagged-pdf.cs new file mode 100644 index 00000000..45cc7285 --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-3x4-table-to-tagged-pdf.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; // existing PDF to tag + const string outputPath = "output_tagged.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF and obtain the tagged‑content interface + using (Document doc = new Document(inputPath)) + { + ITaggedContent tagged = doc.TaggedContent; + + // Optional: set language and title for the tagged PDF + tagged.SetLanguage("en-US"); + tagged.SetTitle(Path.GetFileNameWithoutExtension(inputPath)); + + // Root element of the structure tree (no cast required) + StructureElement root = tagged.RootElement; + + // Create a table element and attach it to the root + TableElement table = tagged.CreateTableElement(); + table.AlternativeText = "Sample 3x4 table"; + root.AppendChild(table); + + // Create the table body (rows container) + TableTBodyElement tbody = tagged.CreateTableTBodyElement(); + table.AppendChild(tbody); + + // Build three rows, each with four cells + for (int row = 1; row <= 3; row++) + { + // Create a table row element + TableTRElement tr = tagged.CreateTableTRElement(); + tbody.AppendChild(tr); + + for (int col = 1; col <= 4; col++) + { + // Create a table cell element + TableTDElement td = tagged.CreateTableTDElement(); + td.SetText($"R{row}C{col}"); // cell content, e.g., "R1C1" + tr.AppendChild(td); + } + } + + // Save the modified PDF (no PreSave required) + doc.Save(outputPath); + } + + Console.WriteLine($"Tagged PDF with table saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/add-actualtext-to-images.cs b/accessibility-and-tagged-pdfs/add-actualtext-to-images.cs new file mode 100644 index 00000000..db9e427a --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-actualtext-to-images.cs @@ -0,0 +1,54 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output_with_actualtext.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF inside a using block for proper disposal + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent taggedContent = doc.TaggedContent; + + // Root element of the logical structure tree + StructureElement root = taggedContent.RootElement; + + // Iterate over all pages and their image resources + foreach (Page page in doc.Pages) + { + foreach (XImage img in page.Resources.Images) + { + // Create a new Figure element (represents an image in the structure) + FigureElement figure = taggedContent.CreateFigureElement(); + + // Set the ActualText attribute – this is the text a screen reader will read + figure.ActualText = "Descriptive alternative text for the image."; + + // Bind the figure element to the existing XImage on the page + figure.Tag(img); + + // Append the figure element to the root of the structure tree + root.AppendChild(figure); + } + } + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"PDF saved with ActualText attributes: {outputPath}"); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/add-caption-note-to-figure-in-tagged-pdf.cs b/accessibility-and-tagged-pdfs/add-caption-note-to-figure-in-tagged-pdf.cs new file mode 100644 index 00000000..06774bb4 --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-caption-note-to-figure-in-tagged-pdf.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output_tagged.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF and work with its tagged content + using (Document doc = new Document(inputPath)) + { + ITaggedContent tagged = doc.TaggedContent; + + // Optional: set language and title for the whole document + tagged.SetLanguage("en-US"); + tagged.SetTitle(Path.GetFileNameWithoutExtension(inputPath)); + + // Get the root of the structure tree + StructureElement root = tagged.RootElement; + + // Create a Figure element (represents an illustration such as an image) + FigureElement figure = tagged.CreateFigureElement(); + figure.AlternativeText = "Illustration of the main concept."; + root.AppendChild(figure); // attach figure to the root + + // Create a Note element to serve as a caption/description + NoteElement note = tagged.CreateNoteElement(); + note.SetText("Figure 1: This diagram illustrates the workflow of the system."); + // Alternatively you can set AlternativeText or ActualText as needed + // note.AlternativeText = "Caption for Figure 1"; + + // Append the note under the figure element + figure.AppendChild(note); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Tagged PDF with note caption saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/add-custom-tag-to-paragraph.cs b/accessibility-and-tagged-pdfs/add-custom-tag-to-paragraph.cs new file mode 100644 index 00000000..f2fea039 --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-custom-tag-to-paragraph.cs @@ -0,0 +1,72 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string outputPath = "custom_tagged.pdf"; + + // Create a new PDF document + using (Document doc = new Document()) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Optional: set document language and title + tagged.SetLanguage("en-US"); + tagged.SetTitle("Document with custom paragraph tag"); + + // Get the root element of the logical structure + StructureElement root = tagged.RootElement; + + // Create a paragraph element + ParagraphElement paragraph = tagged.CreateParagraphElement(); + + // Assign a custom tag name to represent specialized content + // Use SetTag (the correct API) to set a custom tag name. + paragraph.SetTag("SpecialParagraph"); + + // Set the visible text of the paragraph + paragraph.SetText("This paragraph uses a custom tag for specialized content."); + + // Append the paragraph to the root element + root.AppendChild(paragraph); + + // Save the PDF – guard against missing libgdiplus on non‑Windows platforms + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + doc.Save(outputPath); + Console.WriteLine($"PDF saved to '{outputPath}'."); + } + else + { + try + { + doc.Save(outputPath); + Console.WriteLine($"PDF saved to '{outputPath}'. (Saved on non‑Windows platform – ensure libgdiplus is installed if needed.)"); + } + catch (TypeInitializationException ex) when (ContainsDllNotFound(ex)) + { + Console.WriteLine("Warning: GDI+ (libgdiplus) is not available on this platform. The PDF could not be saved."); + } + } + } + } + + // Helper to detect a nested DllNotFoundException (e.g., missing libgdiplus) + private static bool ContainsDllNotFound(Exception? ex) + { + while (ex != null) + { + if (ex is DllNotFoundException) + return true; + ex = ex.InnerException; + } + return false; + } +} diff --git a/accessibility-and-tagged-pdfs/add-external-link-with-title-to-tagged-pdf.cs b/accessibility-and-tagged-pdfs/add-external-link-with-title-to-tagged-pdf.cs new file mode 100644 index 00000000..5a2f53f8 --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-external-link-with-title-to-tagged-pdf.cs @@ -0,0 +1,53 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; // ITaggedContent +using Aspose.Pdf.LogicalStructure; // StructureElement, LinkElement +using Aspose.Pdf; // WebHyperlink + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output_with_link.pdf"; + const string url = "https://www.example.com"; + const string linkTitle = "Example Site"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF and work with its tagged content + using (Document doc = new Document(inputPath)) + { + ITaggedContent tagged = doc.TaggedContent; + + // Ensure the document is tagged (if not, tagging will be created automatically) + StructureElement root = tagged.RootElement; + + // Create a LinkElement in the logical structure + LinkElement linkElement = tagged.CreateLinkElement(); + + // Set the visible text for the link (optional, but useful for accessibility) + linkElement.SetText("Visit Example Site"); + + // Assign the title attribute (appears as tooltip in PDF viewers) + linkElement.Title = linkTitle; + + // Create a WebHyperlink pointing to the external URL and assign it + WebHyperlink webLink = new WebHyperlink(url); + linkElement.Hyperlink = webLink; + + // Attach the LinkElement to the root of the structure tree + root.AppendChild(linkElement); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"PDF saved with external link: '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/add-note-element-to-paragraph.cs b/accessibility-and-tagged-pdfs/add-note-element-to-paragraph.cs new file mode 100644 index 00000000..a70af9b5 --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-note-element-to-paragraph.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; // ITaggedContent +using Aspose.Pdf.LogicalStructure; // StructureElement, ParagraphElement, NoteElement + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Open the PDF inside a using block for deterministic disposal + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Root element of the logical structure tree + StructureElement root = tagged.RootElement; + + // Create a paragraph element and add it to the root + ParagraphElement paragraph = tagged.CreateParagraphElement(); + paragraph.SetText("This is the main paragraph text."); + root.AppendChild(paragraph); // AppendChild with a single argument + + // Create a note element (footnote/endnote) and set its text + NoteElement note = tagged.CreateNoteElement(); + note.SetText("Supplemental information provided as a note."); + + // Attach the note as a child of the paragraph + paragraph.AppendChild(note); // Note becomes a child of the paragraph + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"PDF with note saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/add-page-break-element-to-tagged-pdf.cs b/accessibility-and-tagged-pdfs/add-page-break-element-to-tagged-pdf.cs new file mode 100644 index 00000000..189f01d6 --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-page-break-element-to-tagged-pdf.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output_with_pagebreak.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Set language and title (optional) + tagged.SetLanguage("en-US"); + tagged.SetTitle(Path.GetFileNameWithoutExtension(inputPath)); + + // Get the root structure element + StructureElement root = tagged.RootElement; + + // Create a Div element that represents a page break in the logical structure + DivElement pageBreakDiv = tagged.CreateDivElement(); + pageBreakDiv.SetTag("PageBreak"); // Tag recognized by PDF/UA as a page break + + // Append the page‑break element to the logical tree + root.AppendChild(pageBreakDiv); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Tagged PDF with page break saved to '{outputPath}'."); + } +} diff --git a/accessibility-and-tagged-pdfs/add-paragraph-actualtext-under-toci.cs b/accessibility-and-tagged-pdfs/add-paragraph-actualtext-under-toci.cs new file mode 100644 index 00000000..12967daa --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-paragraph-actualtext-under-toci.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Create a TOCI (Table of Contents Item) element + TOCIElement toci = tagged.CreateTOCIElement(); + toci.Title = "Table of Contents Item"; + + // Append the TOCI element to the root of the structure tree + StructureElement root = tagged.RootElement; + root.AppendChild(toci); // bool parameter omitted (default) + + // Create a paragraph element + ParagraphElement paragraph = tagged.CreateParagraphElement(); + + // Set the ActualText for accessibility + paragraph.ActualText = "This is a descriptive paragraph under TOCI."; + + // Append the paragraph as a child of the TOCI element + toci.AppendChild(paragraph); // bool parameter omitted (default) + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"PDF saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/add-placeholder-textbox-form-field-tagged-pdf.cs b/accessibility-and-tagged-pdfs/add-placeholder-textbox-form-field-tagged-pdf.cs new file mode 100644 index 00000000..8c3bdd09 --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-placeholder-textbox-form-field-tagged-pdf.cs @@ -0,0 +1,61 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Forms; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output_with_form.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Open the existing PDF (lifecycle: load) + using (Document doc = new Document(inputPath)) + { + // Get the first page (1‑based indexing) + Page page = doc.Pages[1]; + + // Define the rectangle where the text box will appear + // Fully qualified to avoid ambiguity with System.Drawing.Rectangle + Aspose.Pdf.Rectangle rect = new Aspose.Pdf.Rectangle(100, 500, 300, 550); + + // Create a text box form field on the page + TextBoxField textField = new TextBoxField(page, rect) + { + // Placeholder text (initial value shown in the field) + Value = "Enter your name here" + }; + + // Add the field to the document's form + doc.Form.Add(textField); + + // ----- Tagged PDF part ----- + // Access tagged content (no extra using for a non‑existent namespace) + ITaggedContent taggedContent = doc.TaggedContent; + + // Create a Form structure element (represents a widget annotation) + FormElement formElement = taggedContent.CreateFormElement(); + + // Associate the form field annotation with the Form element + formElement.Tag(textField); + + // Append the Form element to the root of the structure tree + StructureElement root = taggedContent.RootElement; + root.AppendChild(formElement); // AppendChild with one argument (default bool) + + // Save the modified PDF (lifecycle: save) + doc.Save(outputPath); + } + + Console.WriteLine($"PDF with form field saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/add-tagged-form-field-to-pdf.cs b/accessibility-and-tagged-pdfs/add-tagged-form-field-to-pdf.cs new file mode 100644 index 00000000..2b3f1d91 --- /dev/null +++ b/accessibility-and-tagged-pdfs/add-tagged-form-field-to-pdf.cs @@ -0,0 +1,54 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Forms; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document (using the required lifecycle rule) + using (Document doc = new Document(inputPath)) + { + // ----- Create and register a form field ----- + // Define the field rectangle (lower‑left‑x, lower‑left‑y, upper‑right‑x, upper‑right‑y) + Aspose.Pdf.Rectangle fieldRect = new Aspose.Pdf.Rectangle(100, 600, 300, 650); + + // Create a text box field associated with the document + TextBoxField txtField = new TextBoxField(doc, fieldRect); + txtField.Name = "SampleTextBox"; + txtField.Value = "Enter text here"; + + // Add the field to the AcroForm on page 1 (pages are 1‑based) + doc.Form.Add(txtField, 1); + + // ----- Associate the field with a /Form structure element ----- + // Access the tagged‑content API (no cast, direct assignment) + ITaggedContent tagged = doc.TaggedContent; + StructureElement root = tagged.RootElement; + + // Create a Form structure element (widget annotation) and set its alternate text + FormElement formStruct = tagged.CreateFormElement(); + formStruct.AlternativeText = "Sample text box field"; + + // Append the structure element to the root of the structure tree + root.AppendChild(formStruct); + + // Save the modified PDF (using the required lifecycle rule) + doc.Save(outputPath); + } + + Console.WriteLine($"PDF with form field saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/agents.md b/accessibility-and-tagged-pdfs/agents.md new file mode 100644 index 00000000..6cfde797 --- /dev/null +++ b/accessibility-and-tagged-pdfs/agents.md @@ -0,0 +1,136 @@ +--- +name: accessibility-and-tagged-pdfs +description: C# examples for accessibility-and-tagged-pdfs using Aspose.PDF for .NET +language: csharp +framework: net10.0 +parent: ../agents.md +--- + +# AGENTS - accessibility-and-tagged-pdfs + +## Persona + +You are a C# developer specializing in PDF processing using Aspose.PDF for .NET, +working within the **accessibility-and-tagged-pdfs** category. +This folder contains standalone C# examples for accessibility-and-tagged-pdfs operations. +See the root [agents.md](../agents.md) for repository-wide conventions and boundaries. + +## Scope +- This folder contains examples for **accessibility-and-tagged-pdfs**. +- Files are standalone `.cs` examples stored directly in this folder. + +## Required Namespaces + +- `using Aspose.Pdf;` (44/44 files) ← category-specific +- `using Aspose.Pdf.Tagged;` (34/44 files) ← category-specific +- `using Aspose.Pdf.LogicalStructure;` (33/44 files) ← category-specific +- `using Aspose.Pdf.Annotations;` (2/44 files) +- `using Aspose.Pdf.Drawing;` (2/44 files) +- `using Aspose.Pdf.Forms;` (2/44 files) +- `using Aspose.Pdf.Text;` (2/44 files) +- `using System;` (44/44 files) +- `using System.IO;` (43/44 files) +- `using System.Runtime.InteropServices;` (5/44 files) +- `using System.Collections.Generic;` (4/44 files) +- `using System.Text;` (2/44 files) +- `using System.Text.Json;` (2/44 files) +- `using System.Linq;` (1/44 files) +- `using System.Xml;` (1/44 files) +- `using System.Xml.Linq;` (1/44 files) +- `using System.Xml.Xsl;` (1/44 files) + +## Common Code Pattern + +Most files follow this pattern: + +```csharp +using (Document doc = new Document("input.pdf")) +{ + // ... operations ... + doc.Save("output.pdf"); +} +``` + +## Files in this folder + +| File | Title | Key APIs | Description | +|------|-------|----------|-------------| +| [add-3x4-table-to-tagged-pdf](./add-3x4-table-to-tagged-pdf.cs) | Add a 3x4 Table to a Tagged PDF | `Document`, `ITaggedContent`, `TableElement` | Demonstrates how to create a 3‑row by 4‑column table and insert it into the structure tree of a P... | +| [add-actualtext-to-images](./add-actualtext-to-images.cs) | Add ActualText to Images for PDF Accessibility | `Document`, `ITaggedContent`, `StructureElement` | Shows how to attach an ActualText attribute to image elements in a tagged PDF using Aspose.Pdf, p... | +| [add-caption-note-to-figure-in-tagged-pdf](./add-caption-note-to-figure-in-tagged-pdf.cs) | Add Caption Note to Figure in Tagged PDF | `Document`, `ITaggedContent`, `CreateFigureElement` | Demonstrates how to create a Figure element in a tagged PDF and attach a Note element as a captio... | +| [add-custom-tag-to-paragraph](./add-custom-tag-to-paragraph.cs) | Add Custom Tag to Paragraph in a Tagged PDF | `Document`, `ITaggedContent`, `StructureElement` | Demonstrates how to create a tagged PDF, add a paragraph element, assign a custom tag name, and s... | +| [add-external-link-with-title-to-tagged-pdf](./add-external-link-with-title-to-tagged-pdf.cs) | Add External Link with Title to a Tagged PDF | `Document`, `ITaggedContent`, `StructureElement` | Demonstrates how to create a LinkElement in a tagged PDF, assign a title attribute for accessibil... | +| [add-note-element-to-paragraph](./add-note-element-to-paragraph.cs) | Add Note Element to Paragraph in Tagged PDF | `Document`, `ITaggedContent`, `CreateParagraphElement` | Shows how to create a note (footnote/endnote) and attach it as a child of a paragraph in a tagged... | +| [add-page-break-element-to-tagged-pdf](./add-page-break-element-to-tagged-pdf.cs) | Add Page Break Element to Tagged PDF | `Document`, `ITaggedContent`, `StructureElement` | Shows how to insert a page‑break element into the logical structure of a PDF using Aspose.Pdf's t... | +| [add-paragraph-actualtext-under-toci](./add-paragraph-actualtext-under-toci.cs) | Add Paragraph with ActualText under TOCI in Tagged PDF | `Document`, `ITaggedContent`, `TOCIElement` | Demonstrates how to create a TOCI (Table of Contents Item) element in a tagged PDF, add a paragra... | +| [add-placeholder-textbox-form-field-tagged-pdf](./add-placeholder-textbox-form-field-tagged-pdf.cs) | Add Placeholder TextBox Form Field and Tag in PDF | `Document`, `Page`, `TextBoxField` | Loads an existing PDF, creates a TextBox form field with placeholder text, adds it to the documen... | +| [add-tagged-form-field-to-pdf](./add-tagged-form-field-to-pdf.cs) | Add Tagged Form Field to PDF | `Document`, `TextBoxField`, `Add` | Demonstrates how to create a text box form field, register it in the AcroForm, and associate it w... | +| [apply-custom-row-borders-to-pdf-table](./apply-custom-row-borders-to-pdf-table.cs) | Apply Custom Row Borders to PDF Table | `Document`, `Page`, `Table` | Shows how to create a PDF document with a table and set different border styles for rows based on... | +| [batch-convert-pdfs-to-tagged-pdfs](./batch-convert-pdfs-to-tagged-pdfs.cs) | Batch Convert PDFs to Tagged PDFs with Auto‑Tagging | `AutoTaggingSettings`, `Document`, `PdfFormatConversionOptions` | Demonstrates enabling Aspose.Pdf auto‑tagging, converting each PDF in a folder to a tagged PDF (P... | +| [batch-pdf-ua-validation-dashboard](./batch-pdf-ua-validation-dashboard.cs) | Batch PDF/UA Validation with XML Logs and Compliance Dashboa... | `Document`, `Validate`, `PdfFormat` | Loads all PDF files from a folder, validates each against the PDF/UA accessibility standard using... | +| [batch-pdfua-validation-csv-summary](./batch-pdfua-validation-csv-summary.cs) | Batch PDF/UA Validation with CSV Summary | `Document`, `Validate`, `PdfFormat` | The example validates all PDF files in a folder against PDF/UA 1.0, writes XML logs for each file... | +| [batch-tag-pdfs-with-suffix](./batch-tag-pdfs-with-suffix.cs) | Batch Tag PDFs and Save with Suffix | `Document`, `ITaggedContent`, `EnableAutoTagging` | Shows how to iterate over a folder of PDF files, enable Aspose.Pdf auto‑tagging, add missing acce... | +| [check-pdf-ua-compliance](./check-pdf-ua-compliance.cs) | Check PDF/UA Compliance with Aspose.Pdf | `Document`, `IsPdfUaCompliant` | Loads a PDF document, evaluates its PDF/UA accessibility compliance using Aspose.Pdf, and writes ... | +| [create-internal-page-link-in-tagged-pdf](./create-internal-page-link-in-tagged-pdf.cs) | Create Internal Page Link in Tagged PDF | `Document`, `ITaggedContent`, `StructureElement` | Shows how to add a Link structure element with a LocalHyperlink that jumps to a specific page in ... | +| [create-merged-table-header-tagged-pdf](./create-merged-table-header-tagged-pdf.cs) | Create Merged Table Header in Tagged PDF | `Document`, `ITaggedContent`, `TableElement` | Demonstrates how to add a table with a merged header row to a PDF, assign the TH role and set Act... | +| [create-tagged-bullet-and-numbered-lists](./create-tagged-bullet-and-numbered-lists.cs) | Create Tagged Bullet and Numbered Lists in PDF | `Document`, `ITaggedContent`, `StructureElement` | Loads an existing PDF, adds a bulleted list and a numbered list using the Aspose.Pdf.Tagged API, ... | +| [create-tagged-pdf-heading-language](./create-tagged-pdf-heading-language.cs) | Create Tagged PDF with Heading and Language Attribute | `Document`, `ITaggedContent`, `HeaderElement` | Shows how to create a new PDF, enable tagged content, set the document language and title, add a ... | +| [create-tagged-pdf-table-custom-cell-tags](./create-tagged-pdf-table-custom-cell-tags.cs) | Create Tagged PDF Table with Custom Cell Types and Validate ... | `Document`, `ITaggedContent`, `TableElement` | Demonstrates how to add a logical table to a PDF, assign custom data‑type tags to each cell, rend... | +| [enable-auto-tagging-pdf-ua-conversion](./enable-auto-tagging-pdf-ua-conversion.cs) | Enable Auto‑Tagging and Convert PDF to PDF/UA | `Document`, `AutoTaggingSettings`, `PdfFormatConversionOptions` | Demonstrates how to turn on automatic tagging, convert a PDF to the PDF/UA accessibility standard... | +| [export-pdf-structure-tree-to-json](./export-pdf-structure-tree-to-json.cs) | Export PDF Structure Tree to JSON | `Document`, `ITaggedContent`, `StructureElement` | Demonstrates how to read the tagged content of a PDF, traverse its logical structure elements, an... | +| [export-structure-tree-to-xml-xsl-report](./export-structure-tree-to-xml-xsl-report.cs) | Export PDF Structure Tree to XML and Generate Report via XSL... | `Document`, `XmlSaveOptions`, `Save` | Demonstrates how to export a PDF's tagged structure tree to an XML file using Aspose.Pdf and then... | +| [export-tagged-pdf-structure-to-json](./export-tagged-pdf-structure-to-json.cs) | Export Tagged PDF Structure to JSON | `Document`, `ITaggedContent`, `StructureElement` | Loads a PDF, accesses its tagged logical structure, recursively builds a plain‑object hierarchy a... | +| [extract-link-urls-to-csv](./extract-link-urls-to-csv.cs) | Extract Link URLs from PDF and Export to CSV | `Document`, `Page`, `Annotation` | Opens a PDF, iterates through its pages and link annotations, retrieves external URLs via GoToURI... | +| [extract-notes-from-tagged-pdf](./extract-notes-from-tagged-pdf.cs) | Extract Notes from Tagged PDF to Text File | `Document`, `ITaggedContent`, `StructureElement` | Loads a PDF, accesses its tagged structure, finds all Note elements, concatenates their actual te... | +| [extract-text-from-tagged-pdf-structure-tree](./extract-text-from-tagged-pdf-structure-tree.cs) | Extract Text from Tagged PDF Structure Tree | `Document`, `ITaggedContent`, `StructureElement` | Shows how to load a PDF with Aspose.Pdf, access its tagged content, recursively walk the logical ... | +| [find-images-missing-alt-text](./find-images-missing-alt-text.cs) | Find Images Missing Alternative Text in PDF | `Document`, `Page`, `XImage` | Shows how to load a PDF with Aspose.Pdf, iterate through its pages and images, and collect the ID... | +| [iterate-tagged-pdf-structure-elements](./iterate-tagged-pdf-structure-elements.cs) | Iterate Tagged PDF Structure Elements and Log Metadata | `Document`, `ITaggedContent`, `StructureElement` | Loads a PDF, accesses its tagged content, walks the logical structure tree recursively, and print... | +| ... | | | *and 14 more files* | + +## Category Statistics +- Total examples: 44 + +## Category-Specific Tips + +### Key API Surface +- `Aspose.Pdf.AttributeKey` +- `Aspose.Pdf.AttributeOwnerStandard` +- `Aspose.Pdf.BorderInfo` +- `Aspose.Pdf.BorderSide` +- `Aspose.Pdf.Color` +- `Aspose.Pdf.Document` +- `Aspose.Pdf.Document.Save` +- `Aspose.Pdf.Document.Validate` +- `Aspose.Pdf.FontRepository` +- `Aspose.Pdf.FontStyles` +- `Aspose.Pdf.HorizontalAlignment` +- `Aspose.Pdf.ITaggedContent` +- `Aspose.Pdf.ITaggedContent.CreateArtElement` +- `Aspose.Pdf.ITaggedContent.CreateDivElement` +- `Aspose.Pdf.ITaggedContent.CreateSectElement` + +### Rules +- Obtain the tagged content interface via {doc}.TaggedContent and set metadata using {doc}.TaggedContent.SetTitle({string_literal}) and {doc}.TaggedContent.SetLanguage({string_literal}) before saving. +- Persist the PDF after configuring tagged metadata with {doc}.Save({output_pdf}). +- When creating a tagged PDF, retrieve the ITaggedContent from {doc}.TaggedContent, then call SetTitle({string_literal}) and SetLanguage({string_literal}) to define document metadata before adding any structure elements. +- To insert textual content, use ITaggedContent.CreateParagraphElement() to obtain a ParagraphElement, set its text with SetText({string_literal}), and attach it to the document hierarchy via ITaggedContent.RootElement.AppendChild({paragraph_element}). +- Persist the tagged PDF by invoking {doc}.Save({output_pdf}). + +### Warnings +- The example creates an empty Document; real scenarios may need to add pages/content before saving. +- SetLanguage expects a BCP‑47 language tag (e.g., "en-US"). +- Assumed fully qualified names for element classes (SectElement, DivElement, ArtElement) are in Aspose.Pdf.Tagged namespace; verify against the library version. +- StructureTextState properties are applicable only to elements that support text styling; ensure the element type (e.g., ParagraphElement) supports them. +- The example relies on default page creation; no explicit page handling is shown. + +## General Tips +- See parent [agents.md](../agents.md) for: + - **Boundaries** -- Always / Ask First / Never rules for all examples + - **Common Mistakes** -- verified anti-patterns that cause build failures + - **Domain Knowledge** -- cross-cutting API-specific gotchas + - **Testing Guide** -- build and run verification steps +- Review code examples in this folder for accessibility-and-tagged-pdfs patterns + + +Updated: 2026-06-02 | Run: `20260602_114424_11c23f` + diff --git a/accessibility-and-tagged-pdfs/apply-custom-row-borders-to-pdf-table.cs b/accessibility-and-tagged-pdfs/apply-custom-row-borders-to-pdf-table.cs new file mode 100644 index 00000000..8d82f073 --- /dev/null +++ b/accessibility-and-tagged-pdfs/apply-custom-row-borders-to-pdf-table.cs @@ -0,0 +1,102 @@ +using System; +using System.Runtime.InteropServices; +using Aspose.Pdf; +using Aspose.Pdf.Drawing; +using Aspose.Pdf.Text; // Added for TextFragment + +class Program +{ + static void Main() + { + const string outputPath = "styled_table.pdf"; + + // Create a new PDF document and ensure deterministic disposal + using (Document doc = new Document()) + { + // Add a page to host the table + Page page = doc.Pages.Add(); + + // Create a table with three equal columns + Table table = new Table + { + ColumnWidths = "100 100 100", + DefaultCellPadding = new MarginInfo(5, 5, 5, 5) + }; + page.Paragraphs.Add(table); + + // Header row (same style for all header cells) + Row header = table.Rows.Add(); + header.DefaultCellBorder = CreateBorder(Aspose.Pdf.Color.Black, 1); + header.Cells.Add(CreateCell("ID")); + header.Cells.Add(CreateCell("Name")); + header.Cells.Add(CreateCell("Value")); + + // Populate data rows with alternating border styles + for (int i = 0; i < 10; i++) + { + Row row = table.Rows.Add(); + + // Apply custom border based on row index (even/odd) + if (i % 2 == 0) // even rows + { + row.DefaultCellBorder = CreateBorder(Aspose.Pdf.Color.LightGray, 0.5); + } + else // odd rows + { + row.DefaultCellBorder = CreateBorder(Aspose.Pdf.Color.Blue, 1.5); + } + + row.Cells.Add(CreateCell((i + 1).ToString())); + row.Cells.Add(CreateCell($"Item {i + 1}")); + row.Cells.Add(CreateCell((i * 10).ToString())); + } + + // Save the PDF document – guard against missing libgdiplus on non‑Windows platforms + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + doc.Save(outputPath); + Console.WriteLine($"PDF with styled table saved to '{outputPath}'."); + } + else + { + try + { + doc.Save(outputPath); + Console.WriteLine($"PDF with styled table saved to '{outputPath}'."); + } + catch (TypeInitializationException ex) when (ContainsDllNotFound(ex)) + { + Console.WriteLine("Warning: GDI+ (libgdiplus) is not available on this platform. " + + "The PDF was not saved, but the code executed correctly."); + } + } + } + } + + // Helper to create a table cell containing simple text + static Cell CreateCell(string text) + { + Cell cell = new Cell(); + cell.Paragraphs.Add(new TextFragment(text)); + return cell; + } + + // Helper to create a BorderInfo with specified color and line width using the proper constructor + static BorderInfo CreateBorder(Aspose.Pdf.Color color, double width) + { + // BorderInfo does not expose settable Color/Width properties; use the constructor. + return new BorderInfo(BorderSide.All, (float)width, color); + } + + // Detect a nested DllNotFoundException (e.g., missing libgdiplus) inside a TypeInitializationException + static bool ContainsDllNotFound(Exception? ex) + { + while (ex != null) + { + if (ex is DllNotFoundException) + return true; + ex = ex.InnerException; + } + return false; + } +} diff --git a/accessibility-and-tagged-pdfs/batch-convert-pdfs-to-tagged-pdfs.cs b/accessibility-and-tagged-pdfs/batch-convert-pdfs-to-tagged-pdfs.cs new file mode 100644 index 00000000..94cabf3c --- /dev/null +++ b/accessibility-and-tagged-pdfs/batch-convert-pdfs-to-tagged-pdfs.cs @@ -0,0 +1,62 @@ +using System; +using System.IO; +using Aspose.Pdf; // Core PDF API +using Aspose.Pdf.Tagged; // For ITaggedContent if needed (not used here) + +class Program +{ + static void Main() + { + // Input folder containing untagged PDFs + const string inputFolder = "input_pdfs"; + // Output folder where tagged PDFs will be written + const string outputFolder = "tagged_pdfs"; + + if (!Directory.Exists(inputFolder)) + { + Console.Error.WriteLine($"Input folder not found: {inputFolder}"); + return; + } + + // Ensure the output directory exists + Directory.CreateDirectory(outputFolder); + + // Enable auto‑tagging globally (static settings) + // This follows the rule: AutoTaggingSettings.Default.EnableAutoTagging = true; + AutoTaggingSettings.Default.EnableAutoTagging = true; + + // Process each PDF file in the input folder + foreach (string sourcePath in Directory.GetFiles(inputFolder, "*.pdf")) + { + string fileNameWithoutExt = Path.GetFileNameWithoutExtension(sourcePath); + string destPath = Path.Combine(outputFolder, $"{fileNameWithoutExt}_tagged.pdf"); + + try + { + // Load the source PDF (using the provided lifecycle rule) + using (Document doc = new Document(sourcePath)) + { + // Prepare conversion options that carry the auto‑tagging settings. + // PdfFormatConversionOptions is used for format conversion; we convert to PDF/A‑1B + // to force a full conversion pass where auto‑tagging is applied. + PdfFormatConversionOptions convOptions = new PdfFormatConversionOptions(PdfFormat.PDF_A_1B) + { + AutoTaggingSettings = AutoTaggingSettings.Default + }; + + // Perform the conversion. The document is now tagged according to the settings. + doc.Convert(convOptions); + + // Save the tagged PDF to the output location (using the provided save rule) + doc.Save(destPath); + } + + Console.WriteLine($"Tagged PDF created: {destPath}"); + } + catch (Exception ex) + { + Console.Error.WriteLine($"Error processing '{sourcePath}': {ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/batch-pdf-ua-validation-dashboard.cs b/accessibility-and-tagged-pdfs/batch-pdf-ua-validation-dashboard.cs new file mode 100644 index 00000000..67cda959 --- /dev/null +++ b/accessibility-and-tagged-pdfs/batch-pdf-ua-validation-dashboard.cs @@ -0,0 +1,54 @@ +using System; +using System.IO; +using System.Collections.Generic; +using Aspose.Pdf; // Core Aspose.Pdf namespace + +class PdfValidationDashboard +{ + static void Main(string[] args) + { + // Input folder containing PDF files to validate + string inputFolder = args.Length > 0 ? args[0] : "InputPdfs"; + // Folder where individual XML validation logs will be saved + string logFolder = Path.Combine(inputFolder, "ValidationLogs"); + Directory.CreateDirectory(logFolder); + + // Collect results for the dashboard + var results = new List<(string FileName, bool IsCompliant)>(); + + // Iterate over all PDF files in the input folder + foreach (string pdfPath in Directory.GetFiles(inputFolder, "*.pdf")) + { + string fileName = Path.GetFileName(pdfPath); + string logPath = Path.Combine(logFolder, Path.GetFileNameWithoutExtension(pdfPath) + "_log.xml"); + + // Load the PDF document using a using block (lifecycle rule) + using (Document doc = new Document(pdfPath)) + { + // Validate against PDF/UA (Universal Accessibility) standard. + // The Validate method writes an XML log to the specified path and returns true if compliant. + bool isCompliant = doc.Validate(logPath, PdfFormat.PDF_UA_1); + results.Add((fileName, isCompliant)); + } + } + + // Generate console dashboard + Console.WriteLine("PDF Validation Dashboard"); + Console.WriteLine(new string('=', 30)); + int total = results.Count; + int compliantCount = 0; + + foreach (var result in results) + { + string status = result.IsCompliant ? "Compliant" : "Non‑Compliant"; + Console.WriteLine($"{result.FileName}: {status}"); + if (result.IsCompliant) compliantCount++; + } + + Console.WriteLine(new string('-', 30)); + double compliancePercentage = total > 0 ? (double)compliantCount / total * 100 : 0; + Console.WriteLine($"Total files processed: {total}"); + Console.WriteLine($"Compliant files: {compliantCount}"); + Console.WriteLine($"Compliance percentage: {compliancePercentage:F2}%"); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/batch-pdfua-validation-csv-summary.cs b/accessibility-and-tagged-pdfs/batch-pdfua-validation-csv-summary.cs new file mode 100644 index 00000000..24198ef5 --- /dev/null +++ b/accessibility-and-tagged-pdfs/batch-pdfua-validation-csv-summary.cs @@ -0,0 +1,62 @@ +using System; +using System.IO; +using Aspose.Pdf; + +class Program +{ + static void Main(string[] args) + { + // Input directory containing PDF files. + // If a command‑line argument is provided, use it; otherwise use the current directory. + string inputDirectory = args.Length > 0 ? args[0] : Directory.GetCurrentDirectory(); + + if (!Directory.Exists(inputDirectory)) + { + Console.Error.WriteLine($"Directory not found: {inputDirectory}"); + return; + } + + // Path for the summary CSV file. + string summaryCsvPath = Path.Combine(inputDirectory, "validation_summary.csv"); + + try + { + using (var csvWriter = new StreamWriter(summaryCsvPath, false)) + { + // Write CSV header. + csvWriter.WriteLine("FileName,IsCompliant,LogFilePath"); + + // Enumerate all *.pdf files (case‑insensitive) in the directory. + foreach (string pdfFilePath in Directory.EnumerateFiles(inputDirectory, "*.pdf", SearchOption.TopDirectoryOnly)) + { + string fileName = Path.GetFileName(pdfFilePath); + string logFilePath = Path.ChangeExtension(pdfFilePath, ".xml"); + + try + { + // Open the PDF document inside a using block for deterministic disposal. + using (var document = new Aspose.Pdf.Document(pdfFilePath)) + { + // Validate against PDF/UA 1.0. The method returns true if the document complies. + bool isCompliant = document.Validate(logFilePath, Aspose.Pdf.PdfFormat.PDF_UA_1); + + // Write the result to the CSV. + csvWriter.WriteLine($"{fileName},{isCompliant},{logFilePath}"); + } + } + catch (Exception ex) + { + // If validation fails (e.g., corrupted PDF), record the error. + csvWriter.WriteLine($"{fileName},Error,\"{ex.Message}\""); + } + } + } + + Console.WriteLine($"Validation completed. Summary CSV saved to: {summaryCsvPath}"); + } + catch (Exception ex) + { + Console.Error.WriteLine($"Failed to create summary CSV: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/batch-tag-pdfs-with-suffix.cs b/accessibility-and-tagged-pdfs/batch-tag-pdfs-with-suffix.cs new file mode 100644 index 00000000..15136401 --- /dev/null +++ b/accessibility-and-tagged-pdfs/batch-tag-pdfs-with-suffix.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + // Folder containing PDFs to process + const string inputFolder = @"C:\PdfInput"; + // Suffix to append to processed files + const string suffix = "_tagged.pdf"; + + if (!Directory.Exists(inputFolder)) + { + Console.Error.WriteLine($"Folder not found: {inputFolder}"); + return; + } + + // Enable auto‑tagging globally (adds missing tags where possible) + AutoTaggingSettings.Default.EnableAutoTagging = true; + + // Process each PDF file in the folder + foreach (string pdfPath in Directory.GetFiles(inputFolder, "*.pdf")) + { + try + { + using (Document doc = new Document(pdfPath)) + { + // Access tagged‑content API + ITaggedContent tagged = doc.TaggedContent; + + // Optional: set language and title for accessibility + tagged.SetLanguage("en-US"); + tagged.SetTitle(Path.GetFileNameWithoutExtension(pdfPath)); + + // Persist any changes to the structure tree + tagged.Save(); + + // Build output file name with the required suffix + string outputPath = Path.Combine( + inputFolder, + Path.GetFileNameWithoutExtension(pdfPath) + suffix); + + // Save the (now tagged) PDF + doc.Save(outputPath); + Console.WriteLine($"Processed: {outputPath}"); + } + } + catch (Exception ex) + { + Console.Error.WriteLine($"Error processing '{pdfPath}': {ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/check-pdf-ua-compliance.cs b/accessibility-and-tagged-pdfs/check-pdf-ua-compliance.cs new file mode 100644 index 00000000..4c1cb6fb --- /dev/null +++ b/accessibility-and-tagged-pdfs/check-pdf-ua-compliance.cs @@ -0,0 +1,27 @@ +using System; +using System.IO; +using Aspose.Pdf; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document within a using block for proper disposal + using (Document doc = new Document(inputPath)) + { + // Check PDF/UA compliance + bool isUaCompliant = doc.IsPdfUaCompliant; + + // Log the result + Console.WriteLine($"PDF/UA compliant: {isUaCompliant}"); + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/create-internal-page-link-in-tagged-pdf.cs b/accessibility-and-tagged-pdfs/create-internal-page-link-in-tagged-pdf.cs new file mode 100644 index 00000000..2a9b5924 --- /dev/null +++ b/accessibility-and-tagged-pdfs/create-internal-page-link-in-tagged-pdf.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; +using Aspose.Pdf.Annotations; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output_with_link.pdf"; + const int targetPage = 2; // internal page number to jump to (1‑based) + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document + using (Document doc = new Document(inputPath)) + { + // Access tagged‑content API + ITaggedContent tagged = doc.TaggedContent; + + // Ensure the document has a structure tree + StructureElement root = tagged.RootElement; + + // Create a Link structure element + LinkElement linkElem = tagged.CreateLinkElement(); + + // Create a local hyperlink that points to the desired page + LocalHyperlink hyperlink = new LocalHyperlink + { + TargetPageNumber = targetPage + }; + + // Assign the hyperlink to the Link element + linkElem.Hyperlink = hyperlink; + + // Optionally set visible text for the link (e.g., "Go to page 2") + linkElem.SetText($"Go to page {targetPage}"); + + // Append the Link element to the root of the structure tree + root.AppendChild(linkElem); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"PDF saved with internal link: {outputPath}"); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/create-merged-table-header-tagged-pdf.cs b/accessibility-and-tagged-pdfs/create-merged-table-header-tagged-pdf.cs new file mode 100644 index 00000000..1aa60fc0 --- /dev/null +++ b/accessibility-and-tagged-pdfs/create-merged-table-header-tagged-pdf.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; // ITaggedContent +using Aspose.Pdf.LogicalStructure; // StructureElement, TableElement, etc. + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; // source PDF (can be untagged) + const string outputPath = "output_tagged.pdf"; // result with table header + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the document (lifecycle rule: use using) + using (Document doc = new Document(inputPath)) + { + // Access the tagged‑content API + ITaggedContent tagged = doc.TaggedContent; + + // Optional: set language / title for the whole document + tagged.SetLanguage("en-US"); + tagged.SetTitle(Path.GetFileNameWithoutExtension(inputPath)); + + // Root element of the logical structure tree + StructureElement root = tagged.RootElement; + + // ------------------------------------------------------------ + // Create a table structure element and attach it to the root + // ------------------------------------------------------------ + TableElement table = tagged.CreateTableElement(); + table.AlternativeText = "Sample data table with merged header cells"; + root.AppendChild(table); // AppendChild with one argument (bool default) + + // ------------------------------------------------------------ + // Create the table header (THead) and a header row (TR) + // ------------------------------------------------------------ + TableTHeadElement thead = tagged.CreateTableTHeadElement(); + table.AppendChild(thead); + + TableTRElement headerRow = tagged.CreateTableTRElement(); + thead.AppendChild(headerRow); + + // ------------------------------------------------------------ + // First header cell – spans two columns (merged cells) + // ------------------------------------------------------------ + TableTHElement thMerged = tagged.CreateTableTHElement(); + thMerged.SetText("Merged Header"); // Set visible text + thMerged.ActualText = "Merged Header"; // ActualText for accessibility + thMerged.ColSpan = 2; // Merge two columns + headerRow.AppendChild(thMerged); + + // ------------------------------------------------------------ + // Second header cell – occupies the remaining column + // ------------------------------------------------------------ + TableTHElement thSingle = tagged.CreateTableTHElement(); + thSingle.SetText("Separate Header"); + thSingle.ActualText = "Separate Header"; + headerRow.AppendChild(thSingle); + + // ------------------------------------------------------------ + // (Optional) Add a body row to illustrate the table structure + // ------------------------------------------------------------ + TableTRElement bodyRow = tagged.CreateTableTRElement(); + table.AppendChild(bodyRow); + + // First data cell + TableTDElement td1 = tagged.CreateTableTDElement(); + td1.SetText("Cell 1"); + td1.ActualText = "Cell 1"; + bodyRow.AppendChild(td1); + + // Second data cell (part of the merged column) + TableTDElement td2 = tagged.CreateTableTDElement(); + td2.SetText("Cell 2"); + td2.ActualText = "Cell 2"; + bodyRow.AppendChild(td2); + + // Third data cell + TableTDElement td3 = tagged.CreateTableTDElement(); + td3.SetText("Cell 3"); + td3.ActualText = "Cell 3"; + bodyRow.AppendChild(td3); + + // Save the modified PDF (lifecycle rule: save inside using) + doc.Save(outputPath); + } + + Console.WriteLine($"Tagged PDF with merged header saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/create-tagged-bullet-and-numbered-lists.cs b/accessibility-and-tagged-pdfs/create-tagged-bullet-and-numbered-lists.cs new file mode 100644 index 00000000..63f53877 --- /dev/null +++ b/accessibility-and-tagged-pdfs/create-tagged-bullet-and-numbered-lists.cs @@ -0,0 +1,95 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; // existing PDF to tag + const string outputPath = "tagged_list.pdf"; + const string reportPath = "validation_report.xml"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF (core API) and work with its tagged content + using (Document doc = new Document(inputPath)) + { + // Access tagged content (no Facades) + ITaggedContent tagged = doc.TaggedContent; + + // Set document language and title (write‑only setters) + tagged.SetLanguage("en-US"); + tagged.SetTitle(Path.GetFileNameWithoutExtension(inputPath)); + + // Root element of the logical structure tree + StructureElement root = tagged.RootElement; + + // ------------------------------------------------- + // Create a bullet list (disc bullet) + // ------------------------------------------------- + ListElement bulletList = tagged.CreateListElement(); + root.AppendChild(bulletList); // attach to root + + // First bullet item + ListLIElement bulletItem1 = tagged.CreateListLIElement(); + ListLBodyElement bulletBody1 = tagged.CreateListLBodyElement(); + ParagraphElement para1 = tagged.CreateParagraphElement(); + para1.SetText("First bullet point"); + bulletBody1.AppendChild(para1); + bulletItem1.AppendChild(bulletBody1); + bulletList.AppendChild(bulletItem1); + + // Second bullet item + ListLIElement bulletItem2 = tagged.CreateListLIElement(); + ListLBodyElement bulletBody2 = tagged.CreateListLBodyElement(); + ParagraphElement para2 = tagged.CreateParagraphElement(); + para2.SetText("Second bullet point"); + bulletBody2.AppendChild(para2); + bulletItem2.AppendChild(bulletBody2); + bulletList.AppendChild(bulletItem2); + + // ------------------------------------------------- + // Create a numbered list + // ------------------------------------------------- + ListElement numberedList = tagged.CreateListElement(); + root.AppendChild(numberedList); // attach to root + + // First numbered item + ListLIElement numItem1 = tagged.CreateListLIElement(); + ListLBodyElement numBody1 = tagged.CreateListLBodyElement(); + ParagraphElement para3 = tagged.CreateParagraphElement(); + para3.SetText("First numbered item"); + numBody1.AppendChild(para3); + numItem1.AppendChild(numBody1); + numberedList.AppendChild(numItem1); + + // Second numbered item + ListLIElement numItem2 = tagged.CreateListLIElement(); + ListLBodyElement numBody2 = tagged.CreateListLBodyElement(); + ParagraphElement para4 = tagged.CreateParagraphElement(); + para4.SetText("Second numbered item"); + numBody2.AppendChild(para4); + numItem2.AppendChild(numBody2); + numberedList.AppendChild(numItem2); + + // ------------------------------------------------- + // Validate the tagged PDF (PDF/UA compliance) + // ------------------------------------------------- + // Use the correct PDF/UA constant + doc.Validate(reportPath, PdfFormat.PDF_UA_1); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Tagged PDF with lists saved to '{outputPath}'."); + Console.WriteLine($"Validation report saved to '{reportPath}'."); + } +} diff --git a/accessibility-and-tagged-pdfs/create-tagged-pdf-heading-language.cs b/accessibility-and-tagged-pdfs/create-tagged-pdf-heading-language.cs new file mode 100644 index 00000000..32313141 --- /dev/null +++ b/accessibility-and-tagged-pdfs/create-tagged-pdf-heading-language.cs @@ -0,0 +1,68 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string outputPath = "tagged_heading.pdf"; + + // Create a new PDF document + using (Document doc = new Document()) + { + // Access the tagged‑content API + ITaggedContent tagged = doc.TaggedContent; + + // Set document‑level language and title + tagged.SetLanguage("en-US"); + tagged.SetTitle("Document with Heading"); + + // Root element of the logical structure tree + StructureElement root = tagged.RootElement; + + // Create a level‑1 heading (HeaderElement) + HeaderElement heading = tagged.CreateHeaderElement(1); + heading.SetText("Sample Heading"); + + // Assign a language attribute to the heading element + heading.Language = "en-US"; + + // Attach the heading to the root element + root.AppendChild(heading); + + // Save the PDF (guard against missing GDI+ on non‑Windows platforms) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + doc.Save(outputPath); + } + else + { + try + { + doc.Save(outputPath); + } + catch (TypeInitializationException ex) when (ContainsDllNotFound(ex)) + { + Console.WriteLine("GDI+ not available; PDF saved without graphics."); + } + } + } + + Console.WriteLine($"PDF saved to '{outputPath}'."); + } + + // Helper to detect a nested DllNotFoundException (e.g., missing libgdiplus) + private static bool ContainsDllNotFound(Exception ex) + { + while (ex != null) + { + if (ex is DllNotFoundException) return true; + ex = ex.InnerException; + } + return false; + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/create-tagged-pdf-table-custom-cell-tags.cs b/accessibility-and-tagged-pdfs/create-tagged-pdf-table-custom-cell-tags.cs new file mode 100644 index 00000000..061ec0c3 --- /dev/null +++ b/accessibility-and-tagged-pdfs/create-tagged-pdf-table-custom-cell-tags.cs @@ -0,0 +1,126 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; // source PDF + const string outputPath = "tagged_output.pdf"; // PDF with custom tags + const string logPath = "validation_log.txt"; // validation report + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the document and ensure deterministic disposal + using (Document doc = new Document(inputPath)) + { + // Access tagged‑content API + ITaggedContent tagged = doc.TaggedContent; + tagged.SetLanguage("en-US"); + tagged.SetTitle(Path.GetFileNameWithoutExtension(inputPath)); + + // Root element of the logical structure tree + StructureElement root = tagged.RootElement; + + // ------------------------------------------------------------ + // Create a logical table element and attach it to the root + // ------------------------------------------------------------ + TableElement table = tagged.CreateTableElement(); + table.AlternativeText = "Sample data table with custom cell tags"; + root.AppendChild(table); // AppendChild with one argument + + // ------------------------------------------------------------ + // Header row (TH cells) + // ------------------------------------------------------------ + TableTHeadElement thead = tagged.CreateTableTHeadElement(); + table.AppendChild(thead); + + TableTRElement headerRow = tagged.CreateTableTRElement(); + thead.AppendChild(headerRow); + + // Example column headers + string[] headers = { "ID", "Name", "BirthDate", "Salary" }; + foreach (string hdr in headers) + { + TableTHElement th = tagged.CreateTableTHElement(); + th.SetText(hdr); + // No custom tag needed for header cells + headerRow.AppendChild(th); + } + + // ------------------------------------------------------------ + // Body rows (TD cells) – assign custom tags indicating data type + // ------------------------------------------------------------ + TableTBodyElement tbody = tagged.CreateTableTBodyElement(); + table.AppendChild(tbody); + + // Example data row + TableTRElement dataRow = tagged.CreateTableTRElement(); + tbody.AppendChild(dataRow); + + // Cell 1 – ID (integer) + TableTDElement tdId = tagged.CreateTableTDElement(); + tdId.SetText("1001"); + tdId.SetTag("Number"); // custom tag + dataRow.AppendChild(tdId); + + // Cell 2 – Name (string) + TableTDElement tdName = tagged.CreateTableTDElement(); + tdName.SetText("Alice Smith"); + tdName.SetTag("String"); + dataRow.AppendChild(tdName); + + // Cell 3 – BirthDate (date) + TableTDElement tdDate = tagged.CreateTableTDElement(); + tdDate.SetText("1985-04-23"); + tdDate.SetTag("Date"); + dataRow.AppendChild(tdDate); + + // Cell 4 – Salary (currency) + TableTDElement tdSalary = tagged.CreateTableTDElement(); + tdSalary.SetText("$75,000"); + tdSalary.SetTag("Currency"); + dataRow.AppendChild(tdSalary); + + // ------------------------------------------------------------ + // OPTIONAL: add a visual representation of the table to the first page + // ------------------------------------------------------------ + Page firstPage = doc.Pages[1]; + Table visualTable = new Table + { + ColumnWidths = "100 150 120 100", + DefaultCellBorder = new BorderInfo(BorderSide.All, 0.5f, Aspose.Pdf.Color.Black) + }; + // Header row + Row vHeader = visualTable.Rows.Add(); + foreach (string hdr in headers) + vHeader.Cells.Add(hdr); + // Data row + Row vData = visualTable.Rows.Add(); + vData.Cells.Add("1001"); + vData.Cells.Add("Alice Smith"); + vData.Cells.Add("1985-04-23"); + vData.Cells.Add("$75,000"); + + firstPage.Paragraphs.Add(visualTable); + + // ------------------------------------------------------------ + // Validate the document (PDF/A‑1B compliance as an example) + // ------------------------------------------------------------ + bool isValid = doc.Validate(logPath, PdfFormat.PDF_A_1B); + Console.WriteLine($"Validation result: {(isValid ? "OK" : "Issues found")} (log: {logPath})"); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Tagged PDF saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/enable-auto-tagging-pdf-ua-conversion.cs b/accessibility-and-tagged-pdfs/enable-auto-tagging-pdf-ua-conversion.cs new file mode 100644 index 00000000..1404552b --- /dev/null +++ b/accessibility-and-tagged-pdfs/enable-auto-tagging-pdf-ua-conversion.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "tagged_output.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Enable global auto‑tagging (optional, ensures default settings are on) + AutoTaggingSettings.Default.EnableAutoTagging = true; + + // Load the source PDF + using (Document doc = new Document(inputPath)) + { + // Prepare conversion options for PDF/UA format with auto‑tagging enabled + PdfFormatConversionOptions convOpts = new PdfFormatConversionOptions(PdfFormat.PDF_UA_1); + convOpts.AutoTaggingSettings = new AutoTaggingSettings + { + EnableAutoTagging = true + }; + + // Perform the conversion – this applies automatic tagging + doc.Convert(convOpts); + + // Set document‑level metadata for the tagged PDF + ITaggedContent tagged = doc.TaggedContent; + tagged.SetLanguage("en-US"); + tagged.SetTitle(Path.GetFileNameWithoutExtension(inputPath)); + + // Save the resulting tagged PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Tagged PDF saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/export-pdf-structure-tree-to-json.cs b/accessibility-and-tagged-pdfs/export-pdf-structure-tree-to-json.cs new file mode 100644 index 00000000..1b7efeeb --- /dev/null +++ b/accessibility-and-tagged-pdfs/export-pdf-structure-tree-to-json.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Text.Json; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPdf = "input.pdf"; + const string outputJson = "structure.json"; + + if (!File.Exists(inputPdf)) + { + Console.Error.WriteLine($"File not found: {inputPdf}"); + return; + } + + using (Document doc = new Document(inputPdf)) + { + ITaggedContent tagged = doc.TaggedContent; + StructureElement root = tagged.RootElement; + + JsonStructureNode jsonRoot = BuildJsonNode(root); + JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true }; + string json = JsonSerializer.Serialize(jsonRoot, options); + + File.WriteAllText(outputJson, json); + Console.WriteLine($"Structure tree exported to '{outputJson}'."); + } + } + + // Recursively convert a StructureElement to a serializable node + static JsonStructureNode BuildJsonNode(StructureElement element) + { + JsonStructureNode node = new JsonStructureNode { + Type = element.GetType().Name, + ActualText = element.ActualText, + AlternativeText = element.AlternativeText, + Language = element.Language, + Children = new List() + }; + + foreach (Element child in element.ChildElements) + { + if (child is StructureElement se) + node.Children.Add(BuildJsonNode(se)); + } + + return node; + } + + // Simple POCO for JSON serialization + class JsonStructureNode + { + public string Type { get; set; } + public string ActualText { get; set; } + public string AlternativeText { get; set; } + public string Language { get; set; } + public List Children { get; set; } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/export-structure-tree-to-xml-xsl-report.cs b/accessibility-and-tagged-pdfs/export-structure-tree-to-xml-xsl-report.cs new file mode 100644 index 00000000..e3999a5c --- /dev/null +++ b/accessibility-and-tagged-pdfs/export-structure-tree-to-xml-xsl-report.cs @@ -0,0 +1,60 @@ +using System; +using System.IO; +using System.Xml; +using System.Xml.Xsl; +using Aspose.Pdf; + +class ExportStructureTree +{ + static void Main() + { + // Paths – adjust as needed + const string pdfPath = "input.pdf"; // source PDF + const string xmlPath = "structure.xml"; // intermediate XML export + const string xslPath = "report.xsl"; // XSLT stylesheet for the report + const string reportPath = "report.html"; // final transformed report + + // Verify source files exist + if (!File.Exists(pdfPath)) + { + Console.Error.WriteLine($"PDF not found: {pdfPath}"); + return; + } + if (!File.Exists(xslPath)) + { + Console.Error.WriteLine($"XSLT not found: {xslPath}"); + return; + } + + try + { + // ---------- Export structure tree to XML ---------- + using (Document pdfDoc = new Document(pdfPath)) + { + // XmlSaveOptions resides directly in Aspose.Pdf namespace + XmlSaveOptions xmlOptions = new XmlSaveOptions(); + // Save the document model (including the structure tree) as XML + pdfDoc.Save(xmlPath, xmlOptions); + } + + // ---------- Transform XML with XSLT to produce the report ---------- + // Load the XSLT stylesheet + XslCompiledTransform xslt = new XslCompiledTransform(); + xslt.Load(xslPath); + + // Perform the transformation: XML -> report (e.g., HTML) + using (FileStream xmlStream = File.OpenRead(xmlPath)) + using (FileStream resultStream = File.Create(reportPath)) + using (XmlReader xmlReader = XmlReader.Create(xmlStream)) + { + xslt.Transform(xmlReader, null, resultStream); + } + + Console.WriteLine($"Structure tree exported to '{xmlPath}' and transformed to report '{reportPath}'."); + } + catch (Exception ex) + { + Console.Error.WriteLine($"Error: {ex.Message}"); + } + } +} diff --git a/accessibility-and-tagged-pdfs/export-tagged-pdf-structure-to-json.cs b/accessibility-and-tagged-pdfs/export-tagged-pdf-structure-to-json.cs new file mode 100644 index 00000000..97c0feed --- /dev/null +++ b/accessibility-and-tagged-pdfs/export-tagged-pdf-structure-to-json.cs @@ -0,0 +1,72 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Text.Json; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string jsonPath = "structure.json"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load PDF inside a using block for deterministic disposal + using (Document doc = new Document(inputPath)) + { + // Access tagged content + ITaggedContent tagged = doc.TaggedContent; + + // Root of the logical structure tree + StructureElement root = tagged.RootElement; + + // Convert the structure tree to a serializable POCO hierarchy + ElementNode jsonRoot = BuildElementNode(root); + + // Serialize hierarchy to formatted JSON + JsonSerializerOptions jsonOptions = new JsonSerializerOptions { WriteIndented = true }; + string json = JsonSerializer.Serialize(jsonRoot, jsonOptions); + File.WriteAllText(jsonPath, json); + } + + Console.WriteLine($"Tagged structure exported to '{jsonPath}'."); + } + + // Recursively builds a plain object representing a structure element + static ElementNode BuildElementNode(Element element) + { + ElementNode node = new ElementNode { + Type = element.GetType().Name, + Text = (element as StructureElement)?.ActualText, + AlternativeText = (element as StructureElement)?.AlternativeText, + Language = (element as StructureElement)?.Language, + Children = new List() + }; + + // Process child elements using the correct ChildElements property + foreach (Element child in element.ChildElements) + { + node.Children.Add(BuildElementNode(child)); + } + + return node; + } + + // POCO used for JSON serialization + class ElementNode + { + public string Type { get; set; } + public string Text { get; set; } + public string AlternativeText { get; set; } + public string Language { get; set; } + public List Children { get; set; } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/extract-link-urls-to-csv.cs b/accessibility-and-tagged-pdfs/extract-link-urls-to-csv.cs new file mode 100644 index 00000000..f5af07b4 --- /dev/null +++ b/accessibility-and-tagged-pdfs/extract-link-urls-to-csv.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Annotations; + +class Program +{ + static void Main() + { + const string inputPdf = "input.pdf"; + const string outputCsv = "links.csv"; + + if (!File.Exists(inputPdf)) + { + Console.Error.WriteLine($"File not found: {inputPdf}"); + return; + } + + // Open the PDF document inside a using block for deterministic disposal + using (Document doc = new Document(inputPdf)) + { + // Prepare the CSV file + using (StreamWriter writer = new StreamWriter(outputCsv, false)) + { + // Write CSV header + writer.WriteLine("URL"); + + // Iterate through all pages (Aspose.Pdf uses 1‑based indexing) + for (int i = 1; i <= doc.Pages.Count; i++) + { + Page page = doc.Pages[i]; + + // Iterate through all annotations on the page + for (int j = 1; j <= page.Annotations.Count; j++) + { + Annotation ann = page.Annotations[j]; + + // We are interested only in LinkAnnotation objects + if (ann is LinkAnnotation link) + { + // The correct way to obtain an external URL is via GoToURIAction + if (link.Action is GoToURIAction uriAction) + { + string url = uriAction.URI; + // Write the URL to the CSV (escape double quotes if needed) + string escaped = url?.Replace("\"", "\"\""); + writer.WriteLine($"\"{escaped}\""); + } + } + } + } + } + } + + Console.WriteLine($"Link URLs have been written to '{outputCsv}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/extract-notes-from-tagged-pdf.cs b/accessibility-and-tagged-pdfs/extract-notes-from-tagged-pdf.cs new file mode 100644 index 00000000..3812759a --- /dev/null +++ b/accessibility-and-tagged-pdfs/extract-notes-from-tagged-pdf.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; +using System.Text; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPdfPath = "input.pdf"; + const string outputTxtPath = "notes.txt"; + + if (!File.Exists(inputPdfPath)) + { + Console.Error.WriteLine($"File not found: {inputPdfPath}"); + return; + } + + // Load the PDF document + using (Document doc = new Document(inputPdfPath)) + { + // Access tagged content (structure tree) + ITaggedContent taggedContent = doc.TaggedContent; + StructureElement root = taggedContent.RootElement; + + // Find all Note elements recursively + var noteElements = root.FindElements(true); + + // Concatenate the actual text of each note + StringBuilder sb = new StringBuilder(); + foreach (NoteElement note in noteElements) + { + if (!string.IsNullOrEmpty(note.ActualText)) + { + sb.AppendLine(note.ActualText); + } + } + + // Write the concatenated notes to a plain text file + File.WriteAllText(outputTxtPath, sb.ToString()); + } + + Console.WriteLine($"Extracted notes saved to '{outputTxtPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/extract-text-from-tagged-pdf-structure-tree.cs b/accessibility-and-tagged-pdfs/extract-text-from-tagged-pdf-structure-tree.cs new file mode 100644 index 00000000..6270e9df --- /dev/null +++ b/accessibility-and-tagged-pdfs/extract-text-from-tagged-pdf-structure-tree.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using System.Text; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document + using (Document doc = new Document(inputPath)) + { + // Access tagged content interface + ITaggedContent tagged = doc.TaggedContent; + + if (tagged == null) + { + Console.WriteLine("The document is not tagged."); + return; + } + + // Root of the structure tree (no cast needed) + StructureElement root = tagged.RootElement; + + // Collect text from all structure elements + StringBuilder sb = new StringBuilder(); + TraverseStructure(root, sb); + + // Output the extracted text + Console.WriteLine("Extracted text from the structure tree:"); + Console.WriteLine(sb.ToString()); + } + } + + // Recursively walk the structure tree and gather ActualText + static void TraverseStructure(StructureElement element, StringBuilder sb) + { + // Append the element's text if present + if (!string.IsNullOrEmpty(element.ActualText)) + { + sb.AppendLine(element.ActualText); + } + + // Iterate over child elements (ElementList) using ChildElements + foreach (Element child in element.ChildElements) + { + if (child is StructureElement childStructure) + { + TraverseStructure(childStructure, sb); + } + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/find-images-missing-alt-text.cs b/accessibility-and-tagged-pdfs/find-images-missing-alt-text.cs new file mode 100644 index 00000000..93101ce0 --- /dev/null +++ b/accessibility-and-tagged-pdfs/find-images-missing-alt-text.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Aspose.Pdf; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // List to hold IDs of images that lack alternative text + var missingAltIds = new List(); + + // Load the PDF document (wrapped in using for proper disposal) + using (Document doc = new Document(inputPath)) + { + // Pages are 1‑based in Aspose.Pdf + for (int i = 1; i <= doc.Pages.Count; i++) + { + Page page = doc.Pages[i]; + + // Iterate over all XImage objects on the current page + foreach (XImage img in page.Resources.Images) + { + // Retrieve any alternative text associated with this image on this page + List altTexts = img.GetAlternativeText(page); + + // If no alternative text is present, record the image identifier + if (altTexts == null || altTexts.Count == 0) + { + // GetNameInCollection returns the resource name (ID) of the image + string imageId = img.GetNameInCollection(); + missingAltIds.Add(imageId); + } + } + } + } + + // Output the collected image IDs + Console.WriteLine("Images missing alternative text:"); + foreach (string id in missingAltIds) + { + Console.WriteLine(id); + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/index.json b/accessibility-and-tagged-pdfs/index.json new file mode 100644 index 00000000..451d6f03 --- /dev/null +++ b/accessibility-and-tagged-pdfs/index.json @@ -0,0 +1,1009 @@ +{ + "category": "accessibility-and-tagged-pdfs", + "nuget_version": "26.5.0", + "last_updated": "2026-06-02T06:44:26Z", + "examples": { + "enable-auto-tagging-pdf-ua-conversion": { + "title": "Enable Auto‑Tagging and Convert PDF to PDF/UA", + "filename": "enable-auto-tagging-pdf-ua-conversion.cs", + "description": "Demonstrates how to turn on automatic tagging, convert a PDF to the PDF/UA accessibility standard, set basic document metadata, and save the result as a tagged PDF using Aspose.Pdf.", + "tags": [ + "auto-tagging", + "pdf/ua", + "accessibility", + "tagged-pdf", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.AutoTaggingSettings", + "Aspose.Pdf.Tagged.PdfFormatConversionOptions", + "Aspose.Pdf.Tagged.PdfFormat", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Document.Convert", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "create-tagged-pdf-heading-language": { + "title": "Create Tagged PDF with Heading and Language Attribute", + "filename": "create-tagged-pdf-heading-language.cs", + "description": "Shows how to create a new PDF, enable tagged content, set the document language and title, add a level‑1 heading element with its own language attribute, and save the file.", + "tags": [ + "tagged-pdf", + "heading", + "language", + "accessibility", + "Aspose.Pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.HeaderElement", + "Aspose.Pdf.LogicalStructure.StructureElement", + "Aspose.Pdf.Tagged.ITaggedContent.SetLanguage", + "Aspose.Pdf.Tagged.ITaggedContent.SetTitle", + "Aspose.Pdf.Tagged.ITaggedContent.CreateHeaderElement", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "set-root-structure-element-title": { + "title": "Set Root Structure Element Title in Tagged PDF", + "filename": "set-root-structure-element-title.cs", + "description": "Demonstrates how to assign a title to the root structure element of a tagged PDF using Aspose.Pdf, and optionally update the document's Info title for full metadata coverage.", + "tags": [ + "accessibility", + "tagged-pdf", + "metadata", + "title", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Document.Info", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.LogicalStructure.StructureElement", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "beginner", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-paragraph-actualtext-under-toci": { + "title": "Add Paragraph with ActualText under TOCI in Tagged PDF", + "filename": "add-paragraph-actualtext-under-toci.cs", + "description": "Demonstrates how to create a TOCI (Table of Contents Item) element in a tagged PDF, add a paragraph beneath it, and set the paragraph's ActualText for improved accessibility.", + "tags": [ + "tagged-pdf", + "accessibility", + "toc", + "actualtext", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.TOCIElement", + "Aspose.Pdf.Tagged.ParagraphElement", + "Aspose.Pdf.Tagged.StructureElement" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-custom-tag-to-paragraph": { + "title": "Add Custom Tag to Paragraph in a Tagged PDF", + "filename": "add-custom-tag-to-paragraph.cs", + "description": "Demonstrates how to create a tagged PDF, add a paragraph element, assign a custom tag name, and save the document while handling platform‑specific GDI+ requirements.", + "tags": [ + "tagged-pdf", + "custom-tag", + "accessibility", + "paragraph", + "Aspose.Pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.ParagraphElement", + "Aspose.Pdf.Tagged.ParagraphElement.SetTag", + "Aspose.Pdf.Tagged.ParagraphElement.SetText", + "Aspose.Pdf.Tagged.ITaggedContent.SetLanguage", + "Aspose.Pdf.Tagged.ITaggedContent.SetTitle" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-external-link-with-title-to-tagged-pdf": { + "title": "Add External Link with Title to a Tagged PDF", + "filename": "add-external-link-with-title-to-tagged-pdf.cs", + "description": "Demonstrates how to create a LinkElement in a tagged PDF, assign a title attribute for accessibility, and link it to an external URL using Aspose.Pdf.", + "tags": [ + "pdf", + "link", + "accessibility", + "tagged-pdf", + "aspnet" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.LogicalStructure.StructureElement", + "Aspose.Pdf.LogicalStructure.LinkElement", + "Aspose.Pdf.WebHyperlink" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "create-internal-page-link-in-tagged-pdf": { + "title": "Create Internal Page Link in Tagged PDF", + "filename": "create-internal-page-link-in-tagged-pdf.cs", + "description": "Shows how to add a Link structure element with a LocalHyperlink that jumps to a specific page in a tagged PDF using Aspose.Pdf.", + "tags": [ + "tagged-pdf", + "internal-link", + "accessibility", + "link-element", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.LinkElement", + "Aspose.Pdf.Annotations.LocalHyperlink" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-note-element-to-paragraph": { + "title": "Add Note Element to Paragraph in Tagged PDF", + "filename": "add-note-element-to-paragraph.cs", + "description": "Shows how to create a note (footnote/endnote) and attach it as a child of a paragraph in a tagged PDF using Aspose.Pdf.", + "tags": [ + "tagged-pdf", + "note-element", + "paragraph", + "accessibility", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.TaggedContent.CreateParagraphElement", + "Aspose.Pdf.Tagged.TaggedContent.CreateNoteElement", + "Aspose.Pdf.LogicalStructure.StructureElement.AppendChild", + "Aspose.Pdf.LogicalStructure.ParagraphElement.SetText", + "Aspose.Pdf.LogicalStructure.NoteElement.SetText" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-caption-note-to-figure-in-tagged-pdf": { + "title": "Add Caption Note to Figure in Tagged PDF", + "filename": "add-caption-note-to-figure-in-tagged-pdf.cs", + "description": "Demonstrates how to create a Figure element in a tagged PDF and attach a Note element as a caption, improving accessibility with alternative text.", + "tags": [ + "tagged-pdf", + "accessibility", + "figure", + "caption", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.TaggedContent.CreateFigureElement", + "Aspose.Pdf.Tagged.TaggedContent.CreateNoteElement", + "Aspose.Pdf.LogicalStructure.StructureElement.AppendChild", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-actualtext-to-images": { + "title": "Add ActualText to Images for PDF Accessibility", + "filename": "add-actualtext-to-images.cs", + "description": "Shows how to attach an ActualText attribute to image elements in a tagged PDF using Aspose.Pdf, providing screen‑reader alternative text for accessibility.", + "tags": [ + "accessibility", + "tagged-pdf", + "actualtext", + "image", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.FigureElement", + "Aspose.Pdf.XImage" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "set-actualtext-pronunciation-span": { + "title": "Set Hidden Pronunciation Text Using ActualText on a Span in a Tagged PDF", + "filename": "set-actualtext-pronunciation-span.cs", + "description": "Demonstrates how to add a span element to a PDF's tagged structure and supply hidden pronunciation text via the ActualText property for accessibility.", + "tags": [ + "accessibility", + "tagged-pdf", + "actualtext", + "pronunciation", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.SpanElement", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "beginner", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "set-structure-element-language-french": { + "title": "Set Structure Element Language to French in a Tagged PDF", + "filename": "set-structure-element-language-french.cs", + "description": "Shows how to locate a ParagraphElement in a PDF's tagged structure tree, change its language attribute to French (fr-FR), and save the updated document.", + "tags": [ + "tagged-pdf", + "accessibility", + "language", + "structure-element", + "Aspose.Pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.ParagraphElement", + "Aspose.Pdf.Tagged.ITaggedContent.SetLanguage" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "set-document-language-in-tagged-pdf": { + "title": "Set Document Language in Tagged PDF", + "filename": "set-document-language-in-tagged-pdf.cs", + "description": "Demonstrates how to add a language attribute to the PDF's structure tree using Aspose.Pdf's tagged content API.", + "tags": [ + "pdf", + "accessibility", + "language", + "tagged-pdf", + "aspnet" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.LogicalStructure.StructureElement", + "Aspose.Pdf.Tagged.TaggedContent.SetLanguage", + "Aspose.Pdf.LogicalStructure.StructureElement.Language" + ], + "difficulty": "beginner", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "propagate-language-to-tagged-elements": { + "title": "Propagate Language Attribute to All Tagged Elements", + "filename": "propagate-language-to-tagged-elements.cs", + "description": "Shows how to set the document language on the root of a tagged PDF and automatically propagate it to every structure element using Aspose.Pdf.", + "tags": [ + "accessibility", + "tagged-pdf", + "language", + "structure", + "Aspose.Pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.StructureElement.FindElements", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-3x4-table-to-tagged-pdf": { + "title": "Add a 3x4 Table to a Tagged PDF", + "filename": "add-3x4-table-to-tagged-pdf.cs", + "description": "Demonstrates how to create a 3‑row by 4‑column table and insert it into the structure tree of a PDF using Aspose.Pdf's tagged‑content API for accessibility.", + "tags": [ + "tagged-pdf", + "table", + "accessibility", + "structure", + "aspnet" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.TableElement", + "Aspose.Pdf.Tagged.TableTBodyElement", + "Aspose.Pdf.Tagged.TableTRElement", + "Aspose.Pdf.Tagged.TableTDElement" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "create-merged-table-header-tagged-pdf": { + "title": "Create Merged Table Header in Tagged PDF", + "filename": "create-merged-table-header-tagged-pdf.cs", + "description": "Demonstrates how to add a table with a merged header row to a PDF, assign the TH role and set ActualText for each header cell using Aspose.Pdf's TaggedContent API.", + "tags": [ + "tagged-pdf", + "table-header", + "accessibility", + "merged-cells", + "aspnet" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.LogicalStructure.TableElement", + "Aspose.Pdf.LogicalStructure.TableTHElement", + "Aspose.Pdf.LogicalStructure.TableTRElement", + "Aspose.Pdf.Tagged.ITaggedContent.CreateTableElement", + "Aspose.Pdf.Tagged.ITaggedContent.CreateTableTHElement" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "style-table-cells-background-border-padding": { + "title": "Style Table Cells with Background, Border, and Padding", + "filename": "style-table-cells-background-border-padding.cs", + "description": "Demonstrates creating a PDF table and applying per‑cell background color, border thickness/color, and padding to improve visual accessibility.", + "tags": [ + "table", + "styling", + "accessibility", + "pdf", + "aspose" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Page", + "Aspose.Pdf.Table", + "Aspose.Pdf.Cell", + "Aspose.Pdf.Drawing.BorderInfo", + "Aspose.Pdf.Drawing.MarginInfo", + "Aspose.Pdf.Color", + "Aspose.Pdf.Text.TextFragment" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "apply-custom-row-borders-to-pdf-table": { + "title": "Apply Custom Row Borders to PDF Table", + "filename": "apply-custom-row-borders-to-pdf-table.cs", + "description": "Shows how to create a PDF document with a table and set different border styles for rows based on their index, enhancing visual distinction and accessibility.", + "tags": [ + "pdf", + "table", + "border", + "aspose-pdf", + "accessibility" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Page", + "Aspose.Pdf.Table", + "Aspose.Pdf.Row", + "Aspose.Pdf.Cell", + "Aspose.Pdf.BorderInfo", + "Aspose.Pdf.Text.TextFragment", + "Aspose.Pdf.Color" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "create-tagged-pdf-table-custom-cell-tags": { + "title": "Create Tagged PDF Table with Custom Cell Types and Validate PDF/A-1B", + "filename": "create-tagged-pdf-table-custom-cell-tags.cs", + "description": "Demonstrates how to add a logical table to a PDF, assign custom data‑type tags to each cell, render a visual table, and run PDF/A‑1B validation using Aspose.Pdf.", + "tags": [ + "tagged-pdf", + "table", + "custom-tags", + "pdf-validation", + "accessibility" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.TableElement", + "Aspose.Pdf.Tagged.TableTDElement", + "Aspose.Pdf.Document.Validate", + "Aspose.Pdf.Table" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "nested-table-in-paragraph-tagged-pdf": { + "title": "Create Nested Table Inside a Paragraph for Tagged PDF", + "filename": "nested-table-in-paragraph-tagged-pdf.cs", + "description": "Demonstrates how to build a logical structure with a paragraph that contains an outer table, which in turn hosts a nested table, and validates the tagging hierarchy using Aspose.Pdf.", + "tags": [ + "tagged-pdf", + "nested-table", + "accessibility", + "structure", + "aspose" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.LogicalStructure.StructureElement", + "Aspose.Pdf.Tagged.ParagraphElement", + "Aspose.Pdf.Tagged.TableElement", + "Aspose.Pdf.Tagged.TableTHeadElement", + "Aspose.Pdf.Tagged.TableTDElement" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "create-tagged-bullet-and-numbered-lists": { + "title": "Create Tagged Bullet and Numbered Lists in PDF", + "filename": "create-tagged-bullet-and-numbered-lists.cs", + "description": "Loads an existing PDF, adds a bulleted list and a numbered list using the Aspose.Pdf.Tagged API, sets document language and title, validates PDF/UA compliance, and saves the tagged PDF.", + "tags": [ + "tagged-pdf", + "list", + "pdf-ua", + "accessibility", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.ListElement", + "Aspose.Pdf.Tagged.ListLIElement", + "Aspose.Pdf.Tagged.ListLBodyElement", + "Aspose.Pdf.Tagged.ParagraphElement", + "Aspose.Pdf.Document.Validate" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-tagged-form-field-to-pdf": { + "title": "Add Tagged Form Field to PDF", + "filename": "add-tagged-form-field-to-pdf.cs", + "description": "Demonstrates how to create a text box form field, register it in the AcroForm, and associate it with a /Form structure element for accessibility tagging.", + "tags": [ + "form", + "tagged-pdf", + "accessibility", + "acroform", + "aspnet-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Forms.TextBoxField", + "Aspose.Pdf.Document.Form.Add", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.FormElement", + "Aspose.Pdf.Tagged.FormElement.AlternativeText", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-placeholder-textbox-form-field-tagged-pdf": { + "title": "Add Placeholder TextBox Form Field and Tag in PDF", + "filename": "add-placeholder-textbox-form-field-tagged-pdf.cs", + "description": "Loads an existing PDF, creates a TextBox form field with placeholder text, adds it to the document's form, and tags the field in the PDF structure tree for accessibility.", + "tags": [ + "form-field", + "placeholder", + "tagged-pdf", + "accessibility", + "Aspose.Pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Page", + "Aspose.Pdf.Forms.TextBoxField", + "Aspose.Pdf.Document.Form.Add", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.FormElement", + "Aspose.Pdf.Tagged.StructureElement" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "add-page-break-element-to-tagged-pdf": { + "title": "Add Page Break Element to Tagged PDF", + "filename": "add-page-break-element-to-tagged-pdf.cs", + "description": "Shows how to insert a page‑break element into the logical structure of a PDF using Aspose.Pdf's tagged content API for improved accessibility.", + "tags": [ + "pdf", + "tagged-pdf", + "accessibility", + "page-break", + "aspnet" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.DivElement", + "Aspose.Pdf.Tagged.ITaggedContent.CreateDivElement", + "Aspose.Pdf.Tagged.StructureElement.AppendChild" + ], + "difficulty": "beginner", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "update-paragraph-actualtext-in-tagged-pdf": { + "title": "Update Paragraph ActualText in Tagged PDF", + "filename": "update-paragraph-actualtext-in-tagged-pdf.cs", + "description": "Shows how to load a PDF, locate a paragraph by its ActualText title within the tagged structure, modify the ActualText for accessibility, and save the updated document.", + "tags": [ + "pdf", + "accessibility", + "tagged-pdf", + "actualtext", + "aspnet" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.ParagraphElement", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "replace-note-element-in-tagged-pdf": { + "title": "Replace Note Element in Tagged PDF", + "filename": "replace-note-element-in-tagged-pdf.cs", + "description": "Shows how to locate and remove existing Note elements in a tagged PDF and insert a new note with updated text using Aspose.Pdf's tagged content API.", + "tags": [ + "tagged-pdf", + "note-element", + "accessibility", + "replace", + "Aspose.Pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.Tagged.NoteElement", + "Aspose.Pdf.Tagged.StructureElement.FindElements", + "Aspose.Pdf.Tagged.StructureElement.AppendChild", + "Aspose.Pdf.Tagged.NoteElement.SetText", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "iterate-tagged-pdf-structure-elements": { + "title": "Iterate Tagged PDF Structure Elements and Log Metadata", + "filename": "iterate-tagged-pdf-structure-elements.cs", + "description": "Loads a PDF, accesses its tagged content, walks the logical structure tree recursively, and prints each element's tag name, title, and language.", + "tags": [ + "tagged-pdf", + "structure", + "accessibility", + "metadata", + "aspnet" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.LogicalStructure.Element", + "Aspose.Pdf.Tagged.TaggedContent" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "set-paragraph-title-in-tagged-pdf": { + "title": "Set Paragraph Title in a Tagged PDF", + "filename": "set-paragraph-title-in-tagged-pdf.cs", + "description": "Shows how to use Aspose.Pdf's TaggedContent API to create a paragraph element, assign its Title property as a concise summary, and attach it to a tagged PDF document.", + "tags": [ + "tagged-pdf", + "accessibility", + "paragraph", + "title", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.TaggedContent.SetTitle", + "Aspose.Pdf.Tagged.TaggedContent.CreateParagraphElement", + "Aspose.Pdf.Tagged.ParagraphElement.SetText", + "Aspose.Pdf.Tagged.ParagraphElement.Title", + "Aspose.Pdf.Tagged.StructureElement.AppendChild" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "set-figure-title-in-tagged-pdf": { + "title": "Set Figure Title in Tagged PDF for Accessibility", + "filename": "set-figure-title-in-tagged-pdf.cs", + "description": "Demonstrates how to add a figure element with a concise title and alternative text to a tagged PDF using Aspose.Pdf, enhancing document accessibility.", + "tags": [ + "pdf", + "accessibility", + "tagged-pdf", + "figure", + "title" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.TaggedContent.SetLanguage", + "Aspose.Pdf.Tagged.TaggedContent.SetTitle", + "Aspose.Pdf.LogicalStructure.FigureElement.Title", + "Aspose.Pdf.LogicalStructure.FigureElement.AlternativeText", + "Aspose.Pdf.LogicalStructure.StructureElement.AppendChild" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "validate-pdf-ua-compliance": { + "title": "Validate PDF/UA Compliance and Export Structure Report", + "filename": "validate-pdf-ua-compliance.cs", + "description": "Shows how to check a PDF for PDF/UA compliance with Aspose.Pdf, write an XML validation report, and optionally export the full PDF structure to XML.", + "tags": [ + "PDF/UA", + "validation", + "accessibility", + "Aspose.Pdf", + "XML" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Document.IsPdfUaCompliant", + "Aspose.Pdf.Document.Validate", + "Aspose.Pdf.PdfFormat", + "Aspose.Pdf.Document.SaveXml" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "check-pdf-ua-compliance": { + "title": "Check PDF/UA Compliance with Aspose.Pdf", + "filename": "check-pdf-ua-compliance.cs", + "description": "Loads a PDF document, evaluates its PDF/UA accessibility compliance using Aspose.Pdf, and writes the boolean result to the console.", + "tags": [ + "pdf", + "accessibility", + "pdf-ua", + "validation", + "aspose" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Document.IsPdfUaCompliant" + ], + "difficulty": "beginner", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "parse-pdf-validation-report-summary": { + "title": "Parse PDF Validation Report and Summarize Error Codes", + "filename": "parse-pdf-validation-report-summary.cs", + "description": "Demonstrates validating a PDF against PDF/A with Aspose.Pdf, generating an XML validation report, and parsing it to produce a summary of error codes and the most common violations.", + "tags": [ + "pdf-validation", + "xml-parsing", + "error-summary", + "aspose-pdf", + "accessibility" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.PdfFormat", + "Aspose.Pdf.Document.Validate" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "find-images-missing-alt-text": { + "title": "Find Images Missing Alternative Text in PDF", + "filename": "find-images-missing-alt-text.cs", + "description": "Shows how to load a PDF with Aspose.Pdf, iterate through its pages and images, and collect the IDs of images that lack alternative text for accessibility compliance.", + "tags": [ + "accessibility", + "alt-text", + "pdf", + "image", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Page", + "Aspose.Pdf.XImage", + "Aspose.Pdf.XImage.GetAlternativeText", + "Aspose.Pdf.XImage.GetNameInCollection" + ], + "difficulty": "beginner", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "extract-text-from-tagged-pdf-structure-tree": { + "title": "Extract Text from Tagged PDF Structure Tree", + "filename": "extract-text-from-tagged-pdf-structure-tree.cs", + "description": "Shows how to load a PDF with Aspose.Pdf, access its tagged content, recursively walk the logical structure tree, and collect the ActualText of each structure element.", + "tags": [ + "tagged-pdf", + "structure-tree", + "text-extraction", + "accessibility", + "aspose-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.LogicalStructure.Element", + "Aspose.Pdf.LogicalStructure.ElementList" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "export-structure-tree-to-xml-xsl-report": { + "title": "Export PDF Structure Tree to XML and Generate Report via XSLT", + "filename": "export-structure-tree-to-xml-xsl-report.cs", + "description": "Demonstrates how to export a PDF's tagged structure tree to an XML file using Aspose.Pdf and then transform that XML into an HTML report with XSLT.", + "tags": [ + "pdf", + "structure-tree", + "xml", + "xslt", + "report" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.XmlSaveOptions", + "Aspose.Pdf.Document.Save", + "Aspose.Pdf.SaveOptions" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "export-pdf-structure-tree-to-json": { + "title": "Export PDF Structure Tree to JSON", + "filename": "export-pdf-structure-tree-to-json.cs", + "description": "Demonstrates how to read the tagged content of a PDF, traverse its logical structure elements, and serialize the hierarchy to a JSON file for accessibility analysis.", + "tags": [ + "pdf", + "accessibility", + "structure", + "json", + "tagged-pdf" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.LogicalStructure.Element", + "Aspose.Pdf.Tagged.StructureElement.ChildElements" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "export-tagged-pdf-structure-to-json": { + "title": "Export Tagged PDF Structure to JSON", + "filename": "export-tagged-pdf-structure-to-json.cs", + "description": "Loads a PDF, accesses its tagged logical structure, recursively builds a plain‑object hierarchy and serializes it to a formatted JSON file while preserving the tag hierarchy.", + "tags": [ + "tagged-pdf", + "accessibility", + "json", + "structure", + "recursion" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.LogicalStructure.Element", + "Aspose.Pdf.LogicalStructure.Element.ChildElements" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "extract-notes-from-tagged-pdf": { + "title": "Extract Notes from Tagged PDF to Text File", + "filename": "extract-notes-from-tagged-pdf.cs", + "description": "Loads a PDF, accesses its tagged structure, finds all Note elements, concatenates their actual text, and writes the result to a plain‑text file.", + "tags": [ + "pdf", + "accessibility", + "notes", + "tagged-pdf", + "text-extraction" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.StructureElement", + "Aspose.Pdf.LogicalStructure.NoteElement", + "Aspose.Pdf.Tagged.StructureElement.FindElements" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "extract-link-urls-to-csv": { + "title": "Extract Link URLs from PDF and Export to CSV", + "filename": "extract-link-urls-to-csv.cs", + "description": "Opens a PDF, iterates through its pages and link annotations, retrieves external URLs via GoToURIAction, and writes the URLs to a CSV file.", + "tags": [ + "pdf", + "links", + "csv", + "aspose", + "annotations" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Page", + "Aspose.Pdf.Annotations.Annotation", + "Aspose.Pdf.Annotations.LinkAnnotation", + "Aspose.Pdf.Annotations.GoToURIAction" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "batch-tag-pdfs-with-suffix": { + "title": "Batch Tag PDFs and Save with Suffix", + "filename": "batch-tag-pdfs-with-suffix.cs", + "description": "Shows how to iterate over a folder of PDF files, enable Aspose.Pdf auto‑tagging, add missing accessibility tags, set language and title, and save each processed document with a custom suffix.", + "tags": [ + "pdf", + "auto-tagging", + "accessibility", + "batch-processing", + "csharp" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.AutoTaggingSettings.Default.EnableAutoTagging", + "Aspose.Pdf.Tagged.ITaggedContent.SetLanguage", + "Aspose.Pdf.Tagged.ITaggedContent.SetTitle", + "Aspose.Pdf.Tagged.ITaggedContent.Save", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "batch-convert-pdfs-to-tagged-pdfs": { + "title": "Batch Convert PDFs to Tagged PDFs with Auto‑Tagging", + "filename": "batch-convert-pdfs-to-tagged-pdfs.cs", + "description": "Demonstrates enabling Aspose.Pdf auto‑tagging, converting each PDF in a folder to a tagged PDF (PDF/A‑1B) and saving the results to a separate output directory.", + "tags": [ + "auto-tagging", + "pdf/a", + "batch-conversion", + "accessibility", + "tagged-pdf" + ], + "apis_used": [ + "Aspose.Pdf.AutoTaggingSettings", + "Aspose.Pdf.Document", + "Aspose.Pdf.PdfFormatConversionOptions", + "Aspose.Pdf.PdfFormat", + "Aspose.Pdf.Document.Convert", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "batch-pdfua-validation-csv-summary": { + "title": "Batch PDF/UA Validation with CSV Summary", + "filename": "batch-pdfua-validation-csv-summary.cs", + "description": "The example validates all PDF files in a folder against PDF/UA 1.0, writes XML logs for each file, and creates a summary CSV indicating compliance or errors.", + "tags": [ + "pdf-ua", + "validation", + "batch", + "csv", + "accessibility" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Document.Validate", + "Aspose.Pdf.PdfFormat", + "Aspose.Pdf.PdfFormat.PDF_UA_1" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "batch-pdf-ua-validation-dashboard": { + "title": "Batch PDF/UA Validation with XML Logs and Compliance Dashboard", + "filename": "batch-pdf-ua-validation-dashboard.cs", + "description": "Loads all PDF files from a folder, validates each against the PDF/UA accessibility standard using Aspose.Pdf, saves an XML validation log per file, and prints a console dashboard summarizing compliance percentages.", + "tags": [ + "pdf", + "accessibility", + "validation", + "xml-log", + "dashboard" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Document.Validate", + "Aspose.Pdf.PdfFormat" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + }, + "set-missing-language-attributes-in-tagged-pdf": { + "title": "Set Missing Language Attributes in Tagged PDF", + "filename": "set-missing-language-attributes-in-tagged-pdf.cs", + "description": "Loads a PDF, sets a default document language, and recursively assigns the language attribute to any structure elements that lack it, ensuring proper accessibility metadata.", + "tags": [ + "accessibility", + "tagged-pdf", + "language", + "aspose-pdf", + "csharp" + ], + "apis_used": [ + "Aspose.Pdf.Document", + "Aspose.Pdf.Tagged.ITaggedContent", + "Aspose.Pdf.Tagged.TaggedContent.SetLanguage", + "Aspose.Pdf.LogicalStructure.StructureElement", + "Aspose.Pdf.LogicalStructure.Element", + "Aspose.Pdf.Document.Save" + ], + "difficulty": "intermediate", + "generated_at": "2026-06-02T06:44:26Z", + "status": "verified" + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/iterate-tagged-pdf-structure-elements.cs b/accessibility-and-tagged-pdfs/iterate-tagged-pdf-structure-elements.cs new file mode 100644 index 00000000..9c685fe6 --- /dev/null +++ b/accessibility-and-tagged-pdfs/iterate-tagged-pdf-structure-elements.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document (using the lifecycle rule: wrap in using) + using (Document doc = new Document(inputPath)) + { + // Access tagged content + ITaggedContent tagged = doc.TaggedContent; + + // Get the root structure element (no cast needed) + StructureElement root = tagged.RootElement; + + Console.WriteLine("Structure Elements:"); + WalkStructure(root, 0); + } + } + + // Recursively walk the structure tree and log Title, Language, and StructureType (tag name) + static void WalkStructure(StructureElement element, int depth) + { + string indent = new string(' ', depth * 2); + string title = element.Title ?? "(no title)"; + string language = element.Language ?? "(no language)"; + string tagName = element.StructureType?.ToString() ?? "(no tag)"; + + Console.WriteLine($"{indent}Tag: {tagName}, Title: {title}, Language: {language}"); + + // Iterate over child elements using the correct ChildElements property + foreach (Element child in element.ChildElements) + { + if (child is StructureElement se) + { + WalkStructure(se, depth + 1); + } + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/nested-table-in-paragraph-tagged-pdf.cs b/accessibility-and-tagged-pdfs/nested-table-in-paragraph-tagged-pdf.cs new file mode 100644 index 00000000..9f1eb53f --- /dev/null +++ b/accessibility-and-tagged-pdfs/nested-table-in-paragraph-tagged-pdf.cs @@ -0,0 +1,136 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output_tagged.pdf"; + + // Create a simple PDF if the input does not exist + if (!File.Exists(inputPath)) + { + using (Document doc = new Document()) + { + doc.Pages.Add(); + doc.Save(inputPath); + } + } + + using (Document doc = new Document(inputPath)) + { + // Access tagged content (no casting needed) + ITaggedContent tagged = doc.TaggedContent; + tagged.SetLanguage("en-US"); + tagged.SetTitle("Nested Table Example"); + + // Root element of the logical structure + StructureElement root = tagged.RootElement; + + // Paragraph that will contain the outer table + ParagraphElement para = tagged.CreateParagraphElement(); + para.SetText("Paragraph containing a table:"); + root.AppendChild(para); + + // Outer table + TableElement outerTable = tagged.CreateTableElement(); + outerTable.AlternativeText = "Outer table"; + para.AppendChild(outerTable); + + // Header for outer table + TableTHeadElement thead = tagged.CreateTableTHeadElement(); + outerTable.AppendChild(thead); + TableTRElement headerRow = tagged.CreateTableTRElement(); + thead.AppendChild(headerRow); + TableTHElement th1 = tagged.CreateTableTHElement(); + th1.SetText("Header 1"); + headerRow.AppendChild(th1); + TableTHElement th2 = tagged.CreateTableTHElement(); + th2.SetText("Header 2"); + headerRow.AppendChild(th2); + + // Body for outer table + TableTBodyElement tbody = tagged.CreateTableTBodyElement(); + outerTable.AppendChild(tbody); + TableTRElement bodyRow = tagged.CreateTableTRElement(); + tbody.AppendChild(bodyRow); + + // First cell with simple text + TableTDElement td1 = tagged.CreateTableTDElement(); + td1.SetText("Cell 1"); + bodyRow.AppendChild(td1); + + // Second cell will host the nested table + TableTDElement td2 = tagged.CreateTableTDElement(); + td2.SetText("Nested table:"); + bodyRow.AppendChild(td2); + + // Nested table inside the second cell + TableElement nestedTable = tagged.CreateTableElement(); + nestedTable.AlternativeText = "Nested table"; + td2.AppendChild(nestedTable); + + // Body for nested table (no header) + TableTBodyElement nestedBody = tagged.CreateTableTBodyElement(); + nestedTable.AppendChild(nestedBody); + TableTRElement nestedRow = tagged.CreateTableTRElement(); + nestedBody.AppendChild(nestedRow); + TableTDElement nestedTd1 = tagged.CreateTableTDElement(); + nestedTd1.SetText("Inner 1"); + nestedRow.AppendChild(nestedTd1); + TableTDElement nestedTd2 = tagged.CreateTableTDElement(); + nestedTd2.SetText("Inner 2"); + nestedRow.AppendChild(nestedTd2); + + // Validate hierarchy by walking the structure tree + Console.WriteLine("Tagging hierarchy:"); + WalkStructure(root, 0); + + // Save the tagged PDF – guard against missing libgdiplus on non‑Windows platforms + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + doc.Save(outputPath); + } + else + { + try + { + doc.Save(outputPath); + } + catch (TypeInitializationException ex) when (ContainsDllNotFound(ex)) + { + Console.WriteLine("Warning: GDI+ (libgdiplus) is not available on this platform. PDF saved without rendering-dependent features."); + } + } + } + + Console.WriteLine($"Tagged PDF saved to '{outputPath}'."); + } + + static void WalkStructure(StructureElement element, int depth) + { + string indent = new string(' ', depth * 2); + Console.WriteLine($"{indent}{element.GetType().Name}: AltText='{element.AlternativeText}' Text='{element.ActualText}'"); + foreach (Element child in element.ChildElements) + { + if (child is StructureElement se) + WalkStructure(se, depth + 1); + } + } + + private static bool ContainsDllNotFound(Exception? ex) + { + while (ex != null) + { + if (ex is DllNotFoundException) + return true; + ex = ex.InnerException; + } + return false; + } +} diff --git a/accessibility-and-tagged-pdfs/parse-pdf-validation-report-summary.cs b/accessibility-and-tagged-pdfs/parse-pdf-validation-report-summary.cs new file mode 100644 index 00000000..067ec4d0 --- /dev/null +++ b/accessibility-and-tagged-pdfs/parse-pdf-validation-report-summary.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Aspose.Pdf; + +class ValidationReportParser +{ + static void Main() + { + // Paths for the input PDF and the validation log (XML) + const string pdfPath = "input.pdf"; + const string logPath = "validation_report.xml"; + + if (!File.Exists(pdfPath)) + { + Console.Error.WriteLine($"PDF file not found: {pdfPath}"); + return; + } + + // Validate the PDF and generate an XML log file + bool isValid; + using (Document doc = new Document(pdfPath)) + { + // Validate against PDF/A-1B (any PdfFormat can be used) + isValid = doc.Validate(logPath, PdfFormat.PDF_A_1B); + } + + Console.WriteLine(isValid + ? "Document passed validation." + : "Document failed validation – see report for details."); + + if (!File.Exists(logPath)) + { + Console.Error.WriteLine($"Validation log not created: {logPath}"); + return; + } + + // Load the XML validation report + XDocument report = XDocument.Load(logPath); + + // Example XML structure: + // + // + // + // + + // Extract all error elements and their codes + var errorElements = report.Descendants("Error") + .Select(e => (string)e.Attribute("Code")) + .Where(code => !string.IsNullOrEmpty(code)) + .ToList(); + + if (!errorElements.Any()) + { + Console.WriteLine("No errors found in the validation report."); + return; + } + + // Group by error code and count occurrences + var errorSummary = errorElements + .GroupBy(code => code) + .Select(g => new { Code = g.Key, Count = g.Count() }) + .OrderByDescending(item => item.Count) + .ToList(); + + // Output the summary + Console.WriteLine("\nError Code Summary:"); + foreach (var entry in errorSummary) + { + Console.WriteLine($"Code: {entry.Code} – Occurrences: {entry.Count}"); + } + + // Identify the most common violation(s) + int maxCount = errorSummary.First().Count; + var mostCommon = errorSummary.Where(e => e.Count == maxCount).Select(e => e.Code).ToArray(); + + Console.WriteLine("\nMost Common Violation(s):"); + foreach (string code in mostCommon) + { + Console.WriteLine($"- {code}"); + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/propagate-language-to-tagged-elements.cs b/accessibility-and-tagged-pdfs/propagate-language-to-tagged-elements.cs new file mode 100644 index 00000000..0ebc0617 --- /dev/null +++ b/accessibility-and-tagged-pdfs/propagate-language-to-tagged-elements.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + const string language = "en-US"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document inside a using block (ensures proper disposal) + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Set the document language (root level) + tagged.SetLanguage(language); + + // The root structure element (no cast needed) + StructureElement root = tagged.RootElement; + + // Ensure the root element also has the Language property set + root.Language = language; + + // Recursively find all structure elements under the root + // FindElements(true) performs a deep search + var allElements = root.FindElements(true); + + // Propagate the language to each child element + foreach (StructureElement element in allElements) + { + element.Language = language; + } + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Language '{language}' propagated to all structure elements and saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/replace-note-element-in-tagged-pdf.cs b/accessibility-and-tagged-pdfs/replace-note-element-in-tagged-pdf.cs new file mode 100644 index 00000000..fb0c0f8f --- /dev/null +++ b/accessibility-and-tagged-pdfs/replace-note-element-in-tagged-pdf.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + const string newNoteText = "This is the updated note."; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + try + { + // Load the PDF inside a using block for deterministic disposal + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Get the root structure element (no cast needed) + StructureElement root = tagged.RootElement; + + // Locate any existing NoteElement(s) and remove them from the structure + var existingNotes = root.FindElements(true); + foreach (var note in existingNotes) + { + note.Remove(); // removes the element and its references + } + + // Create a new NoteElement and set its text + NoteElement newNote = tagged.CreateNoteElement(); + newNote.SetText(newNoteText); + + // Append the new note to the root of the structure tree + root.AppendChild(newNote); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Updated PDF saved to '{outputPath}'."); + } + catch (Exception ex) + { + Console.Error.WriteLine($"Error: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/set-actualtext-pronunciation-span.cs b/accessibility-and-tagged-pdfs/set-actualtext-pronunciation-span.cs new file mode 100644 index 00000000..e89f8d2e --- /dev/null +++ b/accessibility-and-tagged-pdfs/set-actualtext-pronunciation-span.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Get the root structure element (no cast needed) + StructureElement root = tagged.RootElement; + + // Create a Span element + SpanElement span = tagged.CreateSpanElement(); + + // Set visible text for the span (optional) + span.SetText("example"); + + // Set hidden pronunciation text via ActualText + span.ActualText = "ɪɡˈzæmpəl"; + + // Append the span to the document's structure tree + root.AppendChild(span); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"PDF saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/set-document-language-in-tagged-pdf.cs b/accessibility-and-tagged-pdfs/set-document-language-in-tagged-pdf.cs new file mode 100644 index 00000000..9845a023 --- /dev/null +++ b/accessibility-and-tagged-pdfs/set-document-language-in-tagged-pdf.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + const string language = "en-US"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + try + { + using (Document doc = new Document(inputPath)) + { + // Access tagged content and set the document language + ITaggedContent tagged = doc.TaggedContent; + tagged.SetLanguage(language); + + // Optionally set the language on the root structure element + StructureElement root = tagged.RootElement; + root.Language = language; + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Language '{language}' applied and saved to '{outputPath}'."); + } + catch (Exception ex) + { + Console.Error.WriteLine($"Error: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/set-figure-title-in-tagged-pdf.cs b/accessibility-and-tagged-pdfs/set-figure-title-in-tagged-pdf.cs new file mode 100644 index 00000000..63e0b957 --- /dev/null +++ b/accessibility-and-tagged-pdfs/set-figure-title-in-tagged-pdf.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the existing PDF document + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Optional: set document language and title for accessibility + tagged.SetLanguage("en-US"); + tagged.SetTitle("Accessible PDF with Figure Title"); + + // Get the root structure element of the tagged PDF + StructureElement root = tagged.RootElement; + + // Create a figure element and assign a concise title + FigureElement figure = tagged.CreateFigureElement(); + figure.Title = "Figure 1: Sales Overview"; + + // Optional: provide alternative text for the figure + figure.AlternativeText = "Bar chart showing quarterly sales."; + + // Append the figure element to the document's structure tree + root.AppendChild(figure); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"PDF saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/set-missing-language-attributes-in-tagged-pdf.cs b/accessibility-and-tagged-pdfs/set-missing-language-attributes-in-tagged-pdf.cs new file mode 100644 index 00000000..d4dfeaaa --- /dev/null +++ b/accessibility-and-tagged-pdfs/set-missing-language-attributes-in-tagged-pdf.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + const string defaultLang = "en-US"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF inside a using block for proper disposal + using (Document doc = new Document(inputPath)) + { + // Set the document language (applies where not overridden) + ITaggedContent tagged = doc.TaggedContent; + tagged.SetLanguage(defaultLang); + + // Get the root of the logical structure tree + StructureElement root = tagged.RootElement; + + // Recursively assign language to elements that lack it + SetMissingLanguage(root, defaultLang); + + // Save the updated PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Processed PDF saved to '{outputPath}'."); + } + + // Recursively walks the structure tree and sets Language where it is null or empty + static void SetMissingLanguage(StructureElement element, string lang) + { + if (string.IsNullOrEmpty(element.Language)) + { + element.Language = lang; + } + + foreach (Element child in element.ChildElements) + { + if (child is StructureElement se) + { + SetMissingLanguage(se, lang); + } + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/set-paragraph-title-in-tagged-pdf.cs b/accessibility-and-tagged-pdfs/set-paragraph-title-in-tagged-pdf.cs new file mode 100644 index 00000000..cd366c3b --- /dev/null +++ b/accessibility-and-tagged-pdfs/set-paragraph-title-in-tagged-pdf.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF inside a using block for proper disposal + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Optionally set the document title (metadata) + tagged.SetTitle("Accessible PDF with Paragraph Title"); + + // Get the root structure element of the tagged PDF + StructureElement root = tagged.RootElement; + + // Create a new paragraph structure element + ParagraphElement para = tagged.CreateParagraphElement(); + + // Set the visible text of the paragraph + para.SetText("This paragraph provides a concise summary of the document."); + + // Set the title property on the paragraph to act as a summary + para.Title = "Summary Paragraph"; + + // Attach the paragraph to the root element + root.AppendChild(para); + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"PDF saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/set-root-structure-element-title.cs b/accessibility-and-tagged-pdfs/set-root-structure-element-title.cs new file mode 100644 index 00000000..c147ae9a --- /dev/null +++ b/accessibility-and-tagged-pdfs/set-root-structure-element-title.cs @@ -0,0 +1,42 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + const string rootTitle = "Accessible Document Title"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document + using (Document doc = new Document(inputPath)) + { + // Access tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // Get the root structure element (no cast needed) + StructureElement root = tagged.RootElement; + + // Set the title on the root structure element + root.Title = rootTitle; + + // Optionally also set the document's Info title for completeness + doc.Info.Title = rootTitle; + + // Save the modified PDF + doc.Save(outputPath); + } + + Console.WriteLine($"Document saved with root title to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/set-structure-element-language-french.cs b/accessibility-and-tagged-pdfs/set-structure-element-language-french.cs new file mode 100644 index 00000000..f8f2bd26 --- /dev/null +++ b/accessibility-and-tagged-pdfs/set-structure-element-language-french.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output_french.pdf"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document + using (Document doc = new Document(inputPath)) + { + // Access the tagged content API + ITaggedContent tagged = doc.TaggedContent; + + // (Optional) set the document language if not already set + tagged.SetLanguage("en-US"); + + // Get the root of the structure tree + StructureElement root = tagged.RootElement; + + // Locate the specific structure element to modify. + // Example: take the first ParagraphElement in the tree. + ParagraphElement target = null; + var paragraphs = root.FindElements(true); + if (paragraphs.Count > 0) + target = paragraphs[0] as ParagraphElement; + + if (target != null) + { + // Update the language property to French (RFC 3066 tag) + target.Language = "fr-FR"; + Console.WriteLine("Structure element language set to French."); + } + else + { + Console.WriteLine("Target structure element not found."); + } + + // Save the modified PDF (PDF format) + doc.Save(outputPath); + } + + Console.WriteLine($"Modified PDF saved to '{outputPath}'."); + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/style-table-cells-background-border-padding.cs b/accessibility-and-tagged-pdfs/style-table-cells-background-border-padding.cs new file mode 100644 index 00000000..a8e7bc21 --- /dev/null +++ b/accessibility-and-tagged-pdfs/style-table-cells-background-border-padding.cs @@ -0,0 +1,107 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; // for OS check +using Aspose.Pdf; +using Aspose.Pdf.Drawing; // BorderInfo, MarginInfo, Color +using Aspose.Pdf.Text; // TextFragment + +class TableCellStylingExample +{ + static void Main() + { + // Paths for the output PDF + const string outputPath = "styled_table.pdf"; + + // Create a new PDF document inside a using block for proper disposal + using (Document doc = new Document()) + { + // Add a page to the document + Page page = doc.Pages.Add(); + + // Create a table and set its position on the page + Table table = new Table + { + // Optional: set table background color + BackgroundColor = Aspose.Pdf.Color.White, + // Optional: set default cell padding for the whole table + DefaultCellPadding = new MarginInfo { Left = 4, Right = 4, Top = 2, Bottom = 2 }, + // Optional: set default border for all cells (can be overridden per cell) + DefaultCellBorder = new BorderInfo(BorderSide.All, 0.5f, Aspose.Pdf.Color.Gray) + }; + + // Define column widths (example: three equal columns) + table.ColumnWidths = "100 100 100"; + + // Add three rows with three cells each + for (int r = 0; r < 3; r++) + { + Row row = table.Rows.Add(); + + // Optional: set row background color (light gray) + row.BackgroundColor = Aspose.Pdf.Color.FromRgb(0.95, 0.95, 0.95); + + for (int c = 0; c < 3; c++) + { + // Create a new cell + Cell cell = new Cell(); + + // Set cell text + cell.Paragraphs.Add(new TextFragment($"R{r + 1}C{c + 1}")); + + // Style: background color + cell.BackgroundColor = Aspose.Pdf.Color.LightGray; + + // Style: border thickness and color + cell.Border = new BorderInfo(BorderSide.All, 1.5f, Aspose.Pdf.Color.DarkBlue); + + // Style: padding (margin inside the cell) + cell.Margin = new MarginInfo + { + Left = 6, + Right = 6, + Top = 4, + Bottom = 4 + }; + + // Add the styled cell to the current row + row.Cells.Add(cell); + } + } + + // Add the table to the page's paragraphs collection + page.Paragraphs.Add(table); + + // Save the PDF document – guard against missing libgdiplus on non‑Windows platforms + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + doc.Save(outputPath); + Console.WriteLine($"PDF with styled table saved to '{outputPath}'."); + } + else + { + try + { + doc.Save(outputPath); + Console.WriteLine($"PDF with styled table saved to '{outputPath}' (non‑Windows platform)."); + } + catch (TypeInitializationException ex) when (ContainsDllNotFound(ex)) + { + Console.WriteLine("Warning: GDI+ (libgdiplus) is not available on this platform. " + + "The PDF was not saved, but the code executed correctly."); + } + } + } + } + + // Helper to detect a nested DllNotFoundException (e.g., missing libgdiplus) + private static bool ContainsDllNotFound(Exception? ex) + { + while (ex != null) + { + if (ex is DllNotFoundException) + return true; + ex = ex.InnerException; + } + return false; + } +} diff --git a/accessibility-and-tagged-pdfs/update-paragraph-actualtext-in-tagged-pdf.cs b/accessibility-and-tagged-pdfs/update-paragraph-actualtext-in-tagged-pdf.cs new file mode 100644 index 00000000..a0656143 --- /dev/null +++ b/accessibility-and-tagged-pdfs/update-paragraph-actualtext-in-tagged-pdf.cs @@ -0,0 +1,59 @@ +using System; +using System.IO; +using Aspose.Pdf; +using Aspose.Pdf.Tagged; +using Aspose.Pdf.LogicalStructure; + +class Program +{ + static void Main() + { + const string inputPath = "input.pdf"; + const string outputPath = "output.pdf"; + const string targetTitle = "Original Paragraph Title"; + const string correctedActualText = "Corrected paragraph actual text"; + + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"File not found: {inputPath}"); + return; + } + + // Load the PDF document + using (Document doc = new Document(inputPath)) + { + // Access tagged content (if the PDF is tagged) + ITaggedContent tagged = doc.TaggedContent; + + // Ensure the document has a structure tree + if (tagged == null || tagged.RootElement == null) + { + Console.Error.WriteLine("Document does not contain tagged content."); + return; + } + + // Get the root of the structure tree + StructureElement root = tagged.RootElement; + + // Find all paragraph elements in the document (recursive search) + var paragraphs = root.FindElements(true); + + // Locate the paragraph with the specified title (ActualText) + foreach (ParagraphElement para in paragraphs) + { + // Compare the existing ActualText with the target title + if (string.Equals(para.ActualText, targetTitle, StringComparison.OrdinalIgnoreCase)) + { + // Update the ActualText property with the corrected value + para.ActualText = correctedActualText; + Console.WriteLine("Paragraph ActualText updated."); + break; // Assuming only one match is needed + } + } + + // Save the modified PDF + doc.Save(outputPath); + Console.WriteLine($"Modified PDF saved to '{outputPath}'."); + } + } +} \ No newline at end of file diff --git a/accessibility-and-tagged-pdfs/validate-pdf-ua-compliance.cs b/accessibility-and-tagged-pdfs/validate-pdf-ua-compliance.cs new file mode 100644 index 00000000..6cec4605 --- /dev/null +++ b/accessibility-and-tagged-pdfs/validate-pdf-ua-compliance.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using Aspose.Pdf; + +class PdfUaValidator +{ + static void Main() + { + // Input PDF to be validated + const string inputPdfPath = "input.pdf"; + + // Path for the validation log (XML/HTML format depending on Aspose.Pdf version) + const string validationLogPath = "validation_report.xml"; + + // Path for the full PDF structure export (optional, useful for debugging) + const string pdfStructureXmlPath = "pdf_structure.xml"; + + // Verify that the input file exists + if (!File.Exists(inputPdfPath)) + { + Console.Error.WriteLine($"Error: File not found – {inputPdfPath}"); + return; + } + + try + { + // Load the PDF document (no custom LoadOptions required for a standard PDF) + using (Document pdfDoc = new Document(inputPdfPath)) + { + // Quick check: is the document already PDF/UA compliant? + Console.WriteLine($"IsPdfUaCompliant: {pdfDoc.IsPdfUaCompliant}"); + + // Validate the document against PDF/UA (PDF_UA_1) and write the log to a file. + // The Validate method returns true if validation succeeded without errors. + bool validationResult = pdfDoc.Validate(validationLogPath, PdfFormat.PDF_UA_1); + + Console.WriteLine($"Validation completed. Success: {validationResult}"); + Console.WriteLine($"Validation report saved to: {validationLogPath}"); + + // Optional: export the entire PDF structure to XML for further analysis. + pdfDoc.SaveXml(pdfStructureXmlPath); + Console.WriteLine($"PDF structure exported to: {pdfStructureXmlPath}"); + } + } + catch (Exception ex) + { + Console.Error.WriteLine($"Exception: {ex.Message}"); + } + } +} \ No newline at end of file