github.com/unidoc/unidoc@v2.2.0+incompatible/pdf/creator/filled_curve.go (about) 1 /* 2 * This file is subject to the terms and conditions defined in 3 * file 'LICENSE.md', which is part of this source code package. 4 */ 5 6 package creator 7 8 import ( 9 pdfcontent "github.com/unidoc/unidoc/pdf/contentstream" 10 "github.com/unidoc/unidoc/pdf/contentstream/draw" 11 pdfcore "github.com/unidoc/unidoc/pdf/core" 12 pdf "github.com/unidoc/unidoc/pdf/model" 13 ) 14 15 // FilledCurve represents a closed path of Bezier curves with a border and fill. 16 type FilledCurve struct { 17 curves []draw.CubicBezierCurve 18 FillEnabled bool // Show fill? 19 fillColor *pdf.PdfColorDeviceRGB 20 BorderEnabled bool // Show border? 21 BorderWidth float64 22 borderColor *pdf.PdfColorDeviceRGB 23 } 24 25 // NewFilledCurve returns a instance of filled curve. 26 func NewFilledCurve() *FilledCurve { 27 curve := FilledCurve{} 28 curve.curves = []draw.CubicBezierCurve{} 29 return &curve 30 } 31 32 // AppendCurve appends a Bezier curve to the filled curve. 33 func (fc *FilledCurve) AppendCurve(curve draw.CubicBezierCurve) *FilledCurve { 34 fc.curves = append(fc.curves, curve) 35 return fc 36 } 37 38 // SetFillColor sets the fill color for the path. 39 func (fc *FilledCurve) SetFillColor(color Color) { 40 fc.fillColor = pdf.NewPdfColorDeviceRGB(color.ToRGB()) 41 } 42 43 // SetBorderColor sets the border color for the path. 44 func (fc *FilledCurve) SetBorderColor(color Color) { 45 fc.borderColor = pdf.NewPdfColorDeviceRGB(color.ToRGB()) 46 } 47 48 // draw draws the filled curve. Can specify a graphics state (gsName) for setting opacity etc. Otherwise leave empty (""). 49 // Returns the content stream as a byte array, the bounding box and an error on failure. 50 func (fc *FilledCurve) draw(gsName string) ([]byte, *pdf.PdfRectangle, error) { 51 bpath := draw.NewCubicBezierPath() 52 for _, c := range fc.curves { 53 bpath = bpath.AppendCurve(c) 54 } 55 56 creator := pdfcontent.NewContentCreator() 57 creator.Add_q() 58 59 if fc.FillEnabled { 60 creator.Add_rg(fc.fillColor.R(), fc.fillColor.G(), fc.fillColor.B()) 61 } 62 if fc.BorderEnabled { 63 creator.Add_RG(fc.borderColor.R(), fc.borderColor.G(), fc.borderColor.B()) 64 creator.Add_w(fc.BorderWidth) 65 } 66 if len(gsName) > 1 { 67 // If a graphics state is provided, use it. (can support transparency). 68 creator.Add_gs(pdfcore.PdfObjectName(gsName)) 69 } 70 71 draw.DrawBezierPathWithCreator(bpath, creator) 72 creator.Add_h() // Close the path. 73 74 if fc.FillEnabled && fc.BorderEnabled { 75 creator.Add_B() // fill and stroke. 76 } else if fc.FillEnabled { 77 creator.Add_f() // Fill. 78 } else if fc.BorderEnabled { 79 creator.Add_S() // Stroke. 80 } 81 creator.Add_Q() 82 83 // Get bounding box. 84 pathBbox := bpath.GetBoundingBox() 85 if fc.BorderEnabled { 86 // Account for stroke width. 87 pathBbox.Height += fc.BorderWidth 88 pathBbox.Width += fc.BorderWidth 89 pathBbox.X -= fc.BorderWidth / 2 90 pathBbox.Y -= fc.BorderWidth / 2 91 } 92 93 // Bounding box - global coordinate system. 94 bbox := &pdf.PdfRectangle{} 95 bbox.Llx = pathBbox.X 96 bbox.Lly = pathBbox.Y 97 bbox.Urx = pathBbox.X + pathBbox.Width 98 bbox.Ury = pathBbox.Y + pathBbox.Height 99 return creator.Bytes(), bbox, nil 100 } 101 102 // GeneratePageBlocks draws the filled curve on page blocks. 103 func (fc *FilledCurve) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) { 104 block := NewBlock(ctx.PageWidth, ctx.PageHeight) 105 106 contents, _, err := fc.draw("") 107 err = block.addContentsByString(string(contents)) 108 if err != nil { 109 return nil, ctx, err 110 } 111 return []*Block{block}, ctx, nil 112 }