From 7c5006543b654248bb1fb640703faf0a53f59f71 Mon Sep 17 00:00:00 2001 From: Brigham Thompson Date: Sun, 11 Aug 2019 20:52:54 -0700 Subject: adds RoundedRect per Issue #272 --- fpdf.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ fpdf_test.go | 13 +++++++++++++ 2 files changed, 62 insertions(+) diff --git a/fpdf.go b/fpdf.go index ca48fb5..46d57df 100644 --- a/fpdf.go +++ b/fpdf.go @@ -1103,6 +1103,55 @@ func (f *Fpdf) Rect(x, y, w, h float64, styleStr string) { f.outf("%.2f %.2f %.2f %.2f re %s", x*f.k, (f.h-y)*f.k, w*f.k, -h*f.k, fillDrawOp(styleStr)) } +// RoundedRect outputs a rectangle of width w and height h with the upper left +// corner positioned at point (x, y). It can be drawn (border only), filled +// (with no border) or both. styleStr can be "F" for filled, "D" for outlined +// only, or "DF" or "FD" for outlined and filled. An empty string will be replaced +// with "D". Drawing uses the current draw color and line width centered on the +// rectangle's perimeter. Filling uses the current fill color. The rounded corners +// of the rectangle are specified by radius r. corners runs clockwise with 1 at the +// top left corner. +func (f *Fpdf) RoundedRect(x, y, w, h, r float64, corners string, stylestr string) { + k := f.k + hp := f.h + myArc := (4.0 / 3.0) * (math.Sqrt2 - 1.0) + f.outf("q %.5f %.5f m", (x+r)*k, (hp-y)*k) + xc := x + w - r + yc := y + r + f.outf("%.5f %.5f l", xc*k, (hp-y)*k) + if strings.Contains(corners, "2") == false { + f.outf("%.5f %.5f l", (x+w)*k, (hp-y)*k) + } else { + f.clipArc(xc+r*myArc, yc-r, xc+r, yc-r*myArc, xc+r, yc) + } + xc = x + w - r + yc = y + h - r + f.outf("%.5f %.5f l", (x+w)*k, (hp-yc)*k) + if strings.Contains(corners, "3") == false { + f.outf("%.5f %.5f l", (x+w)*k, (hp-(y + h))*k) + } else { + f.clipArc(xc+r, yc+r*myArc, xc+r*myArc, yc+r, xc, yc+r) + } + xc = x + r + yc = y + h - r + f.outf("%.5f %.5f l", xc*k, (hp-(y+h))*k) + if strings.Contains(corners, "4") == false { + f.outf("%.5f %.5f l", x*k, (hp-(y+h))*k) + } else { + f.clipArc(xc-r*myArc, yc+r, xc-r, yc+r*myArc, xc-r, yc) + } + xc = x + r + yc = y + r + f.outf("%.5f %.5f l", x*k, (hp-yc)*k) + if strings.Contains(corners, "1") == false { + f.outf("%.5f %.5f l", x*k, (hp-y)*k) + f.outf("%.5f %.5f l", (x+r)*k, (hp-y)*k) + } else { + f.clipArc(xc-r, yc-r*myArc, xc-r*myArc, yc-r, xc, yc-r) + f.outf(" re %s", fillDrawOp(stylestr)) + } +} + // Circle draws a circle centered on point (x, y) with radius r. // // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for diff --git a/fpdf_test.go b/fpdf_test.go index 63c28c5..08814e0 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -2639,3 +2639,16 @@ func ExampleUTF8CutFont() { // Output: // Successfully generated pdf/Fpdf_UTF8CutFont.pdf } + +func ExampleFpdf_RoundedRect() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFillColor(160, 160, 160) + pdf.SetLineWidth(0.5) + pdf.RoundedRect(70, 30, 68, 46, 20, "1234", "FD") + fileStr := example.Filename("Fpdf_RoundedRect") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_RoundedRect.pdf +} -- cgit v1.2.1-24-ge1ad From 0d44f4b8df0f8964427cbaaa5eb70f98ae56a0ca Mon Sep 17 00:00:00 2001 From: Kurt Date: Mon, 12 Aug 2019 09:20:09 -0400 Subject: Revise comment, fix style write, extend example for RoundedRect --- fpdf.go | 83 +++++++++++++++++++++++++++++++----------------------------- fpdf_test.go | 56 ++++++++++++++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 50 deletions(-) diff --git a/fpdf.go b/fpdf.go index 46d57df..28f69cf 100644 --- a/fpdf.go +++ b/fpdf.go @@ -1106,50 +1106,53 @@ func (f *Fpdf) Rect(x, y, w, h float64, styleStr string) { // RoundedRect outputs a rectangle of width w and height h with the upper left // corner positioned at point (x, y). It can be drawn (border only), filled // (with no border) or both. styleStr can be "F" for filled, "D" for outlined -// only, or "DF" or "FD" for outlined and filled. An empty string will be replaced -// with "D". Drawing uses the current draw color and line width centered on the -// rectangle's perimeter. Filling uses the current fill color. The rounded corners -// of the rectangle are specified by radius r. corners runs clockwise with 1 at the -// top left corner. +// only, or "DF" or "FD" for outlined and filled. An empty string will be +// replaced with "D". Drawing uses the current draw color and line width +// centered on the rectangle's perimeter. Filling uses the current fill color. +// The rounded corners of the rectangle are specified by radius r. corners is a +// string that includes "1" to round the upper left corner, "2" to round the +// upper right corner, "3" to round the lower right corner, and "4" to round +// the lower left corner. The RoundedRect example demonstrates this method. func (f *Fpdf) RoundedRect(x, y, w, h, r float64, corners string, stylestr string) { - k := f.k - hp := f.h - myArc := (4.0 / 3.0) * (math.Sqrt2 - 1.0) - f.outf("q %.5f %.5f m", (x+r)*k, (hp-y)*k) - xc := x + w - r + // This routine was adapted by Brigham Thompson from a script by Christophe Prugnaud + k := f.k + hp := f.h + myArc := r * (4.0 / 3.0) * (math.Sqrt2 - 1.0) + f.outf("q %.5f %.5f m", (x+r)*k, (hp-y)*k) + xc := x + w - r yc := y + r - f.outf("%.5f %.5f l", xc*k, (hp-y)*k) - if strings.Contains(corners, "2") == false { - f.outf("%.5f %.5f l", (x+w)*k, (hp-y)*k) - } else { - f.clipArc(xc+r*myArc, yc-r, xc+r, yc-r*myArc, xc+r, yc) - } - xc = x + w - r + f.outf("%.5f %.5f l", xc*k, (hp-y)*k) + if strings.Contains(corners, "2") == false { + f.outf("%.5f %.5f l", (x+w)*k, (hp-y)*k) + } else { + f.clipArc(xc+myArc, yc-r, xc+r, yc-myArc, xc+r, yc) + } + xc = x + w - r + yc = y + h - r + f.outf("%.5f %.5f l", (x+w)*k, (hp-yc)*k) + if strings.Contains(corners, "3") == false { + f.outf("%.5f %.5f l", (x+w)*k, (hp-(y+h))*k) + } else { + f.clipArc(xc+r, yc+myArc, xc+myArc, yc+r, xc, yc+r) + } + xc = x + r yc = y + h - r - f.outf("%.5f %.5f l", (x+w)*k, (hp-yc)*k) - if strings.Contains(corners, "3") == false { - f.outf("%.5f %.5f l", (x+w)*k, (hp-(y + h))*k) - } else { - f.clipArc(xc+r, yc+r*myArc, xc+r*myArc, yc+r, xc, yc+r) - } - xc = x + r - yc = y + h - r - f.outf("%.5f %.5f l", xc*k, (hp-(y+h))*k) - if strings.Contains(corners, "4") == false { - f.outf("%.5f %.5f l", x*k, (hp-(y+h))*k) - } else { - f.clipArc(xc-r*myArc, yc+r, xc-r, yc+r*myArc, xc-r, yc) - } - xc = x + r + f.outf("%.5f %.5f l", xc*k, (hp-(y+h))*k) + if strings.Contains(corners, "4") == false { + f.outf("%.5f %.5f l", x*k, (hp-(y+h))*k) + } else { + f.clipArc(xc-myArc, yc+r, xc-r, yc+myArc, xc-r, yc) + } + xc = x + r yc = y + r - f.outf("%.5f %.5f l", x*k, (hp-yc)*k) - if strings.Contains(corners, "1") == false { - f.outf("%.5f %.5f l", x*k, (hp-y)*k) - f.outf("%.5f %.5f l", (x+r)*k, (hp-y)*k) - } else { - f.clipArc(xc-r, yc-r*myArc, xc-r*myArc, yc-r, xc, yc-r) - f.outf(" re %s", fillDrawOp(stylestr)) - } + f.outf("%.5f %.5f l", x*k, (hp-yc)*k) + if strings.Contains(corners, "1") == false { + f.outf("%.5f %.5f l", x*k, (hp-y)*k) + f.outf("%.5f %.5f l", (x+r)*k, (hp-y)*k) + } else { + f.clipArc(xc-r, yc-myArc, xc-myArc, yc-r, xc, yc-r) + } + f.out(fillDrawOp(stylestr)) } // Circle draws a circle centered on point (x, y) with radius r. diff --git a/fpdf_test.go b/fpdf_test.go index 08814e0..c6020f3 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -2641,14 +2641,50 @@ func ExampleUTF8CutFont() { } func ExampleFpdf_RoundedRect() { - pdf := gofpdf.New("P", "mm", "A4", "") - pdf.AddPage() - pdf.SetFillColor(160, 160, 160) - pdf.SetLineWidth(0.5) - pdf.RoundedRect(70, 30, 68, 46, 20, "1234", "FD") - fileStr := example.Filename("Fpdf_RoundedRect") - err := pdf.OutputFileAndClose(fileStr) - example.Summary(err, fileStr) - // Output: - // Successfully generated pdf/Fpdf_RoundedRect.pdf + const ( + wd = 40.0 + hgap = 10.0 + radius = 10.0 + ht = 60.0 + vgap = 10.0 + ) + corner := func(b1, b2, b3, b4 bool) (cstr string) { + if b1 { + cstr = "1" + } + if b2 { + cstr += "2" + } + if b3 { + cstr += "3" + } + if b4 { + cstr += "4" + } + return + } + pdf := gofpdf.New("P", "mm", "A4", "") // 210 x 297 + pdf.AddPage() + pdf.SetLineWidth(0.5) + y := vgap + r := 40 + g := 30 + b := 20 + for row := 0; row < 4; row++ { + x := hgap + for col := 0; col < 4; col++ { + pdf.SetFillColor(r, g, b) + pdf.RoundedRect(x, y, wd, ht, radius, corner(row&1 == 1, row&2 == 2, col&1 == 1, col&2 == 2), "FD") + r += 8 + g += 10 + b += 12 + x += wd + hgap + } + y += ht + vgap + } + fileStr := example.Filename("Fpdf_RoundedRect") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_RoundedRect.pdf } -- cgit v1.2.1-24-ge1ad