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  }