-
Notifications
You must be signed in to change notification settings - Fork 106
[US-1113] Add document tagging code examples #292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
845c0fb
tagging link annot
3ace 373677a
add list tagging example
3ace 92a7f00
tagging annotations example
3ace ebbea50
tag form example
3ace 0b905f0
tag grid example
3ace a314e9e
tag table example
3ace 734d910
update README file
3ace 567273d
improves code
3ace 6d3b0d5
fix compile error
3ace File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| // This example demonstrates how to create a PDF with text annotations | ||
| // using the UniPDF library. The PDF will contain multiple text annotations | ||
| // with different properties, and the annotations will be properly tagged | ||
| // in the document structure tree for accessibility compliance. | ||
| // | ||
|
|
||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
|
|
||
| "github.com/unidoc/unipdf/v4/common/license" | ||
| "github.com/unidoc/unipdf/v4/core" | ||
| "github.com/unidoc/unipdf/v4/creator" | ||
| "github.com/unidoc/unipdf/v4/model" | ||
| ) | ||
|
|
||
| func init() { | ||
| // Make sure to load your metered License API key prior to using the library. | ||
| // If you need a key, you can sign up and create a free one at https://cloud.unidoc.io | ||
| err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`)) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
| } | ||
|
|
||
| func main() { | ||
| outputPath := "pdf_tag_annots.pdf" | ||
|
|
||
| err := createPdfWithTextAnnotations(outputPath) | ||
| if err != nil { | ||
| fmt.Printf("Error: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| fmt.Printf("Complete, see output file: %s\n", outputPath) | ||
| } | ||
|
|
||
| // Create a new PDF with text annotations. | ||
| func createPdfWithTextAnnotations(outputPath string) error { | ||
| // Create a new Creator. | ||
| c := creator.New() | ||
|
|
||
| // Construct the StructTreeRoot. | ||
| str := model.NewStructTreeRoot() | ||
|
|
||
| // Construct base K dictionary. | ||
| docK := model.NewKDictionary() | ||
| docK.S = core.MakeName(string(model.StructureTypeDocument)) | ||
|
|
||
| str.AddKDict(docK) | ||
|
|
||
| // Create a new page with standard letter size. | ||
| page := model.NewPdfPage() | ||
| mediaBox := core.MakeArrayFromFloats([]float64{0, 0, 612, 792}) | ||
| mediaRect, err := model.NewPdfRectangle(*mediaBox) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create MediaBox rectangle: %w", err) | ||
| } | ||
| page.MediaBox = mediaRect | ||
|
|
||
| // Add first text annotation. | ||
| textAnnotation1 := model.NewPdfAnnotationText() | ||
| textAnnotation1.Contents = core.MakeString("This is a sample text annotation!") | ||
| textAnnotation1.Rect = core.MakeArray( | ||
| core.MakeInteger(100), // x1 | ||
| core.MakeInteger(600), // y1 (from bottom of page) | ||
| core.MakeInteger(150), // x2 (x1 + width) | ||
| core.MakeInteger(650), // y2 (y1 + height) | ||
| ) | ||
| // Set annotation properties. | ||
| textAnnotation1.Open = core.MakeBool(false) // Closed by default | ||
| textAnnotation1.Name = core.MakeName("Comment") | ||
|
|
||
| docK.AddKChild(textAnnotation1.GenerateKDict()) | ||
|
|
||
| // Add second text annotation. | ||
| textAnnotation2 := model.NewPdfAnnotationText() | ||
| textAnnotation2.Contents = core.MakeString("Another annotation with more detailed information about this section.") | ||
| textAnnotation2.Rect = core.MakeArray( | ||
| core.MakeInteger(300), // x1 | ||
| core.MakeInteger(550), // y1 | ||
| core.MakeInteger(350), // x2 | ||
| core.MakeInteger(600), // y2 | ||
| ) | ||
| textAnnotation2.Open = core.MakeBool(true) // Open by default | ||
| textAnnotation2.Name = core.MakeName("Note") | ||
|
|
||
| docK.AddKChild(textAnnotation2.GenerateKDict()) | ||
|
|
||
| // Add third text annotation. | ||
| textAnnotation3 := model.NewPdfAnnotationText() | ||
| textAnnotation3.Contents = core.MakeString("You can click on these yellow icons to view the annotation content.") | ||
| textAnnotation3.Rect = core.MakeArray( | ||
| core.MakeInteger(450), // x1 | ||
| core.MakeInteger(400), // y1 | ||
| core.MakeInteger(500), // x2 | ||
| core.MakeInteger(450), // y2 | ||
| ) | ||
| textAnnotation3.Open = core.MakeBool(false) | ||
| textAnnotation3.Name = core.MakeName("Help") | ||
|
|
||
| docK.AddKChild(textAnnotation3.GenerateKDict()) | ||
|
|
||
| // Add annotations to the page. | ||
| page.AddAnnotation(textAnnotation1.PdfAnnotation) | ||
| page.AddAnnotation(textAnnotation2.PdfAnnotation) | ||
| page.AddAnnotation(textAnnotation3.PdfAnnotation) | ||
|
|
||
| // Add StructTreeRoot to the page. | ||
| c.SetStructTreeRoot(str) | ||
|
|
||
| // Add the page to the writer. | ||
| err = c.AddPage(page) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Write the PDF to file. | ||
| err = c.WriteToFile(outputPath) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,190 @@ | ||
| // This example demonstrates how to create a PDF with form fields | ||
| // using the UniPDF library. The PDF will contain multiple text fields | ||
| // along with submit and reset buttons, and the form fields will be | ||
| // properly tagged in the document structure tree for accessibility compliance. | ||
| // | ||
| // The example covers best practices for PDF/UA compliance: | ||
| // 1. Each form field has an associated label with a tooltip. | ||
| // 2. The document structure tree is constructed with K dictionaries | ||
| // to represent the hierarchical structure of the form elements. | ||
| // 3. Each label is associated with its corresponding form field using | ||
| // marked content IDs (MCID). | ||
| // 4. The submit button is configured to submit the form data to a specified URL. | ||
| // 5. The reset button is configured to reset the specified fields to their default values. | ||
|
|
||
| package main | ||
|
|
||
| import ( | ||
| "log" | ||
| "os" | ||
|
|
||
| "github.com/unidoc/unipdf/v4/annotator" | ||
| "github.com/unidoc/unipdf/v4/common/license" | ||
| "github.com/unidoc/unipdf/v4/contentstream/draw" | ||
| "github.com/unidoc/unipdf/v4/core" | ||
| "github.com/unidoc/unipdf/v4/creator" | ||
| "github.com/unidoc/unipdf/v4/model" | ||
| ) | ||
|
|
||
| func init() { | ||
| // Make sure to load your metered License API key prior to using the library. | ||
| // If you need a key, you can sign up and create a free one at https://cloud.unidoc.io | ||
| err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`)) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
| } | ||
|
|
||
| func main() { | ||
| textFieldsDef := []struct { | ||
| Label string | ||
| Name string | ||
| Rect []float64 | ||
| Tooltip string | ||
| }{ | ||
| {Label: "Full Name", Name: "full_name", Rect: []float64{123.97, 619.02, 343.99, 633.6}, Tooltip: "Enter your full name"}, | ||
| {Label: "Address 1", Name: "address_line_1", Rect: []float64{123.97, 596.82, 343.99, 611.4}, Tooltip: "Enter your primary address"}, | ||
| {Label: "Address 2", Name: "address_line_2", Rect: []float64{123.97, 574.28, 343.99, 588.86}, Tooltip: "Enter your secondary address (optional)"}, | ||
| } | ||
|
|
||
| c := creator.New() | ||
| page := c.NewPage() | ||
| _, pageHeight, err := page.Size() | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| // Construct the StructTreeRoot. | ||
| str := model.NewStructTreeRoot() | ||
|
|
||
| // Construct base K dictionary. | ||
| docK := model.NewKDictionary() | ||
| docK.S = core.MakeName(string(model.StructureTypeDocument)) | ||
|
|
||
| str.AddKDict(docK) | ||
|
|
||
| form := model.NewPdfAcroForm() | ||
| fields := core.MakeArray() | ||
|
|
||
| // Create text fields and its label | ||
| for idx, fdef := range textFieldsDef { | ||
| opt := annotator.TextFieldOptions{} | ||
| textf, err := annotator.NewTextField(page, fdef.Name, fdef.Rect, opt) | ||
3ace marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| textf.DV = core.MakeString("") // Set default value for the field. | ||
| textf.V = core.MakeString("") // Set current value for the field. | ||
| textf.TU = core.MakeString(fdef.Tooltip) // Set tooltip for the field. | ||
|
|
||
| *form.Fields = append(*form.Fields, textf.PdfField) | ||
| page.AddAnnotation(textf.Annotations[0].PdfAnnotation) | ||
|
|
||
| y := pageHeight - fdef.Rect[1] | ||
|
|
||
| p := c.NewStyledParagraph() | ||
| p.SetText(fdef.Label) | ||
| p.SetPos(fdef.Rect[0]-80, y-10) | ||
|
|
||
| // Tag the label paragraph and generate its K dictionary. | ||
| // This will be used to associate the label with the form field. | ||
| p.SetStructureType(model.StructureTypeForm) | ||
|
|
||
| // Set unique ID for each field label. | ||
| p.SetMarkedContentID(int64(idx)) | ||
|
|
||
| k, err := p.GenerateKDict() | ||
| if err != nil { | ||
| log.Fatalf("Error: %v", err) | ||
| } | ||
|
|
||
| k.Alt = core.MakeString(fdef.Tooltip) // Set alternative text for the label. | ||
|
|
||
| docK.AddKChild(k) | ||
|
|
||
| err = c.Draw(p) | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| line := c.NewLine(fdef.Rect[0], y, fdef.Rect[2], y) | ||
| err = c.Draw(line) | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| fields.Append(textf.ToPdfObject()) | ||
| } | ||
|
|
||
| err = addSubmitButton(page, form) | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| err = addResetButton(page, form, fields) | ||
3ace marked this conversation as resolved.
Show resolved
Hide resolved
3ace marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| c.SetForms(form) | ||
| c.SetStructTreeRoot(str) | ||
|
|
||
| err = c.WriteToFile("pdf_tag_form.pdf") | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| } | ||
|
|
||
| // Add Submit button that will submit all field values. | ||
| func addSubmitButton(page *model.PdfPage, form *model.PdfAcroForm) error { | ||
| optSubmit := annotator.FormSubmitActionOptions{ | ||
| Url: "https://unidoc.io", | ||
| Rectangle: draw.Rectangle{ | ||
| X: 400.0, | ||
| Y: 400.0, | ||
| Width: 50.0, | ||
| Height: 20.0, | ||
| FillColor: model.NewPdfColorDeviceRGB(0.0, 1.0, 0.0), | ||
| }, | ||
| Label: "Submit", | ||
| LabelColor: model.NewPdfColorDeviceRGB(1.0, 0.0, 0.0), | ||
| } | ||
|
|
||
| btnSubmitField, err := annotator.NewFormSubmitButtonField(page, optSubmit) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| *form.Fields = append(*form.Fields, btnSubmitField.PdfField) | ||
| page.AddAnnotation(btnSubmitField.Annotations[0].PdfAnnotation) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // Add Reset button that would reset the specified fields to its default value. | ||
| func addResetButton(page *model.PdfPage, form *model.PdfAcroForm, fields *core.PdfObjectArray) error { | ||
| optReset := annotator.FormResetActionOptions{ | ||
| Rectangle: draw.Rectangle{ | ||
| X: 100.0, | ||
| Y: 400.0, | ||
| Width: 50.0, | ||
| Height: 20.0, | ||
| FillColor: model.NewPdfColorDeviceGray(0.5), | ||
| }, | ||
| Label: "Reset", | ||
| LabelColor: model.NewPdfColorDeviceGray(1.0), | ||
| Fields: fields, | ||
| } | ||
|
|
||
| btnResetField, err := annotator.NewFormResetButtonField(page, optReset) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Add widget to existing form. | ||
| *form.Fields = append(*form.Fields, btnResetField.PdfField) | ||
| page.AddAnnotation(btnResetField.Annotations[0].PdfAnnotation) | ||
|
|
||
| return nil | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.