func MergeFiles(dest string, sources ...string) error { merged, err := pdf.Create(dest) if err != nil { return fmt.Errorf("create %q: %v", dest, err) } // because pdf files are mmap'ed and objects are zero copied // the files must remain open until merged is saved closers := make([]io.Closer, 0, len(sources)) defer func() { for _, c := range closers { _ = c.Close() } }() // add the contents of each pdf into the merged pdf // collects the roots of each pdf roots := make([]pdf.ObjectReference, 0, len(sources)) for _, fn := range sources { file, err := pdf.Open(fn) if err != nil { return fmt.Errorf("open %q: %v", fn, err) } closers = append(closers, file) _, root, err := copyReferencedObjects(map[pdf.ObjectReference]pdf.ObjectReference{}, merged, file, file.Root) if err != nil { return err } roots = append(roots, root.(pdf.ObjectReference)) merged.Root = root.(pdf.ObjectReference) } // get the catalogs for each of the pdfs for merging their contents catalogs := make([]pdf.Dictionary, 0, len(roots)) for _, root := range roots { catalogs = append(catalogs, merged.Get(root).(pdf.Dictionary)) } // merge the page trees pageTreeRef, err := mergePageTrees(merged, catalogs) if err != nil { return err } // create a new root merged.Root, err = merged.Add(pdf.Dictionary{ "Type": pdf.Name("Catalog"), "Pages": pageTreeRef, }) if err != nil { return err } return merged.Save() }
func appendPDF(newPDFfilename string, filenames []string) { merged, err := pdf.Create(newPDFfilename) if err != nil { log.Fatalln(err) } // add the contents of each pdf into the merged pdf // collects the roots of each pdf roots := make([]pdf.ObjectReference, 0, len(filenames)) for _, filename := range filenames { file, err := pdf.Open(filename) if err != nil { log.Fatalln(err) } // because pdf files are mmap'ed and objects are zero copied // the files must remain open until merged is saved defer func() { err := file.Close() if err != nil { log.Fatalln(err) } }() _, root := copyReferencedObjects(map[pdf.ObjectReference]pdf.ObjectReference{}, merged, file, file.Root) roots = append(roots, root.(pdf.ObjectReference)) merged.Root = root.(pdf.ObjectReference) } // get the catalogs for each of the pdfs for merging their contents catalogs := make([]pdf.Dictionary, 0, len(roots)) for _, root := range roots { catalogs = append(catalogs, merged.Get(root).(pdf.Dictionary)) } // merge the page trees pageTreeRef := mergePageTrees(merged, catalogs) // create a new root merged.Root, err = merged.Add(pdf.Dictionary{ "Type": pdf.Name("Catalog"), "Pages": pageTreeRef, }) if err != nil { log.Fatalln(err) } err = merged.Save() if err != nil { log.Fatalln(err) } }
// create the minimal file described in H.2 func createMinimalFile() { log.Printf("createMinimalFile") minimal, err := pdf.Create("h7-minimal.pdf") if err != nil { log.Fatalln(errgo.Details(err)) } defer minimal.Close() minimal.Root = pdf.ObjectReference{ObjectNumber: 1} // catalog minimal.Add(pdf.IndirectObject{ ObjectReference: pdf.ObjectReference{ObjectNumber: 1}, Object: pdf.Dictionary{ pdf.Name("Type"): pdf.Name("Catalog"), pdf.Name("Outlines"): pdf.ObjectReference{ ObjectNumber: 2, }, pdf.Name("Pages"): pdf.ObjectReference{ ObjectNumber: 3, }, }, }) // outlines minimal.Add(pdf.IndirectObject{ ObjectReference: pdf.ObjectReference{ObjectNumber: 2}, Object: pdf.Dictionary{ pdf.Name("Type"): pdf.Name("Outlines"), pdf.Name("Count"): pdf.Integer(0), }, }) // pages minimal.Add(pdf.IndirectObject{ ObjectReference: pdf.ObjectReference{ObjectNumber: 3}, Object: pdf.Dictionary{ pdf.Name("Type"): pdf.Name("Pages"), pdf.Name("Kids"): pdf.Array{ pdf.ObjectReference{ ObjectNumber: 4, }, }, pdf.Name("Count"): pdf.Integer(1), }, }) // page minimal.Add(pdf.IndirectObject{ ObjectReference: pdf.ObjectReference{ObjectNumber: 4}, Object: pdf.Dictionary{ pdf.Name("Type"): pdf.Name("Page"), pdf.Name("Parent"): pdf.ObjectReference{ ObjectNumber: 3, }, pdf.Name("MediaBox"): pdf.Array{ pdf.Integer(0), pdf.Integer(0), pdf.Integer(612), pdf.Integer(792), }, pdf.Name("Contents"): pdf.ObjectReference{ ObjectNumber: 5, }, pdf.Name("Resources"): pdf.Dictionary{ pdf.Name("ProcSet"): pdf.ObjectReference{ ObjectNumber: 6, }, }, }, }) // content stream minimal.Add(pdf.IndirectObject{ ObjectReference: pdf.ObjectReference{ObjectNumber: 5}, Object: pdf.Stream{ Dictionary: pdf.Dictionary{ pdf.Name("Length"): pdf.Integer(0), }, }, }) // procset minimal.Add(pdf.IndirectObject{ ObjectReference: pdf.ObjectReference{ObjectNumber: 6}, Object: pdf.Array{ pdf.Name("PDF"), }, }) minimal.Root = pdf.ObjectReference{ObjectNumber: 1} err = minimal.Save() if err != nil { log.Fatalln(errgo.Details(err)) } }