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

     1  package core
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"compress/zlib"
     7  	"errors"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"strconv"
    13  	"strings"
    14  )
    15  
    16  // ErrFontLicenseDoesNotAllowEmbedding Font license does not allow embedding
    17  var ErrFontLicenseDoesNotAllowEmbedding = errors.New("Font license does not allow embedding")
    18  
    19  // FontMaker font maker
    20  type FontMaker struct {
    21  	results []string
    22  }
    23  
    24  // GetResults get result
    25  func (f *FontMaker) GetResults() []string {
    26  	return f.results
    27  }
    28  
    29  // NewFontMaker new FontMaker
    30  func NewFontMaker() *FontMaker {
    31  	return new(FontMaker)
    32  }
    33  
    34  func (f *FontMaker) MakeFont(fontpath string, mappath string, encode string, outfolderpath string) error {
    35  
    36  	encodingpath := mappath + "/" + encode + ".map"
    37  
    38  	//read font file
    39  	if _, err := os.Stat(fontpath); os.IsNotExist(err) {
    40  		return err
    41  	}
    42  
    43  	fileext := filepath.Ext(fontpath)
    44  	if strings.ToLower(fileext) != ".ttf" {
    45  		//now support only ttf :-P
    46  		return errors.New("support only ttf ")
    47  	}
    48  
    49  	fontmaps, err := f.LoadMap(encodingpath)
    50  	if err != nil {
    51  		return err
    52  	}
    53  
    54  	info, err := f.GetInfoFromTrueType(fontpath, fontmaps)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	//zip
    60  	basename := filepath.Base(fontpath)
    61  	tmp := strings.Split(basename, ".")
    62  	basename = strings.Replace(tmp[0], " ", "_", -1)
    63  	gzfilename := basename + ".z"
    64  
    65  	var buff bytes.Buffer
    66  	gzipwriter := zlib.NewWriter(&buff)
    67  
    68  	fontbytes, err := ioutil.ReadFile(fontpath)
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	_, err = gzipwriter.Write(fontbytes)
    74  	if err != nil {
    75  		return err
    76  	}
    77  	gzipwriter.Close()
    78  	err = ioutil.WriteFile(outfolderpath+"/"+gzfilename, buff.Bytes(), 0644)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	info.PushString("File", gzfilename)
    83  	f.results = append(f.results, fmt.Sprintf("Save Z file at %s.", outfolderpath+"/"+gzfilename))
    84  
    85  	//Definition File
    86  	_, err = f.MakeDefinitionFile(f.GoStructName(basename), mappath, outfolderpath+"/"+basename+".font.go", encode, fontmaps, info)
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  func (f *FontMaker) GoStructName(name string) string {
    95  	goname := strings.ToUpper(name[0:1]) + name[1:]
    96  	return goname
    97  }
    98  
    99  func (f *FontMaker) MakeDefinitionFile(gofontname string, mappath string, exportfile string, encode string, fontmaps []FontMap, info TtfInfo) (string, error) {
   100  
   101  	fonttype := "TrueType"
   102  	str := ""
   103  	str += "package fonts //change this\n"
   104  	str += "import (\n"
   105  	str += "	\"github.com/signintech/gopdf\"\n"
   106  	str += ")\n"
   107  	str += "type " + gofontname + " struct {\n"
   108  	str += "\tfamily string\n"
   109  	str += "\tfonttype string\n"
   110  	str += "\tname string\n"
   111  	str += "\tdesc  []gopdf.FontDescItem\n"
   112  	str += "\tup int\n"
   113  	str += "\tut int\n"
   114  	str += "\tcw gopdf.FontCw\n"
   115  	str += "\tenc string\n"
   116  	str += "\tdiff string\n"
   117  	str += "}\n"
   118  
   119  	str += "func (me * " + gofontname + ") Init(){\n"
   120  	widths, err := info.GetMapIntInt64("Widths")
   121  	if err != nil {
   122  		return "", err
   123  	}
   124  
   125  	tmpStr, err := f.MakeWidthArray(widths)
   126  	if err != nil {
   127  		return "", err
   128  	}
   129  	str += tmpStr
   130  
   131  	tmpInt64, err := info.GetInt64("UnderlinePosition")
   132  	if err != nil {
   133  		return "", err
   134  	}
   135  	str += fmt.Sprintf("\tme.up = %d\n", tmpInt64)
   136  
   137  	tmpInt64, err = info.GetInt64("UnderlineThickness")
   138  	if err != nil {
   139  		return "", err
   140  	}
   141  	str += fmt.Sprintf("\tme.ut = %d\n", tmpInt64)
   142  
   143  	str += "\tme.fonttype = \"" + fonttype + "\"\n"
   144  
   145  	tmpStr, err = info.GetString("FontName")
   146  	if err != nil {
   147  		return "", err
   148  	}
   149  	str += fmt.Sprintf("\tme.name = \"%s\"\n", tmpStr)
   150  
   151  	str += "\tme.enc = \"" + encode + "\"\n"
   152  	diff, err := f.MakeFontEncoding(mappath, fontmaps)
   153  	if err != nil {
   154  		return "", err
   155  	}
   156  	if diff != "" {
   157  		str += "\tme.diff = \"" + diff + "\"\n"
   158  	}
   159  
   160  	fd, err := f.MakeFontDescriptor(info)
   161  	if err != nil {
   162  		return "", err
   163  	}
   164  	str += fd
   165  
   166  	str += "}\n"
   167  
   168  	str += "func (me * " + gofontname + ")GetType() string{\n"
   169  	str += "\treturn me.fonttype\n"
   170  	str += "}\n"
   171  	str += "func (me * " + gofontname + ")GetName() string{\n"
   172  	str += "\treturn me.name\n"
   173  	str += "}	\n"
   174  	str += "func (me * " + gofontname + ")GetDesc() []gopdf.FontDescItem{\n"
   175  	str += "\treturn me.desc\n"
   176  	str += "}\n"
   177  	str += "func (me * " + gofontname + ")GetUp() int{\n"
   178  	str += "\treturn me.up\n"
   179  	str += "}\n"
   180  	str += "func (me * " + gofontname + ")GetUt()  int{\n"
   181  	str += "\treturn me.ut\n"
   182  	str += "}\n"
   183  	str += "func (me * " + gofontname + ")GetCw() gopdf.FontCw{\n"
   184  	str += "\treturn me.cw\n"
   185  	str += "}\n"
   186  	str += "func (me * " + gofontname + ")GetEnc() string{\n"
   187  	str += "\treturn me.enc\n"
   188  	str += "}\n"
   189  	str += "func (me * " + gofontname + ")GetDiff() string {\n"
   190  	str += "\treturn me.diff\n"
   191  	str += "}\n"
   192  
   193  	str += "func (me * " + gofontname + ") GetOriginalsize() int{\n"
   194  	str += "\treturn 98764\n"
   195  	str += "}\n"
   196  
   197  	str += "func (me * " + gofontname + ")  SetFamily(family string){\n"
   198  	str += "\tme.family = family\n"
   199  	str += "}\n"
   200  
   201  	str += "func (me * " + gofontname + ") 	GetFamily() string{\n"
   202  	str += "\treturn me.family\n"
   203  	str += "}\n"
   204  
   205  	err = ioutil.WriteFile(exportfile, []byte(str), 0666)
   206  	if err != nil {
   207  		return "", err
   208  	}
   209  	f.results = append(f.results, fmt.Sprintf("Save GO file at %s.", exportfile))
   210  	return str, nil
   211  }
   212  
   213  func (f *FontMaker) MakeFontDescriptor(info TtfInfo) (string, error) {
   214  
   215  	fd := ""
   216  	fd = "\tme.desc = make([]gopdf.FontDescItem,8)\n"
   217  
   218  	// Ascent
   219  	ascender, err := info.GetInt64("Ascender")
   220  	if err != nil {
   221  		return "", err
   222  	}
   223  	fd += fmt.Sprintf("\tme.desc[0] =  gopdf.FontDescItem{ Key:\"Ascent\",Val : \"%d\" }\n", ascender)
   224  
   225  	// Descent
   226  	descender, err := info.GetInt64("Descender")
   227  	if err != nil {
   228  		return "", err
   229  	}
   230  	fd += fmt.Sprintf("\tme.desc[1] =  gopdf.FontDescItem{ Key: \"Descent\", Val : \"%d\" }\n", descender)
   231  
   232  	// CapHeight
   233  	capHeight, err := info.GetInt64("CapHeight")
   234  	if err == nil {
   235  		fd += fmt.Sprintf("\tme.desc[2] =  gopdf.FontDescItem{ Key:\"CapHeight\", Val :  \"%d\" }\n", capHeight)
   236  	} else if err == ERROR_NO_KEY_FOUND {
   237  		fd += fmt.Sprintf("\tme.desc[2] =  gopdf.FontDescItem{ Key:\"CapHeight\", Val :  \"%d\" }\n", ascender)
   238  	} else {
   239  		return "", err
   240  	}
   241  
   242  	// Flags
   243  	flags := 0
   244  	isFixedPitch, err := info.GetBool("IsFixedPitch")
   245  	if err != nil {
   246  		return "", err
   247  	}
   248  
   249  	if isFixedPitch {
   250  		flags += 1 << 0
   251  	}
   252  	flags += 1 << 5
   253  	italicAngle, err := info.GetInt64("ItalicAngle")
   254  	if italicAngle != 0 {
   255  		flags += 1 << 6
   256  	}
   257  	fd += fmt.Sprintf("\tme.desc[3] =  gopdf.FontDescItem{ Key: \"Flags\", Val :  \"%d\" }\n", flags)
   258  	//fmt.Printf("\n----\n")
   259  	// FontBBox
   260  	fbb, err := info.GetInt64s("FontBBox")
   261  	if err != nil {
   262  		return "", err
   263  	}
   264  	fd += fmt.Sprintf("\tme.desc[4] =  gopdf.FontDescItem{ Key:\"FontBBox\", Val :  \"[%d %d %d %d]\" }\n", fbb[0], fbb[1], fbb[2], fbb[3])
   265  
   266  	// ItalicAngle
   267  	fd += fmt.Sprintf("\tme.desc[5] =  gopdf.FontDescItem{ Key:\"ItalicAngle\", Val :  \"%d\" }\n", italicAngle)
   268  
   269  	// StemV
   270  	stdVW, err := info.GetInt64("StdVW")
   271  	issetStdVW := false
   272  	if err == nil {
   273  		issetStdVW = true
   274  	} else if err == ERROR_NO_KEY_FOUND {
   275  		issetStdVW = false
   276  	} else {
   277  		return "", err
   278  	}
   279  
   280  	bold, err := info.GetBool("Bold")
   281  	if err != nil {
   282  		return "", err
   283  	}
   284  
   285  	stemv := int(0)
   286  	if issetStdVW {
   287  		stemv = stdVW
   288  	} else if bold {
   289  		stemv = 120
   290  	} else {
   291  		stemv = 70
   292  	}
   293  	fd += fmt.Sprintf("\tme.desc[6] =  gopdf.FontDescItem{ Key:\"StemV\", Val :  \"%d\" }\n ", stemv)
   294  
   295  	// MissingWidth
   296  	missingWidth, err := info.GetInt64("MissingWidth")
   297  	if err != nil {
   298  		return "", err
   299  	}
   300  	fd += fmt.Sprintf("\tme.desc[7] =  gopdf.FontDescItem{ Key:\"MissingWidth\", Val :  \"%d\" } \n ", missingWidth)
   301  	return fd, nil
   302  }
   303  
   304  func (f *FontMaker) MakeFontEncoding(mappath string, fontmaps []FontMap) (string, error) {
   305  
   306  	refpath := mappath + "/cp1252.map"
   307  	ref, err := f.LoadMap(refpath)
   308  	if err != nil {
   309  		return "", err
   310  	}
   311  	s := ""
   312  	last := 0
   313  	for c := 0; c <= 255; c++ {
   314  		if fontmaps[c].Name != ref[c].Name {
   315  			if c != last+1 {
   316  				s += fmt.Sprintf("%d ", c)
   317  			}
   318  			last = c
   319  			s += "/" + fontmaps[c].Name + " "
   320  		}
   321  	}
   322  	return strings.TrimSpace(s), nil
   323  }
   324  
   325  func (f *FontMaker) MakeWidthArray(widths map[int]int) (string, error) {
   326  
   327  	str := "\tme.cw = make(gopdf.FontCw)\n"
   328  	for c := 0; c <= 255; c++ {
   329  		str += "\tme.cw["
   330  		chr := string(c)
   331  		if chr == "\"" {
   332  			str += "gopdf.ToByte(\"\\\"\")"
   333  		} else if chr == "\\" {
   334  			str += "gopdf.ToByte(\"\\\\\")"
   335  		} else if c >= 32 && c <= 126 {
   336  			str += "gopdf.ToByte(\"" + chr + "\")"
   337  		} else {
   338  			str += fmt.Sprintf("gopdf.Chr(%d)", c)
   339  		}
   340  		str += fmt.Sprintf("]=%d\n", widths[c])
   341  	}
   342  	return str, nil
   343  }
   344  
   345  func (f *FontMaker) FileSize(path string) (int64, error) {
   346  
   347  	file, err := os.Open(path)
   348  	if err != nil {
   349  		return -1, err
   350  	}
   351  	defer file.Close()
   352  
   353  	// get the file size
   354  	stat, err := file.Stat()
   355  	if err != nil {
   356  		return -1, err
   357  	}
   358  	return stat.Size(), nil
   359  }
   360  
   361  func (f *FontMaker) GetInfoFromTrueType(fontpath string, fontmaps []FontMap) (TtfInfo, error) {
   362  
   363  	var parser TTFParser
   364  	err := parser.Parse(fontpath)
   365  	if err != nil {
   366  		return nil, err
   367  	}
   368  
   369  	if !parser.Embeddable {
   370  		return nil, ErrFontLicenseDoesNotAllowEmbedding
   371  	}
   372  
   373  	info := NewTtfInfo()
   374  
   375  	fileContent, err := ioutil.ReadFile(fontpath)
   376  	if err != nil {
   377  		return nil, err
   378  	}
   379  	info.PushBytes("Data", fileContent)
   380  
   381  	size, err := f.FileSize(fontpath)
   382  	if err != nil {
   383  		return nil, err
   384  	}
   385  	info.PushInt64("OriginalSize", size)
   386  
   387  	k := float64(1000.0 / float64(parser.unitsPerEm))
   388  	info.PushString("FontName", parser.postScriptName)
   389  	info.PushBool("Bold", parser.Bold)
   390  	info.PushInt("ItalicAngle", parser.italicAngle)
   391  	info.PushBool("IsFixedPitch", parser.isFixedPitch)
   392  	info.PushInt("Ascender", f.MultiplyAndRound(k, parser.typoAscender))
   393  	info.PushInt("Descender", f.MultiplyAndRound(k, parser.typoDescender))
   394  	info.PushInt("UnderlineThickness", f.MultiplyAndRound(k, parser.underlineThickness))
   395  	info.PushInt("UnderlinePosition", f.MultiplyAndRound(k, parser.underlinePosition))
   396  	fontBBoxs := []int{
   397  		f.MultiplyAndRound(k, parser.xMin),
   398  		f.MultiplyAndRound(k, parser.yMin),
   399  		f.MultiplyAndRound(k, parser.xMax),
   400  		f.MultiplyAndRound(k, parser.yMax),
   401  	}
   402  	info.PushInt64s("FontBBox", fontBBoxs)
   403  	info.PushInt("CapHeight", f.MultiplyAndRound(k, parser.capHeight))
   404  	missingWidth := f.MultiplyAndRoundWithUInt64(k, parser.widths[0])
   405  	info.PushInt("MissingWidth", missingWidth)
   406  
   407  	widths := make(map[int]int)
   408  	max := 256
   409  	c := 0
   410  	for c < max {
   411  		widths[c] = missingWidth
   412  		c++
   413  	}
   414  
   415  	c = 0 //reset
   416  	for c < max {
   417  		if fontmaps[c].Name != ".notdef" {
   418  			uv := fontmaps[c].Uv
   419  			if val, ok := parser.chars[int(uv)]; ok {
   420  				w := parser.widths[val]
   421  				widths[c] = f.MultiplyAndRoundWithUInt64(k, w)
   422  			} else {
   423  				f.results = append(f.results, fmt.Sprintf("Warning: Character %s (%d) is missing", fontmaps[c].Name, fontmaps[c].Uv))
   424  			}
   425  		}
   426  		c++
   427  	}
   428  	info.PushMapIntInt64("Widths", widths)
   429  
   430  	return info, nil
   431  }
   432  
   433  func (f *FontMaker) MultiplyAndRoundWithUInt64(k float64, v uint) int {
   434  	r := k * float64(v)
   435  	return f.Round(r)
   436  }
   437  
   438  func (f *FontMaker) MultiplyAndRound(k float64, v int) int {
   439  	r := k * float64(v)
   440  	return f.Round(r)
   441  }
   442  
   443  func (f *FontMaker) Round(value float64) int {
   444  	return Round(value)
   445  }
   446  
   447  func (f *FontMaker) LoadMap(encodingpath string) ([]FontMap, error) {
   448  
   449  	if _, err := os.Stat(encodingpath); os.IsNotExist(err) {
   450  		return nil, err
   451  	}
   452  
   453  	var fontmaps []FontMap
   454  	i := 0
   455  	max := 256
   456  	for i < max {
   457  		fontmaps = append(fontmaps, FontMap{Uv: -1, Name: ".notdef"})
   458  		i++
   459  	}
   460  
   461  	file, err := os.Open(encodingpath)
   462  	if err != nil {
   463  		return nil, err
   464  	}
   465  	defer file.Close()
   466  
   467  	scanner := bufio.NewScanner(file)
   468  	scanner.Split(bufio.ScanLines)
   469  	for scanner.Scan() {
   470  		line := strings.TrimSpace(scanner.Text())
   471  		e := strings.Split(line, " ")
   472  		strC := (e[0])[1:]
   473  		strUv := (e[1])[2:]
   474  		c, err := strconv.ParseInt(strC, 16, 0)
   475  		if err != nil {
   476  			return nil, err
   477  		}
   478  		uv, err := strconv.ParseInt(strUv, 16, 0)
   479  		if err != nil {
   480  			return nil, err
   481  		}
   482  		name := e[2]
   483  		//fmt.Println("strC = "+strC+"strUv = "+strUv+" c=%d , uv= %d", c, uv)
   484  		fontmaps[c].Name = name
   485  		fontmaps[c].Uv = int(uv)
   486  	}
   487  
   488  	return fontmaps, nil
   489  }