unipdf/pdf/model/appender_test.go

893 lines
20 KiB
Go
Raw Normal View History

2018-12-11 16:06:34 +03:00
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package model_test
2018-12-11 16:06:34 +03:00
import (
2018-12-19 18:36:15 +03:00
"bytes"
"crypto/rsa"
2019-03-15 20:58:40 +02:00
"errors"
"fmt"
2018-12-19 18:36:15 +03:00
"io/ioutil"
2019-02-19 21:48:51 +02:00
"log"
2018-12-11 16:06:34 +03:00
"os"
"path/filepath"
"testing"
"time"
2018-12-11 16:06:34 +03:00
"golang.org/x/crypto/pkcs12"
2018-12-11 16:06:34 +03:00
"github.com/unidoc/unidoc/common"
2019-02-19 21:48:51 +02:00
"github.com/unidoc/unidoc/pdf/annotator"
2018-12-11 16:06:34 +03:00
"github.com/unidoc/unidoc/pdf/core"
"github.com/unidoc/unidoc/pdf/model"
"github.com/unidoc/unidoc/pdf/model/sighandler"
2018-12-11 16:06:34 +03:00
)
// This test file contains multiple tests to generate PDFs from existing Pdf files. The outputs are written
// into TMPDIR as files. The files themselves need to be observed to check for correctness as we don't have
// a good way to automatically check if every detail is correct.
2018-12-11 16:06:34 +03:00
func init() {
common.SetLogger(common.NewConsoleLogger(common.LogLevelDebug))
}
const testPdfFile1 = "./testdata/minimal.pdf"
const testPdfLoremIpsumFile = "./testdata/lorem.pdf"
const testPdf3pages = "./testdata/pages3.pdf"
const imgPdfFile1 = "./testdata/img1-1.pdf"
const imgPdfFile2 = "./testdata/img1-2.pdf"
// source http://foersom.com/net/HowTo/data/OoPdfFormExample.pdf
const testPdfAcroFormFile1 = "./testdata/OoPdfFormExample.pdf"
2018-12-19 18:36:15 +03:00
const testPdfSignedPDFDocument = "./testdata/SampleSignedPDFDocument.pdf"
const testPKS12Key = "./testdata/certificate.p12"
2018-12-19 18:36:15 +03:00
const testPKS12KeyPassword = "password"
2019-03-15 20:58:40 +02:00
const testSampleSignatureFile = "./testdata/sample_signature"
2018-12-19 18:36:15 +03:00
2018-12-11 16:06:34 +03:00
func tempFile(name string) string {
return filepath.Join(os.TempDir(), name)
}
func TestAppenderAddPage(t *testing.T) {
f1, err := os.Open(testPdfLoremIpsumFile)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
f2, err := os.Open(testPdfFile1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f2.Close()
pdf2, err := model.NewPdfReader(f2)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender.AddPages(pdf1.PageList...)
appender.AddPages(pdf2.PageList...)
appender.AddPages(pdf2.PageList...)
err = appender.WriteToFile(tempFile("appender_add_page_1.pdf"))
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
}
func TestAppenderAddPage2(t *testing.T) {
f1, err := os.Open(testPdfLoremIpsumFile)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
f2, err := os.Open(testPdfAcroFormFile1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f2.Close()
pdf2, err := model.NewPdfReader(f2)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender.AddPages(pdf2.PageList...)
appender.ReplaceAcroForm(pdf2.AcroForm)
err = appender.WriteToFile(tempFile("appender_add_page_2.pdf"))
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
}
func TestAppenderRemovePage(t *testing.T) {
f1, err := os.Open(testPdf3pages)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender.RemovePage(1)
appender.RemovePage(2)
err = appender.WriteToFile(tempFile("appender_remove_page_1.pdf"))
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
}
func TestAppenderReplacePage(t *testing.T) {
f1, err := os.Open(testPdf3pages)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
f2, err := os.Open(testPdfFile1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f2.Close()
pdf2, err := model.NewPdfReader(f2)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender.ReplacePage(1, pdf1.PageList[1])
appender.ReplacePage(3, pdf2.PageList[0])
err = appender.WriteToFile(tempFile("appender_replace_page_1.pdf"))
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
}
func TestAppenderAddAnnotation(t *testing.T) {
f1, err := os.Open(testPdf3pages)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
page := pdf1.PageList[0]
annotation := model.NewPdfAnnotationSquare()
rect := model.PdfRectangle{Ury: 250.0, Urx: 150.0, Lly: 50.0, Llx: 50.0}
2018-12-11 16:06:34 +03:00
annotation.Rect = rect.ToPdfObject()
annotation.IC = core.MakeArrayFromFloats([]float64{4.0, 0.0, 0.3})
annotation.CA = core.MakeFloat(0.5)
page.Annotations = append(page.Annotations, annotation.PdfAnnotation)
appender.ReplacePage(1, page)
err = appender.WriteToFile(tempFile("appender_add_annotation_1.pdf"))
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
}
func TestAppenderMergePage(t *testing.T) {
f1, err := os.Open(testPdf3pages)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
f2, err := os.Open(testPdfFile1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f2.Close()
pdf2, err := model.NewPdfReader(f2)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
err = appender.MergePageWith(1, pdf2.PageList[0])
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
err = appender.WriteToFile(tempFile("appender_merge_page_1.pdf"))
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
}
func TestAppenderMergePage2(t *testing.T) {
f1, err := os.Open(imgPdfFile1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
f2, err := os.Open(imgPdfFile2)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f2.Close()
pdf2, err := model.NewPdfReader(f2)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
err = appender.MergePageWith(1, pdf2.PageList[0])
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender.AddPages(pdf2.PageList...)
err = appender.WriteToFile(tempFile("appender_merge_page_2.pdf"))
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
}
func TestAppenderMergePage3(t *testing.T) {
f1, err := os.Open(testPdfFile1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
f2, err := os.Open(testPdfLoremIpsumFile)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f2.Close()
pdf2, err := model.NewPdfReader(f2)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
2018-12-11 16:06:34 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
err = appender.MergePageWith(1, pdf2.PageList[0])
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
err = appender.WriteToFile(tempFile("appender_merge_page_3.pdf"))
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
}
2018-12-19 18:36:15 +03:00
func validateFile(t *testing.T, fileName string) {
t.Logf("Validating %s", fileName)
2018-12-19 18:36:15 +03:00
data, err := ioutil.ReadFile(fileName)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
reader, err := model.NewPdfReader(bytes.NewReader(data))
2018-12-19 18:36:15 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
handler, _ := sighandler.NewAdobeX509RSASHA1(nil, nil)
handler2, _ := sighandler.NewAdobePKCS7Detached(nil, nil)
handlers := []model.SignatureHandler{handler, handler2}
2018-12-19 18:36:15 +03:00
res, err := reader.ValidateSignatures(handlers)
2018-12-19 18:36:15 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
if len(res) == 0 {
t.Errorf("Fail: signature fields not found")
return
}
if !res[0].IsSigned || !res[0].IsVerified {
t.Errorf("Fail: validation failed")
return
}
for i, item := range res {
t.Logf("== Signature %d", i+1)
t.Logf("%s", item.String())
}
2018-12-19 18:36:15 +03:00
}
2019-03-15 20:58:40 +02:00
func parseByteRange(byteRange *core.PdfObjectArray) ([]int64, error) {
if byteRange == nil {
return nil, errors.New("byte range cannot be nil")
}
if byteRange.Len() != 4 {
return nil, errors.New("invalid byte range length")
}
s1, err := core.GetNumberAsInt64(byteRange.Get(0))
if err != nil {
return nil, errors.New("invalid byte range value")
}
l1, err := core.GetNumberAsInt64(byteRange.Get(1))
if err != nil {
return nil, errors.New("invalid byte range value")
}
s2, err := core.GetNumberAsInt64(byteRange.Get(2))
if err != nil {
return nil, errors.New("invalid byte range value")
}
l2, err := core.GetNumberAsInt64(byteRange.Get(3))
if err != nil {
return nil, errors.New("invalid byte range value")
}
return []int64{s1, s1 + l1, s2, s2 + l2}, nil
}
2018-12-19 18:36:15 +03:00
func TestAppenderSignPage4(t *testing.T) {
// TODO move to reader_test.go
validateFile(t, testPdfSignedPDFDocument)
f1, err := os.Open(testPdfFile1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
2018-12-19 18:36:15 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
2018-12-19 18:36:15 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
f, _ := ioutil.ReadFile(testPKS12Key)
privateKey, cert, err := pkcs12.Decode(f, testPKS12KeyPassword)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
handler, err := sighandler.NewAdobePKCS7Detached(privateKey.(*rsa.PrivateKey), cert)
2018-12-19 18:36:15 +03:00
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
// Create signature field and appearance.
signature := model.NewPdfSignature(handler)
signature.SetName("Test Appender")
signature.SetReason("TestAppenderSignPage4")
signature.SetDate(time.Now(), "")
2019-02-21 00:20:47 +02:00
if err := signature.Initialize(); err != nil {
return
}
sigField := model.NewPdfFieldSignature(signature)
sigField.T = core.MakeString("Signature1")
sigField.Rect = core.MakeArray(
core.MakeInteger(0),
core.MakeInteger(0),
core.MakeInteger(0),
core.MakeInteger(0),
)
if err = appender.Sign(1, sigField); err != nil {
2018-12-19 18:36:15 +03:00
t.Errorf("Fail: %v\n", err)
return
}
err = appender.WriteToFile(tempFile("appender_sign_page_4.pdf"))
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
validateFile(t, tempFile("appender_sign_page_4.pdf"))
}
func TestAppenderSignMultiple(t *testing.T) {
inputPath := testPdfFile1
for i := 0; i < 3; i++ {
f, err := os.Open(inputPath)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
pdfReader, err := model.NewPdfReader(f)
if err != nil {
t.Errorf("Fail: %v\n", err)
f.Close()
return
}
t.Logf("Fields: %d", len(pdfReader.AcroForm.AllFields()))
if len(pdfReader.AcroForm.AllFields()) != i {
t.Fatalf("fields != %d (got %d)", i, len(pdfReader.AcroForm.AllFields()))
}
t.Logf("Annotations: %d", len(pdfReader.PageList[0].Annotations))
if len(pdfReader.PageList[0].Annotations) != i {
t.Fatalf("page annotations != %d (got %d)", i, len(pdfReader.PageList[0].Annotations))
}
appender, err := model.NewPdfAppender(pdfReader)
if err != nil {
t.Errorf("Fail: %v\n", err)
f.Close()
return
}
pfxData, _ := ioutil.ReadFile(testPKS12Key)
privateKey, cert, err := pkcs12.Decode(pfxData, testPKS12KeyPassword)
if err != nil {
t.Errorf("Fail: %v\n", err)
f.Close()
return
}
handler, err := sighandler.NewAdobePKCS7Detached(privateKey.(*rsa.PrivateKey), cert)
if err != nil {
t.Errorf("Fail: %v\n", err)
f.Close()
return
}
// Create signature field and appearance.
signature := model.NewPdfSignature(handler)
signature.SetName(fmt.Sprintf("Test Appender - Round %d", i+1))
signature.SetReason(fmt.Sprintf("Test Appender - Round %d", i+1))
signature.SetDate(time.Now(), "")
2019-02-21 00:20:47 +02:00
if err := signature.Initialize(); err != nil {
return
}
sigField := model.NewPdfFieldSignature(signature)
sigField.T = core.MakeString(fmt.Sprintf("Signature %d", i+1))
sigField.Rect = core.MakeArray(
core.MakeInteger(0),
core.MakeInteger(0),
core.MakeInteger(0),
core.MakeInteger(0),
)
if err = appender.Sign(1, sigField); err != nil {
t.Errorf("Fail: %v\n", err)
f.Close()
return
}
outPath := tempFile(fmt.Sprintf("appender_sign_multiple_%d.pdf", i+1))
err = appender.WriteToFile(outPath)
if err != nil {
t.Errorf("Fail: %v\n", err)
f.Close()
return
}
validateFile(t, outPath)
inputPath = outPath
f.Close()
}
}
2019-02-19 21:48:51 +02:00
func TestSignatureAppearance(t *testing.T) {
f, err := os.Open(testPdf3pages)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f.Close()
pdfReader, err := model.NewPdfReader(f)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
t.Logf("Fields: %d", len(pdfReader.AcroForm.AllFields()))
appender, err := model.NewPdfAppender(pdfReader)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
pfxData, _ := ioutil.ReadFile(testPKS12Key)
privateKey, cert, err := pkcs12.Decode(pfxData, testPKS12KeyPassword)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
handler, err := sighandler.NewAdobePKCS7Detached(privateKey.(*rsa.PrivateKey), cert)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
// Create signature.
signature := model.NewPdfSignature(handler)
signature.SetName("Test Signature Appearance Name")
signature.SetReason("TestSignatureAppearance Reason")
signature.SetDate(time.Now(), "")
2019-02-21 00:20:47 +02:00
if err := signature.Initialize(); err != nil {
return
}
2019-02-19 21:48:51 +02:00
numPages, err := pdfReader.GetNumPages()
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
for i := 0; i < numPages; i++ {
pageNum := i + 1
// Annot1
opts := annotator.NewSignatureFieldOpts()
opts.FontSize = 10
opts.Rect = []float64{10, 25, 75, 60}
sigField, err := annotator.NewSignatureField(
signature,
[]*annotator.SignatureLine{
annotator.NewSignatureLine("Name", "Jane Doe"),
annotator.NewSignatureLine("Date", "2019.01.03"),
annotator.NewSignatureLine("Reason", "Some reason"),
annotator.NewSignatureLine("Location", "New York"),
annotator.NewSignatureLine("DN", "authority1:name1"),
},
opts,
)
2019-02-21 00:20:47 +02:00
sigField.T = core.MakeString(fmt.Sprintf("Signature %d", pageNum))
2019-02-19 21:48:51 +02:00
if err = appender.Sign(pageNum, sigField); err != nil {
t.Errorf("Fail: %v\n", err)
return
}
// Annot2
opts = annotator.NewSignatureFieldOpts()
opts.FontSize = 8
opts.Rect = []float64{250, 25, 325, 70}
opts.TextColor = model.NewPdfColorDeviceRGB(255, 0, 0)
sigField, err = annotator.NewSignatureField(
signature,
[]*annotator.SignatureLine{
annotator.NewSignatureLine("Name", "John Doe"),
annotator.NewSignatureLine("Date", "2019.03.14"),
annotator.NewSignatureLine("Reason", "No reason"),
annotator.NewSignatureLine("Location", "London"),
annotator.NewSignatureLine("DN", "authority2:name2"),
},
opts,
)
2019-02-21 00:20:47 +02:00
sigField.T = core.MakeString(fmt.Sprintf("Signature2 %d", pageNum))
2019-02-19 21:48:51 +02:00
if err = appender.Sign(pageNum, sigField); err != nil {
log.Fatalf("Fail: %v\n", err)
}
// Annot3
opts = annotator.NewSignatureFieldOpts()
opts.BorderSize = 1
opts.FontSize = 10
opts.Rect = []float64{475, 25, 590, 80}
opts.FillColor = model.NewPdfColorDeviceRGB(255, 255, 0)
opts.TextColor = model.NewPdfColorDeviceRGB(0, 0, 200)
2019-02-19 21:48:51 +02:00
sigField, err = annotator.NewSignatureField(
signature,
[]*annotator.SignatureLine{
annotator.NewSignatureLine("Name", "John Smith"),
annotator.NewSignatureLine("Date", "2019.02.19"),
annotator.NewSignatureLine("Reason", "Another reason"),
annotator.NewSignatureLine("Location", "Paris"),
annotator.NewSignatureLine("DN", "authority3:name3"),
},
opts,
)
2019-02-21 00:20:47 +02:00
sigField.T = core.MakeString(fmt.Sprintf("Signature3 %d", pageNum))
2019-02-19 21:48:51 +02:00
if err = appender.Sign(pageNum, sigField); err != nil {
log.Fatalf("Fail: %v\n", err)
}
}
outPath := tempFile("appender_signature_appearance.pdf")
if err = appender.WriteToFile(outPath); err != nil {
t.Errorf("Fail: %v\n", err)
return
}
validateFile(t, outPath)
}
2019-03-15 20:58:40 +02:00
func TestAppenderExternalSignature(t *testing.T) {
validateFile(t, testPdfSignedPDFDocument)
f1, err := os.Open(testPdfFile1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
reader, err := model.NewPdfReader(f1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(reader)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
handler, err := sighandler.NewEmptyAdobePKCS7Detached(8192)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
// Create signature.
signature := model.NewPdfSignature(handler)
signature.SetName("Test External Signature")
signature.SetReason("TestAppenderExternalSignature")
signature.SetDate(time.Date(2019, 3, 24, 7, 30, 24, 0, time.UTC), "")
2019-03-15 20:58:40 +02:00
if err := signature.Initialize(); err != nil {
return
}
// Create signature field and appearance.
opts := annotator.NewSignatureFieldOpts()
opts.FontSize = 10
opts.Rect = []float64{10, 25, 75, 60}
sigField, err := annotator.NewSignatureField(
signature,
[]*annotator.SignatureLine{
annotator.NewSignatureLine("Name", "John Doe"),
annotator.NewSignatureLine("Date", "2019.15.03"),
annotator.NewSignatureLine("Reason", "External signature test"),
},
opts,
)
sigField.T = core.MakeString("External signature")
if err = appender.Sign(1, sigField); err != nil {
t.Errorf("Fail: %v\n", err)
return
}
// Write PDF file to buffer.
pdfBuf := bytes.NewBuffer(nil)
if err = appender.Write(pdfBuf); err != nil {
t.Errorf("Fail: %v\n", err)
return
}
pdfData := pdfBuf.Bytes()
// Parse signature byte range.
byteRange, err := parseByteRange(signature.ByteRange)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
// This would be the time to send the PDF buffer to a signing device or
// signing web service and get back the signature. We will simulate this by
// reading the signature from a sample signature file.
// Read external signature data.
signatureData, err := ioutil.ReadFile(testSampleSignatureFile)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
// Apply external signature to the PDF data buffer.
sigBytes := make([]byte, 8192)
copy(sigBytes, signatureData)
sig := core.MakeHexString(string(sigBytes)).WriteString()
copy(pdfData[byteRange[1]:byteRange[2]], []byte(sig))
// Write output file.
outputPath := tempFile("appender_sign_external_signature.pdf")
if err := ioutil.WriteFile(outputPath, pdfData, os.ModePerm); err != nil {
t.Errorf("Fail: %v\n", err)
return
}
// Validate output file.
validateFile(t, outputPath)
}
// Each Appender can only be written out once, further invokations of Write should result in an error.
func TestAppenderAttemptMultiWrite(t *testing.T) {
f1, err := os.Open(testPdfLoremIpsumFile)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f1.Close()
pdf1, err := model.NewPdfReader(f1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
f2, err := os.Open(testPdfFile1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
defer f2.Close()
pdf2, err := model.NewPdfReader(f2)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender, err := model.NewPdfAppender(pdf1)
if err != nil {
t.Errorf("Fail: %v\n", err)
return
}
appender.AddPages(pdf1.PageList...)
appender.AddPages(pdf2.PageList...)
appender.AddPages(pdf2.PageList...)
// Write twice to buffer and compare results.
var buf1, buf2 bytes.Buffer
err = appender.Write(&buf1)
if err != nil {
t.Fatalf("Error: %v", err)
}
err = appender.Write(&buf2)
if err == nil {
t.Fatalf("Second invokation of appender.Write should yield an error")
}
}