summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKurt Jung <kurt.w.jung@gmail.com>2015-07-12 11:30:00 -0400
committerKurt Jung <kurt.w.jung@gmail.com>2015-07-12 11:30:00 -0400
commit0fc3e570463d3cbe35071b0dc71e3f63c074f7d1 (patch)
treea363671fb0fd63a61fe4ed084b576799a4c843d8
parent1451e353048cd88e1083c1be60cceaddc0d9b84d (diff)
parentf00c0a597be2dca589bdd7bd6ba5937b19ebdcfe (diff)
Merge pull request #26 from stanim/fontdesc
Implement vertical baseline alignment for text
-rw-r--r--.gitignore1
-rw-r--r--def.go90
-rw-r--r--fpdf.go39
-rw-r--r--fpdf_test.go42
4 files changed, 141 insertions, 31 deletions
diff --git a/.gitignore b/.gitignore
index d23e6cd..91bef76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ pdf/*.pdf
look
open
pdf.txt
+private
*.sublime*
font/Ubuntu-*
*.0
diff --git a/def.go b/def.go
index 15836d0..3973351 100644
--- a/def.go
+++ b/def.go
@@ -246,21 +246,91 @@ type fontBoxType struct {
Xmin, Ymin, Xmax, Ymax int
}
-type fontDescType struct {
- Ascent int
- Descent int
- CapHeight int
- Flags int
- FontBBox fontBoxType
- ItalicAngle int
- StemV int
+// Font flags for FontDescType.Flags as defined in the pdf specification.
+const (
+ // FontFlagFixedPitch is set if all glyphs have the same width (as
+ // opposed to proportional or variable-pitch fonts, which have
+ // different widths).
+ FontFlagFixedPitch = 1 << 0
+ // FontFlagSerif is set if glyphs have serifs, which are short
+ // strokes drawn at an angle on the top and bottom of glyph stems.
+ // (Sans serif fonts do not have serifs.)
+ FontFlagSerif = 1 << 1
+ // FontFlagSymbolic is set if font contains glyphs outside the
+ // Adobe standard Latin character set. This flag and the
+ // Nonsymbolic flag shall not both be set or both be clear.
+ FontFlagSymbolic = 1 << 2
+ // FontFlagScript is set if glyphs resemble cursive handwriting.
+ FontFlagScript = 1 << 3
+ // FontFlagNonsymbolic is set if font uses the Adobe standard
+ // Latin character set or a subset of it.
+ FontFlagNonsymbolic = 1 << 5
+ // FontFlagItalic is set if glyphs have dominant vertical strokes
+ // that are slanted.
+ FontFlagItalic = 1 << 6
+ // FontFlagAllCap is set if font contains no lowercase letters;
+ // typically used for display purposes, such as for titles or
+ // headlines.
+ FontFlagAllCap = 1 << 16
+ // SmallCap is set if font contains both uppercase and lowercase
+ // letters. The uppercase letters are similar to those in the
+ // regular version of the same typeface family. The glyphs for the
+ // lowercase letters have the same shapes as the corresponding
+ // uppercase letters, but they are sized and their proportions
+ // adjusted so that they have the same size and stroke weight as
+ // lowercase glyphs in the same typeface family.
+ SmallCap = 1 << 18
+ // ForceBold determines whether bold glyphs shall be painted with
+ // extra pixels even at very small text sizes by a conforming
+ // reader. If the ForceBold flag is set, features of bold glyphs
+ // may be thickened at small text sizes.
+ ForceBold = 1 << 18
+)
+
+// FontDescType (font descriptor) specifies metrics and other
+// attributes of a font, as distinct from the metrics of individual
+// glyphs (as defined in the pdf specification).
+type FontDescType struct {
+ // The maximum height above the baseline reached by glyphs in this
+ // font (for example for "S"). The height of glyphs for accented
+ // characters shall be excluded.
+ Ascent int
+ // The maximum depth below the baseline reached by glyphs in this
+ // font. The value shall be a negative number.
+ Descent int
+ // The vertical coordinate of the top of flat capital letters,
+ // measured from the baseline (for example "H").
+ CapHeight int
+ // A collection of flags defining various characteristics of the
+ // font. (See the FontFlag* constants.)
+ Flags int
+ // A rectangle, expressed in the glyph coordinate system, that
+ // shall specify the font bounding box. This should be the smallest
+ // rectangle enclosing the shape that would result if all of the
+ // glyphs of the font were placed with their origins coincident
+ // and then filled.
+ FontBBox fontBoxType
+ // The angle, expressed in degrees counterclockwise from the
+ // vertical, of the dominant vertical strokes of the font. (The
+ // 9-o’clock position is 90 degrees, and the 3-o’clock position
+ // is –90 degrees.) The value shall be negative for fonts that
+ // slope to the right, as almost all italic fonts do.
+ ItalicAngle int
+ // The thickness, measured horizontally, of the dominant vertical
+ // stems of glyphs in the font.
+ StemV int
+ // The width to use for character codes whose widths are not
+ // specified in a font dictionary’s Widths array. This shall have
+ // a predictable effect only if all such codes map to glyphs whose
+ // actual widths are the same as the value of the MissingWidth
+ // entry. (Default value: 0.)
MissingWidth int
}
type fontDefType struct {
Tp string // "Core", "TrueType", ...
Name string // "Courier-Bold", ...
- Desc fontDescType // Font descriptor
+ Desc FontDescType // Font descriptor
Up int // Underline position
Ut int // Underline thickness
Cw [256]int // Character width by ordinal
@@ -285,5 +355,5 @@ type fontInfoType struct {
UnderlinePosition int
Widths [256]int
Size1, Size2 uint32
- Desc fontDescType
+ Desc FontDescType
}
diff --git a/fpdf.go b/fpdf.go
index 1fe9b1b..fd0c91f 100644
--- a/fpdf.go
+++ b/fpdf.go
@@ -1376,6 +1376,16 @@ func (f *Fpdf) AddFont(familyStr, styleStr, fileStr string) {
f.AddFontFromReader(familyStr, styleStr, file)
}
+// getFontKey is used by AddFontFromReader and GetFontDesc
+func getFontKey(familyStr, styleStr string) string {
+ familyStr = strings.ToLower(familyStr)
+ styleStr = strings.ToUpper(styleStr)
+ if styleStr == "IB" {
+ styleStr = "BI"
+ }
+ return familyStr + styleStr
+}
+
// AddFontFromReader imports a TrueType, OpenType or Type1 font and makes it
// available using a reader that satisifies the io.Reader interface. See
// AddFont for details about familyStr and styleStr.
@@ -1385,12 +1395,7 @@ func (f *Fpdf) AddFontFromReader(familyStr, styleStr string, r io.Reader) {
}
// dbg("Adding family [%s], style [%s]", familyStr, styleStr)
var ok bool
- familyStr = strings.ToLower(familyStr)
- styleStr = strings.ToUpper(styleStr)
- if styleStr == "IB" {
- styleStr = "BI"
- }
- fontkey := familyStr + styleStr
+ fontkey := getFontKey(familyStr, styleStr)
_, ok = f.fonts[fontkey]
if ok {
return
@@ -1429,6 +1434,14 @@ func (f *Fpdf) AddFontFromReader(familyStr, styleStr string, r io.Reader) {
return
}
+// GetFontDesc returns the font descriptor, which can be used for
+// example to find the baseline of a font. See FontDescType for
+// documentation about the font descriptor.
+// See AddFont for details about familyStr and styleStr.
+func (f *Fpdf) GetFontDesc(familyStr, styleStr string) FontDescType {
+ return f.fonts[getFontKey(familyStr, styleStr)].Desc
+}
+
// SetFont sets the font used to print character strings. It is mandatory to
// call this method at least once before printing text or the resulting
// document will not be valid.
@@ -1677,8 +1690,8 @@ func (f *Fpdf) SetAcceptPageBreakFunc(fnc func() bool) {
// alignStr specifies how the text is to be positionined within the cell.
// Horizontal alignment is controlled by including "L", "C" or "R" (left,
// center, right) in alignStr. Vertical alignment is controlled by including
-// "T", "M" or "B" (top, middle, bottom) in alignStr. The default alignment is
-// left middle.
+// "T", "M", "B" or "A" (top, middle, bottom, baseline) in alignStr. The default
+// alignment is left middle.
//
// fill is true to paint the cell background or false to leave it transparent.
//
@@ -1769,6 +1782,16 @@ func (f *Fpdf) CellFormat(w, h float64, txtStr string, borderStr string, ln int,
dy = (f.fontSize - h) / 2.0
} else if strings.Index(alignStr, "B") != -1 {
dy = (h - f.fontSize) / 2.0
+ } else if strings.Index(alignStr, "A") != -1 {
+ var descent float64
+ d := f.currentFont.Desc
+ if d.Descent == 0 {
+ // not defined (standard font?), use average of 19%
+ descent = -0.19 * f.fontSize
+ } else {
+ descent = float64(d.Descent) * f.fontSize / float64(d.Ascent-d.Descent)
+ }
+ dy = (h-f.fontSize)/2.0 - descent
} else {
dy = 0
}
diff --git a/fpdf_test.go b/fpdf_test.go
index fdc3334..63d4655 100644
--- a/fpdf_test.go
+++ b/fpdf_test.go
@@ -1175,25 +1175,41 @@ func ExampleFpdf_CellFormat_2() {
recType{"BC", "bottom center"},
recType{"BR", "bottom right"},
}
- pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0
- pdf.SetFont("Helvetica", "", 16)
- linkStr := ""
- for pageJ := 0; pageJ < 2; pageJ++ {
- pdf.AddPage()
- pdf.SetMargins(10, 10, 10)
- pdf.SetAutoPageBreak(false, 0)
- borderStr := "1"
- for _, rec := range recList {
- pdf.SetXY(20, 20)
- pdf.CellFormat(170, 257, rec.txt, borderStr, 0, rec.align, false, 0, linkStr)
- borderStr = ""
+ recListBaseline := []recType{
+ recType{"AL", "baseline left"},
+ recType{"AC", "baseline center"},
+ recType{"AR", "baseline right"},
+ }
+ var formatRect = func(pdf *gofpdf.Fpdf, recList []recType) {
+ linkStr := ""
+ for pageJ := 0; pageJ < 2; pageJ++ {
+ pdf.AddPage()
+ pdf.SetMargins(10, 10, 10)
+ pdf.SetAutoPageBreak(false, 0)
+ borderStr := "1"
+ for _, rec := range recList {
+ pdf.SetXY(20, 20)
+ pdf.CellFormat(170, 257, rec.txt, borderStr, 0, rec.align, false, 0, linkStr)
+ borderStr = ""
+ }
+ linkStr = "https://github.com/jung-kurt/gofpdf"
}
- linkStr = "https://github.com/jung-kurt/gofpdf"
}
+ pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0
+ pdf.SetFont("Helvetica", "", 16)
+ formatRect(pdf, recList)
+ formatRect(pdf, recListBaseline)
+ var fr fontResourceType
+ pdf.SetFontLoader(fr)
+ pdf.AddFont("Calligrapher", "", "calligra.json")
+ pdf.SetFont("Calligrapher", "", 16)
+ formatRect(pdf, recListBaseline)
fileStr := exampleFilename("Fpdf_CellFormat_2_align")
err := pdf.OutputFileAndClose(fileStr)
summary(err, fileStr)
// Output:
+ // Generalized font loader reading calligra.json
+ // Generalized font loader reading calligra.z
// Successfully generated pdf/Fpdf_CellFormat_2_align.pdf
}