|
@@ -0,0 +1,441 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "bufio"
|
|
|
+ "encoding/binary"
|
|
|
+ "flag"
|
|
|
+ "fmt"
|
|
|
+ "os"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+)
|
|
|
+
|
|
|
+func ListFonts(filename string) {
|
|
|
+ f, err := os.Open(filename)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Printf("Open(%s): %s\n", filename, err)
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+ defer f.Close()
|
|
|
+ tdfonts := make([]byte, 20)
|
|
|
+ f.Read(tdfonts)
|
|
|
+ for true {
|
|
|
+ fontdef := make([]byte, 4)
|
|
|
+ read, _ := f.Read(fontdef)
|
|
|
+ if read != 4 {
|
|
|
+ fmt.Println("*END*")
|
|
|
+ break
|
|
|
+ }
|
|
|
+ fontname := make([]byte, 13)
|
|
|
+ f.Read(fontname)
|
|
|
+ Name := strings.Trim(string(fontname[1:]), "\x00")
|
|
|
+ // fmt.Printf("Font: %s\n", Name)
|
|
|
+ f.Read(fontdef)
|
|
|
+ single := make([]byte, 1)
|
|
|
+
|
|
|
+ var FontType int8
|
|
|
+ binary.Read(f, binary.LittleEndian, &FontType)
|
|
|
+
|
|
|
+ // f.Read(single) // FontType
|
|
|
+ // FontType := int(single[0])
|
|
|
+ fmt.Printf("Font: %s (type %d)\n", Name, FontType)
|
|
|
+ f.Read(single) // Spacing
|
|
|
+
|
|
|
+ // blocksize := make([]byte, 2)
|
|
|
+ // f.Read(blocksize)
|
|
|
+
|
|
|
+ var BlockSize int16
|
|
|
+ binary.Read(f, binary.LittleEndian, &BlockSize)
|
|
|
+ // fmt.Printf("Size: %d / %x\n", BlockSize, BlockSize)
|
|
|
+
|
|
|
+ letterOffsets := make([]int16, 94)
|
|
|
+ binary.Read(f, binary.LittleEndian, &letterOffsets)
|
|
|
+
|
|
|
+ if false {
|
|
|
+ for idx, i := range letterOffsets {
|
|
|
+ fmt.Printf(" %04X", i)
|
|
|
+ if (idx+1)%10 == 0 {
|
|
|
+ fmt.Println("")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fmt.Println("")
|
|
|
+ }
|
|
|
+
|
|
|
+ data := make([]byte, BlockSize)
|
|
|
+ binary.Read(f, binary.LittleEndian, &data)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func byte_to_text(line []byte) string {
|
|
|
+ var output string
|
|
|
+
|
|
|
+ for _, ch := range line {
|
|
|
+ output += fmt.Sprintf("0x%02x,", ch)
|
|
|
+ }
|
|
|
+ if len(output) > 0 {
|
|
|
+ output = output[:len(output)-1]
|
|
|
+ }
|
|
|
+ return output
|
|
|
+}
|
|
|
+
|
|
|
+func text_to_hextext(line string) string {
|
|
|
+ var output string
|
|
|
+ // output = "\""
|
|
|
+ for _, ch := range []byte(line) {
|
|
|
+ // output += fmt.Sprintf("\\x%02x", ch)
|
|
|
+ output += fmt.Sprintf("0x%02x,", ch)
|
|
|
+ }
|
|
|
+ if len(output) > 1 {
|
|
|
+ output = output[:len(output)-1]
|
|
|
+ }
|
|
|
+ // output += "\""
|
|
|
+ return output
|
|
|
+}
|
|
|
+
|
|
|
+func ExtractColor(name string, offsets []uint16, data []byte) {
|
|
|
+ fmt.Printf("Extract Color Font: %s\n", name)
|
|
|
+ var indexes []int
|
|
|
+ var blocks [][][]byte
|
|
|
+ var current [][]byte
|
|
|
+ w := -1
|
|
|
+ h := -1
|
|
|
+ ch := -1
|
|
|
+ var line []byte
|
|
|
+
|
|
|
+ for idx, b := range data {
|
|
|
+ if w == -1 {
|
|
|
+ indexes = append(indexes, idx)
|
|
|
+ current = make([][]byte, 0)
|
|
|
+ line = make([]byte, 0)
|
|
|
+ w = int(b)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if h == -1 {
|
|
|
+ h = int(b)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if ch == -1 {
|
|
|
+ ch = int(b)
|
|
|
+ if ch == 0x0d {
|
|
|
+ ch = -1
|
|
|
+ current = append(current, line)
|
|
|
+ line = make([]byte, 0)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if ch == 0 {
|
|
|
+ current = append(current, line)
|
|
|
+ blocks = append(blocks, current)
|
|
|
+ current = make([][]byte, 0)
|
|
|
+ line = make([]byte, 0)
|
|
|
+ w = -1
|
|
|
+ h = -1
|
|
|
+ ch = -1
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if ch == 0x26 {
|
|
|
+ // & descender mark
|
|
|
+ ch = -1
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ // line += string(rune(ch))
|
|
|
+ line = append(line, byte(ch))
|
|
|
+ ch = -1
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // offset optimization:
|
|
|
+ var single []int
|
|
|
+ for _, o := range offsets {
|
|
|
+ if o == 65535 {
|
|
|
+ single = append(single, -1)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ for idx, i := range indexes {
|
|
|
+ if o == uint16(i) {
|
|
|
+ single = append(single, idx)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Handle Names with spaces
|
|
|
+ filename := fmt.Sprintf("%s_font.go", strings.Replace(name, " ", "", -1))
|
|
|
+
|
|
|
+ fp, err := os.Create(filename)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+ fmt.Printf("Writing: %s\n", filename)
|
|
|
+
|
|
|
+ defer fp.Close()
|
|
|
+ writer := bufio.NewWriter(fp)
|
|
|
+
|
|
|
+ // writer.WriteString("package main\n")
|
|
|
+ writer.WriteString("// " + name + "\n\n")
|
|
|
+
|
|
|
+ // Name := strings.ToUpper(name)
|
|
|
+ Name := strings.Replace(name, " ", "", -1)
|
|
|
+
|
|
|
+ writer.WriteString("func Font" + Name + "() ColorFont {\n")
|
|
|
+ var output string
|
|
|
+ output = " return ColorFont{characters: []int{"
|
|
|
+ for _, s := range single {
|
|
|
+ output += strconv.Itoa(s) + ", "
|
|
|
+ }
|
|
|
+ output = output[:len(output)-2] + "},\n"
|
|
|
+ writer.WriteString(output)
|
|
|
+ writer.Flush()
|
|
|
+
|
|
|
+ output = " data: [][][]byte{"
|
|
|
+ for _, blk := range blocks {
|
|
|
+ output += "{"
|
|
|
+ if len(blk) == 0 {
|
|
|
+ output += "{},"
|
|
|
+ } else {
|
|
|
+ for _, inner := range blk {
|
|
|
+ // output += text_to_hextext(b) + ","
|
|
|
+ output += "{" + byte_to_text(inner) + "},"
|
|
|
+ }
|
|
|
+ output = output[:len(output)-1]
|
|
|
+ }
|
|
|
+
|
|
|
+ output += "},\n"
|
|
|
+ writer.WriteString(output)
|
|
|
+ output = " "
|
|
|
+ }
|
|
|
+ writer.WriteString(" }}\n")
|
|
|
+ writer.WriteString("}\n")
|
|
|
+ writer.Flush()
|
|
|
+}
|
|
|
+
|
|
|
+func ExtractBlock(name string, offsets []uint16, data []byte) {
|
|
|
+ fmt.Printf("Extract Block Font: %s\n", name)
|
|
|
+ var indexes []int
|
|
|
+ var blocks [][][]byte
|
|
|
+ var current [][]byte
|
|
|
+ w := -1
|
|
|
+ h := -1
|
|
|
+ ch := -1
|
|
|
+ var line []byte
|
|
|
+
|
|
|
+ for idx, b := range data {
|
|
|
+ if w == -1 {
|
|
|
+ indexes = append(indexes, idx)
|
|
|
+ current = make([][]byte, 0)
|
|
|
+ line = make([]byte, 0)
|
|
|
+ w = int(b)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if h == -1 {
|
|
|
+ h = int(b)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if ch == -1 {
|
|
|
+ ch = int(b)
|
|
|
+ if ch == 0x0d {
|
|
|
+ ch = -1
|
|
|
+ current = append(current, line)
|
|
|
+ line = make([]byte, 0)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if ch == 0 {
|
|
|
+ current = append(current, line)
|
|
|
+ blocks = append(blocks, current)
|
|
|
+ current = make([][]byte, 0)
|
|
|
+ line = make([]byte, 0)
|
|
|
+ w = -1
|
|
|
+ h = -1
|
|
|
+ ch = -1
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if ch == 0x26 {
|
|
|
+ // & descender mark
|
|
|
+ ch = -1
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ line = append(line, byte(ch))
|
|
|
+ ch = -1
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // offset optimization:
|
|
|
+ var single []int
|
|
|
+ for _, o := range offsets {
|
|
|
+ if o == 65535 {
|
|
|
+ single = append(single, -1)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ for idx, i := range indexes {
|
|
|
+ if o == uint16(i) {
|
|
|
+ single = append(single, idx)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Handle Names with spaces
|
|
|
+ filename := fmt.Sprintf("%s_font.go", strings.Replace(name, " ", "", -1))
|
|
|
+
|
|
|
+ fp, err := os.Create(filename)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+ fmt.Printf("Writing: %s\n", filename)
|
|
|
+
|
|
|
+ defer fp.Close()
|
|
|
+ writer := bufio.NewWriter(fp)
|
|
|
+
|
|
|
+ // writer.WriteString("package main\n")
|
|
|
+ writer.WriteString("// " + name + "\n\n")
|
|
|
+
|
|
|
+ // Name := strings.ToUpper(name)
|
|
|
+ Name := strings.Replace(name, " ", "", -1)
|
|
|
+
|
|
|
+ writer.WriteString("func Font" + Name + "() BlockFont {\n")
|
|
|
+ var output string
|
|
|
+ output = " return BlockFont{characters: []int{"
|
|
|
+ for _, s := range single {
|
|
|
+ output += strconv.Itoa(s) + ", "
|
|
|
+ }
|
|
|
+ output = output[:len(output)-2] + "},\n"
|
|
|
+ writer.WriteString(output)
|
|
|
+ writer.Flush()
|
|
|
+
|
|
|
+ output = " data: [][][]byte{"
|
|
|
+ for _, blk := range blocks {
|
|
|
+ output += "{"
|
|
|
+ if len(blk) == 0 {
|
|
|
+ output += "{},"
|
|
|
+ } else {
|
|
|
+ for _, inner := range blk {
|
|
|
+ output += "{" + byte_to_text(inner) + "},"
|
|
|
+ }
|
|
|
+ output = output[:len(output)-1]
|
|
|
+ }
|
|
|
+
|
|
|
+ output += "},\n"
|
|
|
+
|
|
|
+ // output = output[:len(output)-1]
|
|
|
+ // output += "},\n"
|
|
|
+ writer.WriteString(output)
|
|
|
+ output = " "
|
|
|
+ }
|
|
|
+ writer.WriteString(" }}\n")
|
|
|
+ writer.WriteString("}\n")
|
|
|
+ writer.Flush()
|
|
|
+}
|
|
|
+
|
|
|
+func ExtractFonts(filename string, fonts []string) {
|
|
|
+ f, err := os.Open(filename)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Printf("Open(%s): %s\n", filename, err)
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+ defer f.Close()
|
|
|
+ tdfonts := make([]byte, 20)
|
|
|
+ f.Read(tdfonts)
|
|
|
+ for true {
|
|
|
+ fontdef := make([]byte, 4)
|
|
|
+ read, _ := f.Read(fontdef)
|
|
|
+ if read != 4 {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ fontname := make([]byte, 13)
|
|
|
+ f.Read(fontname)
|
|
|
+ Name := strings.Trim(string(fontname[1:]), "\x00")
|
|
|
+ // fmt.Printf("Font: %s\n", Name)
|
|
|
+ f.Read(fontdef)
|
|
|
+ single := make([]byte, 1)
|
|
|
+
|
|
|
+ var FontType int8
|
|
|
+ binary.Read(f, binary.LittleEndian, &FontType)
|
|
|
+
|
|
|
+ // fmt.Printf("Font: %s (type %d)\n", Name, FontType)
|
|
|
+ f.Read(single) // Spacing
|
|
|
+
|
|
|
+ var BlockSize int16
|
|
|
+ binary.Read(f, binary.LittleEndian, &BlockSize)
|
|
|
+
|
|
|
+ letterOffsets := make([]uint16, 94)
|
|
|
+ binary.Read(f, binary.LittleEndian, &letterOffsets)
|
|
|
+
|
|
|
+ if false {
|
|
|
+ for idx, i := range letterOffsets {
|
|
|
+ fmt.Printf(" %04X", i)
|
|
|
+ if (idx+1)%10 == 0 {
|
|
|
+ fmt.Println("")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fmt.Println("")
|
|
|
+ }
|
|
|
+
|
|
|
+ data := make([]byte, BlockSize)
|
|
|
+ binary.Read(f, binary.LittleEndian, &data)
|
|
|
+
|
|
|
+ // Special case where they are asking for all fonts
|
|
|
+ if len(fonts) == 1 && fonts[0] == "*" {
|
|
|
+ switch FontType {
|
|
|
+ case 1:
|
|
|
+ ExtractBlock(Name, letterOffsets, data)
|
|
|
+ case 2:
|
|
|
+ ExtractColor(Name, letterOffsets, data)
|
|
|
+ default:
|
|
|
+ fmt.Printf("Sorry, I can't handle Font: %s Type %d!\n", Name, FontType)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for _, f := range fonts {
|
|
|
+ if Name == f {
|
|
|
+ switch FontType {
|
|
|
+ case 1:
|
|
|
+ ExtractBlock(Name, letterOffsets, data)
|
|
|
+ case 2:
|
|
|
+ ExtractColor(Name, letterOffsets, data)
|
|
|
+ default:
|
|
|
+ fmt.Printf("Sorry, I can't handle Font: %s Type %d!\n", Name, FontType)
|
|
|
+ }
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func main() {
|
|
|
+ fmt.Println("Font-Out - A TDF (TheDraw Font) file processor.")
|
|
|
+ var fontfile string
|
|
|
+ var fonts string
|
|
|
+ var defaultPackage string = "main"
|
|
|
+ var listFonts bool
|
|
|
+ var allFonts bool
|
|
|
+
|
|
|
+ flag.StringVar(&fontfile, "tdf", "", "TheDraw Font File")
|
|
|
+ flag.StringVar(&fonts, "f", "", "Font(s) to extract")
|
|
|
+ flag.BoolVar(&allFonts, "a", false, "Extract All Fonts")
|
|
|
+ flag.StringVar(&defaultPackage, "p", "main", "Package name to use")
|
|
|
+ flag.BoolVar(&listFonts, "l", false, "List Fonts")
|
|
|
+ flag.Parse()
|
|
|
+
|
|
|
+ if len(fontfile) == 0 {
|
|
|
+ fmt.Println("I need a TDF filename.")
|
|
|
+ flag.PrintDefaults()
|
|
|
+ os.Exit(2)
|
|
|
+ }
|
|
|
+
|
|
|
+ if listFonts {
|
|
|
+ ListFonts(fontfile)
|
|
|
+ }
|
|
|
+
|
|
|
+ var fontList []string
|
|
|
+ if len(fonts) > 0 {
|
|
|
+ fontList = strings.Split(fonts, ",")
|
|
|
+ }
|
|
|
+
|
|
|
+ if allFonts {
|
|
|
+ fontList = make([]string, 0)
|
|
|
+ fontList = append(fontList, "*")
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(fontList) > 0 {
|
|
|
+ ExtractFonts(fontfile, fontList)
|
|
|
+ }
|
|
|
+}
|