github.com/signintech/pdft@v0.5.0/minigopdf/cache_content_text.go (about) 1 package gopdf 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "strconv" 8 ) 9 10 // ContentTypeCell cell 11 const ContentTypeCell = 0 12 13 // ContentTypeText text 14 const ContentTypeText = 1 15 16 type cacheContentText struct { 17 //---setup--- 18 rectangle *Rect 19 textColor Rgb 20 grayFill float64 21 fontCountIndex int //Curr.Font_FontCount+1 22 fontSize int 23 fontStyle int 24 setXCount int //จำนวนครั้งที่ใช้ setX 25 x, y float64 26 fontSubset *SubsetFontObj 27 pageheight float64 28 contentType int 29 cellOpt CellOption 30 lineWidth float64 31 //---result--- 32 content bytes.Buffer 33 text bytes.Buffer 34 cellWidthPdfUnit, textWidthPdfUnit float64 35 cellHeightPdfUnit float64 36 } 37 38 func (c *cacheContentText) isSame(cache cacheContentText) bool { 39 if c.rectangle != nil { 40 //if rectangle != nil we assumes this is not same content 41 return false 42 } 43 if c.textColor.equal(cache.textColor) && 44 c.grayFill == cache.grayFill && 45 c.fontCountIndex == cache.fontCountIndex && 46 c.fontSize == cache.fontSize && 47 c.fontStyle == cache.fontStyle && 48 c.setXCount == cache.setXCount && 49 c.y == cache.y { 50 return true 51 } 52 53 return false 54 } 55 56 func (c *cacheContentText) setPageHeight(pageheight float64) { 57 c.pageheight = pageheight 58 } 59 60 func (c *cacheContentText) pageHeight() float64 { 61 return c.pageheight //841.89 62 } 63 64 func convertTypoUnit(val float64, unitsPerEm uint, fontSize float64) float64 { 65 val = val * 1000.00 / float64(unitsPerEm) 66 return val * fontSize / 1000.0 67 } 68 69 func (c *cacheContentText) calTypoAscender() float64 { 70 return convertTypoUnit(float64(c.fontSubset.ttfp.TypoAscender()), c.fontSubset.ttfp.UnitsPerEm(), float64(c.fontSize)) 71 } 72 73 func (c *cacheContentText) calTypoDescender() float64 { 74 return convertTypoUnit(float64(c.fontSubset.ttfp.TypoDescender()), c.fontSubset.ttfp.UnitsPerEm(), float64(c.fontSize)) 75 } 76 77 func (c *cacheContentText) calY() (float64, error) { 78 pageHeight := c.pageHeight() 79 if c.contentType == ContentTypeText { 80 return pageHeight - c.y, nil 81 } else if c.contentType == ContentTypeCell { 82 y := float64(0.0) 83 if c.cellOpt.Align&Bottom == Bottom { 84 y = pageHeight - c.y - c.cellHeightPdfUnit - c.calTypoDescender() 85 } else if c.cellOpt.Align&Middle == Middle { 86 y = pageHeight - c.y - c.cellHeightPdfUnit*0.5 - (c.calTypoDescender()+c.calTypoAscender())*0.5 87 } else { 88 //top 89 y = pageHeight - c.y - c.calTypoAscender() 90 } 91 92 return y, nil 93 } 94 return 0.0, errors.New("contentType not found") 95 } 96 97 func (c *cacheContentText) calX() (float64, error) { 98 if c.contentType == ContentTypeText { 99 return c.x, nil 100 } else if c.contentType == ContentTypeCell { 101 x := float64(0.0) 102 if c.cellOpt.Align&Right == Right { 103 x = c.x + c.cellWidthPdfUnit - c.textWidthPdfUnit 104 } else if c.cellOpt.Align&Center == Center { 105 x = c.x + c.cellWidthPdfUnit*0.5 - c.textWidthPdfUnit*0.5 106 } else { 107 x = c.x 108 } 109 return x, nil 110 } 111 return 0.0, errors.New("contentType not found") 112 } 113 114 func (c *cacheContentText) toStream(protection *PDFProtection) (*bytes.Buffer, error) { 115 116 var stream bytes.Buffer 117 r := c.textColor.r 118 g := c.textColor.g 119 b := c.textColor.b 120 x, err := c.calX() 121 if err != nil { 122 return nil, err 123 } 124 y, err := c.calY() 125 if err != nil { 126 return nil, err 127 } 128 129 stream.WriteString("BT\n") 130 stream.WriteString(fmt.Sprintf("%0.2f %0.2f TD\n", x, y)) 131 stream.WriteString("/F" + strconv.Itoa(c.fontCountIndex) + " " + strconv.Itoa(c.fontSize) + " Tf\n") 132 if r+g+b != 0 { 133 rFloat := float64(r) * 0.00392156862745 134 gFloat := float64(g) * 0.00392156862745 135 bFloat := float64(b) * 0.00392156862745 136 rgb := fmt.Sprintf("%0.2f %0.2f %0.2f rg\n", rFloat, gFloat, bFloat) 137 stream.WriteString(rgb) 138 } else { 139 //c.AppendStreamSetGrayFill(grayFill) 140 } 141 142 //stream.WriteString("[<" + c.content.String() + ">] TJ\n") 143 stream.WriteString(c.content.String()) 144 stream.WriteString("ET\n") 145 146 if c.fontStyle&Underline == Underline { 147 underlineStream, err := c.underline(c.x, c.y, c.x+c.cellWidthPdfUnit, c.y) 148 if err != nil { 149 return nil, err 150 } 151 _, err = underlineStream.WriteTo(&stream) 152 if err != nil { 153 return nil, err 154 } 155 } 156 157 c.drawBorder(&stream) 158 159 return &stream, nil 160 } 161 162 func (c *cacheContentText) drawBorder(stream *bytes.Buffer) error { 163 164 //stream.WriteString(fmt.Sprintf("%.2f w\n", 0.1)) 165 lineOffset := c.lineWidth * 0.5 166 167 if c.cellOpt.Border&Top == Top { 168 169 startX := c.x - lineOffset 170 startY := c.pageHeight() - c.y 171 endX := c.x + c.cellWidthPdfUnit + lineOffset 172 endY := startY 173 _, err := stream.WriteString(fmt.Sprintf("%0.2f %0.2f m %0.2f %0.2f l s\n", startX, startY, endX, endY)) 174 if err != nil { 175 return err 176 } 177 } 178 179 if c.cellOpt.Border&Left == Left { 180 startX := c.x 181 startY := c.pageHeight() - c.y 182 endX := c.x 183 endY := startY - c.cellHeightPdfUnit 184 _, err := stream.WriteString(fmt.Sprintf("%0.2f %0.2f m %0.2f %0.2f l s\n", startX, startY, endX, endY)) 185 if err != nil { 186 return err 187 } 188 } 189 190 if c.cellOpt.Border&Right == Right { 191 startX := c.x + c.cellWidthPdfUnit 192 startY := c.pageHeight() - c.y 193 endX := c.x + c.cellWidthPdfUnit 194 endY := startY - c.cellHeightPdfUnit 195 _, err := stream.WriteString(fmt.Sprintf("%0.2f %0.2f m %0.2f %0.2f l s\n", startX, startY, endX, endY)) 196 if err != nil { 197 return err 198 } 199 } 200 201 if c.cellOpt.Border&Bottom == Bottom { 202 startX := c.x - lineOffset 203 startY := c.pageHeight() - c.y - c.cellHeightPdfUnit 204 endX := c.x + c.cellWidthPdfUnit + lineOffset 205 endY := startY 206 _, err := stream.WriteString(fmt.Sprintf("%0.2f %0.2f m %0.2f %0.2f l s\n", startX, startY, endX, endY)) 207 if err != nil { 208 return err 209 } 210 } 211 212 return nil 213 } 214 215 func (c *cacheContentText) underline(startX float64, startY float64, endX float64, endY float64) (*bytes.Buffer, error) { 216 217 if c.fontSubset == nil { 218 return nil, errors.New("error AppendUnderline not found font") 219 } 220 unitsPerEm := float64(c.fontSubset.ttfp.UnitsPerEm()) 221 h := c.pageHeight() 222 ut := float64(c.fontSubset.GetUt()) 223 up := float64(c.fontSubset.GetUp()) 224 var buff bytes.Buffer 225 textH := ContentObj_CalTextHeight(c.fontSize) 226 arg3 := float64(h) - (float64(startY) - ((up / unitsPerEm) * float64(c.fontSize))) - textH 227 arg4 := (ut / unitsPerEm) * float64(c.fontSize) 228 buff.WriteString(fmt.Sprintf("%0.2f %0.2f %0.2f -%0.2f re f\n", startX, arg3, endX-startX, arg4)) 229 //fmt.Printf("arg3=%f arg4=%f\n", arg3, arg4) 230 231 return &buff, nil 232 } 233 234 func (c *cacheContentText) createContent() (float64, float64, error) { 235 236 c.content.Truncate(0) //clear 237 cellWidthPdfUnit, cellHeightPdfUnit, textWidthPdfUnit, err := createContent(c.fontSubset, c.text.String(), c.fontSize, c.rectangle, &c.content) 238 if err != nil { 239 return 0, 0, err 240 } 241 c.cellWidthPdfUnit = cellWidthPdfUnit 242 c.cellHeightPdfUnit = cellHeightPdfUnit 243 c.textWidthPdfUnit = textWidthPdfUnit 244 return cellWidthPdfUnit, cellHeightPdfUnit, nil 245 } 246 247 func createContent(f *SubsetFontObj, text string, fontSize int, rectangle *Rect, out *bytes.Buffer) (float64, float64, float64, error) { 248 249 unitsPerEm := int(f.ttfp.UnitsPerEm()) 250 var leftRune rune 251 var leftRuneIndex uint 252 sumWidth := int(0) 253 //fmt.Printf("unitsPerEm = %d", unitsPerEm) 254 out.WriteString("[<") 255 runeIndex := 0 256 for i, r := range text { 257 258 glyphindex, err := f.CharIndex(r) 259 if err != nil { 260 return 0, 0, 0, err 261 } 262 263 pairvalPdfUnit := 0 264 if i > 0 && f.ttfFontOption.UseKerning { //kerning 265 pairval := kern(f, leftRune, r, leftRuneIndex, glyphindex) 266 pairvalPdfUnit = convertTTFUnit2PDFUnit(int(pairval), unitsPerEm) 267 if pairvalPdfUnit != 0 && out != nil { 268 out.WriteString(fmt.Sprintf(">%d<", (-1)*pairvalPdfUnit)) 269 } 270 } 271 272 if f.funcTextriseOverride != nil { 273 //fmt.Printf("gopdf i=%d\n", runeIndex) 274 val := textrise(f, leftRune, r, leftRuneIndex, glyphindex, fontSize, text, runeIndex) 275 out.WriteString(">] TJ\n") 276 out.WriteString(fmt.Sprintf("%.2f Ts\n", val)) 277 out.WriteString("[<") 278 } 279 280 if out != nil { 281 out.WriteString(fmt.Sprintf("%04X", glyphindex)) 282 } 283 width, err := f.CharWidth(r) 284 if err != nil { 285 return 0, 0, 0, err 286 } 287 288 sumWidth += int(width) + int(pairvalPdfUnit) 289 leftRune = r 290 leftRuneIndex = glyphindex 291 runeIndex++ 292 } 293 out.WriteString(">] TJ\n") 294 295 cellWidthPdfUnit := float64(0) 296 cellHeightPdfUnit := float64(0) 297 if rectangle == nil { 298 cellWidthPdfUnit = float64(sumWidth) * (float64(fontSize) / 1000.0) 299 typoAscender := convertTypoUnit(float64(f.ttfp.TypoAscender()), f.ttfp.UnitsPerEm(), float64(fontSize)) 300 typoDescender := convertTypoUnit(float64(f.ttfp.TypoDescender()), f.ttfp.UnitsPerEm(), float64(fontSize)) 301 cellHeightPdfUnit = typoAscender - typoDescender 302 } else { 303 cellWidthPdfUnit = rectangle.W 304 cellHeightPdfUnit = rectangle.H 305 } 306 textWidthPdfUnit := float64(sumWidth) * (float64(fontSize) / 1000.0) 307 308 return cellWidthPdfUnit, cellHeightPdfUnit, textWidthPdfUnit, nil 309 } 310 311 func kern(f *SubsetFontObj, leftRune rune, rightRune rune, leftIndex uint, rightIndex uint) int16 { 312 313 pairVal := int16(0) 314 if haveKerning, kval := f.KernValueByLeft(leftIndex); haveKerning { 315 if ok, v := kval.ValueByRight(rightIndex); ok { 316 pairVal = v 317 } 318 } 319 320 if f.funcKernOverride != nil { 321 pairVal = f.funcKernOverride( 322 leftRune, 323 rightRune, 324 leftIndex, 325 rightIndex, 326 pairVal, 327 ) 328 } 329 return pairVal 330 } 331 332 func textrise(f *SubsetFontObj, leftRune rune, rightRune rune, leftIndex uint, rightIndex uint, fontSize int, allText string, currTextIndex int) float32 { 333 pairVal := float32(0) 334 if f.funcTextriseOverride != nil { 335 pairVal = f.funcTextriseOverride( 336 leftRune, 337 rightRune, 338 fontSize, 339 allText, 340 currTextIndex, 341 ) 342 } 343 return pairVal 344 } 345 346 // CacheContent Export cacheContent 347 type CacheContent struct { 348 cacheContentText 349 } 350 351 // Setup setup all infomation for cacheContent 352 func (c *CacheContent) Setup(rectangle *Rect, 353 textColor Rgb, 354 grayFill float64, 355 fontCountIndex int, //Curr.Font_FontCount+1 356 fontSize int, 357 fontStyle int, 358 setXCount int, //จำนวนครั้งที่ใช้ setX 359 x, y float64, 360 fontSubset *SubsetFontObj, 361 pageheight float64, 362 contentType int, 363 cellOpt CellOption, 364 lineWidth float64, 365 ) { 366 c.cacheContentText = cacheContentText{ 367 fontSubset: fontSubset, 368 rectangle: rectangle, 369 textColor: textColor, 370 grayFill: grayFill, 371 fontCountIndex: fontCountIndex, 372 fontSize: fontSize, 373 fontStyle: fontStyle, 374 setXCount: setXCount, 375 x: x, 376 y: y, 377 pageheight: pageheight, 378 contentType: ContentTypeCell, 379 cellOpt: cellOpt, 380 lineWidth: lineWidth, 381 } 382 } 383 384 // WriteTextToContent write text to content 385 func (c *CacheContent) WriteTextToContent(text string) { 386 c.cacheContentText.text.WriteString(text) 387 } 388 389 // ToStream create stream of content 390 func (c *CacheContent) ToStream(protection *PDFProtection) (*bytes.Buffer, error) { 391 c.cacheContentText.createContent() 392 return c.cacheContentText.toStream(protection) 393 } 394 395 // MeasureTextWidth measure text width 396 func (c *CacheContent) MeasureTextWidth(text string) (float64, error) { 397 c.WriteTextToContent(text) 398 _, _, err := c.cacheContentText.createContent() 399 return float64(c.cacheContentText.textWidthPdfUnit), err 400 }