tdfont.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. package door
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. )
  8. // Not possible to do, without help from:
  9. // http://www.roysac.com/blog/2014/04/thedraw-fonts-file-tdf-specifications/
  10. type BlockFont struct {
  11. Characters []int
  12. Data [][][]byte
  13. }
  14. /*
  15. func BytesHexed(output []byte) {
  16. fmt.Printf("BH: ")
  17. for _, ch := range output {
  18. fmt.Printf("%02x ", ch)
  19. }
  20. fmt.Println("")
  21. }
  22. func BytesArrayHexed(output *[][]byte) {
  23. for _, out := range *output {
  24. BytesHexed(out)
  25. }
  26. }
  27. */
  28. // Make []strings all the same length
  29. func normalizeBlock(block *[][]byte) {
  30. var max int
  31. // StringO(block)
  32. for _, line := range *block {
  33. var l int = len(line)
  34. if max < l {
  35. max = l
  36. }
  37. }
  38. // fmt.Printf("max = %d\n", max)
  39. for idx := range *block {
  40. // l := len(line)
  41. for len((*block)[idx]) < max {
  42. //(*block)[idx] += byte(0x20) //append((*block)[idx], byte{0x20})
  43. (*block)[idx] = append((*block)[idx], byte(0x20))
  44. }
  45. }
  46. // StringO(block)
  47. // fmt.Println("== normalized ==")
  48. }
  49. // Get Character information from BlockFont return Normalize
  50. func (bf *BlockFont) GetCharacter(c int) [][]byte {
  51. var result [][]byte
  52. if c == 32 {
  53. // Space character
  54. result = append(result, []byte{0x20, 0x20})
  55. return result
  56. }
  57. // 33-126 are the possible characters.
  58. if c >= 33 && c <= 126 {
  59. c -= 33
  60. var idx int = bf.Characters[c]
  61. if idx == -1 {
  62. // This character is not supported by this font.
  63. return result
  64. }
  65. result = bf.Data[bf.Characters[c]]
  66. // fmt.Println("normalizeCharBlock")
  67. normalizeBlock(&result)
  68. // fmt.Println("normalizeChar done")
  69. return result
  70. } else {
  71. return result
  72. }
  73. }
  74. func expandBlock(block *[][]byte) {
  75. // l := len((*block)[0])
  76. var l int = len((*block)[0])
  77. var blank []byte = []byte{0x20}
  78. *block = append(*block, bytes.Repeat(blank, l))
  79. }
  80. // Given text, translate to thedraw font.
  81. func (bf *BlockFont) Output(input string) ([]string, int) {
  82. var out [][]byte
  83. var max int
  84. for _, ch := range input {
  85. // fmt.Printf("%d %x\n", ch, ch)
  86. block := bf.GetCharacter(int(ch))
  87. // fmt.Println("ok")
  88. var l int = len(block)
  89. max += l
  90. if l != 0 {
  91. if len(out) == 0 {
  92. // First time
  93. out = append(out, block...)
  94. /*
  95. for _, b := range block {
  96. out = append(out, b)
  97. }
  98. */
  99. } else {
  100. if len(out) != 0 {
  101. for l > len(out) {
  102. // We need to expand the out
  103. // fmt.Println("expandBlock")
  104. expandBlock(&out)
  105. }
  106. }
  107. // fmt.Println("Append block to out")
  108. // Ok, we have something!
  109. for idx, b := range block {
  110. out[idx] = append(out[idx], byte(0x20))
  111. out[idx] = append(out[idx], b...)
  112. /*
  113. for _, inner := range b {
  114. out[idx] = append(out[idx], inner)
  115. }
  116. */
  117. // out[idx] += byte(0x20) + b
  118. // fmt.Printf("%s\n", CP437_to_Unicode(b))
  119. }
  120. }
  121. }
  122. // fmt.Println("normalizeBlock")
  123. normalizeBlock(&out)
  124. // fmt.Println("normalizeBlock done")
  125. }
  126. var output []string
  127. for idx := range out {
  128. if Unicode {
  129. output = append(output, CP437_to_Unicode(string(out[idx])))
  130. } else {
  131. output = append(output, string(out[idx]))
  132. }
  133. }
  134. return output, len(out[0])
  135. }
  136. type ColorFont struct {
  137. Characters []int
  138. Data [][][]byte
  139. }
  140. func normalizeColor(block *[][]byte) int {
  141. var max int
  142. for _, line := range *block {
  143. l := len(line)
  144. if max < l {
  145. max = l
  146. }
  147. }
  148. for idx := range *block {
  149. // l := len(line)
  150. var blank []byte = []byte{0x20, 0x0f}
  151. for len((*block)[idx]) < max {
  152. (*block)[idx] = append((*block)[idx], blank...)
  153. /*
  154. for _, b := range blank {
  155. (*block)[idx] = append((*block)[idx], b)
  156. }
  157. */
  158. // (*block)[idx] += strings.Repeat(" \x0f", max-l/2)
  159. }
  160. }
  161. return max
  162. }
  163. func (cf *ColorFont) GetCharacter(c int) ([][]byte, int) {
  164. var result [][]byte
  165. if c == 32 {
  166. var blank []byte = []byte{0x20, 0x0f, 0x20, 0x0f}
  167. result = append(result, blank) // " \x0f \x0f")
  168. return result, len(result[0]) / 2
  169. }
  170. if c >= 33 && c <= 126 {
  171. c -= 33
  172. var idx int = cf.Characters[c]
  173. if idx == -1 {
  174. return result, 0
  175. }
  176. result = cf.Data[cf.Characters[c]]
  177. // fmt.Println("Character:")
  178. // BytesArrayHexed(&result)
  179. // fmt.Println("normalizing...")
  180. var max int = normalizeColor(&result)
  181. // BytesArrayHexed(&result)
  182. // StringHexO(&result)
  183. return result, max
  184. } else {
  185. return result, 0
  186. }
  187. }
  188. func thedraw_to_ansi(c int) int {
  189. var trans []int = []int{0, 4, 2, 6, 1, 5, 3, 7}
  190. // 0, 1, 2, 3, 4, 5, 6, 7
  191. return trans[c]
  192. }
  193. /*
  194. // Before color output was optimized
  195. func colorout(c int) string {
  196. bg := thedraw_to_ansi(c / 16)
  197. fg := c % 16
  198. bold := (fg & 0x8) == 0x8
  199. fg = thedraw_to_ansi(fg & 0x7)
  200. if bold {
  201. return fmt.Sprintf("\x1b[0;1;%d;%dm", fg+30, bg+40)
  202. } else {
  203. return fmt.Sprintf("\x1b[0;%d;%dm", fg+30, bg+40)
  204. }
  205. }
  206. */
  207. type ColorParts struct {
  208. Background int
  209. Foreground int
  210. Bold bool
  211. }
  212. func ColorSplit(color int) ColorParts {
  213. return ColorParts{Background: thedraw_to_ansi(color / 16), Foreground: thedraw_to_ansi(color & 7), Bold: (color%16)&0x08 == 0x08}
  214. }
  215. func ColorOutput(previous int, color int) string {
  216. var prev ColorParts = ColorSplit(previous)
  217. var c ColorParts = ColorSplit(color)
  218. var codes []int8
  219. if c.Bold {
  220. if !prev.Bold {
  221. codes = append(codes, 1)
  222. }
  223. } else {
  224. if prev.Bold {
  225. // bold was set previously, there's only one way to reset it
  226. codes = append(codes, 0)
  227. prev.Background = 0
  228. prev.Foreground = 7
  229. }
  230. }
  231. if prev.Background == 0 && prev.Foreground == 0 {
  232. // output everything
  233. codes = append(codes, int8(c.Foreground)+30)
  234. codes = append(codes, int8(c.Background)+40)
  235. } else {
  236. if c.Foreground != prev.Foreground {
  237. codes = append(codes, int8(c.Foreground)+30)
  238. }
  239. if c.Background != prev.Background {
  240. codes = append(codes, int8(c.Background)+40)
  241. }
  242. }
  243. if len(codes) == 0 {
  244. // Everything matched
  245. return ""
  246. }
  247. var text []string
  248. for _, code := range codes {
  249. text = append(text, strconv.Itoa(int(code)))
  250. }
  251. return "\x1b[" + strings.Join(text, ";") + "m"
  252. }
  253. func Colorize(input []byte) []byte {
  254. var result []byte
  255. // runes := []rune(input)
  256. var previous int
  257. // BytesHexed(input)
  258. for pos := 0; pos < len(input); pos += 2 {
  259. var ch byte = input[pos]
  260. var color int = int(input[pos+1])
  261. // fmt.Printf("%d : CH %d / %x, Color %d / %x\n", pos, ch, ch, color, color)
  262. var colorstring string = ColorOutput(previous, color)
  263. result = append(result, []byte(colorstring)...)
  264. /*
  265. for _, c := range []byte(colorstring) {
  266. result = append(result, c)
  267. }
  268. */
  269. // result = append(result, []byte(colorstring))
  270. // result += []byte(ColorOutput(previous, color))
  271. // result += ColorOutput(previous, color) + string(ch)
  272. result = append(result, ch)
  273. // result += string(ch)
  274. previous = color
  275. // result += colorout(color) + string(ch)
  276. }
  277. return result
  278. }
  279. /*
  280. func __expandColor(block *[]string, need int) {
  281. *block = append(*block, strings.Repeat(" \x0f", need))
  282. }
  283. */
  284. func expandColor(block *[][]byte, need int) {
  285. var blank []byte = []byte{0x20, 0x0f}
  286. // *block = append(*block, strings.Repeat(" \x0f", need))
  287. *block = append(*block, bytes.Repeat(blank, need))
  288. }
  289. func (bf *ColorFont) Output(input string) ([]string, int) {
  290. var out [][]byte
  291. var max int
  292. for _, ch := range input {
  293. // fmt.Printf("%d %x\n", ch, ch)
  294. var block [][]byte
  295. var blklen int
  296. block, blklen = bf.GetCharacter(int(ch))
  297. if blklen == 0 {
  298. continue
  299. }
  300. var l int = len(block)
  301. max += blklen
  302. if l != 0 {
  303. if len(out) == 0 {
  304. // First time
  305. out = append(out, block...)
  306. /*
  307. for _, b := range block {
  308. out = append(out, b)
  309. }
  310. */
  311. } else {
  312. if len(out) != 0 {
  313. for l > len(out) {
  314. // We need to expand the out
  315. expandColor(&out, len(out[0])/2)
  316. // ExpandColor(&out)
  317. }
  318. }
  319. for len(out) > len(block) {
  320. // We need to expand the block out
  321. expandColor(&block, len(block)/2)
  322. }
  323. // Normalizing the character blocks
  324. normalizeColor(&block)
  325. if len(out) != len(block) {
  326. panic(fmt.Sprintf("len(out) %d != len(block) %d", len(out), len(block)))
  327. }
  328. var blank []byte = []byte{0x20, 0x0f}
  329. // Ok, we have something!
  330. for idx, b := range block {
  331. /*
  332. out[idx] = append(out[idx], byte(0x20))
  333. out[idx] = append(out[idx], byte(0x0f))
  334. */
  335. out[idx] = append(out[idx], blank...)
  336. out[idx] = append(out[idx], b...)
  337. /*
  338. for _, inner := range b {
  339. out[idx] = append(out[idx], inner)
  340. }
  341. */
  342. //out[idx] += " \x0f" + b
  343. // fmt.Printf("%s\n", CP437_to_Unicode(b))
  344. }
  345. }
  346. // NormalizeColor(&out)
  347. }
  348. }
  349. if len(out) == 0 {
  350. return []string{}, 0
  351. }
  352. // StringHexO(&out)
  353. max = len(out[0]) / 2
  354. for idx := range out {
  355. out[idx] = Colorize(out[idx])
  356. }
  357. var output []string
  358. for idx := range out {
  359. if Unicode {
  360. output = append(output, CP437_to_Unicode(string(out[idx])))
  361. } else {
  362. output = append(output, string(out[idx]))
  363. }
  364. }
  365. return output, max
  366. }
  367. // Given a color to look for, see if it is in the color byte.
  368. // 0x01 = Upper match
  369. // 0x02 = Lower match
  370. func MatchStyle(color byte, look byte) int {
  371. var match int = 0
  372. if ((color >> 4) & 0x07) == look {
  373. // Top
  374. match |= 1
  375. }
  376. if (color & 0x07) == look {
  377. // Bottom
  378. match |= 2
  379. }
  380. return match
  381. }
  382. // Update a color byte with the new color information.
  383. // Style 0x01 = Upper, 0x02 = Lower, 0x03 = Both.
  384. func PatchColor(color byte, new_color byte, style int) byte {
  385. var c byte = color
  386. if style&1 == 1 {
  387. c = (c & 0x8f) | new_color<<4
  388. }
  389. if style&2 == 2 {
  390. c = (c & 0xf8) | new_color
  391. }
  392. return c
  393. }
  394. type ColorMap map[[2]int][][2]int
  395. // Scan a ColorFont for a specific color.
  396. // This returns a map key of character Index + line Index
  397. // with an array of [2]int (Index, Style) to change.
  398. func (cf *ColorFont) Scan(find_color int) ColorMap {
  399. var Targets ColorMap = make(ColorMap, 0)
  400. // Scan the font looking for the given color FG/BG
  401. // Covert color code to TheDraw Color
  402. var actual byte = byte(thedraw_to_ansi(find_color))
  403. for charIndex := range cf.Data {
  404. for lineIndex := range cf.Data[charIndex] {
  405. var found bool = false
  406. var patches [][2]int = make([][2]int, 0)
  407. for offset := 1; offset < len(cf.Data[charIndex][lineIndex]); offset += 2 {
  408. var color byte = cf.Data[charIndex][lineIndex][offset]
  409. var style int = MatchStyle(color, actual)
  410. if style != 0 {
  411. // log.Printf("color: %x actual %x style: %d\n", color, actual, style)
  412. patches = append(patches, [2]int{offset, style})
  413. found = true
  414. }
  415. }
  416. if found {
  417. var pos [2]int = [2]int{charIndex, lineIndex}
  418. Targets[pos] = make([][2]int, len(patches))
  419. copy(Targets[pos], patches)
  420. /*
  421. for i := range patches {
  422. Targets[pos][i] = patches[i]
  423. }
  424. */
  425. // Targets[pos] = patches
  426. }
  427. }
  428. }
  429. return Targets
  430. }
  431. // This modifies the font color, using the Targets found with
  432. // Scan.
  433. func (cf *ColorFont) Modify(new_color int, Targets ColorMap) {
  434. // Covert color code to TheDraw Color
  435. var actual byte = byte(thedraw_to_ansi(new_color))
  436. for pos, patch := range Targets {
  437. for _, p := range patch {
  438. cf.Data[pos[0]][pos[1]][p[0]] = PatchColor(cf.Data[pos[0]][pos[1]][p[0]], actual, p[1])
  439. }
  440. }
  441. }