diff options
| author | Kurt Jung <kurt.w.jung@code.google.com> | 2013-08-24 16:11:53 -0400 | 
|---|---|---|
| committer | Kurt Jung <kurt.w.jung@code.google.com> | 2013-08-24 16:11:53 -0400 | 
| commit | 2794792c13f56dbb2bbabe2c640b9ee29117709f (patch) | |
| tree | c70c3d0f07ba6a20b783e49e701fff8b04df7a64 | |
| parent | 1fd34b058bc3f9408613f027fa3bb0795fdff2a6 (diff) | |
Added PageSize() and NewCustom() methods
| -rw-r--r-- | def.go | 22 | ||||
| -rw-r--r-- | fpdf.go | 216 | ||||
| -rw-r--r-- | fpdf_test.go | 45 | ||||
| -rw-r--r-- | ttfparser.go | 1 | 
4 files changed, 168 insertions, 116 deletions
| @@ -36,12 +36,15 @@ type gradientType struct {  	objNum            int  } -type sizeType struct { -	wd, ht float64 +// Wd and Ht specify the horizontal and vertical extents of a document page. +type SizeType struct { +	Wd, Ht float64  } -type pointType struct { -	x, y float64 +// X and Y specify the horizontal and vertical coordinates of a point, +// typically used in drawing. +type PointType struct { +	X, Y float64  }  type imageInfoType struct { @@ -86,10 +89,11 @@ type Fpdf struct {  	k                float64                  // scale factor (number of points in user unit)  	defOrientation   string                   // default orientation  	curOrientation   string                   // current orientation -	stdpageSizes     map[string]sizeType      // standard page sizes -	defPageSize      sizeType                 // default page size -	curPageSize      sizeType                 // current page size -	pageSizes        map[int]sizeType         // used for pages with non default sizes or orientations +	stdPageSizes     map[string]SizeType      // standard page sizes +	defPageSize      SizeType                 // default page size +	curPageSize      SizeType                 // current page size +	pageSizes        map[int]SizeType         // used for pages with non default sizes or orientations +	unitStr          string                   // unit of measure for all rendered objects except fonts  	wPt, hPt         float64                  // dimensions of current page in points  	w, h             float64                  // dimensions of current page in user unit  	lMargin          float64                  // left margin @@ -141,7 +145,7 @@ type Fpdf struct {  	blendList        []blendModeType          // slice[idx] of alpha transparency modes, 1-based  	blendMap         map[string]int           // map into blendList  	gradientList     []gradientType           // slice[idx] of gradient records -	clipActive       bool                     // clippping operation is underway +	clipNest         int                      // Number of active clipping contexts  	err              error                    // Set if error occurs during life cycle of instance  } @@ -45,24 +45,7 @@ func (b *fmtBuffer) printf(fmtStr string, args ...interface{}) {  	b.Buffer.WriteString(fmt.Sprintf(fmtStr, args...))  } -// New returns a pointer to a new Fpdf instance. Its methods are subsequently -// called to produce a single PDF document. -// -// orientationStr specifies the default page orientation. For portrait mode, -// specify "P" or "Portrait". For landscape mode, specify "L" or "Landscape". -// An empty string will be replaced with "P". -// -// unitStr specifies the unit of length used in size parameters for elements -// other than fonts, which are always measured in points. Specify "pt" for -// point, "mm" for millimeter, "cm" for centimeter, or "in" for inch. An empty -// string will be replaced with "mm". -// -// sizeStr specifies the page size. Acceptable values are "A3", "A4", "A5", -// "Letter", or "Legal". An empty string will be replaced with "A4". -// -// fontDirStr specifies the file system location in which font resources will -// be found. An empty string is replaced with ".". -func New(orientationStr, unitStr, sizeStr, fontDirStr string) (f *Fpdf) { +func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType) (f *Fpdf) {  	f = new(Fpdf)  	if orientationStr == "" {  		orientationStr = "P" @@ -80,7 +63,7 @@ func New(orientationStr, unitStr, sizeStr, fontDirStr string) (f *Fpdf) {  	f.n = 2  	f.pages = make([]*bytes.Buffer, 0, 8)  	f.pages = append(f.pages, bytes.NewBufferString("")) // pages[0] is unused (1-based) -	f.pageSizes = make(map[int]sizeType) +	f.pageSizes = make(map[int]SizeType)  	f.state = 0  	f.fonts = make(map[string]fontDefType)  	f.fontFiles = make(map[string]fontFileType) @@ -125,16 +108,21 @@ func New(orientationStr, unitStr, sizeStr, fontDirStr string) (f *Fpdf) {  		f.err = fmt.Errorf("Incorrect unit %s", unitStr)  		return  	} +	f.unitStr = unitStr  	// Page sizes -	f.stdpageSizes = make(map[string]sizeType) -	f.stdpageSizes["a3"] = sizeType{841.89, 1190.55} -	f.stdpageSizes["a4"] = sizeType{595.28, 841.89} -	f.stdpageSizes["a5"] = sizeType{420.94, 595.28} -	f.stdpageSizes["letter"] = sizeType{612, 792} -	f.stdpageSizes["legal"] = sizeType{612, 1008} -	f.defPageSize = f.getpagesizestr(sizeStr) -	if f.err != nil { -		return +	f.stdPageSizes = make(map[string]SizeType) +	f.stdPageSizes["a3"] = SizeType{841.89, 1190.55} +	f.stdPageSizes["a4"] = SizeType{595.28, 841.89} +	f.stdPageSizes["a5"] = SizeType{420.94, 595.28} +	f.stdPageSizes["letter"] = SizeType{612, 792} +	f.stdPageSizes["legal"] = SizeType{612, 1008} +	if size.Wd > 0 && size.Ht > 0 { +		f.defPageSize = size +	} else { +		f.defPageSize = f.getpagesizestr(sizeStr) +		if f.err != nil { +			return +		}  	}  	f.curPageSize = f.defPageSize  	// Page orientation @@ -142,13 +130,13 @@ func New(orientationStr, unitStr, sizeStr, fontDirStr string) (f *Fpdf) {  	switch orientationStr {  	case "p", "portrait":  		f.defOrientation = "P" -		f.w = f.defPageSize.wd -		f.h = f.defPageSize.ht +		f.w = f.defPageSize.Wd +		f.h = f.defPageSize.Ht  		// dbg("Assign h: %8.2f", f.h)  	case "l", "landscape":  		f.defOrientation = "L" -		f.w = f.defPageSize.ht -		f.h = f.defPageSize.wd +		f.w = f.defPageSize.Ht +		f.h = f.defPageSize.Wd  	default:  		f.err = fmt.Errorf("Incorrect orientation: %s", orientationStr)  		return @@ -185,6 +173,46 @@ func New(orientationStr, unitStr, sizeStr, fontDirStr string) (f *Fpdf) {  	return  } +// InitType is used with NewCustom() to customize an Fpdf instance. +// OrientationStr, UnitStr, SizeStr and FontDirStr correspond to the arguments +// accepted by New(). If the Wd and Ht fields of Size are each greater than +// zero, Size will be used to set the default page size rather than SizeStr. +type InitType struct { +	OrientationStr string +	UnitStr        string +	SizeStr        string +	Size           SizeType +	FontDirStr     string +} + +// NewCustom returns a pointer to a new Fpdf instance. Its methods are +// subsequently called to produce a single PDF document. NewCustom() is an +// alternative to New() that provides additional customization. +func NewCustom(init *InitType) (f *Fpdf) { +	return fpdfNew(init.OrientationStr, init.UnitStr, init.SizeStr, init.FontDirStr, init.Size) +} + +// New returns a pointer to a new Fpdf instance. Its methods are subsequently +// called to produce a single PDF document. +// +// orientationStr specifies the default page orientation. For portrait mode, +// specify "P" or "Portrait". For landscape mode, specify "L" or "Landscape". +// An empty string will be replaced with "P". +// +// unitStr specifies the unit of length used in size parameters for elements +// other than fonts, which are always measured in points. Specify "pt" for +// point, "mm" for millimeter, "cm" for centimeter, or "in" for inch. An empty +// string will be replaced with "mm". +// +// sizeStr specifies the page size. Acceptable values are "A3", "A4", "A5", +// "Letter", or "Legal". An empty string will be replaced with "A4". +// +// fontDirStr specifies the file system location in which font resources will +// be found. An empty string is replaced with ".". +func New(orientationStr, unitStr, sizeStr, fontDirStr string) (f *Fpdf) { +	return fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr, SizeType{0, 0}) +} +  // Returns true if no processing errors have occurred.  func (f *Fpdf) Ok() bool {  	return f.err == nil @@ -407,7 +435,7 @@ func (f *Fpdf) open() {  // an invalid document.  func (f *Fpdf) Close() {  	if f.err == nil { -		if f.clipActive { +		if f.clipNest > 0 {  			f.err = fmt.Errorf("Clip procedure must be explicitly ended")  		}  	} @@ -436,13 +464,27 @@ func (f *Fpdf) Close() {  	return  } +// Returns the width and height of the specified page in the units established +// in New(). These return values are followed by the unit of measure itself. If +// pageNum is zero or otherwise out of bounds, it returns the default page +// size, that is, the size of the page that would be added by AddPage(). +func (f *Fpdf) PageSize(pageNum int) (wd, ht float64, unitStr string) { +	sz, ok := f.pageSizes[pageNum] +	if ok { +		sz.Wd, sz.Ht = sz.Wd/f.k, sz.Ht/f.k +	} else { +		sz = f.defPageSize // user units +	} +	return sz.Wd, sz.Ht, f.unitStr +} +  // Adds a new page with non-default orientation or size. See AddPage() for more  // details.  //  // See New() for a description of orientationStr.  //  // size specifies the size of the new page in the units established in New(). -func (f *Fpdf) AddPageFormat(orientationStr string, size sizeType) { +func (f *Fpdf) AddPageFormat(orientationStr string, size SizeType) {  	if f.err != nil {  		return  	} @@ -948,17 +990,6 @@ func (f *Fpdf) RadialGradient(x, y, w, h float64, r1, g1, b1 int, r2, g2, b2 int  	f.gradientClipEnd()  } -func (f *Fpdf) setClipActive() bool { -	if f.err == nil { -		if f.clipActive { -			f.err = fmt.Errorf("Clipping operation already active") -		} else { -			f.clipActive = true -		} -	} -	return f.err == nil -} -  // Begins a rectangular clipping operation. The rectangle is of width w and  // height h. Its upper left corner is positioned at point (x, y). outline is  // true to draw a border with the current draw color and line width centered on @@ -969,9 +1000,7 @@ func (f *Fpdf) setClipActive() bool {  //  // See tutorial 14 for an example of this function.  func (f *Fpdf) ClipRect(x, y, w, h float64, outline bool) { -	if !f.setClipActive() { -		return -	} +	f.clipNest++  	f.outf("q %.2f %.2f %.2f %.2f re W %s", x*f.k, (f.h-y)*f.k, w*f.k, -h*f.k, strIf(outline, "S", "n"))  } @@ -986,9 +1015,7 @@ func (f *Fpdf) ClipRect(x, y, w, h float64, outline bool) {  //  // See tutorial 14 for an example of this function.  func (f *Fpdf) ClipText(x, y float64, txtStr string, outline bool) { -	if !f.setClipActive() { -		return -	} +	f.clipNest++  	f.outf("q BT %.2f %.2f Td %d Tr (%s) Tj ET", x*f.k, (f.h-y)*f.k, intIf(outline, 5, 7), f.escape(txtStr))  } @@ -1009,9 +1036,7 @@ func (f *Fpdf) clipArc(x1, y1, x2, y2, x3, y3 float64) {  //  // See tutorial 14 for an example of this function.  func (f *Fpdf) ClipRoundedRect(x, y, w, h, r float64, outline bool) { -	if !f.setClipActive() { -		return -	} +	f.clipNest++  	k := f.k  	hp := f.h  	myArc := (4.0 / 3.0) * (math.Sqrt2 - 1.0) @@ -1045,9 +1070,7 @@ func (f *Fpdf) ClipRoundedRect(x, y, w, h, r float64, outline bool) {  //  // See tutorial 14 for an example of this function.  func (f *Fpdf) ClipEllipse(x, y, rx, ry float64, outline bool) { -	if !f.setClipActive() { -		return -	} +	f.clipNest++  	lx := (4.0 / 3.0) * rx * (math.Sqrt2 - 1)  	ly := (4.0 / 3.0) * ry * (math.Sqrt2 - 1)  	k := f.k @@ -1095,16 +1118,14 @@ func (f *Fpdf) ClipCircle(x, y, r float64, outline bool) {  // ClipEnd() to restore unclipped operations.  //  // See tutorial 14 for an example of this function. -func (f *Fpdf) ClipPolygon(points []pointType, outline bool) { -	if !f.setClipActive() { -		return -	} +func (f *Fpdf) ClipPolygon(points []PointType, outline bool) { +	f.clipNest++  	var s fmtBuffer  	h := f.h  	k := f.k  	s.printf("q ")  	for j, pt := range points { -		s.printf("%.2f %.2f %s ", pt.x*k, (h-pt.y)*k, strIf(j == 0, "m", "l")) +		s.printf("%.2f %.2f %s ", pt.X*k, (h-pt.Y)*k, strIf(j == 0, "m", "l"))  	}  	s.printf("h W %s", strIf(outline, "S", "n"))  	f.out(s.String()) @@ -1112,14 +1133,14 @@ func (f *Fpdf) ClipPolygon(points []pointType, outline bool) {  // Ends a clipping operation that was started with a call to ClipRect(),  // ClipRoundedRect(), ClipText(), ClipEllipse(), ClipCircle() or ClipPolygon(). -// Only one clipping operation can be active at a time, and the document cannot -// be successfully output while a clipping operation is active. +// Clipping operations can be nested. The document cannot be successfully +// output while a clipping operation is active.  //  // See tutorial 14 for an example of this function.  func (f *Fpdf) ClipEnd() {  	if f.err == nil { -		if f.clipActive { -			f.clipActive = false +		if f.clipNest > 0 { +			f.clipNest--  			f.out("Q")  		} else {  			f.err = fmt.Errorf("Error attempting to end clip operation") @@ -1965,45 +1986,40 @@ func (f *Fpdf) Output(w io.Writer) error {  	if err != nil {  		f.err = err  	} -	dump("pdf.txt", f.stdpageSizes, +	dump("pdf.txt", f.stdPageSizes,  		f.defPageSize,  		f.curPageSize,  		f.pageSizes)  	return f.err  } -func (f *Fpdf) getpagesizestr(sizeStr string) (size sizeType) { +func (f *Fpdf) getpagesizestr(sizeStr string) (size SizeType) {  	if f.err != nil {  		return  	}  	sizeStr = strings.ToLower(sizeStr)  	// dbg("Size [%s]", sizeStr) -	if sizeStr == "" { -		// dbg("not found %s", sizeStr) -		size = f.defPageSize -	} else { -		var ok bool -		size, ok = f.stdpageSizes[sizeStr] -		if ok { -			// dbg("found %s", sizeStr) -			size.wd /= f.k -			size.ht /= f.k +	var ok bool +	size, ok = f.stdPageSizes[sizeStr] +	if ok { +		// dbg("found %s", sizeStr) +		size.Wd /= f.k +		size.Ht /= f.k -		} else { -			f.err = fmt.Errorf("Unknown page size %s", sizeStr) -		} +	} else { +		f.err = fmt.Errorf("Unknown page size %s", sizeStr)  	}  	return  } -func (f *Fpdf) _getpagesize(size sizeType) sizeType { -	if size.wd > size.ht { -		size.wd, size.ht = size.ht, size.wd +func (f *Fpdf) _getpagesize(size SizeType) SizeType { +	if size.Wd > size.Ht { +		size.Wd, size.Ht = size.Ht, size.Wd  	}  	return size  } -func (f *Fpdf) beginpage(orientationStr string, size sizeType) { +func (f *Fpdf) beginpage(orientationStr string, size SizeType) {  	if f.err != nil {  		return  	} @@ -2020,14 +2036,14 @@ func (f *Fpdf) beginpage(orientationStr string, size sizeType) {  	} else {  		orientationStr = strings.ToUpper(orientationStr[0:1])  	} -	if orientationStr != f.curOrientation || size.wd != f.curPageSize.wd || size.ht != f.curPageSize.ht { +	if orientationStr != f.curOrientation || size.Wd != f.curPageSize.Wd || size.Ht != f.curPageSize.Ht {  		// New size or orientation  		if orientationStr == "P" { -			f.w = size.wd -			f.h = size.ht +			f.w = size.Wd +			f.h = size.Ht  		} else { -			f.w = size.ht -			f.h = size.wd +			f.w = size.Ht +			f.h = size.Wd  		}  		f.wPt = f.w * f.k  		f.hPt = f.h * f.k @@ -2035,8 +2051,8 @@ func (f *Fpdf) beginpage(orientationStr string, size sizeType) {  		f.curOrientation = orientationStr  		f.curPageSize = size  	} -	if orientationStr != f.defOrientation || size.wd != f.defPageSize.wd || size.ht != f.defPageSize.ht { -		f.pageSizes[f.page] = sizeType{f.wPt, f.hPt} +	if orientationStr != f.defOrientation || size.Wd != f.defPageSize.Wd || size.Ht != f.defPageSize.Ht { +		f.pageSizes[f.page] = SizeType{f.wPt, f.hPt}  	}  	return  } @@ -2411,7 +2427,7 @@ func (f *Fpdf) outf(fmtStr string, args ...interface{}) {  func (f *Fpdf) putpages() {  	var wPt, hPt float64 -	var pageSize sizeType +	var pageSize SizeType  	// var linkList []linkType  	var ok bool  	nb := f.page @@ -2428,11 +2444,11 @@ func (f *Fpdf) putpages() {  		}  	}  	if f.defOrientation == "P" { -		wPt = f.defPageSize.wd * f.k -		hPt = f.defPageSize.ht * f.k +		wPt = f.defPageSize.Wd * f.k +		hPt = f.defPageSize.Ht * f.k  	} else { -		wPt = f.defPageSize.ht * f.k -		hPt = f.defPageSize.wd * f.k +		wPt = f.defPageSize.Ht * f.k +		hPt = f.defPageSize.Wd * f.k  	}  	for n := 1; n <= nb; n++ {  		// Page @@ -2441,7 +2457,7 @@ func (f *Fpdf) putpages() {  		f.out("/Parent 1 0 R")  		pageSize, ok = f.pageSizes[n]  		if ok { -			f.outf("/MediaBox [0 0 %.2f %.2f]", pageSize.wd, pageSize.ht) +			f.outf("/MediaBox [0 0 %.2f %.2f]", pageSize.Wd, pageSize.Ht)  		}  		f.out("/Resources 2 0 R")  		// Links @@ -2455,11 +2471,11 @@ func (f *Fpdf) putpages() {  					annots.printf("/A <</S /URI /URI %s>>>>", f.textstring(pl.linkStr))  				} else {  					l := f.links[pl.link] -					var sz sizeType +					var sz SizeType  					var h float64  					sz, ok = f.pageSizes[l.page]  					if ok { -						h = sz.ht +						h = sz.Ht  					} else {  						h = hPt  					} diff --git a/fpdf_test.go b/fpdf_test.go index c27263e..9113057 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -798,11 +798,15 @@ func ExampleFpdf_tutorial14() {  	pdf.ClipEnd()  	y += 55 -	pdf.ClipRect(10, y, 160, 20, true) -	pdf.SetFillColor(64, 128, 128) -	pdf.Circle(40, y+10, 15, "F") -	pdf.SetFillColor(128, 64, 64) -	pdf.Ellipse(90, y+10, 30, 40, 45, "F") +	pdf.ClipRect(10, y, 105, 20, true) +	pdf.SetFillColor(255, 255, 255) +	pdf.Rect(10, y, 105, 20, "F") +	pdf.ClipCircle(40, y+10, 15, false) +	pdf.RadialGradient(25, y, 30, 30, 220, 250, 220, 40, 60, 40, 0.3, 0.85, 0.3, 0.85, 0.5) +	pdf.ClipEnd() +	pdf.ClipEllipse(80, y+10, 20, 15, false) +	pdf.RadialGradient(60, y, 40, 30, 250, 220, 220, 60, 40, 40, 0.3, 0.85, 0.3, 0.85, 0.5) +	pdf.ClipEnd()  	pdf.ClipEnd()  	y += 28 @@ -814,8 +818,8 @@ func ExampleFpdf_tutorial14() {  	pdf.RadialGradient(50, y, 20, 20, 220, 220, 250, 40, 40, 60, 0.3, 0.7, 0.3, 0.7, 0.5)  	pdf.ClipEnd() -	pdf.ClipPolygon([]pointType{{80, y + 20}, {90, y}, {100, y + 20}}, true) -	pdf.LinearGradient(80, y, 20, 20, 240, 240, 250, 80, 80, 220, 0.5, 1, 0.5, 0) +	pdf.ClipPolygon([]PointType{{80, y + 20}, {90, y}, {100, y + 20}}, true) +	pdf.LinearGradient(80, y, 20, 20, 250, 220, 250, 60, 40, 60, 0.5, 1, 0.5, 0.5)  	pdf.ClipEnd()  	y += 30 @@ -832,3 +836,30 @@ func ExampleFpdf_tutorial14() {  	// Output:  	// Successfully generated pdf/tutorial14.pdf  } + +// Page size example +func ExampleFpdf_tutorial15() { +	pdf := NewCustom(&InitType{UnitStr: "in", Size: SizeType{6, 6}, FontDirStr: FONT_DIR}) +	pdf.SetMargins(0.5, 1, 0.5) +	pdf.SetFont("Times", "", 14) +	pdf.AddPageFormat("L", SizeType{3, 12}) +	pdf.SetXY(0.5, 1.5) +	pdf.CellFormat(11, 0.2, "12 in x 3 in", "", 0, "C", false, 0, "") +	pdf.AddPage() // Default size established in NewCustom() +	pdf.SetXY(0.5, 3) +	pdf.CellFormat(5, 0.2, "6 in x 6 in", "", 0, "C", false, 0, "") +	pdf.AddPageFormat("P", SizeType{3, 12}) +	pdf.SetXY(0.5, 6) +	pdf.CellFormat(2, 0.2, "3 in x 12 in", "", 0, "C", false, 0, "") +	for j := 0; j <= 3; j++ { +		wd, ht, u := pdf.PageSize(j) +		fmt.Printf("%d: %6.2f %s, %6.2f %s\n", j, wd, u, ht, u) +	} +	pdf.OutputAndClose(docWriter(pdf, 15)) +	// Output: +	// 0:   6.00 in,   6.00 in +	// 1:  12.00 in,   3.00 in +	// 2:   6.00 in,   6.00 in +	// 3:   3.00 in,  12.00 in +	// Successfully generated pdf/tutorial15.pdf +} diff --git a/ttfparser.go b/ttfparser.go index 323f144..41574e2 100644 --- a/ttfparser.go +++ b/ttfparser.go @@ -30,6 +30,7 @@ import (  	"strings"  ) +// This structure contains metrics of a TrueType font.  type TtfType struct {  	Embeddable             bool  	UnitsPerEm             uint16 | 
