codeberg.org/go-pdf/fpdf@v0.11.1/svgwrite.go (about) 1 // Copyright ©2023 The go-pdf Authors. All rights reserved. 2 // Use of this source code is governed by a MIT-style 3 // license that can be found in the LICENSE file. 4 5 /* 6 * Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung) 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 package fpdf 22 23 // SVGBasicWrite renders the paths encoded in the basic SVG image specified by 24 // sb. The scale value is used to convert the coordinates in the path to the 25 // unit of measure specified in New(). If scale is 0, SVGBasicWrite automatically adapts the SVG document 26 // to the PDF document unit. The current position (as set with a call 27 // to SetXY()) is used as the origin of the image. The current line cap style 28 // (as set with SetLineCapStyle()), line width (as set with SetLineWidth()), 29 // and draw color (as set with SetDrawColor()) are used in drawing the image 30 // paths. 31 func (f *Fpdf) SVGBasicWrite(sb *SVGBasicType, scale float64) { 32 originX, originY := f.GetXY() 33 var x, y, newX, newY float64 34 var cx0, cy0, cx1, cy1 float64 35 var path []SVGBasicSegmentType 36 var seg SVGBasicSegmentType 37 var startX, startY float64 38 if scale == 0.0 { 39 scale = 1.0 / f.k 40 } 41 sval := func(origin float64, arg int) float64 { 42 return origin + scale*seg.Arg[arg] 43 } 44 xval := func(arg int) float64 { 45 return sval(originX, arg) 46 } 47 yval := func(arg int) float64 { 48 return sval(originY, arg) 49 } 50 val := func(arg int) (float64, float64) { 51 return xval(arg), yval(arg + 1) 52 } 53 for j := 0; j < len(sb.Segments) && f.Ok(); j++ { 54 path = sb.Segments[j] 55 for k := 0; k < len(path) && f.Ok(); k++ { 56 seg = path[k] 57 switch seg.Cmd { 58 case 'M': 59 x, y = val(0) 60 startX, startY = x, y 61 f.SetXY(x, y) 62 case 'L': 63 newX, newY = val(0) 64 f.Line(x, y, newX, newY) 65 x, y = newX, newY 66 case 'C': 67 cx0, cy0 = val(0) 68 cx1, cy1 = val(2) 69 newX, newY = val(4) 70 f.CurveCubic(x, y, cx0, cy0, newX, newY, cx1, cy1, "D") 71 x, y = newX, newY 72 case 'Q': 73 cx0, cy0 = val(0) 74 newX, newY = val(2) 75 f.Curve(x, y, cx0, cy0, newX, newY, "D") 76 x, y = newX, newY 77 case 'H': 78 newX = xval(0) 79 f.Line(x, y, newX, y) 80 x = newX 81 case 'V': 82 newY = yval(0) 83 f.Line(x, y, x, newY) 84 y = newY 85 case 'Z': 86 f.Line(x, y, startX, startY) 87 x, y = startX, startY 88 default: 89 f.SetErrorf("Unexpected path command '%c'", seg.Cmd) 90 } 91 } 92 } 93 } 94 95 // SVGBasicDraw renders the paths in the provided SVGBasicType, but each SVG shape is written 96 // as a path that can be filled. 97 // 98 // styleStr can be "F" for filled, "D" for outlined only, or "DF" or 99 // "FD" for outlined and filled. An empty string will be replaced with 100 // "D". Drawing uses the current draw color and line width centered on 101 // the ellipse's perimeter. Filling uses the current fill color. 102 func (f *Fpdf) SVGBasicDraw(sb *SVGBasicType, scale float64, styleStr string) { 103 originX, originY := f.GetXY() 104 var newX, newY float64 105 var cx0, cy0, cx1, cy1 float64 106 var path []SVGBasicSegmentType 107 var seg SVGBasicSegmentType 108 var startX, startY float64 109 if scale == 0.0 { 110 scale = 1.0 / f.k 111 } 112 sval := func(origin float64, arg int) float64 { 113 return origin + scale*seg.Arg[arg] 114 } 115 xval := func(arg int) float64 { 116 return sval(originX, arg) 117 } 118 yval := func(arg int) float64 { 119 return sval(originY, arg) 120 } 121 val := func(arg int) (float64, float64) { 122 return xval(arg), yval(arg + 1) 123 } 124 for j := 0; j < len(sb.Segments) && f.Ok(); j++ { 125 path = sb.Segments[j] 126 for k := 0; k < len(path) && f.Ok(); k++ { 127 seg = path[k] 128 switch seg.Cmd { 129 case 'M': 130 startX, startY = val(0) 131 f.MoveTo(startX, startY) 132 case 'L': 133 newX, newY = val(0) 134 f.LineTo(newX, newY) 135 case 'C': 136 cx0, cy0 = val(0) 137 cx1, cy1 = val(2) 138 newX, newY = val(4) 139 f.CurveBezierCubicTo(cx0, cy0, cx1, cy1, newX, newY) 140 case 'Q': 141 cx0, cy0 = val(0) 142 newX, newY = val(2) 143 f.CurveTo(cx0, cy0, newX, newY) 144 case 'H': 145 newX = xval(0) 146 f.LineTo(newX, f.GetY()) 147 case 'V': 148 newY = yval(0) 149 f.LineTo(f.GetX(), newY) 150 case 'Z': 151 f.ClosePath() 152 f.DrawPath(styleStr) 153 default: 154 f.SetErrorf("Unexpected path command '%c'", seg.Cmd) 155 } 156 } 157 } 158 }