diff options
| -rw-r--r-- | def.go | 31 | ||||
| -rw-r--r-- | fpdf.go | 35 | ||||
| -rw-r--r-- | fpdf_test.go | 14 | ||||
| -rw-r--r-- | spotcolor.go | 184 | 
4 files changed, 247 insertions, 17 deletions
| @@ -39,6 +39,34 @@ type gradientType struct {  	objNum            int  } +type colorMode int + +const ( +	colorModeRGB colorMode = iota +	colorModeSpot +	colorModeCMYK +) + +type colorType struct { +	r, g, b    float64 +	ir, ig, ib int +	mode       colorMode +	spotStr    string // name of current spot color +	gray       bool +	str        string +} + +// SpotColorType specifies a named spot color value +type spotColorType struct { +	id, objID int +	val       cmykColorType +} + +// CMYKColorType specifies an ink-based CMYK color value +type cmykColorType struct { +	c, m, y, k byte // 0% to 100% +} +  // SizeType fields Wd and Ht specify the horizontal and vertical extents of a  // document element such as a page.  type SizeType struct { @@ -254,8 +282,9 @@ type Fpdf struct {  	colorFlag        bool                      // indicates whether fill and text colors are different  	color            struct {  		// Composite values of colors -		draw, fill, text clrType +		draw, fill, text colorType  	} +	spotColorMap map[string]spotColorType // Map of named ink-based colors  }  type encType struct { @@ -180,6 +180,7 @@ func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType)  	}  	// Enable compression  	f.SetCompression(!gl.noCompress) +	f.spotColorMap = make(map[string]spotColorType)  	f.blendList = make([]blendModeType, 0, 8)  	f.blendList = append(f.blendList, blendModeType{}) // blendList[0] is unused (1-based)  	f.blendMap = make(map[string]int) @@ -721,13 +722,6 @@ func (f *Fpdf) PageNo() int {  	return f.page  } -type clrType struct { -	r, g, b    float64 -	ir, ig, ib int -	gray       bool -	str        string -} -  func colorComp(v int) (int, float64) {  	if v < 0 {  		v = 0 @@ -737,10 +731,11 @@ func colorComp(v int) (int, float64) {  	return v, float64(v) / 255.0  } -func colorValue(r, g, b int, grayStr, fullStr string) (clr clrType) { +func rgbColorValue(r, g, b int, grayStr, fullStr string) (clr colorType) {  	clr.ir, clr.r = colorComp(r)  	clr.ig, clr.g = colorComp(g)  	clr.ib, clr.b = colorComp(b) +	clr.mode = colorModeRGB  	clr.gray = clr.ir == clr.ig && clr.r == clr.b  	if len(grayStr) > 0 {  		if clr.gray { @@ -759,13 +754,15 @@ func colorValue(r, g, b int, grayStr, fullStr string) (clr clrType) {  // The method can be called before the first page is created. The value is  // retained from page to page.  func (f *Fpdf) SetDrawColor(r, g, b int) { -	f.color.draw = colorValue(r, g, b, "G", "RG") +	f.color.draw = rgbColorValue(r, g, b, "G", "RG")  	if f.page > 0 {  		f.out(f.color.draw.str)  	}  } -// GetDrawColor returns the current draw color as RGB components (0 - 255). +// GetDrawColor returns the most recently set draw color as RGB components (0 - +// 255). This will not be the current value if a draw color of some other type +// (for example, spot) has been more recently set.  func (f *Fpdf) GetDrawColor() (int, int, int) {  	return f.color.draw.ir, f.color.draw.ig, f.color.draw.ib  } @@ -775,14 +772,16 @@ func (f *Fpdf) GetDrawColor() (int, int, int) {  // -255). The method can be called before the first page is created and the  // value is retained from page to page.  func (f *Fpdf) SetFillColor(r, g, b int) { -	f.color.fill = colorValue(r, g, b, "g", "rg") +	f.color.fill = rgbColorValue(r, g, b, "g", "rg")  	f.colorFlag = f.color.fill.str != f.color.text.str  	if f.page > 0 {  		f.out(f.color.fill.str)  	}  } -// GetFillColor returns the current fill color as RGB components (0 - 255). +// GetFillColor returns the most recently set fill color as RGB components (0 - +// 255). This will not be the current value if a fill color of some other type +// (for example, spot) has been more recently set.  func (f *Fpdf) GetFillColor() (int, int, int) {  	return f.color.fill.ir, f.color.fill.ig, f.color.fill.ib  } @@ -791,11 +790,13 @@ func (f *Fpdf) GetFillColor() (int, int, int) {  // components (0 - 255). The method can be called before the first page is  // created. The value is retained from page to page.  func (f *Fpdf) SetTextColor(r, g, b int) { -	f.color.text = colorValue(r, g, b, "g", "rg") +	f.color.text = rgbColorValue(r, g, b, "g", "rg")  	f.colorFlag = f.color.fill.str != f.color.text.str  } -// GetTextColor returns the current text color as RGB components (0 - 255). +// GetTextColor returns the most recently set text color as RGB components (0 - +// 255). This will not be the current value if a text color of some other type +// (for example, spot) has been more recently set.  func (f *Fpdf) GetTextColor() (int, int, int) {  	return f.color.text.ir, f.color.text.ig, f.color.text.ib  } @@ -1183,8 +1184,8 @@ func (f *Fpdf) gradientClipEnd() {  func (f *Fpdf) gradient(tp int, r1, g1, b1 int, r2, g2, b2 int, x1, y1 float64, x2, y2 float64, r float64) {  	pos := len(f.gradientList) -	clr1 := colorValue(r1, g1, b1, "", "") -	clr2 := colorValue(r2, g2, b2, "", "") +	clr1 := rgbColorValue(r1, g1, b1, "", "") +	clr2 := rgbColorValue(r2, g2, b2, "", "")  	f.gradientList = append(f.gradientList, gradientType{tp, clr1.str, clr2.str,  		x1, y1, x2, y2, r, 0})  	f.outf("/Sh%d sh", pos) @@ -3477,6 +3478,7 @@ func (f *Fpdf) putresourcedict() {  	}  	// Layers  	f.layerPutResourceDict() +	f.spotColorPutResourceDict()  }  func (f *Fpdf) putBlendModes() { @@ -3542,6 +3544,7 @@ func (f *Fpdf) putresources() {  	f.layerPutLayers()  	f.putBlendModes()  	f.putGradients() +	f.putSpotColors()  	f.putfonts()  	if f.err != nil {  		return diff --git a/fpdf_test.go b/fpdf_test.go index db46528..76ef558 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -2046,3 +2046,17 @@ func ExampleFpdf_SetJavascript() {  	// Output:  	// Successfully generated pdf/Fpdf_SetJavascript.pdf  } + +// This example demonstrates spot color use +func ExampleFpdf_AddSpotColor() { +	pdf := gofpdf.New("P", "mm", "A4", "") +	pdf.AddSpotColor("PANTONE 145 CVC", 0, 42, 100, 25) +	pdf.AddPage() +	pdf.SetFillSpotColor("PANTONE 145 CVC", 90) +	pdf.Rect(80, 40, 50, 50, "F") +	fileStr := example.Filename("Fpdf_AddSpotColor") +	err := pdf.OutputFileAndClose(fileStr) +	example.Summary(err, fileStr) +	// Output: +	// Successfully generated pdf/Fpdf_AddSpotColor.pdf +} diff --git a/spotcolor.go b/spotcolor.go new file mode 100644 index 0000000..33aca82 --- /dev/null +++ b/spotcolor.go @@ -0,0 +1,184 @@ +// Copyright (c) Kurt Jung (Gmail: kurt.w.jung) +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// Adapted from http://www.fpdf.org/en/script/script89.php by Olivier PLATHEY + +package gofpdf + +import ( +	"fmt" +	"strings" +) + +func byteBound(v byte) byte { +	if v > 100 { +		return 100 +	} +	return v +} + +// AddSpotColor adds an ink-based CMYK color to the gofpdf instance and +// associates it with the specified name. The individual components specify +// percentages ranging from 0 to 100. Values above this are quietly capped to +// 100. An error occurs if the specified name is already associated with a +// color. +func (f *Fpdf) AddSpotColor(nameStr string, c, m, y, k byte) { +	if f.err == nil { +		_, ok := f.spotColorMap[nameStr] +		if !ok { +			id := len(f.spotColorMap) + 1 +			f.spotColorMap[nameStr] = spotColorType{ +				id: id, +				val: cmykColorType{ +					c: byteBound(c), +					m: byteBound(m), +					y: byteBound(y), +					k: byteBound(k), +				}, +			} +		} else { +			f.err = fmt.Errorf("name \"%s\" is already associated with a spot color", nameStr) +		} +	} +} + +func (f *Fpdf) getSpotColor(nameStr string) (clr spotColorType, ok bool) { +	if f.err == nil { +		clr, ok = f.spotColorMap[nameStr] +		if !ok { +			f.err = fmt.Errorf("spot color name \"%s\" is not registered", nameStr) +		} +	} +	return +} + +// SetDrawSpotColor sets the current draw color to the spot color associated +// with nameStr. An error occurs if the name is not associated with a color. +// The value for tint ranges from 0 (no intensity) to 100 (full intensity). It +// is quietly bounded to this range. +func (f *Fpdf) SetDrawSpotColor(nameStr string, tint byte) { +	var clr spotColorType +	var ok bool + +	clr, ok = f.getSpotColor(nameStr) +	if ok { +		f.color.draw.mode = colorModeSpot +		f.color.draw.spotStr = nameStr +		f.color.draw.str = sprintf("/CS%d CS %.3f SCN", clr.id, float64(byteBound(tint))/100) +		if f.page > 0 { +			f.out(f.color.draw.str) +		} +	} +} + +// SetFillSpotColor sets the current fill color to the spot color associated +// with nameStr. An error occurs if the name is not associated with a color. +// The value for tint ranges from 0 (no intensity) to 100 (full intensity). It +// is quietly bounded to this range. +func (f *Fpdf) SetFillSpotColor(nameStr string, tint byte) { +	var clr spotColorType +	var ok bool + +	clr, ok = f.getSpotColor(nameStr) +	if ok { +		f.color.fill.mode = colorModeSpot +		f.color.fill.spotStr = nameStr +		f.color.fill.str = sprintf("/CS%d cs %.3f scn", clr.id, float64(byteBound(tint))/100) +		f.colorFlag = f.color.fill.str != f.color.text.str +		if f.page > 0 { +			f.out(f.color.fill.str) +		} +	} +} + +// SetTextSpotColor sets the current text color to the spot color associated +// with nameStr. An error occurs if the name is not associated with a color. +// The value for tint ranges from 0 (no intensity) to 100 (full intensity). It +// is quietly bounded to this range. +func (f *Fpdf) SetTextSpotColor(nameStr string, tint byte) { +	var clr spotColorType +	var ok bool + +	clr, ok = f.getSpotColor(nameStr) +	if ok { +		f.color.text.mode = colorModeSpot +		f.color.text.spotStr = nameStr +		f.color.text.str = sprintf("/CS%d cs %.3f scn", clr.id, float64(byteBound(tint))/100) +		f.colorFlag = f.color.text.str != f.color.text.str +	} +} + +func (f *Fpdf) returnSpotColor(clr colorType) (name string, c, m, y, k byte) { +	var spotClr spotColorType +	var ok bool + +	name = clr.spotStr +	if name != "" { +		spotClr, ok = f.getSpotColor(name) +		if ok { +			c = spotClr.val.c +			m = spotClr.val.m +			y = spotClr.val.y +			k = spotClr.val.k +		} +	} +	return +} + +// GetDrawSpotColor returns the most recently used spot color information for +// drawing. This will not be the current drawing color if some other color type +// such as RGB is active. If no spot color has been set for drawing, zero +// values are returned. +func (f *Fpdf) GetDrawSpotColor() (name string, c, m, y, k byte) { +	return f.returnSpotColor(f.color.draw) +} + +// GetTextSpotColor returns the most recently used spot color information for +// text output. This will not be the current text color if some other color +// type such as RGB is active. If no spot color has been set for text, zero +// values are returned. +func (f *Fpdf) GetTextSpotColor() (name string, c, m, y, k byte) { +	return f.returnSpotColor(f.color.text) +} + +// GetFillSpotColor returns the most recently used spot color information for +// fill output. This will not be the current fill color if some other color +// type such as RGB is active. If no fill spot color has been set, zero values +// are returned. +func (f *Fpdf) GetFillSpotColor() (name string, c, m, y, k byte) { +	return f.returnSpotColor(f.color.fill) +} + +func (f *Fpdf) putSpotColors() { +	for k, v := range f.spotColorMap { +		f.newobj() +		f.outf("[/Separation /%s", strings.Replace(k, " ", "#20", -1)) +		f.out("/DeviceCMYK <<") +		f.out("/Range [0 1 0 1 0 1 0 1] /C0 [0 0 0 0] ") +		f.outf("/C1 [%.3f %.3f %.3f %.3f] ", float64(v.val.c)/100, float64(v.val.m)/100, +			float64(v.val.y)/100, float64(v.val.k)/100) +		f.out("/FunctionType 2 /Domain [0 1] /N 1>>]") +		f.out("endobj") +		v.objID = f.n +		f.spotColorMap[k] = v +	} +} + +func (f *Fpdf) spotColorPutResourceDict() { +	f.out("/ColorSpace <<") +	for _, clr := range f.spotColorMap { +		f.outf("/CS%d %d 0 R", clr.id, clr.objID) +	} +	f.out(">>") +} | 
