github.com/unidoc/unidoc@v2.2.0+incompatible/pdf/contentstream/creator.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 contentstream 7 8 import ( 9 "math" 10 11 . "github.com/unidoc/unidoc/pdf/core" 12 ) 13 14 type ContentCreator struct { 15 operands ContentStreamOperations 16 } 17 18 func NewContentCreator() *ContentCreator { 19 creator := &ContentCreator{} 20 creator.operands = ContentStreamOperations{} 21 return creator 22 } 23 24 // Get the list of operations. 25 func (this *ContentCreator) Operations() *ContentStreamOperations { 26 return &this.operands 27 } 28 29 // Convert a set of content stream operations to a content stream byte presentation, i.e. the kind that can be 30 // stored as a PDF stream or string format. 31 func (this *ContentCreator) Bytes() []byte { 32 return this.operands.Bytes() 33 } 34 35 // Same as Bytes() except returns as a string for convenience. 36 func (this *ContentCreator) String() string { 37 return string(this.operands.Bytes()) 38 } 39 40 /* Graphics state operators. */ 41 42 // Save the current graphics state on the stack - push. 43 func (this *ContentCreator) Add_q() *ContentCreator { 44 op := ContentStreamOperation{} 45 op.Operand = "q" 46 this.operands = append(this.operands, &op) 47 return this 48 } 49 50 // Restore the most recently stored state from the stack - pop. 51 func (this *ContentCreator) Add_Q() *ContentCreator { 52 op := ContentStreamOperation{} 53 op.Operand = "Q" 54 this.operands = append(this.operands, &op) 55 return this 56 } 57 58 // Display XObject - image or form. 59 func (this *ContentCreator) Add_Do(name PdfObjectName) *ContentCreator { 60 op := ContentStreamOperation{} 61 op.Operand = "Do" 62 op.Params = makeParamsFromNames([]PdfObjectName{name}) 63 this.operands = append(this.operands, &op) 64 return this 65 } 66 67 // Modify the current transformation matrix (ctm). 68 func (this *ContentCreator) Add_cm(a, b, c, d, e, f float64) *ContentCreator { 69 op := ContentStreamOperation{} 70 op.Operand = "cm" 71 op.Params = makeParamsFromFloats([]float64{a, b, c, d, e, f}) 72 this.operands = append(this.operands, &op) 73 return this 74 } 75 76 // Convenience function for generating a cm operation to translate the transformation matrix. 77 func (this *ContentCreator) Translate(tx, ty float64) *ContentCreator { 78 return this.Add_cm(1, 0, 0, 1, tx, ty) 79 } 80 81 // Convenience function for generating a cm command to scale the transformation matrix. 82 func (this *ContentCreator) Scale(sx, sy float64) *ContentCreator { 83 return this.Add_cm(sx, 0, 0, sy, 0, 0) 84 } 85 86 // Convenience function for generating a cm command to rotate transformation matrix. 87 func (this *ContentCreator) RotateDeg(angle float64) *ContentCreator { 88 u1 := math.Cos(angle * math.Pi / 180.0) 89 u2 := math.Sin(angle * math.Pi / 180.0) 90 u3 := -math.Sin(angle * math.Pi / 180.0) 91 u4 := math.Cos(angle * math.Pi / 180.0) 92 return this.Add_cm(u1, u2, u3, u4, 0, 0) 93 } 94 95 // Set the line width. 96 func (this *ContentCreator) Add_w(lineWidth float64) *ContentCreator { 97 op := ContentStreamOperation{} 98 op.Operand = "w" 99 op.Params = makeParamsFromFloats([]float64{lineWidth}) 100 this.operands = append(this.operands, &op) 101 return this 102 } 103 104 // Set the line cap style. 105 func (this *ContentCreator) Add_J(lineCapStyle string) *ContentCreator { 106 op := ContentStreamOperation{} 107 op.Operand = "J" 108 op.Params = makeParamsFromNames([]PdfObjectName{PdfObjectName(lineCapStyle)}) 109 this.operands = append(this.operands, &op) 110 return this 111 } 112 113 // Set the line join style. 114 func (this *ContentCreator) Add_j(lineJoinStyle string) *ContentCreator { 115 op := ContentStreamOperation{} 116 op.Operand = "j" 117 op.Params = makeParamsFromNames([]PdfObjectName{PdfObjectName(lineJoinStyle)}) 118 this.operands = append(this.operands, &op) 119 return this 120 } 121 122 // Set the miter limit. 123 func (this *ContentCreator) Add_M(miterlimit float64) *ContentCreator { 124 op := ContentStreamOperation{} 125 op.Operand = "M" 126 op.Params = makeParamsFromFloats([]float64{miterlimit}) 127 this.operands = append(this.operands, &op) 128 return this 129 } 130 131 // Set the line dash pattern. 132 func (this *ContentCreator) Add_d(dashArray []int64, dashPhase int64) *ContentCreator { 133 op := ContentStreamOperation{} 134 op.Operand = "d" 135 136 op.Params = []PdfObject{} 137 op.Params = append(op.Params, MakeArrayFromIntegers64(dashArray)) 138 op.Params = append(op.Params, MakeInteger(dashPhase)) 139 this.operands = append(this.operands, &op) 140 return this 141 } 142 143 // Set the color rendering intent. 144 func (this *ContentCreator) Add_ri(intent PdfObjectName) *ContentCreator { 145 op := ContentStreamOperation{} 146 op.Operand = "ri" 147 op.Params = makeParamsFromNames([]PdfObjectName{intent}) 148 this.operands = append(this.operands, &op) 149 return this 150 } 151 152 // Set the flatness tolerance. 153 func (this *ContentCreator) Add_i(flatness float64) *ContentCreator { 154 op := ContentStreamOperation{} 155 op.Operand = "i" 156 op.Params = makeParamsFromFloats([]float64{flatness}) 157 this.operands = append(this.operands, &op) 158 return this 159 } 160 161 // Set the graphics state. 162 func (this *ContentCreator) Add_gs(dictName PdfObjectName) *ContentCreator { 163 op := ContentStreamOperation{} 164 op.Operand = "gs" 165 op.Params = makeParamsFromNames([]PdfObjectName{dictName}) 166 this.operands = append(this.operands, &op) 167 return this 168 } 169 170 /* Path construction operators. */ 171 172 // m: Move the current point to (x,y). 173 func (this *ContentCreator) Add_m(x, y float64) *ContentCreator { 174 op := ContentStreamOperation{} 175 op.Operand = "m" 176 op.Params = makeParamsFromFloats([]float64{x, y}) 177 this.operands = append(this.operands, &op) 178 return this 179 } 180 181 // l: Append a straight line segment from the current point to (x,y). 182 func (this *ContentCreator) Add_l(x, y float64) *ContentCreator { 183 op := ContentStreamOperation{} 184 op.Operand = "l" 185 op.Params = makeParamsFromFloats([]float64{x, y}) 186 this.operands = append(this.operands, &op) 187 return this 188 } 189 190 // c: Append a Bezier curve to the current path from the current point to (x3,y3) with (x1,x1) and (x2,y2) as control 191 // points. 192 func (this *ContentCreator) Add_c(x1, y1, x2, y2, x3, y3 float64) *ContentCreator { 193 op := ContentStreamOperation{} 194 op.Operand = "c" 195 op.Params = makeParamsFromFloats([]float64{x1, y1, x2, y2, x3, y3}) 196 this.operands = append(this.operands, &op) 197 return this 198 } 199 200 // v: Append a Bezier curve to the current path from the current point to (x3,y3) with the current point and (x2,y2) as 201 // control points. 202 func (this *ContentCreator) Add_v(x2, y2, x3, y3 float64) *ContentCreator { 203 op := ContentStreamOperation{} 204 op.Operand = "v" 205 op.Params = makeParamsFromFloats([]float64{x2, y2, x3, y3}) 206 this.operands = append(this.operands, &op) 207 return this 208 } 209 210 // y: Append a Bezier curve to the current path from the current point to (x3,y3) with (x1, y1) and (x3,y3) as 211 // control points. 212 func (this *ContentCreator) Add_y(x1, y1, x3, y3 float64) *ContentCreator { 213 op := ContentStreamOperation{} 214 op.Operand = "y" 215 op.Params = makeParamsFromFloats([]float64{x1, y1, x3, y3}) 216 this.operands = append(this.operands, &op) 217 return this 218 } 219 220 // h: Close the current subpath by adding a line between the current position and the starting position. 221 func (this *ContentCreator) Add_h() *ContentCreator { 222 op := ContentStreamOperation{} 223 op.Operand = "h" 224 this.operands = append(this.operands, &op) 225 return this 226 } 227 228 // re: Append a rectangle to the current path as a complete subpath, with lower left corner (x,y). 229 func (this *ContentCreator) Add_re(x, y, width, height float64) *ContentCreator { 230 op := ContentStreamOperation{} 231 op.Operand = "re" 232 op.Params = makeParamsFromFloats([]float64{x, y, width, height}) 233 this.operands = append(this.operands, &op) 234 return this 235 } 236 237 /* Path painting operators. */ 238 239 // S: stroke the path. 240 func (this *ContentCreator) Add_S() *ContentCreator { 241 op := ContentStreamOperation{} 242 op.Operand = "S" 243 this.operands = append(this.operands, &op) 244 return this 245 } 246 247 // s: Close and stroke the path. 248 func (this *ContentCreator) Add_s() *ContentCreator { 249 op := ContentStreamOperation{} 250 op.Operand = "s" 251 this.operands = append(this.operands, &op) 252 return this 253 } 254 255 // f: Fill the path using the nonzero winding number rule to determine fill region. 256 func (this *ContentCreator) Add_f() *ContentCreator { 257 op := ContentStreamOperation{} 258 op.Operand = "f" 259 this.operands = append(this.operands, &op) 260 return this 261 } 262 263 // f*: Fill the path using the even-odd rule to determine fill region. 264 func (this *ContentCreator) Add_f_starred() *ContentCreator { 265 op := ContentStreamOperation{} 266 op.Operand = "f*" 267 this.operands = append(this.operands, &op) 268 return this 269 } 270 271 // B: Fill and then stroke the path (nonzero winding number rule). 272 func (this *ContentCreator) Add_B() *ContentCreator { 273 op := ContentStreamOperation{} 274 op.Operand = "B" 275 this.operands = append(this.operands, &op) 276 return this 277 } 278 279 // B*: Fill and then stroke the path (even-odd rule). 280 func (this *ContentCreator) Add_B_starred() *ContentCreator { 281 op := ContentStreamOperation{} 282 op.Operand = "B*" 283 this.operands = append(this.operands, &op) 284 return this 285 } 286 287 // b: Close, fill and then stroke the path (nonzero winding number rule). 288 func (this *ContentCreator) Add_b() *ContentCreator { 289 op := ContentStreamOperation{} 290 op.Operand = "b" 291 this.operands = append(this.operands, &op) 292 return this 293 } 294 295 // b*: Close, fill and then stroke the path (even-odd winding number rule). 296 func (this *ContentCreator) Add_b_starred() *ContentCreator { 297 op := ContentStreamOperation{} 298 op.Operand = "b*" 299 this.operands = append(this.operands, &op) 300 return this 301 } 302 303 // n: End the path without filling or stroking. 304 func (this *ContentCreator) Add_n() *ContentCreator { 305 op := ContentStreamOperation{} 306 op.Operand = "n" 307 this.operands = append(this.operands, &op) 308 return this 309 } 310 311 /* Clipping path operators. */ 312 313 // W: Modify the current clipping path by intersecting with the current path (nonzero winding rule). 314 func (this *ContentCreator) Add_W() *ContentCreator { 315 op := ContentStreamOperation{} 316 op.Operand = "W" 317 this.operands = append(this.operands, &op) 318 return this 319 } 320 321 // W*: Modify the current clipping path by intersecting with the current path (even odd rule). 322 func (this *ContentCreator) Add_W_starred() *ContentCreator { 323 op := ContentStreamOperation{} 324 op.Operand = "W*" 325 this.operands = append(this.operands, &op) 326 return this 327 } 328 329 /* Color operators. */ 330 331 // CS: Set the current colorspace for stroking operations. 332 func (this *ContentCreator) Add_CS(name PdfObjectName) *ContentCreator { 333 op := ContentStreamOperation{} 334 op.Operand = "CS" 335 op.Params = makeParamsFromNames([]PdfObjectName{name}) 336 this.operands = append(this.operands, &op) 337 return this 338 } 339 340 // cs: Same as CS but for non-stroking operations. 341 func (this *ContentCreator) Add_cs(name PdfObjectName) *ContentCreator { 342 op := ContentStreamOperation{} 343 op.Operand = "cs" 344 op.Params = makeParamsFromNames([]PdfObjectName{name}) 345 this.operands = append(this.operands, &op) 346 return this 347 } 348 349 // SC: Set color for stroking operations. Input: c1, ..., cn. 350 func (this *ContentCreator) Add_SC(c ...float64) *ContentCreator { 351 op := ContentStreamOperation{} 352 op.Operand = "SC" 353 op.Params = makeParamsFromFloats(c) 354 this.operands = append(this.operands, &op) 355 return this 356 } 357 358 // SCN: Same as SC but supports more colorspaces. 359 func (this *ContentCreator) Add_SCN(c ...float64) *ContentCreator { 360 op := ContentStreamOperation{} 361 op.Operand = "SCN" 362 op.Params = makeParamsFromFloats(c) 363 this.operands = append(this.operands, &op) 364 return this 365 } 366 367 // SCN with name attribute (for pattern). Syntax: c1 ... cn name SCN. 368 func (this *ContentCreator) Add_SCN_pattern(name PdfObjectName, c ...float64) *ContentCreator { 369 op := ContentStreamOperation{} 370 op.Operand = "SCN" 371 op.Params = makeParamsFromFloats(c) 372 op.Params = append(op.Params, MakeName(string(name))) 373 this.operands = append(this.operands, &op) 374 return this 375 } 376 377 // scn: Same as SC but for nonstroking operations. 378 func (this *ContentCreator) Add_scn(c ...float64) *ContentCreator { 379 op := ContentStreamOperation{} 380 op.Operand = "scn" 381 op.Params = makeParamsFromFloats(c) 382 this.operands = append(this.operands, &op) 383 return this 384 } 385 386 // scn with name attribute (for pattern). Syntax: c1 ... cn name scn. 387 func (this *ContentCreator) Add_scn_pattern(name PdfObjectName, c ...float64) *ContentCreator { 388 op := ContentStreamOperation{} 389 op.Operand = "scn" 390 op.Params = makeParamsFromFloats(c) 391 op.Params = append(op.Params, MakeName(string(name))) 392 this.operands = append(this.operands, &op) 393 return this 394 } 395 396 // G: Set the stroking colorspace to DeviceGray and sets the gray level (0-1). 397 func (this *ContentCreator) Add_G(gray float64) *ContentCreator { 398 op := ContentStreamOperation{} 399 op.Operand = "G" 400 op.Params = makeParamsFromFloats([]float64{gray}) 401 this.operands = append(this.operands, &op) 402 return this 403 } 404 405 // g: Same as G but used for nonstroking operations. 406 func (this *ContentCreator) Add_g(gray float64) *ContentCreator { 407 op := ContentStreamOperation{} 408 op.Operand = "g" 409 op.Params = makeParamsFromFloats([]float64{gray}) 410 this.operands = append(this.operands, &op) 411 return this 412 } 413 414 // RG: Set the stroking colorspace to DeviceRGB and sets the r,g,b colors (0-1 each). 415 func (this *ContentCreator) Add_RG(r, g, b float64) *ContentCreator { 416 op := ContentStreamOperation{} 417 op.Operand = "RG" 418 op.Params = makeParamsFromFloats([]float64{r, g, b}) 419 this.operands = append(this.operands, &op) 420 return this 421 } 422 423 // rg: Same as RG but used for nonstroking operations. 424 func (this *ContentCreator) Add_rg(r, g, b float64) *ContentCreator { 425 op := ContentStreamOperation{} 426 op.Operand = "rg" 427 op.Params = makeParamsFromFloats([]float64{r, g, b}) 428 this.operands = append(this.operands, &op) 429 return this 430 } 431 432 // K: Set the stroking colorspace to DeviceCMYK and sets the c,m,y,k color (0-1 each component). 433 func (this *ContentCreator) Add_K(c, m, y, k float64) *ContentCreator { 434 op := ContentStreamOperation{} 435 op.Operand = "K" 436 op.Params = makeParamsFromFloats([]float64{c, m, y, k}) 437 this.operands = append(this.operands, &op) 438 return this 439 } 440 441 // k: Same as K but used for nonstroking operations. 442 func (this *ContentCreator) Add_k(c, m, y, k float64) *ContentCreator { 443 op := ContentStreamOperation{} 444 op.Operand = "k" 445 op.Params = makeParamsFromFloats([]float64{c, m, y, k}) 446 this.operands = append(this.operands, &op) 447 return this 448 } 449 450 /* Shading operators. */ 451 452 func (this *ContentCreator) Add_sh(name PdfObjectName) *ContentCreator { 453 op := ContentStreamOperation{} 454 op.Operand = "sh" 455 op.Params = makeParamsFromNames([]PdfObjectName{name}) 456 this.operands = append(this.operands, &op) 457 return this 458 } 459 460 /* Text related operators */ 461 462 /* Text state operators */ 463 464 // BT: Begin text. 465 func (this *ContentCreator) Add_BT() *ContentCreator { 466 op := ContentStreamOperation{} 467 op.Operand = "BT" 468 this.operands = append(this.operands, &op) 469 return this 470 } 471 472 // ET: End text. 473 func (this *ContentCreator) Add_ET() *ContentCreator { 474 op := ContentStreamOperation{} 475 op.Operand = "ET" 476 this.operands = append(this.operands, &op) 477 return this 478 } 479 480 // Tc: Set character spacing. 481 func (this *ContentCreator) Add_Tc(charSpace float64) *ContentCreator { 482 op := ContentStreamOperation{} 483 op.Operand = "Tc" 484 op.Params = makeParamsFromFloats([]float64{charSpace}) 485 this.operands = append(this.operands, &op) 486 return this 487 } 488 489 // Tw: Set word spacing. 490 func (this *ContentCreator) Add_Tw(wordSpace float64) *ContentCreator { 491 op := ContentStreamOperation{} 492 op.Operand = "Tw" 493 op.Params = makeParamsFromFloats([]float64{wordSpace}) 494 this.operands = append(this.operands, &op) 495 return this 496 } 497 498 // Tz: Set horizontal scaling. 499 func (this *ContentCreator) Add_Tz(scale float64) *ContentCreator { 500 op := ContentStreamOperation{} 501 op.Operand = "Tz" 502 op.Params = makeParamsFromFloats([]float64{scale}) 503 this.operands = append(this.operands, &op) 504 return this 505 } 506 507 // TL: Set leading. 508 func (this *ContentCreator) Add_TL(leading float64) *ContentCreator { 509 op := ContentStreamOperation{} 510 op.Operand = "TL" 511 op.Params = makeParamsFromFloats([]float64{leading}) 512 this.operands = append(this.operands, &op) 513 return this 514 } 515 516 // Tf: Set font and font size. 517 func (this *ContentCreator) Add_Tf(fontName PdfObjectName, fontSize float64) *ContentCreator { 518 op := ContentStreamOperation{} 519 op.Operand = "Tf" 520 op.Params = makeParamsFromNames([]PdfObjectName{fontName}) 521 op.Params = append(op.Params, makeParamsFromFloats([]float64{fontSize})...) 522 this.operands = append(this.operands, &op) 523 return this 524 } 525 526 // Tr: Set text rendering mode. 527 func (this *ContentCreator) Add_Tr(render int64) *ContentCreator { 528 op := ContentStreamOperation{} 529 op.Operand = "Tr" 530 op.Params = makeParamsFromInts([]int64{render}) 531 this.operands = append(this.operands, &op) 532 return this 533 } 534 535 // Ts: Set text rise. 536 func (this *ContentCreator) Add_Ts(rise float64) *ContentCreator { 537 op := ContentStreamOperation{} 538 op.Operand = "Ts" 539 op.Params = makeParamsFromFloats([]float64{rise}) 540 this.operands = append(this.operands, &op) 541 return this 542 } 543 544 /* Text positioning operators. */ 545 546 // Td: Move to start of next line with offset (tx, ty). 547 func (this *ContentCreator) Add_Td(tx, ty float64) *ContentCreator { 548 op := ContentStreamOperation{} 549 op.Operand = "Td" 550 op.Params = makeParamsFromFloats([]float64{tx, ty}) 551 this.operands = append(this.operands, &op) 552 return this 553 } 554 555 // TD: Move to start of next line with offset (tx, ty). 556 func (this *ContentCreator) Add_TD(tx, ty float64) *ContentCreator { 557 op := ContentStreamOperation{} 558 op.Operand = "TD" 559 op.Params = makeParamsFromFloats([]float64{tx, ty}) 560 this.operands = append(this.operands, &op) 561 return this 562 } 563 564 // Tm: Set the text line matrix. 565 func (this *ContentCreator) Add_Tm(a, b, c, d, e, f float64) *ContentCreator { 566 op := ContentStreamOperation{} 567 op.Operand = "Tm" 568 op.Params = makeParamsFromFloats([]float64{a, b, c, d, e, f}) 569 this.operands = append(this.operands, &op) 570 return this 571 } 572 573 // T*: Move to the start of next line. 574 func (this *ContentCreator) Add_Tstar() *ContentCreator { 575 op := ContentStreamOperation{} 576 op.Operand = "T*" 577 this.operands = append(this.operands, &op) 578 return this 579 } 580 581 /* Text showing operators */ 582 583 // Tj: Show a text string. 584 func (this *ContentCreator) Add_Tj(textstr PdfObjectString) *ContentCreator { 585 op := ContentStreamOperation{} 586 op.Operand = "Tj" 587 op.Params = makeParamsFromStrings([]PdfObjectString{textstr}) 588 this.operands = append(this.operands, &op) 589 return this 590 } 591 592 // ': Move to next line and show a string. 593 func (this *ContentCreator) Add_quote(textstr PdfObjectString) *ContentCreator { 594 op := ContentStreamOperation{} 595 op.Operand = "'" 596 op.Params = makeParamsFromStrings([]PdfObjectString{textstr}) 597 this.operands = append(this.operands, &op) 598 return this 599 } 600 601 // '': Move to next line and show a string, using aw and ac as word and character spacing respectively. 602 func (this *ContentCreator) Add_quotes(textstr PdfObjectString, aw, ac float64) *ContentCreator { 603 op := ContentStreamOperation{} 604 op.Operand = "''" 605 op.Params = makeParamsFromFloats([]float64{aw, ac}) 606 op.Params = append(op.Params, makeParamsFromStrings([]PdfObjectString{textstr})...) 607 this.operands = append(this.operands, &op) 608 return this 609 } 610 611 // TJ. Show one or more text string. Array of numbers (displacement) and strings. 612 func (this *ContentCreator) Add_TJ(vals ...PdfObject) *ContentCreator { 613 op := ContentStreamOperation{} 614 op.Operand = "TJ" 615 op.Params = []PdfObject{MakeArray(vals...)} 616 this.operands = append(this.operands, &op) 617 return this 618 }