package main import ( "bufio" "encoding/binary" "flag" "fmt" "os" "strconv" "strings" ) var Conversion [][2]int // copied from tdfont.go, and modified func thedraw_to_ansi(c int) int { trans := []int{0, 4, 2, 6, 1, 5, 3, 7} // 0, 1, 2, 3, 4, 5, 6, 7 return trans[c] } func MatchStyle(color byte, look byte) int { var match int = 0 if ((color >> 4) & 0x07) == look { // Top match |= 1 } if (color & 0x07) == look { // Bottom match |= 2 } return match } func PatchColor(color byte, new_color byte, style int) byte { var c byte = color if style&1 == 1 { c = (c & 0x8f) | new_color<<4 } if style&2 == 2 { c = (c & 0xf8) | new_color } return c } type ColorMap map[[2]int][][2]int func Scan(block [][][]byte, find_color int) ColorMap { var Targets ColorMap = make(ColorMap, 0) // Scan the font looking for the given color FG/BG // Covert color code to TheDraw Color actual := byte(thedraw_to_ansi(find_color)) for charIndex := range block { for lineIndex := range block[charIndex] { var found bool = false var patches [][2]int = make([][2]int, 0) for offset := 1; offset < len(block[charIndex][lineIndex]); offset += 2 { color := block[charIndex][lineIndex][offset] style := MatchStyle(color, actual) if style != 0 { // log.Printf("color: %x actual %x style: %d\n", color, actual, style) patches = append(patches, [2]int{offset, style}) found = true } } if found { pos := [2]int{charIndex, lineIndex} Targets[pos] = make([][2]int, len(patches)) for i := range patches { Targets[pos][i] = patches[i] } // Targets[pos] = patches } } } return Targets } func Modify(block [][][]byte, new_color int, Targets ColorMap) { // Covert color code to TheDraw Color actual := byte(thedraw_to_ansi(new_color)) for pos, patch := range Targets { for _, p := range patch { block[pos[0]][pos[1]][p[0]] = PatchColor(block[pos[0]][pos[1]][p[0]], actual, p[1]) } } } 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 var line []byte pos := 0 for pos < len(data) { indexes = append(indexes, pos) current = make([][]byte, 0) line = make([]byte, 0) // We don't use these. // w = data[pos] // h = data[pos+1] pos += 2 // process this character for pos < len(data) { ch := data[pos] pos++ if ch == 0x00 { // end of character current = append(current, line) blocks = append(blocks, current) current = make([][]byte, 0) line = make([]byte, 0) break } if ch == 0x0d { // end of this character line current = append(current, line) line = make([]byte, 0) continue } if ch == 0x26 { // & descender mark continue } line = append(line, ch) color := data[pos] pos++ line = append(line, color) } } // 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 := bufio.NewWriter(os.Stdout) // writer.WriteString("package main\n") writer.WriteString("// " + name + "\n\n") // Name := strings.ToUpper(name) Name := strings.Replace(name, " ", "", -1) writer.WriteString("func Font" + Name + "() door.ColorFont {\n") var output string output = " return door.ColorFont{Characters: []int{" for _, s := range single { output += strconv.Itoa(s) + ", " } output = output[:len(output)-2] + "},\n" writer.WriteString(output) writer.Flush() if len(Conversion) > 0 { // Color Convert time! var Maps []map[[2]int][][2]int = make([]map[[2]int][][2]int, len(Conversion)) for idx, codes := range Conversion { Maps[idx] = Scan(blocks, codes[0]) } for idx, codes := range Conversion { Modify(blocks, codes[1], Maps[idx]) } } 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 var line []byte pos := 0 for pos < len(data) { indexes = append(indexes, pos) current = make([][]byte, 0) line = make([]byte, 0) // We don't use these // w = data[pos] // h = data[pos+1] pos += 2 // process this character for pos < len(data) { ch := data[pos] pos++ if ch == 0x00 { // end of character current = append(current, line) blocks = append(blocks, current) current = make([][]byte, 0) line = make([]byte, 0) break } if ch == 0x0d { // end of this character line current = append(current, line) line = make([]byte, 0) continue } if ch == 0x26 { // & descender mark continue } line = append(line, ch) } } // 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 := bufio.NewWriter(os.Stdout) // Should this output routine be part of the BlockFont? // I think so! // writer.WriteString("package main\n") writer.WriteString("// " + name + "\n\n") // Name := strings.ToUpper(name) Name := strings.Replace(name, " ", "", -1) writer.WriteString("func Font" + Name + "() door.BlockFont {\n") var output string output = " return door.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 } } } } } // Created so that multiple inputs can be accecpted type arrayFlags []string func (i *arrayFlags) String() string { // change this, this is just can example to satisfy the interface result := "" for _, str := range *i { if result != "" { result += ", " } result += str } return result } func (i *arrayFlags) Set(value string) error { *i = append(*i, strings.TrimSpace(value)) return nil } func ParseColorConvert(convert arrayFlags) { Conversion = make([][2]int, 0) if len(convert) > 0 { // Something to do for _, color := range convert { split := strings.Split(color, ",") v1, _ := strconv.Atoi(split[0]) v2, _ := strconv.Atoi(split[1]) Conversion = append(Conversion, [2]int{v1, v2}) } } } func main() { var fonts string var defaultPackage string = "main" var listFonts bool var allFonts bool var convert arrayFlags 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.Var(&convert, "c", "Convert Color to Color n,n") flag.Parse() ParseColorConvert(convert) // fmt.Printf("Convert: %#v\n", convert) // fmt.Printf("Conversion: %#v\n", Conversion) if flag.NArg() == 0 { fmt.Println("Font-Out - A TDF (TheDraw Font) file processor.") fmt.Println("No TDF filenames given.") flag.PrintDefaults() os.Exit(2) } if !listFonts { fmt.Printf("package %s\n\n", defaultPackage) fmt.Println("import (") fmt.Println(" \"red-green/door\"") fmt.Println(")") fmt.Println("") } else { fmt.Println("Font-Out - A TDF (TheDraw Font) file processor.") } var fontList []string if len(fonts) > 0 { fontList = strings.Split(fonts, ",") } if allFonts { fontList = make([]string, 0) fontList = append(fontList, "*") } if !listFonts && len(fontList) == 0 { fmt.Println("Default to -l (List Fonts)") listFonts = true } for _, fontfile := range flag.Args() { if listFonts { ListFonts(fontfile) } else { if len(fontList) > 0 { ExtractFonts(fontfile, fontList) } } } }