From 49c0e81fbc7de8b74fabaf6b959ec1fa162bfe62 Mon Sep 17 00:00:00 2001 From: Kurt Jung Date: Tue, 15 Apr 2014 19:10:09 -0400 Subject: Document protection and example --- def.go | 1 + doc.go | 5 ++++- fpdf.go | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- fpdf_test.go | 12 +++++++++++ 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/def.go b/def.go index 15e6939..422eb1c 100644 --- a/def.go +++ b/def.go @@ -196,6 +196,7 @@ type Fpdf struct { clipNest int // Number of active clipping contexts transformNest int // Number of active transformation contexts err error // Set if error occurs during life cycle of instance + protect protectType // document protection structure colorFlag bool // indicates whether fill and text colors are different color struct { // Composite values of colors draw, fill, text clrType diff --git a/doc.go b/doc.go index db47f92..5399b02 100644 --- a/doc.go +++ b/doc.go @@ -44,6 +44,8 @@ Features • Clipping +• Document protection + gofpdf has no dependencies other than the Go standard library. All tests pass on Linux, Mac and Windows platforms. Like FPDF version 1.7, from which gofpdf is derived, this package does not yet support UTF-8 fonts. However, support is @@ -59,7 +61,8 @@ transparency script by Martin Hall-May. Support for gradients and clipping is adapted from FPDF scripts by Andreas Würmser. Support for outline bookmarks is adapted from Olivier Plathey by Manuel Cornes. Support for transformations is adapted from the FPDF transformation script by Moritz Wagner and Andreas -Würmser. Lawrence Kesteloot provided code to allow an image's extent to be +Würmser. PDF protection is adapted from the work of Klemen Vodopivec for the +FPDF product. Lawrence Kesteloot provided code to allow an image's extent to be determined prior to placement. Support for vertical alignment within a cell was provided by Stefan Schroeder. Ivan Daniluk generalized the font and image loading code to use the Reader interface while maintaining backward diff --git a/fpdf.go b/fpdf.go index 8b4e452..7a6f0c2 100644 --- a/fpdf.go +++ b/fpdf.go @@ -1281,7 +1281,8 @@ func (f *Fpdf) AddFontFromReader(familyStr, styleStr string, r io.Reader) { // document will not be valid. // // The font can be either a standard one or a font added via the AddFont() -// method. Standard fonts use the Windows encoding cp1252 (Western Europe). +// method or AddFontFromReader() method. Standard fonts use the Windows +// encoding cp1252 (Western Europe). // // The method can be called before the first page is created and the font is // kept from page to page. If you just wish to change the current font size, it @@ -1290,10 +1291,10 @@ func (f *Fpdf) AddFontFromReader(familyStr, styleStr string, r io.Reader) { // Note: the font definition file must be accessible. An error is set if the // file cannot be read. // -// familyStr specifies the font fammily. It can be either a name defined by -// AddFont() or one of the standard families (case insensitive): "Courier" for -// fixed-width, "Helvetica" or "Arial" for sans serif, "Times" for serif, -// "Symbol" or "ZapfDingbats" for symbolic. +// familyStr specifies the font family. It can be either a name defined by +// AddFont(), AddFontFromReader() or one of the standard families (case +// insensitive): "Courier" for fixed-width, "Helvetica" or "Arial" for sans +// serif, "Times" for serif, "Symbol" or "ZapfDingbats" for symbolic. // // styleStr can be "B" (bold), "I" (italic), "U" (underscore) or any // combination. The default value (specified with an empty string) is regular. @@ -2153,6 +2154,31 @@ func (f *Fpdf) SetXY(x, y float64) { f.SetX(x) } +// SetProtection applies certain constraints on the finished PDF document. +// +// actionFlag is a bitflag that controls various document operations. +// CnProtectPrint allows the document to be printed. CnProtectModify allows a +// document to be modified by a PDF editor. CnProtectCopy allows text and +// images to be copied into the system clipboard. CnProtectAnnotForms allows +// annotations and forms to be added by a PDF editor. These values can be +// combined by or-ing them together, for example, +// CnProtectCopy|CnProtectModify. This flag is advisory; not all PDF readers +// implement the constraints that this argument attempts to control. +// +// userPassStr specifies the password that will need to be provided to view the +// contents of the PDF. The permissions specified by actionFlag will apply. +// +// ownerPassStr specifies the password that will need to be provided to gain +// full access to the document regardless of the actionFlag value. An empty +// string for this argument will be replaced with a random value, effectively +// prohibiting full access to the document. +func (f *Fpdf) SetProtection(actionFlag byte, userPassStr, ownerPassStr string) { + if f.err != nil { + return + } + f.protect.setProtection(actionFlag, userPassStr, ownerPassStr) +} + // OutputAndClose sends the PDF document to the writer specified by w. This // method will close both f and w, even if an error is detected and no document // is produced. @@ -2298,6 +2324,11 @@ func (f *Fpdf) escape(s string) string { // Format a text string func (f *Fpdf) textstring(s string) string { + if f.protect.encrypted { + b := []byte(s) + f.protect.rc4(uint32(f.n), &b) + s = string(b) + } return "(" + f.escape(s) + ")" } @@ -2590,6 +2621,9 @@ func (f *Fpdf) newobj() { func (f *Fpdf) putstream(b []byte) { // dbg("putstream") + if f.protect.encrypted { + f.protect.rc4(uint32(f.n), &b) + } f.out("stream") f.out(string(b)) f.out("endstream") @@ -2923,7 +2957,7 @@ func (f *Fpdf) putresourcedict() { f.putxobjectdict() f.out(">>") count := len(f.blendList) - if count > 0 { + if count > 1 { f.out("/ExtGState <<") for j := 1; j < count; j++ { f.outf("/GS%d %d 0 R", j, f.blendList[j].objNum) @@ -2931,7 +2965,7 @@ func (f *Fpdf) putresourcedict() { f.out(">>") } count = len(f.gradientList) - if count > 0 { + if count > 1 { f.out("/Shading <<") for j := 1; j < count; j++ { f.outf("/Sh%d %d 0 R", j, f.gradientList[j].objNum) @@ -2996,6 +3030,19 @@ func (f *Fpdf) putresources() { f.putresourcedict() f.out(">>") f.out("endobj") + if f.protect.encrypted { + f.newobj() + f.protect.objNum = f.n + f.out("<<") + f.out("/Filter /Standard") + f.out("/V 1") + f.out("/R 2") + f.outf("/O (%s)", f.escape(string(f.protect.oValue))) + f.outf("/U (%s)", f.escape(string(f.protect.uValue))) + f.outf("/P %d", f.protect.pValue) + f.out(">>") + f.out("endobj") + } return } @@ -3058,6 +3105,10 @@ func (f *Fpdf) puttrailer() { f.outf("/Size %d", f.n+1) f.outf("/Root %d 0 R", f.n) f.outf("/Info %d 0 R", f.n-1) + if f.protect.encrypted { + f.outf("/Encrypt %d 0 R", f.protect.objNum) + f.out("/ID [()()]") + } } func (f *Fpdf) putbookmarks() { diff --git a/fpdf_test.go b/fpdf_test.go index 9ef3b3f..fc9d6a5 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -1184,3 +1184,15 @@ func ExampleFpdf_tutorial23() { // Output: // Successfully generated pdf/tutorial23.pdf } + +// This example demonstrates document protection. +func ExampleFpdf_tutorial24() { + pdf := gofpdf.New("P", "mm", "A4", cnFontDir) // A4 210.0 x 297.0 + pdf.SetProtection(gofpdf.CnProtectPrint, "123", "abc") + pdf.AddPage() + pdf.SetFont("Arial", "", 12) + pdf.Write(10, "You can print me but not copy my text.") + pdf.OutputAndClose(docWriter(pdf, 24)) + // Output: + // Successfully generated pdf/tutorial24.pdf +} -- cgit v1.2.1-24-ge1ad