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  }