github.com/signintech/pdft@v0.5.0/minigopdf/pdf_dictionary_obj.go (about)

     1  package gopdf
     2  
     3  import (
     4  	"bytes"
     5  	"compress/zlib"
     6  	"errors"
     7  	"sort"
     8  	"strconv"
     9  
    10  	"github.com/signintech/pdft/minigopdf/fontmaker/core"
    11  )
    12  
    13  // EntrySelectors entry selectors
    14  var EntrySelectors = []int{
    15  	0, 0, 1, 1, 2, 2,
    16  	2, 2, 3, 3, 3, 3,
    17  	3, 3, 3, 3, 4, 4,
    18  	4, 4, 4, 4, 4, 4,
    19  	4, 4, 4, 4, 4, 4, 4,
    20  }
    21  
    22  // ErrNotSupportShortIndexYet not suport none short index yet
    23  var ErrNotSupportShortIndexYet = errors.New("not suport none short index yet")
    24  
    25  // PdfDictionaryObj pdf dictionary object
    26  type PdfDictionaryObj struct {
    27  	buffer             bytes.Buffer
    28  	PtrToSubsetFontObj *SubsetFontObj
    29  	//getRoot            func() *GoPdf
    30  	pdfProtection *PDFProtection
    31  }
    32  
    33  func (p *PdfDictionaryObj) init(funcGetRoot func() *GoPdf) {
    34  	//p.getRoot = funcGetRoot
    35  }
    36  
    37  func (p *PdfDictionaryObj) setProtection(pr *PDFProtection) {
    38  	p.pdfProtection = pr
    39  }
    40  
    41  func (p *PdfDictionaryObj) protection() *PDFProtection {
    42  	return p.pdfProtection
    43  }
    44  
    45  func (p *PdfDictionaryObj) build(objID int) error {
    46  	b, err := p.makeFont()
    47  	if err != nil {
    48  		//log.Panicf("%s", err.Error())
    49  		return err
    50  	}
    51  
    52  	//zipvar buff bytes.Buffer
    53  	var zbuff bytes.Buffer
    54  	gzipwriter := zlib.NewWriter(&zbuff)
    55  	_, err = gzipwriter.Write(b)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	gzipwriter.Close()
    60  
    61  	p.buffer.WriteString("<</Length " + strconv.Itoa(zbuff.Len()) + "\n")
    62  	p.buffer.WriteString("/Filter /FlateDecode\n")
    63  	p.buffer.WriteString("/Length1 " + strconv.Itoa(len(b)) + "\n")
    64  	p.buffer.WriteString(">>\n")
    65  	p.buffer.WriteString("stream\n")
    66  	if p.protection() != nil {
    67  		tmp, err := rc4Cip(p.protection().objectkey(objID), zbuff.Bytes())
    68  		if err != nil {
    69  			return err
    70  		}
    71  		p.buffer.Write(tmp)
    72  		//p.buffer.WriteString("\n")
    73  	} else {
    74  		p.buffer.Write(zbuff.Bytes())
    75  	}
    76  	p.buffer.WriteString("\nendstream\n")
    77  	return nil
    78  }
    79  
    80  func (p *PdfDictionaryObj) getType() string {
    81  	return "PdfDictionary"
    82  }
    83  
    84  func (p *PdfDictionaryObj) getObjBuff() *bytes.Buffer {
    85  	return &p.buffer
    86  }
    87  
    88  // SetPtrToSubsetFontObj set subsetFontObj pointer
    89  func (p *PdfDictionaryObj) SetPtrToSubsetFontObj(ptr *SubsetFontObj) {
    90  	p.PtrToSubsetFontObj = ptr
    91  }
    92  
    93  func (p *PdfDictionaryObj) makeGlyfAndLocaTable() ([]byte, []int, error) {
    94  	ttfp := p.PtrToSubsetFontObj.GetTTFParser()
    95  	var glyf core.TableDirectoryEntry
    96  
    97  	numGlyphs := int(ttfp.NumGlyphs())
    98  
    99  	glyphArray := p.completeGlyphClosure(p.PtrToSubsetFontObj.CharacterToGlyphIndex)
   100  	glyphCount := len(glyphArray)
   101  	sort.Ints(glyphArray)
   102  
   103  	size := 0
   104  	for idx := 0; idx < glyphCount; idx++ {
   105  		size += p.getGlyphSize(glyphArray[idx])
   106  	}
   107  	glyf.Length = uint(size)
   108  
   109  	glyphTable := make([]byte, glyf.PaddedLength())
   110  	locaTable := make([]int, numGlyphs+1)
   111  
   112  	glyphOffset := 0
   113  	glyphIndex := 0
   114  	for idx := 0; idx < numGlyphs; idx++ {
   115  		locaTable[idx] = glyphOffset
   116  		if glyphIndex < glyphCount && glyphArray[glyphIndex] == idx {
   117  			glyphIndex++
   118  			bytes := p.getGlyphData(idx)
   119  			length := len(bytes)
   120  			if length > 0 {
   121  				for i := 0; i < length; i++ {
   122  					glyphTable[glyphOffset+i] = bytes[i]
   123  				}
   124  				glyphOffset += length
   125  			}
   126  		}
   127  	} //end for
   128  	locaTable[numGlyphs] = glyphOffset
   129  	return glyphTable, locaTable, nil
   130  }
   131  
   132  func (p *PdfDictionaryObj) getGlyphSize(glyph int) int {
   133  
   134  	ttfp := p.PtrToSubsetFontObj.GetTTFParser()
   135  	glyf := ttfp.GetTables()["glyf"]
   136  	start := int(glyf.Offset + ttfp.LocaTable[glyph])
   137  	next := int(glyf.Offset + ttfp.LocaTable[glyph+1])
   138  	return next - start
   139  }
   140  
   141  func (p *PdfDictionaryObj) getGlyphData(glyph int) []byte {
   142  	ttfp := p.PtrToSubsetFontObj.GetTTFParser()
   143  	glyf := ttfp.GetTables()["glyf"]
   144  	start := int(glyf.Offset + ttfp.LocaTable[glyph])
   145  	next := int(glyf.Offset + ttfp.LocaTable[glyph+1])
   146  	count := next - start
   147  	var data []byte
   148  	i := 0
   149  	for i < count {
   150  		data = append(data, ttfp.FontData()[start+i])
   151  		i++
   152  	}
   153  	return data
   154  }
   155  
   156  func (p *PdfDictionaryObj) makeFont() ([]byte, error) {
   157  	var buff Buff
   158  	ttfp := p.PtrToSubsetFontObj.GetTTFParser()
   159  	tables := make(map[string]core.TableDirectoryEntry)
   160  	tables["cvt "] = ttfp.GetTables()["cvt "] //มีช่องว่างด้วยนะ
   161  	tables["fpgm"] = ttfp.GetTables()["fpgm"]
   162  	tables["glyf"] = ttfp.GetTables()["glyf"]
   163  	tables["head"] = ttfp.GetTables()["head"]
   164  	tables["hhea"] = ttfp.GetTables()["hhea"]
   165  	tables["hmtx"] = ttfp.GetTables()["hmtx"]
   166  	tables["loca"] = ttfp.GetTables()["loca"]
   167  	tables["maxp"] = ttfp.GetTables()["maxp"]
   168  	tables["prep"] = ttfp.GetTables()["prep"]
   169  	tableCount := len(tables)
   170  	selector := EntrySelectors[tableCount]
   171  
   172  	glyphTable, locaTable, err := p.makeGlyfAndLocaTable()
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	WriteUInt32(&buff, 0x00010000)
   178  	WriteUInt16(&buff, uint(tableCount))
   179  	WriteUInt16(&buff, ((1 << uint(selector)) * 16))
   180  	WriteUInt16(&buff, uint(selector))
   181  	WriteUInt16(&buff, (uint(tableCount)-(1<<uint(selector)))*16)
   182  
   183  	var tags []string
   184  	for tag := range tables {
   185  		tags = append(tags, tag) //copy all tag
   186  	}
   187  	sort.Strings(tags) //order
   188  	idx := 0
   189  	tablePosition := int(12 + 16*tableCount)
   190  	for idx < tableCount {
   191  		entry := tables[tags[idx]]
   192  		//write data
   193  		offset := uint64(tablePosition)
   194  		buff.SetPosition(tablePosition)
   195  		if tags[idx] == "glyf" {
   196  			entry.Length = uint(len(glyphTable))
   197  			entry.CheckSum = CheckSum(glyphTable)
   198  			WriteBytes(&buff, glyphTable, 0, entry.PaddedLength())
   199  		} else if tags[idx] == "loca" {
   200  			if ttfp.IsShortIndex {
   201  				entry.Length = uint(len(locaTable) * 2)
   202  			} else {
   203  				entry.Length = uint(len(locaTable) * 4)
   204  			}
   205  
   206  			data := make([]byte, entry.PaddedLength())
   207  			length := len(locaTable)
   208  			byteIdx := 0
   209  			if ttfp.IsShortIndex {
   210  				for idx := 0; idx < length; idx++ {
   211  					val := locaTable[idx] / 2
   212  					data[byteIdx] = byte(val >> 8)
   213  					byteIdx++
   214  					data[byteIdx] = byte(val)
   215  					byteIdx++
   216  				}
   217  			} else {
   218  				for idx := 0; idx < length; idx++ {
   219  					val := locaTable[idx]
   220  					data[byteIdx] = byte(val >> 24)
   221  					byteIdx++
   222  					data[byteIdx] = byte(val >> 16)
   223  					byteIdx++
   224  					data[byteIdx] = byte(val >> 8)
   225  					byteIdx++
   226  					data[byteIdx] = byte(val)
   227  					byteIdx++
   228  				}
   229  			}
   230  			entry.CheckSum = CheckSum(data)
   231  			WriteBytes(&buff, data, 0, len(data))
   232  		} else {
   233  			WriteBytes(&buff, ttfp.FontData(), int(entry.Offset), entry.PaddedLength())
   234  		}
   235  		endPosition := buff.Position()
   236  		tablePosition = endPosition
   237  
   238  		//write table
   239  		buff.SetPosition(idx*16 + 12)
   240  		WriteTag(&buff, tags[idx])
   241  		WriteUInt32(&buff, uint(entry.CheckSum))
   242  		WriteUInt32(&buff, uint(offset)) //offset
   243  		WriteUInt32(&buff, uint(entry.Length))
   244  
   245  		tablePosition = endPosition
   246  		idx++
   247  	}
   248  	//DebugSubType(buff.Bytes())
   249  	//me.buffer.Write(buff.Bytes())
   250  	return buff.Bytes(), nil
   251  }
   252  
   253  func (p *PdfDictionaryObj) completeGlyphClosure(mapOfglyphs *MapOfCharacterToGlyphIndex) []int {
   254  	var glyphArray []int
   255  	//copy
   256  	isContainZero := false
   257  	glyphs := mapOfglyphs.AllVals()
   258  	for _, v := range glyphs {
   259  		glyphArray = append(glyphArray, int(v))
   260  		if v == 0 {
   261  			isContainZero = true
   262  		}
   263  	}
   264  	if !isContainZero {
   265  		glyphArray = append(glyphArray, 0)
   266  	}
   267  
   268  	i := 0
   269  	count := len(glyphs)
   270  	for i < count {
   271  		p.AddCompositeGlyphs(&glyphArray, glyphArray[i])
   272  		i++
   273  	}
   274  	return glyphArray
   275  }
   276  
   277  // AddCompositeGlyphs add composite glyph
   278  // composite glyph is a Unicode entity that can be defined as a sequence of one or more other characters.
   279  func (p *PdfDictionaryObj) AddCompositeGlyphs(glyphArray *[]int, glyph int) {
   280  	start := p.GetOffset(int(glyph))
   281  	if start == p.GetOffset(int(glyph)+1) {
   282  		return
   283  	}
   284  
   285  	offset := start
   286  	ttfp := p.PtrToSubsetFontObj.GetTTFParser()
   287  	fontData := ttfp.FontData()
   288  	numContours, step := ReadShortFromByte(fontData, offset)
   289  	offset += step
   290  	if numContours >= 0 {
   291  		return
   292  	}
   293  
   294  	offset += 8
   295  	for {
   296  		flags, step1 := ReadUShortFromByte(fontData, offset)
   297  		offset += step1
   298  		cGlyph, step2 := ReadUShortFromByte(fontData, offset)
   299  		offset += step2
   300  		//check cGlyph is contain in glyphArray?
   301  		glyphContainsKey := false
   302  		for _, g := range *glyphArray {
   303  			if g == int(cGlyph) {
   304  				glyphContainsKey = true
   305  				break
   306  			}
   307  		}
   308  		if !glyphContainsKey {
   309  			*glyphArray = append(*glyphArray, int(cGlyph))
   310  		}
   311  
   312  		if (flags & MORE_COMPONENTS) == 0 {
   313  			return
   314  		}
   315  		offsetAppend := 4
   316  		if (flags & ARG_1_AND_2_ARE_WORDS) == 0 {
   317  			offsetAppend = 2
   318  		}
   319  		if (flags & WE_HAVE_A_SCALE) != 0 {
   320  			offsetAppend += 2
   321  		} else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0 {
   322  			offsetAppend += 4
   323  		}
   324  		if (flags & WE_HAVE_A_TWO_BY_TWO) != 0 {
   325  			offsetAppend += 8
   326  		}
   327  		offset += offsetAppend
   328  	}
   329  }
   330  
   331  const WE_HAVE_A_SCALE = 8
   332  const MORE_COMPONENTS = 32
   333  const ARG_1_AND_2_ARE_WORDS = 1
   334  const WE_HAVE_AN_X_AND_Y_SCALE = 64
   335  const WE_HAVE_A_TWO_BY_TWO = 128
   336  
   337  // GetOffset get offset from glyf table
   338  func (p *PdfDictionaryObj) GetOffset(glyph int) int {
   339  	ttfp := p.PtrToSubsetFontObj.GetTTFParser()
   340  	glyf := ttfp.GetTables()["glyf"]
   341  	offset := int(glyf.Offset + ttfp.LocaTable[glyph])
   342  	return offset
   343  }
   344  
   345  // Build build buffer
   346  func (p *PdfDictionaryObj) Build(objID int) error {
   347  	return p.build(objID)
   348  }
   349  
   350  // GetObjBuff get buffer
   351  func (p *PdfDictionaryObj) GetObjBuff() *bytes.Buffer {
   352  	return p.getObjBuff()
   353  }
   354  
   355  // CheckSum check sum
   356  func CheckSum(data []byte) uint {
   357  
   358  	var byte3, byte2, byte1, byte0 uint64
   359  	byte3 = 0
   360  	byte2 = 0
   361  	byte1 = 0
   362  	byte0 = 0
   363  	length := len(data)
   364  	i := 0
   365  	for i < length {
   366  		byte3 += uint64(data[i])
   367  		i++
   368  		byte2 += uint64(data[i])
   369  		i++
   370  		byte1 += uint64(data[i])
   371  		i++
   372  		byte0 += uint64(data[i])
   373  		i++
   374  	}
   375  	//var result uint32
   376  	result := uint32(byte3<<24) + uint32(byte2<<16) + uint32(byte1<<8) + uint32(byte0)
   377  	return uint(result)
   378  }