font-out.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. package main
  2. import (
  3. "bufio"
  4. "encoding/binary"
  5. "flag"
  6. "fmt"
  7. "os"
  8. "strconv"
  9. "strings"
  10. )
  11. func ListFonts(filename string) {
  12. f, err := os.Open(filename)
  13. if err != nil {
  14. fmt.Printf("Open(%s): %s\n", filename, err)
  15. panic(err)
  16. }
  17. defer f.Close()
  18. tdfonts := make([]byte, 20)
  19. f.Read(tdfonts)
  20. for true {
  21. fontdef := make([]byte, 4)
  22. read, _ := f.Read(fontdef)
  23. if read != 4 {
  24. fmt.Println("*END*")
  25. break
  26. }
  27. fontname := make([]byte, 13)
  28. f.Read(fontname)
  29. Name := strings.Trim(string(fontname[1:]), "\x00")
  30. // fmt.Printf("Font: %s\n", Name)
  31. f.Read(fontdef)
  32. single := make([]byte, 1)
  33. var FontType int8
  34. binary.Read(f, binary.LittleEndian, &FontType)
  35. // f.Read(single) // FontType
  36. // FontType := int(single[0])
  37. fmt.Printf("Font: %s (type %d)\n", Name, FontType)
  38. f.Read(single) // Spacing
  39. // blocksize := make([]byte, 2)
  40. // f.Read(blocksize)
  41. var BlockSize int16
  42. binary.Read(f, binary.LittleEndian, &BlockSize)
  43. // fmt.Printf("Size: %d / %x\n", BlockSize, BlockSize)
  44. letterOffsets := make([]int16, 94)
  45. binary.Read(f, binary.LittleEndian, &letterOffsets)
  46. if false {
  47. for idx, i := range letterOffsets {
  48. fmt.Printf(" %04X", i)
  49. if (idx+1)%10 == 0 {
  50. fmt.Println("")
  51. }
  52. }
  53. fmt.Println("")
  54. }
  55. data := make([]byte, BlockSize)
  56. binary.Read(f, binary.LittleEndian, &data)
  57. }
  58. }
  59. func byte_to_text(line []byte) string {
  60. var output string
  61. for _, ch := range line {
  62. output += fmt.Sprintf("0x%02x,", ch)
  63. }
  64. if len(output) > 0 {
  65. output = output[:len(output)-1]
  66. }
  67. return output
  68. }
  69. func text_to_hextext(line string) string {
  70. var output string
  71. // output = "\""
  72. for _, ch := range []byte(line) {
  73. // output += fmt.Sprintf("\\x%02x", ch)
  74. output += fmt.Sprintf("0x%02x,", ch)
  75. }
  76. if len(output) > 1 {
  77. output = output[:len(output)-1]
  78. }
  79. // output += "\""
  80. return output
  81. }
  82. func ExtractColor(name string, offsets []uint16, data []byte) {
  83. fmt.Printf("Extract Color Font: %s\n", name)
  84. var indexes []int
  85. var blocks [][][]byte
  86. var current [][]byte
  87. var line []byte
  88. pos := 0
  89. for pos < len(data) {
  90. indexes = append(indexes, pos)
  91. current = make([][]byte, 0)
  92. line = make([]byte, 0)
  93. // We don't use these.
  94. // w = data[pos]
  95. // h = data[pos+1]
  96. pos += 2
  97. // process this character
  98. for pos < len(data) {
  99. ch := data[pos]
  100. pos++
  101. if ch == 0x00 {
  102. // end of character
  103. current = append(current, line)
  104. blocks = append(blocks, current)
  105. current = make([][]byte, 0)
  106. line = make([]byte, 0)
  107. break
  108. }
  109. if ch == 0x0d {
  110. // end of this character line
  111. current = append(current, line)
  112. line = make([]byte, 0)
  113. continue
  114. }
  115. if ch == 0x26 {
  116. // & descender mark
  117. continue
  118. }
  119. line = append(line, ch)
  120. color := data[pos]
  121. pos++
  122. line = append(line, color)
  123. }
  124. }
  125. // offset optimization:
  126. var single []int
  127. for _, o := range offsets {
  128. if o == 65535 {
  129. single = append(single, -1)
  130. continue
  131. }
  132. for idx, i := range indexes {
  133. if o == uint16(i) {
  134. single = append(single, idx)
  135. break
  136. }
  137. }
  138. }
  139. // Handle Names with spaces
  140. filename := fmt.Sprintf("%s_font.go", strings.Replace(name, " ", "", -1))
  141. fp, err := os.Create(filename)
  142. if err != nil {
  143. panic(err)
  144. }
  145. fmt.Printf("Writing: %s\n", filename)
  146. defer fp.Close()
  147. writer := bufio.NewWriter(fp)
  148. // writer.WriteString("package main\n")
  149. writer.WriteString("// " + name + "\n\n")
  150. // Name := strings.ToUpper(name)
  151. Name := strings.Replace(name, " ", "", -1)
  152. writer.WriteString("func Font" + Name + "() door.ColorFont {\n")
  153. var output string
  154. output = " return door.ColorFont{Characters: []int{"
  155. for _, s := range single {
  156. output += strconv.Itoa(s) + ", "
  157. }
  158. output = output[:len(output)-2] + "},\n"
  159. writer.WriteString(output)
  160. writer.Flush()
  161. output = " Data: [][][]byte{"
  162. for _, blk := range blocks {
  163. output += "{"
  164. if len(blk) == 0 {
  165. output += "{},"
  166. } else {
  167. for _, inner := range blk {
  168. // output += text_to_hextext(b) + ","
  169. output += "{" + byte_to_text(inner) + "},"
  170. }
  171. output = output[:len(output)-1]
  172. }
  173. output += "},\n"
  174. writer.WriteString(output)
  175. output = " "
  176. }
  177. writer.WriteString(" }}\n")
  178. writer.WriteString("}\n")
  179. writer.Flush()
  180. }
  181. func ExtractBlock(name string, offsets []uint16, data []byte) {
  182. fmt.Printf("Extract Block Font: %s\n", name)
  183. var indexes []int
  184. var blocks [][][]byte
  185. var current [][]byte
  186. var line []byte
  187. pos := 0
  188. for pos < len(data) {
  189. indexes = append(indexes, pos)
  190. current = make([][]byte, 0)
  191. line = make([]byte, 0)
  192. // We don't use these
  193. // w = data[pos]
  194. // h = data[pos+1]
  195. pos += 2
  196. // process this character
  197. for pos < len(data) {
  198. ch := data[pos]
  199. pos++
  200. if ch == 0x00 {
  201. // end of character
  202. current = append(current, line)
  203. blocks = append(blocks, current)
  204. current = make([][]byte, 0)
  205. line = make([]byte, 0)
  206. break
  207. }
  208. if ch == 0x0d {
  209. // end of this character line
  210. current = append(current, line)
  211. line = make([]byte, 0)
  212. continue
  213. }
  214. if ch == 0x26 {
  215. // & descender mark
  216. continue
  217. }
  218. line = append(line, ch)
  219. }
  220. }
  221. // offset optimization:
  222. var single []int
  223. for _, o := range offsets {
  224. if o == 65535 {
  225. single = append(single, -1)
  226. continue
  227. }
  228. for idx, i := range indexes {
  229. if o == uint16(i) {
  230. single = append(single, idx)
  231. break
  232. }
  233. }
  234. }
  235. // Handle Names with spaces
  236. filename := fmt.Sprintf("%s_font.go", strings.Replace(name, " ", "", -1))
  237. fp, err := os.Create(filename)
  238. if err != nil {
  239. panic(err)
  240. }
  241. fmt.Printf("Writing: %s\n", filename)
  242. defer fp.Close()
  243. writer := bufio.NewWriter(fp)
  244. // Should this output routine be part of the BlockFont?
  245. // I think so!
  246. // writer.WriteString("package main\n")
  247. writer.WriteString("// " + name + "\n\n")
  248. // Name := strings.ToUpper(name)
  249. Name := strings.Replace(name, " ", "", -1)
  250. writer.WriteString("func Font" + Name + "() door.BlockFont {\n")
  251. var output string
  252. output = " return door.BlockFont{Characters: []int{"
  253. for _, s := range single {
  254. output += strconv.Itoa(s) + ", "
  255. }
  256. output = output[:len(output)-2] + "},\n"
  257. writer.WriteString(output)
  258. writer.Flush()
  259. output = " Data: [][][]byte{"
  260. for _, blk := range blocks {
  261. output += "{"
  262. if len(blk) == 0 {
  263. output += "{},"
  264. } else {
  265. for _, inner := range blk {
  266. output += "{" + byte_to_text(inner) + "},"
  267. }
  268. output = output[:len(output)-1]
  269. }
  270. output += "},\n"
  271. // output = output[:len(output)-1]
  272. // output += "},\n"
  273. writer.WriteString(output)
  274. output = " "
  275. }
  276. writer.WriteString(" }}\n")
  277. writer.WriteString("}\n")
  278. writer.Flush()
  279. }
  280. func ExtractFonts(filename string, fonts []string) {
  281. f, err := os.Open(filename)
  282. if err != nil {
  283. fmt.Printf("Open(%s): %s\n", filename, err)
  284. panic(err)
  285. }
  286. defer f.Close()
  287. tdfonts := make([]byte, 20)
  288. f.Read(tdfonts)
  289. for true {
  290. fontdef := make([]byte, 4)
  291. read, _ := f.Read(fontdef)
  292. if read != 4 {
  293. break
  294. }
  295. fontname := make([]byte, 13)
  296. f.Read(fontname)
  297. Name := strings.Trim(string(fontname[1:]), "\x00")
  298. // fmt.Printf("Font: %s\n", Name)
  299. f.Read(fontdef)
  300. single := make([]byte, 1)
  301. var FontType int8
  302. binary.Read(f, binary.LittleEndian, &FontType)
  303. // fmt.Printf("Font: %s (type %d)\n", Name, FontType)
  304. f.Read(single) // Spacing
  305. var BlockSize int16
  306. binary.Read(f, binary.LittleEndian, &BlockSize)
  307. letterOffsets := make([]uint16, 94)
  308. binary.Read(f, binary.LittleEndian, &letterOffsets)
  309. if false {
  310. for idx, i := range letterOffsets {
  311. fmt.Printf(" %04X", i)
  312. if (idx+1)%10 == 0 {
  313. fmt.Println("")
  314. }
  315. }
  316. fmt.Println("")
  317. }
  318. data := make([]byte, BlockSize)
  319. binary.Read(f, binary.LittleEndian, &data)
  320. // Special case where they are asking for all fonts
  321. if len(fonts) == 1 && fonts[0] == "*" {
  322. switch FontType {
  323. case 1:
  324. ExtractBlock(Name, letterOffsets, data)
  325. case 2:
  326. ExtractColor(Name, letterOffsets, data)
  327. default:
  328. fmt.Printf("Sorry, I can't handle Font: %s Type %d!\n", Name, FontType)
  329. }
  330. } else {
  331. for _, f := range fonts {
  332. if Name == f {
  333. switch FontType {
  334. case 1:
  335. ExtractBlock(Name, letterOffsets, data)
  336. case 2:
  337. ExtractColor(Name, letterOffsets, data)
  338. default:
  339. fmt.Printf("Sorry, I can't handle Font: %s Type %d!\n", Name, FontType)
  340. }
  341. break
  342. }
  343. }
  344. }
  345. }
  346. }
  347. func main() {
  348. fmt.Println("Font-Out - A TDF (TheDraw Font) file processor.")
  349. var fonts string
  350. var defaultPackage string = "main"
  351. var listFonts bool
  352. var allFonts bool
  353. flag.StringVar(&fonts, "f", "", "Font(s) to extract")
  354. flag.BoolVar(&allFonts, "a", false, "Extract All Fonts")
  355. flag.StringVar(&defaultPackage, "p", "main", "Package name to use")
  356. flag.BoolVar(&listFonts, "l", false, "List Fonts")
  357. flag.Parse()
  358. if flag.NArg() == 0 {
  359. fmt.Println("No TDF filenames given.")
  360. flag.PrintDefaults()
  361. os.Exit(2)
  362. }
  363. var fontList []string
  364. if len(fonts) > 0 {
  365. fontList = strings.Split(fonts, ",")
  366. }
  367. if allFonts {
  368. fontList = make([]string, 0)
  369. fontList = append(fontList, "*")
  370. }
  371. if !listFonts && len(fontList) == 0 {
  372. fmt.Println("Default to -l (List Fonts)")
  373. listFonts = true
  374. }
  375. for _, fontfile := range flag.Args() {
  376. if listFonts {
  377. ListFonts(fontfile)
  378. }
  379. if len(fontList) > 0 {
  380. ExtractFonts(fontfile, fontList)
  381. }
  382. }
  383. }