github.com/phpdave11/gofpdf@v1.4.2/utf8fontfile.go (about)

     1  /*
     2   * Copyright (c) 2019 Arteom Korotkiy (Gmail: arteomkorotkiy)
     3   *
     4   * Permission to use, copy, modify, and distribute this software for any
     5   * purpose with or without fee is hereby granted, provided that the above
     6   * copyright notice and this permission notice appear in all copies.
     7   *
     8   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     9   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    10   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    11   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    12   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    13   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    14   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    15   */
    16  
    17  package gofpdf
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/binary"
    22  	"fmt"
    23  	"math"
    24  	"sort"
    25  )
    26  
    27  // flags
    28  const symbolWords = 1 << 0
    29  const symbolScale = 1 << 3
    30  const symbolContinue = 1 << 5
    31  const symbolAllScale = 1 << 6
    32  const symbol2x2 = 1 << 7
    33  
    34  // CID map Init
    35  const toUnicode = "/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo\n<</Registry (Adobe)\n/Ordering (UCS)\n/Supplement 0\n>> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange\n<0000> <FFFF>\nendcodespacerange\n1 beginbfrange\n<0000> <FFFF> <0000>\nendbfrange\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend"
    36  
    37  type utf8FontFile struct {
    38  	fileReader           *fileReader
    39  	LastRune             int
    40  	tableDescriptions    map[string]*tableDescription
    41  	outTablesData        map[string][]byte
    42  	symbolPosition       []int
    43  	charSymbolDictionary map[int]int
    44  	Ascent               int
    45  	Descent              int
    46  	fontElementSize      int
    47  	Bbox                 fontBoxType
    48  	CapHeight            int
    49  	StemV                int
    50  	ItalicAngle          int
    51  	Flags                int
    52  	UnderlinePosition    float64
    53  	UnderlineThickness   float64
    54  	CharWidths           []int
    55  	DefaultWidth         float64
    56  	symbolData           map[int]map[string][]int
    57  	CodeSymbolDictionary map[int]int
    58  }
    59  
    60  type tableDescription struct {
    61  	name     string
    62  	checksum []int
    63  	position int
    64  	size     int
    65  }
    66  
    67  type fileReader struct {
    68  	readerPosition int64
    69  	array          []byte
    70  }
    71  
    72  func (fr *fileReader) Read(s int) []byte {
    73  	b := fr.array[fr.readerPosition : fr.readerPosition+int64(s)]
    74  	fr.readerPosition += int64(s)
    75  	return b
    76  }
    77  
    78  func (fr *fileReader) seek(shift int64, flag int) (int64, error) {
    79  	if flag == 0 {
    80  		fr.readerPosition = shift
    81  	} else if flag == 1 {
    82  		fr.readerPosition += shift
    83  	} else if flag == 2 {
    84  		fr.readerPosition = int64(len(fr.array)) - shift
    85  	}
    86  	return int64(fr.readerPosition), nil
    87  }
    88  
    89  func newUTF8Font(reader *fileReader) *utf8FontFile {
    90  	utf := utf8FontFile{
    91  		fileReader: reader,
    92  	}
    93  	return &utf
    94  }
    95  
    96  func (utf *utf8FontFile) parseFile() error {
    97  	utf.fileReader.readerPosition = 0
    98  	utf.symbolPosition = make([]int, 0)
    99  	utf.charSymbolDictionary = make(map[int]int)
   100  	utf.tableDescriptions = make(map[string]*tableDescription)
   101  	utf.outTablesData = make(map[string][]byte)
   102  	utf.Ascent = 0
   103  	utf.Descent = 0
   104  	codeType := uint32(utf.readUint32())
   105  	if codeType == 0x4F54544F {
   106  		return fmt.Errorf("not supported\n ")
   107  	}
   108  	if codeType == 0x74746366 {
   109  		return fmt.Errorf("not supported\n ")
   110  	}
   111  	if codeType != 0x00010000 && codeType != 0x74727565 {
   112  		return fmt.Errorf("Not a TrueType font: codeType=%v\n ", codeType)
   113  	}
   114  	utf.generateTableDescriptions()
   115  	utf.parseTables()
   116  	return nil
   117  }
   118  
   119  func (utf *utf8FontFile) generateTableDescriptions() {
   120  
   121  	tablesCount := utf.readUint16()
   122  	_ = utf.readUint16()
   123  	_ = utf.readUint16()
   124  	_ = utf.readUint16()
   125  	utf.tableDescriptions = make(map[string]*tableDescription)
   126  
   127  	for i := 0; i < tablesCount; i++ {
   128  		record := tableDescription{
   129  			name:     utf.readTableName(),
   130  			checksum: []int{utf.readUint16(), utf.readUint16()},
   131  			position: utf.readUint32(),
   132  			size:     utf.readUint32(),
   133  		}
   134  		utf.tableDescriptions[record.name] = &record
   135  	}
   136  }
   137  
   138  func (utf *utf8FontFile) readTableName() string {
   139  	return string(utf.fileReader.Read(4))
   140  }
   141  
   142  func (utf *utf8FontFile) readUint16() int {
   143  	s := utf.fileReader.Read(2)
   144  	return (int(s[0]) << 8) + int(s[1])
   145  }
   146  
   147  func (utf *utf8FontFile) readUint32() int {
   148  	s := utf.fileReader.Read(4)
   149  	return (int(s[0]) * 16777216) + (int(s[1]) << 16) + (int(s[2]) << 8) + int(s[3]) // 	16777216  = 1<<24
   150  }
   151  
   152  func (utf *utf8FontFile) calcInt32(x, y []int) []int {
   153  	answer := make([]int, 2)
   154  	if y[1] > x[1] {
   155  		x[1] += 1 << 16
   156  		x[0]++
   157  	}
   158  	answer[1] = x[1] - y[1]
   159  	if y[0] > x[0] {
   160  		x[0] += 1 << 16
   161  	}
   162  	answer[0] = x[0] - y[0]
   163  	answer[0] = answer[0] & 0xFFFF
   164  	return answer
   165  }
   166  
   167  func (utf *utf8FontFile) generateChecksum(data []byte) []int {
   168  	if (len(data) % 4) != 0 {
   169  		for i := 0; (len(data) % 4) != 0; i++ {
   170  			data = append(data, 0)
   171  		}
   172  	}
   173  	answer := []int{0x0000, 0x0000}
   174  	for i := 0; i < len(data); i += 4 {
   175  		answer[0] += (int(data[i]) << 8) + int(data[i+1])
   176  		answer[1] += (int(data[i+2]) << 8) + int(data[i+3])
   177  		answer[0] += answer[1] >> 16
   178  		answer[1] = answer[1] & 0xFFFF
   179  		answer[0] = answer[0] & 0xFFFF
   180  	}
   181  	return answer
   182  }
   183  
   184  func (utf *utf8FontFile) seek(shift int) {
   185  	_, _ = utf.fileReader.seek(int64(shift), 0)
   186  }
   187  
   188  func (utf *utf8FontFile) skip(delta int) {
   189  	_, _ = utf.fileReader.seek(int64(delta), 1)
   190  }
   191  
   192  //SeekTable position
   193  func (utf *utf8FontFile) SeekTable(name string) int {
   194  	return utf.seekTable(name, 0)
   195  }
   196  
   197  func (utf *utf8FontFile) seekTable(name string, offsetInTable int) int {
   198  	_, _ = utf.fileReader.seek(int64(utf.tableDescriptions[name].position+offsetInTable), 0)
   199  	return int(utf.fileReader.readerPosition)
   200  }
   201  
   202  func (utf *utf8FontFile) readInt16() int16 {
   203  	s := utf.fileReader.Read(2)
   204  	a := (int16(s[0]) << 8) + int16(s[1])
   205  	if (int(a) & (1 << 15)) == 0 {
   206  		a = int16(int(a) - (1 << 16))
   207  	}
   208  	return a
   209  }
   210  
   211  func (utf *utf8FontFile) getUint16(pos int) int {
   212  	_, _ = utf.fileReader.seek(int64(pos), 0)
   213  	s := utf.fileReader.Read(2)
   214  	return (int(s[0]) << 8) + int(s[1])
   215  }
   216  
   217  func (utf *utf8FontFile) splice(stream []byte, offset int, value []byte) []byte {
   218  	stream = append([]byte{}, stream...)
   219  	return append(append(stream[:offset], value...), stream[offset+len(value):]...)
   220  }
   221  
   222  func (utf *utf8FontFile) insertUint16(stream []byte, offset int, value int) []byte {
   223  	up := make([]byte, 2)
   224  	binary.BigEndian.PutUint16(up, uint16(value))
   225  	return utf.splice(stream, offset, up)
   226  }
   227  
   228  func (utf *utf8FontFile) getRange(pos, length int) []byte {
   229  	_, _ = utf.fileReader.seek(int64(pos), 0)
   230  	if length < 1 {
   231  		return make([]byte, 0)
   232  	}
   233  	s := utf.fileReader.Read(length)
   234  	return s
   235  }
   236  
   237  func (utf *utf8FontFile) getTableData(name string) []byte {
   238  	desckrip := utf.tableDescriptions[name]
   239  	if desckrip == nil {
   240  		return nil
   241  	}
   242  	if desckrip.size == 0 {
   243  		return nil
   244  	}
   245  	_, _ = utf.fileReader.seek(int64(desckrip.position), 0)
   246  	s := utf.fileReader.Read(desckrip.size)
   247  	return s
   248  }
   249  
   250  func (utf *utf8FontFile) setOutTable(name string, data []byte) {
   251  	if data == nil {
   252  		return
   253  	}
   254  	if name == "head" {
   255  		data = utf.splice(data, 8, []byte{0, 0, 0, 0})
   256  	}
   257  	utf.outTablesData[name] = data
   258  }
   259  
   260  func arrayKeys(arr map[int]string) []int {
   261  	answer := make([]int, len(arr))
   262  	i := 0
   263  	for key := range arr {
   264  		answer[i] = key
   265  		i++
   266  	}
   267  	return answer
   268  }
   269  
   270  func inArray(s int, arr []int) bool {
   271  	for _, i := range arr {
   272  		if s == i {
   273  			return true
   274  		}
   275  	}
   276  	return false
   277  }
   278  
   279  func (utf *utf8FontFile) parseNAMETable() int {
   280  	namePosition := utf.SeekTable("name")
   281  	format := utf.readUint16()
   282  	if format != 0 {
   283  		fmt.Printf("Illegal format %d\n", format)
   284  		return format
   285  	}
   286  	nameCount := utf.readUint16()
   287  	stringDataPosition := namePosition + utf.readUint16()
   288  	names := map[int]string{1: "", 2: "", 3: "", 4: "", 6: ""}
   289  	keys := arrayKeys(names)
   290  	counter := len(names)
   291  	for i := 0; i < nameCount; i++ {
   292  		system := utf.readUint16()
   293  		code := utf.readUint16()
   294  		local := utf.readUint16()
   295  		nameID := utf.readUint16()
   296  		size := utf.readUint16()
   297  		position := utf.readUint16()
   298  		if !inArray(nameID, keys) {
   299  			continue
   300  		}
   301  		currentName := ""
   302  		if system == 3 && code == 1 && local == 0x409 {
   303  			oldPos := utf.fileReader.readerPosition
   304  			utf.seek(stringDataPosition + position)
   305  			if size%2 != 0 {
   306  				fmt.Printf("name is not binar byte format\n")
   307  				return format
   308  			}
   309  			size /= 2
   310  			currentName = ""
   311  			for size > 0 {
   312  				char := utf.readUint16()
   313  				currentName += string(rune(char))
   314  				size--
   315  			}
   316  			utf.fileReader.readerPosition = oldPos
   317  			utf.seek(int(oldPos))
   318  		} else if system == 1 && code == 0 && local == 0 {
   319  			oldPos := utf.fileReader.readerPosition
   320  			currentName = string(utf.getRange(stringDataPosition+position, size))
   321  			utf.fileReader.readerPosition = oldPos
   322  			utf.seek(int(oldPos))
   323  		}
   324  		if currentName != "" && names[nameID] == "" {
   325  			names[nameID] = currentName
   326  			counter--
   327  			if counter == 0 {
   328  				break
   329  			}
   330  		}
   331  	}
   332  	return format
   333  }
   334  
   335  func (utf *utf8FontFile) parseHEADTable() {
   336  	utf.SeekTable("head")
   337  	utf.skip(18)
   338  	utf.fontElementSize = utf.readUint16()
   339  	scale := 1000.0 / float64(utf.fontElementSize)
   340  	utf.skip(16)
   341  	xMin := utf.readInt16()
   342  	yMin := utf.readInt16()
   343  	xMax := utf.readInt16()
   344  	yMax := utf.readInt16()
   345  	utf.Bbox = fontBoxType{int(float64(xMin) * scale), int(float64(yMin) * scale), int(float64(xMax) * scale), int(float64(yMax) * scale)}
   346  	utf.skip(3 * 2)
   347  	_ = utf.readUint16()
   348  	symbolDataFormat := utf.readUint16()
   349  	if symbolDataFormat != 0 {
   350  		fmt.Printf("Unknown symbol data format %d\n", symbolDataFormat)
   351  		return
   352  	}
   353  }
   354  
   355  func (utf *utf8FontFile) parseHHEATable() int {
   356  	metricsCount := 0
   357  	if _, OK := utf.tableDescriptions["hhea"]; OK {
   358  		scale := 1000.0 / float64(utf.fontElementSize)
   359  		utf.SeekTable("hhea")
   360  		utf.skip(4)
   361  		hheaAscender := utf.readInt16()
   362  		hheaDescender := utf.readInt16()
   363  		utf.Ascent = int(float64(hheaAscender) * scale)
   364  		utf.Descent = int(float64(hheaDescender) * scale)
   365  		utf.skip(24)
   366  		metricDataFormat := utf.readUint16()
   367  		if metricDataFormat != 0 {
   368  			fmt.Printf("Unknown horizontal metric data format %d\n", metricDataFormat)
   369  			return 0
   370  		}
   371  		metricsCount = utf.readUint16()
   372  		if metricsCount == 0 {
   373  			fmt.Printf("Number of horizontal metrics is 0\n")
   374  			return 0
   375  		}
   376  	}
   377  	return metricsCount
   378  }
   379  
   380  func (utf *utf8FontFile) parseOS2Table() int {
   381  	var weightType int
   382  	scale := 1000.0 / float64(utf.fontElementSize)
   383  	if _, OK := utf.tableDescriptions["OS/2"]; OK {
   384  		utf.SeekTable("OS/2")
   385  		version := utf.readUint16()
   386  		utf.skip(2)
   387  		weightType = utf.readUint16()
   388  		utf.skip(2)
   389  		fsType := utf.readUint16()
   390  		if fsType == 0x0002 || (fsType&0x0300) != 0 {
   391  			fmt.Printf("ERROR - copyright restrictions.\n")
   392  			return 0
   393  		}
   394  		utf.skip(20)
   395  		_ = utf.readInt16()
   396  
   397  		utf.skip(36)
   398  		sTypoAscender := utf.readInt16()
   399  		sTypoDescender := utf.readInt16()
   400  		if utf.Ascent == 0 {
   401  			utf.Ascent = int(float64(sTypoAscender) * scale)
   402  		}
   403  		if utf.Descent == 0 {
   404  			utf.Descent = int(float64(sTypoDescender) * scale)
   405  		}
   406  		if version > 1 {
   407  			utf.skip(16)
   408  			sCapHeight := utf.readInt16()
   409  			utf.CapHeight = int(float64(sCapHeight) * scale)
   410  		} else {
   411  			utf.CapHeight = utf.Ascent
   412  		}
   413  	} else {
   414  		weightType = 500
   415  		if utf.Ascent == 0 {
   416  			utf.Ascent = int(float64(utf.Bbox.Ymax) * scale)
   417  		}
   418  		if utf.Descent == 0 {
   419  			utf.Descent = int(float64(utf.Bbox.Ymin) * scale)
   420  		}
   421  		utf.CapHeight = utf.Ascent
   422  	}
   423  	utf.StemV = 50 + int(math.Pow(float64(weightType)/65.0, 2))
   424  	return weightType
   425  }
   426  
   427  func (utf *utf8FontFile) parsePOSTTable(weight int) {
   428  	utf.SeekTable("post")
   429  	utf.skip(4)
   430  	utf.ItalicAngle = int(utf.readInt16()) + utf.readUint16()/65536.0
   431  	scale := 1000.0 / float64(utf.fontElementSize)
   432  	utf.UnderlinePosition = float64(utf.readInt16()) * scale
   433  	utf.UnderlineThickness = float64(utf.readInt16()) * scale
   434  	fixed := utf.readUint32()
   435  
   436  	utf.Flags = 4
   437  
   438  	if utf.ItalicAngle != 0 {
   439  		utf.Flags = utf.Flags | 64
   440  	}
   441  	if weight >= 600 {
   442  		utf.Flags = utf.Flags | 262144
   443  	}
   444  	if fixed != 0 {
   445  		utf.Flags = utf.Flags | 1
   446  	}
   447  }
   448  
   449  func (utf *utf8FontFile) parseCMAPTable(format int) int {
   450  	cmapPosition := utf.SeekTable("cmap")
   451  	utf.skip(2)
   452  	cmapTableCount := utf.readUint16()
   453  	cidCMAPPosition := 0
   454  	for i := 0; i < cmapTableCount; i++ {
   455  		system := utf.readUint16()
   456  		coded := utf.readUint16()
   457  		position := utf.readUint32()
   458  		oldReaderPosition := utf.fileReader.readerPosition
   459  		if (system == 3 && coded == 1) || system == 0 { // Microsoft, Unicode
   460  			format = utf.getUint16(cmapPosition + position)
   461  			if format == 4 {
   462  				if cidCMAPPosition == 0 {
   463  					cidCMAPPosition = cmapPosition + position
   464  				}
   465  				break
   466  			}
   467  		}
   468  		utf.seek(int(oldReaderPosition))
   469  	}
   470  	if cidCMAPPosition == 0 {
   471  		fmt.Printf("Font does not have cmap for Unicode\n")
   472  		return cidCMAPPosition
   473  	}
   474  	return cidCMAPPosition
   475  }
   476  
   477  func (utf *utf8FontFile) parseTables() {
   478  	f := utf.parseNAMETable()
   479  	utf.parseHEADTable()
   480  	n := utf.parseHHEATable()
   481  	w := utf.parseOS2Table()
   482  	utf.parsePOSTTable(w)
   483  	runeCMAPPosition := utf.parseCMAPTable(f)
   484  
   485  	utf.SeekTable("maxp")
   486  	utf.skip(4)
   487  	numSymbols := utf.readUint16()
   488  
   489  	symbolCharDictionary := make(map[int][]int)
   490  	charSymbolDictionary := make(map[int]int)
   491  	utf.generateSCCSDictionaries(runeCMAPPosition, symbolCharDictionary, charSymbolDictionary)
   492  
   493  	scale := 1000.0 / float64(utf.fontElementSize)
   494  	utf.parseHMTXTable(n, numSymbols, symbolCharDictionary, scale)
   495  }
   496  
   497  func (utf *utf8FontFile) generateCMAP() map[int][]int {
   498  	cmapPosition := utf.SeekTable("cmap")
   499  	utf.skip(2)
   500  	cmapTableCount := utf.readUint16()
   501  	runeCmapPosition := 0
   502  	for i := 0; i < cmapTableCount; i++ {
   503  		system := utf.readUint16()
   504  		coder := utf.readUint16()
   505  		position := utf.readUint32()
   506  		oldPosition := utf.fileReader.readerPosition
   507  		if (system == 3 && coder == 1) || system == 0 {
   508  			format := utf.getUint16(cmapPosition + position)
   509  			if format == 4 {
   510  				runeCmapPosition = cmapPosition + position
   511  				break
   512  			}
   513  		}
   514  		utf.seek(int(oldPosition))
   515  	}
   516  
   517  	if runeCmapPosition == 0 {
   518  		fmt.Printf("Font does not have cmap for Unicode\n")
   519  		return nil
   520  	}
   521  
   522  	symbolCharDictionary := make(map[int][]int)
   523  	charSymbolDictionary := make(map[int]int)
   524  	utf.generateSCCSDictionaries(runeCmapPosition, symbolCharDictionary, charSymbolDictionary)
   525  
   526  	utf.charSymbolDictionary = charSymbolDictionary
   527  
   528  	return symbolCharDictionary
   529  }
   530  
   531  func (utf *utf8FontFile) parseSymbols(usedRunes map[int]int) (map[int]int, map[int]int, map[int]int, []int) {
   532  	symbolCollection := map[int]int{0: 0}
   533  	charSymbolPairCollection := make(map[int]int)
   534  	for _, char := range usedRunes {
   535  		if _, OK := utf.charSymbolDictionary[char]; OK {
   536  			symbolCollection[utf.charSymbolDictionary[char]] = char
   537  			charSymbolPairCollection[char] = utf.charSymbolDictionary[char]
   538  
   539  		}
   540  		utf.LastRune = max(utf.LastRune, char)
   541  	}
   542  
   543  	begin := utf.tableDescriptions["glyf"].position
   544  
   545  	symbolArray := make(map[int]int)
   546  	symbolCollectionKeys := keySortInt(symbolCollection)
   547  
   548  	symbolCounter := 0
   549  	maxRune := 0
   550  	for _, oldSymbolIndex := range symbolCollectionKeys {
   551  		maxRune = max(maxRune, symbolCollection[oldSymbolIndex])
   552  		symbolArray[oldSymbolIndex] = symbolCounter
   553  		symbolCounter++
   554  	}
   555  	charSymbolPairCollectionKeys := keySortInt(charSymbolPairCollection)
   556  	runeSymbolPairCollection := make(map[int]int)
   557  	for _, runa := range charSymbolPairCollectionKeys {
   558  		runeSymbolPairCollection[runa] = symbolArray[charSymbolPairCollection[runa]]
   559  	}
   560  	utf.CodeSymbolDictionary = runeSymbolPairCollection
   561  
   562  	symbolCollectionKeys = keySortInt(symbolCollection)
   563  	for _, oldSymbolIndex := range symbolCollectionKeys {
   564  		_, symbolArray, symbolCollection, symbolCollectionKeys = utf.getSymbols(oldSymbolIndex, &begin, symbolArray, symbolCollection, symbolCollectionKeys)
   565  	}
   566  
   567  	return runeSymbolPairCollection, symbolArray, symbolCollection, symbolCollectionKeys
   568  }
   569  
   570  func (utf *utf8FontFile) generateCMAPTable(cidSymbolPairCollection map[int]int, numSymbols int) []byte {
   571  	cidSymbolPairCollectionKeys := keySortInt(cidSymbolPairCollection)
   572  	cidID := 0
   573  	cidArray := make(map[int][]int)
   574  	prevCid := -2
   575  	prevSymbol := -1
   576  	for _, cid := range cidSymbolPairCollectionKeys {
   577  		if cid == (prevCid+1) && cidSymbolPairCollection[cid] == (prevSymbol+1) {
   578  			if n, OK := cidArray[cidID]; !OK || n == nil {
   579  				cidArray[cidID] = make([]int, 0)
   580  			}
   581  			cidArray[cidID] = append(cidArray[cidID], cidSymbolPairCollection[cid])
   582  		} else {
   583  			cidID = cid
   584  			cidArray[cidID] = make([]int, 0)
   585  			cidArray[cidID] = append(cidArray[cidID], cidSymbolPairCollection[cid])
   586  		}
   587  		prevCid = cid
   588  		prevSymbol = cidSymbolPairCollection[cid]
   589  	}
   590  	cidArrayKeys := keySortArrayRangeMap(cidArray)
   591  	segCount := len(cidArray) + 1
   592  
   593  	searchRange := 1
   594  	entrySelector := 0
   595  	for searchRange*2 <= segCount {
   596  		searchRange = searchRange * 2
   597  		entrySelector = entrySelector + 1
   598  	}
   599  	searchRange = searchRange * 2
   600  	rangeShift := segCount*2 - searchRange
   601  	length := 16 + (8 * segCount) + (numSymbols + 1)
   602  	cmap := []int{0, 1, 3, 1, 0, 12, 4, length, 0, segCount * 2, searchRange, entrySelector, rangeShift}
   603  
   604  	for _, start := range cidArrayKeys {
   605  		endCode := start + (len(cidArray[start]) - 1)
   606  		cmap = append(cmap, endCode)
   607  	}
   608  	cmap = append(cmap, 0xFFFF)
   609  	cmap = append(cmap, 0)
   610  
   611  	for _, cidKey := range cidArrayKeys {
   612  		cmap = append(cmap, cidKey)
   613  	}
   614  	cmap = append(cmap, 0xFFFF)
   615  	for _, cidKey := range cidArrayKeys {
   616  		idDelta := -(cidKey - cidArray[cidKey][0])
   617  		cmap = append(cmap, idDelta)
   618  	}
   619  	cmap = append(cmap, 1)
   620  	for range cidArray {
   621  		cmap = append(cmap, 0)
   622  
   623  	}
   624  	cmap = append(cmap, 0)
   625  	for _, start := range cidArrayKeys {
   626  		for _, glidx := range cidArray[start] {
   627  			cmap = append(cmap, glidx)
   628  		}
   629  	}
   630  	cmap = append(cmap, 0)
   631  	cmapstr := make([]byte, 0)
   632  	for _, cm := range cmap {
   633  		cmapstr = append(cmapstr, packUint16(cm)...)
   634  	}
   635  	return cmapstr
   636  }
   637  
   638  //GenerateCutFont fill utf8FontFile from .utf file, only with runes from usedRunes
   639  func (utf *utf8FontFile) GenerateCutFont(usedRunes map[int]int) []byte {
   640  	utf.fileReader.readerPosition = 0
   641  	utf.symbolPosition = make([]int, 0)
   642  	utf.charSymbolDictionary = make(map[int]int)
   643  	utf.tableDescriptions = make(map[string]*tableDescription)
   644  	utf.outTablesData = make(map[string][]byte)
   645  	utf.Ascent = 0
   646  	utf.Descent = 0
   647  	utf.skip(4)
   648  	utf.LastRune = 0
   649  	utf.generateTableDescriptions()
   650  
   651  	utf.SeekTable("head")
   652  	utf.skip(50)
   653  	LocaFormat := utf.readUint16()
   654  
   655  	utf.SeekTable("hhea")
   656  	utf.skip(34)
   657  	metricsCount := utf.readUint16()
   658  	oldMetrics := metricsCount
   659  
   660  	utf.SeekTable("maxp")
   661  	utf.skip(4)
   662  	numSymbols := utf.readUint16()
   663  
   664  	symbolCharDictionary := utf.generateCMAP()
   665  	if symbolCharDictionary == nil {
   666  		return nil
   667  	}
   668  
   669  	utf.parseHMTXTable(metricsCount, numSymbols, symbolCharDictionary, 1.0)
   670  
   671  	utf.parseLOCATable(LocaFormat, numSymbols)
   672  
   673  	cidSymbolPairCollection, symbolArray, symbolCollection, symbolCollectionKeys := utf.parseSymbols(usedRunes)
   674  
   675  	metricsCount = len(symbolCollection)
   676  	numSymbols = metricsCount
   677  
   678  	utf.setOutTable("name", utf.getTableData("name"))
   679  	utf.setOutTable("cvt ", utf.getTableData("cvt "))
   680  	utf.setOutTable("fpgm", utf.getTableData("fpgm"))
   681  	utf.setOutTable("prep", utf.getTableData("prep"))
   682  	utf.setOutTable("gasp", utf.getTableData("gasp"))
   683  
   684  	postTable := utf.getTableData("post")
   685  	postTable = append(append([]byte{0x00, 0x03, 0x00, 0x00}, postTable[4:16]...), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}...)
   686  	utf.setOutTable("post", postTable)
   687  
   688  	delete(cidSymbolPairCollection, 0)
   689  
   690  	utf.setOutTable("cmap", utf.generateCMAPTable(cidSymbolPairCollection, numSymbols))
   691  
   692  	symbolData := utf.getTableData("glyf")
   693  
   694  	offsets := make([]int, 0)
   695  	glyfData := make([]byte, 0)
   696  	pos := 0
   697  	hmtxData := make([]byte, 0)
   698  	utf.symbolData = make(map[int]map[string][]int, 0)
   699  
   700  	for _, originalSymbolIdx := range symbolCollectionKeys {
   701  		hm := utf.getMetrics(oldMetrics, originalSymbolIdx)
   702  		hmtxData = append(hmtxData, hm...)
   703  
   704  		offsets = append(offsets, pos)
   705  		symbolPos := utf.symbolPosition[originalSymbolIdx]
   706  		symbolLen := utf.symbolPosition[originalSymbolIdx+1] - symbolPos
   707  		data := symbolData[symbolPos : symbolPos+symbolLen]
   708  		var up int
   709  		if symbolLen > 0 {
   710  			up = unpackUint16(data[0:2])
   711  		}
   712  
   713  		if symbolLen > 2 && (up&(1<<15)) != 0 {
   714  			posInSymbol := 10
   715  			flags := symbolContinue
   716  			nComponentElements := 0
   717  			for (flags & symbolContinue) != 0 {
   718  				nComponentElements++
   719  				up = unpackUint16(data[posInSymbol : posInSymbol+2])
   720  				flags = up
   721  				up = unpackUint16(data[posInSymbol+2 : posInSymbol+4])
   722  				symbolIdx := up
   723  				if _, OK := utf.symbolData[originalSymbolIdx]; !OK {
   724  					utf.symbolData[originalSymbolIdx] = make(map[string][]int)
   725  				}
   726  				if _, OK := utf.symbolData[originalSymbolIdx]["compSymbols"]; !OK {
   727  					utf.symbolData[originalSymbolIdx]["compSymbols"] = make([]int, 0)
   728  				}
   729  				utf.symbolData[originalSymbolIdx]["compSymbols"] = append(utf.symbolData[originalSymbolIdx]["compSymbols"], symbolIdx)
   730  				data = utf.insertUint16(data, posInSymbol+2, symbolArray[symbolIdx])
   731  				posInSymbol += 4
   732  				if (flags & symbolWords) != 0 {
   733  					posInSymbol += 4
   734  				} else {
   735  					posInSymbol += 2
   736  				}
   737  				if (flags & symbolScale) != 0 {
   738  					posInSymbol += 2
   739  				} else if (flags & symbolAllScale) != 0 {
   740  					posInSymbol += 4
   741  				} else if (flags & symbol2x2) != 0 {
   742  					posInSymbol += 8
   743  				}
   744  			}
   745  		}
   746  
   747  		glyfData = append(glyfData, data...)
   748  		pos += symbolLen
   749  		if pos%4 != 0 {
   750  			padding := 4 - (pos % 4)
   751  			glyfData = append(glyfData, make([]byte, padding)...)
   752  			pos += padding
   753  		}
   754  	}
   755  
   756  	offsets = append(offsets, pos)
   757  	utf.setOutTable("glyf", glyfData)
   758  
   759  	utf.setOutTable("hmtx", hmtxData)
   760  
   761  	locaData := make([]byte, 0)
   762  	if ((pos + 1) >> 1) > 0xFFFF {
   763  		LocaFormat = 1
   764  		for _, offset := range offsets {
   765  			locaData = append(locaData, packUint32(offset)...)
   766  		}
   767  	} else {
   768  		LocaFormat = 0
   769  		for _, offset := range offsets {
   770  			locaData = append(locaData, packUint16(offset/2)...)
   771  		}
   772  	}
   773  	utf.setOutTable("loca", locaData)
   774  
   775  	headData := utf.getTableData("head")
   776  	headData = utf.insertUint16(headData, 50, LocaFormat)
   777  	utf.setOutTable("head", headData)
   778  
   779  	hheaData := utf.getTableData("hhea")
   780  	hheaData = utf.insertUint16(hheaData, 34, metricsCount)
   781  	utf.setOutTable("hhea", hheaData)
   782  
   783  	maxp := utf.getTableData("maxp")
   784  	maxp = utf.insertUint16(maxp, 4, numSymbols)
   785  	utf.setOutTable("maxp", maxp)
   786  
   787  	os2Data := utf.getTableData("OS/2")
   788  	utf.setOutTable("OS/2", os2Data)
   789  
   790  	return utf.assembleTables()
   791  }
   792  
   793  func (utf *utf8FontFile) getSymbols(originalSymbolIdx int, start *int, symbolSet map[int]int, SymbolsCollection map[int]int, SymbolsCollectionKeys []int) (*int, map[int]int, map[int]int, []int) {
   794  	symbolPos := utf.symbolPosition[originalSymbolIdx]
   795  	symbolSize := utf.symbolPosition[originalSymbolIdx+1] - symbolPos
   796  	if symbolSize == 0 {
   797  		return start, symbolSet, SymbolsCollection, SymbolsCollectionKeys
   798  	}
   799  	utf.seek(*start + symbolPos)
   800  
   801  	lineCount := utf.readInt16()
   802  
   803  	if lineCount < 0 {
   804  		utf.skip(8)
   805  		flags := symbolContinue
   806  		for flags&symbolContinue != 0 {
   807  			flags = utf.readUint16()
   808  			symbolIndex := utf.readUint16()
   809  			if _, OK := symbolSet[symbolIndex]; !OK {
   810  				symbolSet[symbolIndex] = len(SymbolsCollection)
   811  				SymbolsCollection[symbolIndex] = 1
   812  				SymbolsCollectionKeys = append(SymbolsCollectionKeys, symbolIndex)
   813  			}
   814  			oldPosition, _ := utf.fileReader.seek(0, 1)
   815  			_, _, _, SymbolsCollectionKeys = utf.getSymbols(symbolIndex, start, symbolSet, SymbolsCollection, SymbolsCollectionKeys)
   816  			utf.seek(int(oldPosition))
   817  			if flags&symbolWords != 0 {
   818  				utf.skip(4)
   819  			} else {
   820  				utf.skip(2)
   821  			}
   822  			if flags&symbolScale != 0 {
   823  				utf.skip(2)
   824  			} else if flags&symbolAllScale != 0 {
   825  				utf.skip(4)
   826  			} else if flags&symbol2x2 != 0 {
   827  				utf.skip(8)
   828  			}
   829  		}
   830  	}
   831  	return start, symbolSet, SymbolsCollection, SymbolsCollectionKeys
   832  }
   833  
   834  func (utf *utf8FontFile) parseHMTXTable(numberOfHMetrics, numSymbols int, symbolToChar map[int][]int, scale float64) {
   835  	var widths int
   836  	start := utf.SeekTable("hmtx")
   837  	arrayWidths := 0
   838  	var arr []int
   839  	utf.CharWidths = make([]int, 256*256)
   840  	charCount := 0
   841  	arr = unpackUint16Array(utf.getRange(start, numberOfHMetrics*4))
   842  	for symbol := 0; symbol < numberOfHMetrics; symbol++ {
   843  		arrayWidths = arr[(symbol*2)+1]
   844  		if _, OK := symbolToChar[symbol]; OK || symbol == 0 {
   845  
   846  			if arrayWidths >= (1 << 15) {
   847  				arrayWidths = 0
   848  			}
   849  			if symbol == 0 {
   850  				utf.DefaultWidth = scale * float64(arrayWidths)
   851  				continue
   852  			}
   853  			for _, char := range symbolToChar[symbol] {
   854  				if char != 0 && char != 65535 {
   855  					widths = int(math.Round(scale * float64(arrayWidths)))
   856  					if widths == 0 {
   857  						widths = 65535
   858  					}
   859  					if char < 196608 {
   860  						utf.CharWidths[char] = widths
   861  						charCount++
   862  					}
   863  				}
   864  			}
   865  		}
   866  	}
   867  	diff := numSymbols - numberOfHMetrics
   868  	for pos := 0; pos < diff; pos++ {
   869  		symbol := pos + numberOfHMetrics
   870  		if _, OK := symbolToChar[symbol]; OK {
   871  			for _, char := range symbolToChar[symbol] {
   872  				if char != 0 && char != 65535 {
   873  					widths = int(math.Round(scale * float64(arrayWidths)))
   874  					if widths == 0 {
   875  						widths = 65535
   876  					}
   877  					if char < 196608 {
   878  						utf.CharWidths[char] = widths
   879  						charCount++
   880  					}
   881  				}
   882  			}
   883  		}
   884  	}
   885  	utf.CharWidths[0] = charCount
   886  }
   887  
   888  func (utf *utf8FontFile) getMetrics(metricCount, gid int) []byte {
   889  	start := utf.SeekTable("hmtx")
   890  	var metrics []byte
   891  	if gid < metricCount {
   892  		utf.seek(start + (gid * 4))
   893  		metrics = utf.fileReader.Read(4)
   894  	} else {
   895  		utf.seek(start + ((metricCount - 1) * 4))
   896  		metrics = utf.fileReader.Read(2)
   897  		utf.seek(start + (metricCount * 2) + (gid * 2))
   898  		metrics = append(metrics, utf.fileReader.Read(2)...)
   899  	}
   900  	return metrics
   901  }
   902  
   903  func (utf *utf8FontFile) parseLOCATable(format, numSymbols int) {
   904  	start := utf.SeekTable("loca")
   905  	utf.symbolPosition = make([]int, 0)
   906  	if format == 0 {
   907  		data := utf.getRange(start, (numSymbols*2)+2)
   908  		arr := unpackUint16Array(data)
   909  		for n := 0; n <= numSymbols; n++ {
   910  			utf.symbolPosition = append(utf.symbolPosition, arr[n+1]*2)
   911  		}
   912  	} else if format == 1 {
   913  		data := utf.getRange(start, (numSymbols*4)+4)
   914  		arr := unpackUint32Array(data)
   915  		for n := 0; n <= numSymbols; n++ {
   916  			utf.symbolPosition = append(utf.symbolPosition, arr[n+1])
   917  		}
   918  	} else {
   919  		fmt.Printf("Unknown loca table format %d\n", format)
   920  		return
   921  	}
   922  }
   923  
   924  func (utf *utf8FontFile) generateSCCSDictionaries(runeCmapPosition int, symbolCharDictionary map[int][]int, charSymbolDictionary map[int]int) {
   925  	maxRune := 0
   926  	utf.seek(runeCmapPosition + 2)
   927  	size := utf.readUint16()
   928  	rim := runeCmapPosition + size
   929  	utf.skip(2)
   930  
   931  	segmentSize := utf.readUint16() / 2
   932  	utf.skip(6)
   933  	completers := make([]int, 0)
   934  	for i := 0; i < segmentSize; i++ {
   935  		completers = append(completers, utf.readUint16())
   936  	}
   937  	utf.skip(2)
   938  	beginners := make([]int, 0)
   939  	for i := 0; i < segmentSize; i++ {
   940  		beginners = append(beginners, utf.readUint16())
   941  	}
   942  	sizes := make([]int, 0)
   943  	for i := 0; i < segmentSize; i++ {
   944  		sizes = append(sizes, int(utf.readInt16()))
   945  	}
   946  	readerPositionStart := utf.fileReader.readerPosition
   947  	positions := make([]int, 0)
   948  	for i := 0; i < segmentSize; i++ {
   949  		positions = append(positions, utf.readUint16())
   950  	}
   951  	var symbol int
   952  	for n := 0; n < segmentSize; n++ {
   953  		completePosition := completers[n] + 1
   954  		for char := beginners[n]; char < completePosition; char++ {
   955  			if positions[n] == 0 {
   956  				symbol = (char + sizes[n]) & 0xFFFF
   957  			} else {
   958  				position := (char-beginners[n])*2 + positions[n]
   959  				position = int(readerPositionStart) + 2*n + position
   960  				if position >= rim {
   961  					symbol = 0
   962  				} else {
   963  					symbol = utf.getUint16(position)
   964  					if symbol != 0 {
   965  						symbol = (symbol + sizes[n]) & 0xFFFF
   966  					}
   967  				}
   968  			}
   969  			charSymbolDictionary[char] = symbol
   970  			if char < 196608 {
   971  				maxRune = max(char, maxRune)
   972  			}
   973  			symbolCharDictionary[symbol] = append(symbolCharDictionary[symbol], char)
   974  		}
   975  	}
   976  }
   977  
   978  func max(i, n int) int {
   979  	if n > i {
   980  		return n
   981  	}
   982  	return i
   983  }
   984  
   985  func (utf *utf8FontFile) assembleTables() []byte {
   986  	answer := make([]byte, 0)
   987  	tablesCount := len(utf.outTablesData)
   988  	findSize := 1
   989  	writer := 0
   990  	for findSize*2 <= tablesCount {
   991  		findSize = findSize * 2
   992  		writer = writer + 1
   993  	}
   994  	findSize = findSize * 16
   995  	rOffset := tablesCount*16 - findSize
   996  
   997  	answer = append(answer, packHeader(0x00010000, tablesCount, findSize, writer, rOffset)...)
   998  
   999  	tables := utf.outTablesData
  1000  	tablesNames := keySortStrings(tables)
  1001  
  1002  	offset := 12 + tablesCount*16
  1003  	begin := 0
  1004  
  1005  	for _, name := range tablesNames {
  1006  		if name == "head" {
  1007  			begin = offset
  1008  		}
  1009  		answer = append(answer, []byte(name)...)
  1010  		checksum := utf.generateChecksum(tables[name])
  1011  		answer = append(answer, pack2Uint16(checksum[0], checksum[1])...)
  1012  		answer = append(answer, pack2Uint32(offset, len(tables[name]))...)
  1013  		paddedLength := (len(tables[name]) + 3) &^ 3
  1014  		offset = offset + paddedLength
  1015  	}
  1016  
  1017  	for _, key := range tablesNames {
  1018  		data := append([]byte{}, tables[key]...)
  1019  		data = append(data, []byte{0, 0, 0}...)
  1020  		answer = append(answer, data[:(len(data)&^3)]...)
  1021  	}
  1022  
  1023  	checksum := utf.generateChecksum([]byte(answer))
  1024  	checksum = utf.calcInt32([]int{0xB1B0, 0xAFBA}, checksum)
  1025  	answer = utf.splice(answer, (begin + 8), pack2Uint16(checksum[0], checksum[1]))
  1026  	return answer
  1027  }
  1028  
  1029  func unpackUint16Array(data []byte) []int {
  1030  	answer := make([]int, 1)
  1031  	r := bytes.NewReader(data)
  1032  	bs := make([]byte, 2)
  1033  	var e error
  1034  	var c int
  1035  	c, e = r.Read(bs)
  1036  	for e == nil && c > 0 {
  1037  		answer = append(answer, int(binary.BigEndian.Uint16(bs)))
  1038  		c, e = r.Read(bs)
  1039  	}
  1040  	return answer
  1041  }
  1042  
  1043  func unpackUint32Array(data []byte) []int {
  1044  	answer := make([]int, 1)
  1045  	r := bytes.NewReader(data)
  1046  	bs := make([]byte, 4)
  1047  	var e error
  1048  	var c int
  1049  	c, e = r.Read(bs)
  1050  	for e == nil && c > 0 {
  1051  		answer = append(answer, int(binary.BigEndian.Uint32(bs)))
  1052  		c, e = r.Read(bs)
  1053  	}
  1054  	return answer
  1055  }
  1056  
  1057  func unpackUint16(data []byte) int {
  1058  	return int(binary.BigEndian.Uint16(data))
  1059  }
  1060  
  1061  func packHeader(N uint32, n1, n2, n3, n4 int) []byte {
  1062  	answer := make([]byte, 0)
  1063  	bs4 := make([]byte, 4)
  1064  	binary.BigEndian.PutUint32(bs4, N)
  1065  	answer = append(answer, bs4...)
  1066  	bs := make([]byte, 2)
  1067  	binary.BigEndian.PutUint16(bs, uint16(n1))
  1068  	answer = append(answer, bs...)
  1069  	binary.BigEndian.PutUint16(bs, uint16(n2))
  1070  	answer = append(answer, bs...)
  1071  	binary.BigEndian.PutUint16(bs, uint16(n3))
  1072  	answer = append(answer, bs...)
  1073  	binary.BigEndian.PutUint16(bs, uint16(n4))
  1074  	answer = append(answer, bs...)
  1075  	return answer
  1076  }
  1077  
  1078  func pack2Uint16(n1, n2 int) []byte {
  1079  	answer := make([]byte, 0)
  1080  	bs := make([]byte, 2)
  1081  	binary.BigEndian.PutUint16(bs, uint16(n1))
  1082  	answer = append(answer, bs...)
  1083  	binary.BigEndian.PutUint16(bs, uint16(n2))
  1084  	answer = append(answer, bs...)
  1085  	return answer
  1086  }
  1087  
  1088  func pack2Uint32(n1, n2 int) []byte {
  1089  	answer := make([]byte, 0)
  1090  	bs := make([]byte, 4)
  1091  	binary.BigEndian.PutUint32(bs, uint32(n1))
  1092  	answer = append(answer, bs...)
  1093  	binary.BigEndian.PutUint32(bs, uint32(n2))
  1094  	answer = append(answer, bs...)
  1095  	return answer
  1096  }
  1097  
  1098  func packUint32(n1 int) []byte {
  1099  	bs := make([]byte, 4)
  1100  	binary.BigEndian.PutUint32(bs, uint32(n1))
  1101  	return bs
  1102  }
  1103  
  1104  func packUint16(n1 int) []byte {
  1105  	bs := make([]byte, 2)
  1106  	binary.BigEndian.PutUint16(bs, uint16(n1))
  1107  	return bs
  1108  }
  1109  
  1110  func keySortStrings(s map[string][]byte) []string {
  1111  	keys := make([]string, len(s))
  1112  	i := 0
  1113  	for key := range s {
  1114  		keys[i] = key
  1115  		i++
  1116  	}
  1117  	sort.Strings(keys)
  1118  	return keys
  1119  }
  1120  
  1121  func keySortInt(s map[int]int) []int {
  1122  	keys := make([]int, len(s))
  1123  	i := 0
  1124  	for key := range s {
  1125  		keys[i] = key
  1126  		i++
  1127  	}
  1128  	sort.Ints(keys)
  1129  	return keys
  1130  }
  1131  
  1132  func keySortArrayRangeMap(s map[int][]int) []int {
  1133  	keys := make([]int, len(s))
  1134  	i := 0
  1135  	for key := range s {
  1136  		keys[i] = key
  1137  		i++
  1138  	}
  1139  	sort.Ints(keys)
  1140  	return keys
  1141  }
  1142  
  1143  // UTF8CutFont is a utility function that generates a TrueType font composed
  1144  // only of the runes included in cutset. The rune glyphs are copied from This
  1145  // function is demonstrated in ExampleUTF8CutFont().
  1146  func UTF8CutFont(inBuf []byte, cutset string) (outBuf []byte) {
  1147  	f := newUTF8Font(&fileReader{readerPosition: 0, array: inBuf})
  1148  	runes := map[int]int{}
  1149  	for i, r := range cutset {
  1150  		runes[i] = int(r)
  1151  	}
  1152  	outBuf = f.GenerateCutFont(runes)
  1153  	return
  1154  }