From 5d510c1aa2c794e82c114cf0adf540f6829886d7 Mon Sep 17 00:00:00 2001 From: Kurt Jung Date: Tue, 13 Aug 2013 11:41:22 -0400 Subject: Added support with example for transparency in a variety of blending modes. This was adapted from the FPDF transparency script by Martin Hall-May. --- def.go | 7 ++++++ doc.go | 5 ++++- fpdf.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fpdf_test.go | 17 ++++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) diff --git a/def.go b/def.go index 6d0e83a..ca31526 100644 --- a/def.go +++ b/def.go @@ -24,6 +24,11 @@ const ( FPDF_VERSION = "1.7" ) +type blendModeType struct { + strokeStr, fillStr, modeStr string + objNum int +} + type sizeType struct { wd, ht float64 } @@ -122,6 +127,8 @@ type Fpdf struct { fontDirStr string // location of font definition files capStyle int // line cap style: butt 0, round 1, square 2 joinStyle int // line segment join style: miter 0, round 1, bevel 2 + blendList []blendModeType // slice[idx] of alpha transparency modes, 1-based + blendMap map[string]int // map into blendList err error // Set if error occurs during life cycle of instance } diff --git a/doc.go b/doc.go index abb8518..fcf9ba3 100644 --- a/doc.go +++ b/doc.go @@ -20,7 +20,10 @@ Package gofpdf implements a PDF document generator. This package's code and documentation are closely derived from the FPDF library created by Olivier Plathey, and a number of font and image resources are copied directly from it. Drawing support is adapted from the FPDF geometric figures -script by David Hernández Sanz. The FPDF website is http://www.fpdf.org/. +script by David Hernández Sanz. Transparency support is adapted from the FPDF +transparency script by Martin Hall-May + +The FPDF website is http://www.fpdf.org/. Features diff --git a/fpdf.go b/fpdf.go index 2755891..78be090 100644 --- a/fpdf.go +++ b/fpdf.go @@ -175,6 +175,9 @@ func New(orientationStr, unitStr, sizeStr, fontDirStr string) (f *Fpdf) { } // Enable compression f.SetCompression(true) + f.blendList = make([]blendModeType, 0, 8) + f.blendList = append(f.blendList, blendModeType{}) //blendMode[0] is unused (1-based) + f.blendMap = make(map[string]int) // Set default PDF version number f.pdfVersion = "1.3" return @@ -808,6 +811,46 @@ func (f *Fpdf) Arc(x, y, rx, ry, degRotate, degStart, degEnd float64, styleStr s } } +// Set the alpha blending channel. The blending effect applies to text, +// drawings and images. alpha must be a value between 0.0 (fully transparent) +// to 1.0 (fully opaque). Values outside of this range result in an error. +// blendModeStr must be one of "Normal", "Multiply", "Screen", "Overlay", +// "Darken", "Lighten", "ColorDodge", "ColorBurn","HardLight", "SoftLight", +// "Difference", "Exclusion", "Hue", "Saturation", "Color", or "Luminosity". An +// empty string is replaced with "Normal". To reset normal rendering after +// applying a blending mode, call this method with alpha set to 1.0 and +// blendModeStr set to "Normal". +func (f *Fpdf) SetAlpha(alpha float64, blendModeStr string) { + if f.err != nil { + return + } + var bl blendModeType + switch blendModeStr { + case "Normal", "Multiply", "Screen", "Overlay", + "Darken", "Lighten", "ColorDodge", "ColorBurn", "HardLight", "SoftLight", + "Difference", "Exclusion", "Hue", "Saturation", "Color", "Luminosity": + bl.modeStr = blendModeStr + case "": + bl.modeStr = "Normal" + default: + f.err = fmt.Errorf("Unrecognized blend mode \"%s\"", blendModeStr) + return + } + if alpha < 0.0 || alpha > 1.0 { + f.err = fmt.Errorf("Alpha value (0.0 - 1.0) is out of range: %.3f", alpha) + return + } + alphaStr := sprintf("%.3f", alpha) + keyStr := sprintf("%s %s", alphaStr, blendModeStr) + pos, ok := f.blendMap[keyStr] + if !ok { + pos = len(f.blendList) // at least 1 + f.blendList = append(f.blendList, blendModeType{alphaStr, alphaStr, blendModeStr, 0}) + f.blendMap[keyStr] = pos + } + f.outf("/GS%d gs", pos) +} + // Imports a TrueType, OpenType or Type1 font and makes it available. It is // necessary to generate a font definition file first with the makefont // utility. It is not necessary to call this function for the core PDF fonts @@ -1491,9 +1534,16 @@ func (f *Fpdf) Ln(h float64) { // // If x is negative, the current abscissa is used. // +// If flow is true, the current y value is advanced after placing the image and +// a page break may be made if necessary. +// // tp specifies the image format. Possible values are (case insensitive): // "JPG", "JPEG", "PNG" and "GIF". If not specified, the type is inferred from // the file extension. +// +// If link refers to an internal page anchor (that is, it is non-zero; see +// AddLink()), the image will be a clickable internal link. Otherwise, if +// linkStr specifies a URL, the image will be a clickable external link. func (f *Fpdf) Image(fileStr string, x, y, w, h float64, flow bool, tp string, link int, linkStr string) { if f.err != nil { return @@ -2381,12 +2431,31 @@ func (f *Fpdf) putresourcedict() { f.out("/XObject <<") f.putxobjectdict() f.out(">>") + f.out("/ExtGState <<") + count := len(f.blendList) + for j := 1; j < count; j++ { + f.outf("/GS%d %d 0 R", j, f.blendList[j].objNum) + } + f.out(">>") +} + +func (f *Fpdf) putBlendModes() { + count := len(f.blendList) + for j := 1; j < count; j++ { + bl := f.blendList[j] + f.newobj() + f.blendList[j].objNum = f.n + f.outf("<>", + bl.fillStr, bl.strokeStr, bl.modeStr) + f.out("endobj") + } } func (f *Fpdf) putresources() { if f.err != nil { return } + f.putBlendModes() f.putfonts() if f.err != nil { return @@ -2446,6 +2515,9 @@ func (f *Fpdf) putcatalog() { } func (f *Fpdf) putheader() { + if len(f.blendMap) > 0 && f.pdfVersion < "1.4" { + f.pdfVersion = "1.4" + } f.outf("%%PDF-%s", f.pdfVersion) } diff --git a/fpdf_test.go b/fpdf_test.go index 494d281..c121260 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -704,3 +704,20 @@ func ExampleFpdf_tutorial11() { // Output: // Successfully generated pdf/tutorial11.pdf } + +// Transparency +func ExampleFpdf_tutorial12() { + pdf := New("", "", "", FONT_DIR) + pdf.SetFont("Helvetica", "", 48) + pdf.SetLineWidth(4) + pdf.SetFillColor(180, 180, 180) + pdf.AddPage() + pdf.SetXY(55, 60) + pdf.CellFormat(100, 40, "Go", "1", 0, "C", true, 0, "") + pdf.SetAlpha(0.5, "Normal") + pdf.Image(IMG_DIR+"/golang-gopher.png", 30, 10, 150, 0, false, "", 0, "") + pdf.SetAlpha(1.0, "Normal") + pdf.OutputAndClose(docWriter(pdf, 12)) + // Output: + // Successfully generated pdf/tutorial12.pdf +} -- cgit v1.2.1-24-ge1ad