diff options
| author | nsfisis <nsfisis@gmail.com> | 2022-04-24 13:12:59 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2022-04-24 13:12:59 +0900 |
| commit | 83754f16833766420cdca1f8527177dbc4b6ace1 (patch) | |
| tree | e713bf6e0d6d9ce74e9b361b2aeebb6f4f45c51b | |
| parent | 7f4f96b94f1111fbbe71dc99c4bed506a4b4b406 (diff) | |
| download | term-banner-83754f16833766420cdca1f8527177dbc4b6ace1.tar.gz term-banner-83754f16833766420cdca1f8527177dbc4b6ace1.tar.zst term-banner-83754f16833766420cdca1f8527177dbc4b6ace1.zip | |
implementv1.0.0
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | LICENSE | 21 | ||||
| -rw-r--r-- | Makefile | 24 | ||||
| -rw-r--r-- | README.md | 55 | ||||
| -rw-r--r-- | assets/misaki.txt | 261 | ||||
| -rw-r--r-- | assets/misaki_gothic_2nd_4x8.png | bin | 0 -> 1073 bytes | |||
| -rw-r--r-- | assets/misaki_mincho.png | bin | 0 -> 54886 bytes | |||
| -rw-r--r-- | go.mod | 17 | ||||
| -rw-r--r-- | go.sum | 19 | ||||
| -rw-r--r-- | main.go | 392 | ||||
| -rw-r--r-- | screenshot.png | bin | 0 -> 27573 bytes |
11 files changed, 790 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7673e14 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/term-banner @@ -0,0 +1,21 @@ +MIT License + +Copyright 2022 nsfisis + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d4abc9b --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +BIN := term-banner + +all: build + +.PHONY: run +run: build + ./$(BIN) + +.PHONY: build +build: $(BIN) + +$(BIN): main.go + go build -o $(BIN) + +.PHONY: fmt +fmt: + go fmt + +.PHONY: clean +clean: + go clean + +test: build + ./$(BIN) 'Hello, World!' 'こんにちは、' '世界!' diff --git a/README.md b/README.md new file mode 100644 index 0000000..8b2a990 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# term-banner + +Show a banner in your terminal. + +## Supported characters + +* All of ASCII characters +* Some of Japanese Kanji and symbols (JIS第一・第二水準) + +Special thanks to Num Kadoma, the author of the awesome font! + + +# Usage + +Pass a messsage as command line arguments: + +``` +$ ./term-banner 'Hello, World!' +``` + +Multiple arguments are displayed in multiple lines. + +``` +$ ./term-banner foo bar baz +``` + + +# Requirements + +* Go toolchains + + +# Build + +1. Clone this repository. +2. `make build` + + +# Screenshot + +``` +$ make test +``` + + + + +# License + +This program uses [美咲フォント 2021-05-05a 版](https://littlelimit.net/misaki.htm) for rendering Japanese text. +Note that the license and copyright holder of the font is different from the program's. + +See [assets/misaki.txt](./assets/misaki.txt) for license of font. + +See [LICENSE](./LICENSE) for license of the program. diff --git a/assets/misaki.txt b/assets/misaki.txt new file mode 100644 index 0000000..3a1ae30 --- /dev/null +++ b/assets/misaki.txt @@ -0,0 +1,261 @@ +=============================================================================== + + 8×8 ドット日本語フォント「美咲フォント」 + (2021-05-05a 版) + + Copyright(C) 2002-2021 Num Kadoma + +=============================================================================== + +------------------------------------------------------------------------------- + 概要 +------------------------------------------------------------------------------- + 美咲フォントは 8×8 ドットの日本語ビットマップフォントです。 + JIS第一・第二水準をサポートしています。 + 一部の記号を除いた全ての文字は 7×7 ドットの範囲に収まっているため、 + 文字同士を隣接させても行間・字間が確保できます。 + + フォント名は制作のきっかけとなった美咲 礼威氏からいただきました。 + + +------------------------------------------------------------------------------- + バリエーション +------------------------------------------------------------------------------- +・「美咲明朝」は、美咲ゴシックの非漢字部を明朝風の字形に差し替えたものです。 +・「美咲ゴシック第2」は美咲ゴシックをベースに、半角文字は縦 7 px、 + 全角仮名は横 7 px をいっぱいに使う字形に差し替えたものです。 + + 各機種用のアーカイブに、差替え済みのフォントファイルを同梱してあります。 + + +------------------------------------------------------------------------------- + ライセンス +------------------------------------------------------------------------------- + These fonts are free softwares. + Unlimited permission is granted to use, copy, and distribute it, with or without modification, either commercially and noncommercially. + THESE FONTS ARE PROVIDED "AS IS" WITHOUT WARRANTY. + + これらのフォントはフリー(自由な)ソフトウエアです。 + あらゆる改変の有無に関わらず、また商業的な利用であっても、自由にご利用、複製、再配布することができますが、全て無保証とさせていただきます。 + + +------------------------------------------------------------------------------- + 制作履歴 +------------------------------------------------------------------------------- +■2021-05-05a +・(PNG) 左へのずれを修正: ¨¥¢§ + +■2021-05-05 +・文字を追加 + 共通: ␣ +・字形を修正・変更 + 共通: № + ゴシック第2: プヴ +・(TTF) ビットマップを埋込み + +■2019-10-19 +・ドキュメントの文字コードを UTF-8N、改行コードを LF に統一 +・(TTF, BDF) 記号を追加: + ▁▂▃▄▅▆▇█▏▎▍▌▋▊▉▔▕╭╮╰╯♠♥♦♣╱╲╳♤♡♢♧ + +■2019-08-18 +・各ファイルのパーミッションから、不要な実行ビットを除去 (フォントの変更はなし) + +■2019-06-03 +・新フォント「美咲ゴシック第2」を追加。英語名「MisakiGothic2nd」 +・「令和」の合字を追加 +・各種字形の修正 +・(E500) ファイル名のつけ方を変更して配布を再開 +・(BDF) 一部仕様を変更して配布を再開 + エンコーディングは ISO 10646-1 のみとし、全ての文字を 1 ファイルに収録 + XLFD 変更 + BITMAP を文字の上下左右端の空白を削った形とし、BBX で位置を指定する形に修正 + +■2019-02-03a +・制作履歴における、変更した文字の抜け (ゴシックの「と」「ね」「ゐ」) を修正 + +■2019-02-03 +・ゴシック・明朝共通の変更: &,.‘’()〔〕[]{}〈〉【】°′″№0索二 + 半角 (「&」字形変更) + 記号類 (主に括弧類の位置調整) + 数字 (ゼロにスラッシュを追加) + 漢字 (「索」「二」の字形変更) +・ゴシックのみの変更: 69CGOQΟОСЭぐぜとどねばぶゐガグゾダバヴ + 数字 (「6」「9」の先端を伸ばす形に変更) + アルファベット (オーなどの丸み変更) + 仮名 (主に濁点/半濁点つき文字の調整) +・明朝のみの変更: ぐでとどなぶウグケサザソゾダドワヱヴЁ + 仮名 (各種字形変更) + キリル (「Ё」の字形変更) + +■2015-04-10 +・誤字になっていた「喪」を修正 +・(TTF) ウェイトを「Regular」に変更 + 一部の記号を追加、変更 + バージョン番号を「yyyy.mmdd」の形に変更 + その他、パラメータを見直し + 埋込みビットマップ版の同梱を取り止め + +■2012-06-03 +・正式公開初版 + +■2012-03-31 +・各種ファイル名、ドキュメントの見直し +・BDF 版以外のアーカイブ形式を zip に変更 +・(TTF) アウトライン版の正式採用、Mac におそらく対応 +・(FONTX) 4X8.FNT の 00h~1Fh に DOS/V 罫線を追加 + +■2011-03-08 +・(TTF-Outline) 生成手順の改善に伴い periodβ11 作成・公開 + +■2010-03-07 +・(BDF) FOUNDRY, POINT_SIZE, AVERAGE_WIDTH, SWIDTH, XLFD, 各ファイル名の変更 + +■2006-10-01 +・(TTF-Outline) 試作版配布開始 + +■2006-04-01 +・(PNG) 配布開始 + +■2006-03-26 +・(E500) 13 区追加版・軽量版 (第一水準のみ) 同梱開始 + フォントファイルの命名規則変更 +・(BDF) 美咲明朝の配布形態をゴシックとの差分から実ファイル同梱へ + BITMAP の記述方法を修正 (16 進 4 桁から 2 桁へ) +・(FONTX) 配布再開 + +■2005-07-20 +・アーカイブの命名規則を変更 +・(TTF, BDF) 著作権表記を変更 +・(BDF) 1 バイト文字フォントのファイル名をそれぞれ 4x8.bdf, 4x8_8859.bdf に + +■2004-09-12 +・(TTF, BDF) 13 区の文字追加 + +■2004-06-24 +・フォントの名称変更 +・(美咲フォントを美咲ゴシック、ファミリーの総称を美咲フォントに) + +■2004-05-09 +・美咲明朝の同梱開始 + +■2004-04-19 +・半濁点の処理を変更 + +■2004-04-11 +・3 フォント同時編集ツール「"SCRNJPN.FNT" Editor」完成 + +■2004-02-09 +・濁点の処理を変更 + +■2003-09-21 +・制作履歴の日付ミスを修正 (美咲氏 Thanx!) + +■2003-06-04 +・ライセンスに関する記述を変更 + +■2003-05-04 +・(BDF) 3x7_8859.bdf の CHARS の値を修正 +・(BDF) 3x7_8859.bdf のファイル名が 3X7_8859.bdf になっていたのを修正 + +■2003-03-26 +・マニュアルをフォントの説明と各形式の説明に分離 + +■2003-01-02 +・各部のフォント間での統一化作業を本格的に開始 + +■2002-06-10 +・JIS X 0208-1983 での文字の変更、JIS X 0208-1990 での文字の追加に対応 + +■2002-06-06 +・未定義文字のフォントを 3×3 の ■ に + +■2002-06-01 +・第二水準完成 + +■2002-05-22 +・制作再開 + +■2002-05-21 +・フォント作成専用ツール「'SCRNJPN.FNT' Editor」完成 + +■2002-05-11 +・E650 暴走により第二水準中の 600 文字近くが消滅→制作中断 + +■2002-04-初 +・第一水準完成 + +■2002-03-中 +・制作開始 + + +------------------------------------------------------------------------------- + バージョン情報 +------------------------------------------------------------------------------- +■2021-05-05 +・美咲フォント 2021-05-05 版 (E500/BDF/TTF/PNG) + +■2019-10-19 +・美咲フォント 2019-10-19 版 (E500/BDF/TTF/PNG) + +■2019-08-18 +・美咲フォント 2019-06-03a 版 (E500/BDF/TTF/PNG) + +■2019-06-03 +・美咲フォント 2019-06-03 版 (E500/BDF/TTF/PNG) + +■2019-02-03 +・美咲フォント 2019-02-03 版 (TTF/PNG) + +■2015-04-10 +・美咲フォント 2015-04-10 版 (TTF/PNG) + +■2012-06-03 +・美咲フォント 2012-06-03 版 (E500/BDF/TTF/Ruputer/FONTX/PNG) + +■2012-03-31 +・美咲フォント periodβ12 (E500/BDF/TTF/Ruputer/FONTX/PNG) + +■2010-03-07 +・美咲フォント periodβ11a (BDF) + +■2008-06-03 +・美咲フォント periodβ11 (E500/BDF/TTF/Ruputer/FONTX/PNG/TTF-Outline) + +■2006-03-26 +・美咲フォント periodβ10 (E500/BDF/TTF/Ruputer/FONTX/PNG/TTF-Outline) + +■2005-07-20 +・美咲フォント periodβ9 (E500/BDF/TTF/Ruputer) + +■2004-05-09 +・美咲フォント periodβ8 (E500/BDF/TTF/Ruputer) + +■2003-09-21 +・美咲フォント periodβ7 (E500/BDF/TTF/Ruputer) + +■2003-06-04 +・美咲フォント periodβ6 (E500/BDF/TTF/Ruputer) + +■2003-05-04 +・美咲フォント periodβ5 (E500/BDF/TTF/Ruputer) + +■2003-03-26 +・美咲フォント periodβ4 (E500/BDF/TTF/Ruputer/FONTX) + +■2002-12-14 +・美咲フォント periodβ3 (E500) + +■2002-06-18 +・美咲フォント periodβ2 (E500) + +■2002-06-03 +・美咲フォント periodβ1 (E500) + + +------------------------------------------------------------------------------- + 連絡先 +------------------------------------------------------------------------------- + 門真 なむ (Num Kadoma) + ・Twitter: @num_kadoma + ・Website: http://littlelimit.net/ diff --git a/assets/misaki_gothic_2nd_4x8.png b/assets/misaki_gothic_2nd_4x8.png Binary files differnew file mode 100644 index 0000000..edcfc97 --- /dev/null +++ b/assets/misaki_gothic_2nd_4x8.png diff --git a/assets/misaki_mincho.png b/assets/misaki_mincho.png Binary files differnew file mode 100644 index 0000000..874b91e --- /dev/null +++ b/assets/misaki_mincho.png @@ -0,0 +1,17 @@ +module github.com/nsfisis/term-banner + +go 1.18 + +require ( + github.com/gdamore/tcell/v2 v2.5.0 + golang.org/x/text v0.3.7 +) + +require ( + github.com/gdamore/encoding v1.0.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 // indirect + golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect +) @@ -0,0 +1,19 @@ +github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell/v2 v2.5.0 h1:/LA5f/wqTP5mWT79czngibKVVx5wOgdFTIXPQ68fMO8= +github.com/gdamore/tcell/v2 v2.5.0/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 h1:saXMvIOKvRFwbOMicHXr0B1uwoxq9dGmLe5ExMES6c4= +golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -0,0 +1,392 @@ +package main + +import ( + "embed" + "image/png" + "log" + "os" + + "github.com/gdamore/tcell/v2" + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/japanese" +) + +const ( + // Bit width of half-width characters. + bitsHW = 32 + // Glyph width of half-width characters. + glyphWidthHW = 4 + // Glyph height of half-width characters. + glyphHeightHW = 8 + // Bit width of full-width characters. + bitsFW = 64 + // Glyph width of full-width characters. + glyphWidthFW = 8 + // Glyph height of full-width characters. + glyphHeightFW = 8 + + fw1FirstByteStart = 0x81 + fw1FirstByteEnd = 0x9F + fw2FirstByteStart = 0xE0 + fw2FirstByteEnd = 0xEF + fwSecondByteStart = 0x40 + fwSecondByteEnd = 0x9F +) + +//go:embed assets/*.png +var fontFiles embed.FS + +// One glyph for half-width characters. +type GlyphHW uint32 + +// One glyph for full-width characters. +type GlyphFW uint64 + +type Font struct { + // Half-width glyphs. It is keyed by a raw character code. + glyphsHW *[256]GlyphHW + // Full-width glyphs. + glyphsFW1 *[31][189]GlyphFW + // Full-width glyphs. + glyphsFW2 *[16][189]GlyphFW +} + +type CharClass uint8 + +const ( + charClassHW = iota + charClassFW1 + charClassFW2 +) + +// Get character class. +func getCharClass(b byte) CharClass { + if fw1FirstByteStart <= b && b <= fw1FirstByteEnd { + return charClassFW1 + } else if fw2FirstByteStart <= b && b <= fw2FirstByteEnd { + return charClassFW2 + } else { + return charClassHW + } +} + +func glyphHWToglyphFW(gHW GlyphHW) GlyphFW { + gFW := GlyphFW(0) + for i := 0; i < bitsHW; i++ { + if gHW&(1<<i) != 0 { + j := i/4*8 + i%4 + gFW |= 1 << j + } + } + return gFW +} + +func utf8ToShiftJISReplacingUnsupported(in string) (string, error) { + e := encoding.ReplaceUnsupported(japanese.ShiftJIS.NewEncoder()) + return e.String(in) +} + +type Banner []string + +func NewBanner(lines []string) (Banner, error) { + b := make(Banner, len(lines)) + for i, line := range lines { + lineShiftJIS, err := utf8ToShiftJISReplacingUnsupported(line) + if err != nil { + return nil, err + } + b[i] = lineShiftJIS + } + return b, nil +} + +type Renderer struct { + scr tcell.Screen + squareWidth int + squareHeight int + bgStyle tcell.Style + fgStyle tcell.Style +} + +func NewRenderer(bgStyle, fgStyle tcell.Style) (*Renderer, error) { + scr, err := tcell.NewScreen() + if err != nil { + return nil, err + } + err = scr.Init() + if err != nil { + return nil, err + } + + r := &Renderer{scr, 0, 0, bgStyle, fgStyle} + return r, nil +} + +func (r *Renderer) ScreenSize() (int, int) { + return r.scr.Size() +} + +func (r *Renderer) SetSquareSize(w, h int) { + r.squareWidth = w + r.squareHeight = h +} + +func (r *Renderer) Fini() { + r.scr.Fini() +} + +func (r *Renderer) Show() { + r.scr.Show() +} + +func (r *Renderer) PollEvent() tcell.Event { + return r.scr.PollEvent() +} + +func (r *Renderer) Sync() { + r.scr.Sync() +} + +func (r *Renderer) ClearScreen() { + r.scr.SetStyle(r.bgStyle) + r.scr.Clear() +} + +func (r *Renderer) DrawSquare(sx, sy int) { + w, h := r.squareWidth, r.squareHeight + for dx := 0; dx < w; dx++ { + for dy := 0; dy < h; dy++ { + r.scr.SetContent(sx*w+dx, sy*h+dy, ' ', nil, r.fgStyle) + } + } +} + +func drawGlyph(r *Renderer, g GlyphFW, sx, sy int) { + for i := 0; i < bitsFW; i++ { + filled := g&(1<<i) != 0 + if !filled { + continue + } + dx := i % glyphWidthFW + dy := i / glyphWidthFW + r.DrawSquare(sx+dx, sy+dy) + } +} + +func calcGridWidth(s string) int { + w := 0 + for i := 0; i < len(s); i++ { + switch getCharClass(s[i]) { + case charClassHW: + w += 1 + case charClassFW1, charClassFW2: + i++ + w += 2 + } + } + + return w * glyphWidthHW +} + +func calcSquareSizeAndOffset(r *Renderer, banner Banner) (int, int, []int, int) { + scrW, scrH := r.ScreenSize() + + gridWidthMax := 0 + gridWidths := make([]int, len(banner)) + for i, line := range banner { + gridWidths[i] = calcGridWidth(line) + if gridWidthMax < gridWidths[i] { + gridWidthMax = gridWidths[i] + } + } + gridHeight := glyphHeightFW * len(banner) + + squareW := scrW / gridWidthMax + squareH := scrH / gridHeight + if squareW > squareH*8 { + squareW = squareH*8 + } + if squareH > squareW { + squareH = squareW + } + + xOffsets := make([]int, len(banner)) + for i, gridWidth := range gridWidths { + xOffsets[i] = (scrW/squareW - gridWidth) / 2 + } + yOffset := (scrH/squareH - gridHeight) / 2 + + return squareW, squareH, xOffsets, yOffset +} + +func drawOneLine(r *Renderer, s string, xOffset, yOffset int, font *Font) { + for i := 0; i < len(s); i++ { + b := s[i] + x := xOffset + i*glyphWidthHW + y := yOffset + var g GlyphFW + switch getCharClass(b) { + case charClassHW: + g = glyphHWToglyphFW(font.glyphsHW[b]) + case charClassFW1: + b2 := s[i+1] + g = font.glyphsFW1[b-fw1FirstByteStart][b2-fwSecondByteStart] + i++ + case charClassFW2: + b2 := s[i+1] + g = font.glyphsFW1[b-fw2FirstByteStart][b2-fwSecondByteStart] + i++ + } + drawGlyph(r, g, x, y) + } +} + +func drawBanner(r *Renderer, banner Banner, font *Font) { + r.ClearScreen() + + sw, sh, xOffsets, yOffset := calcSquareSizeAndOffset(r, banner) + r.SetSquareSize(sw, sh) + + for i, line := range banner { + drawOneLine(r, line, xOffsets[i], yOffset+i*glyphHeightFW, font) + } +} + +func parseGlyphsHW(filePath string) (*[256]GlyphHW, error) { + fp, err := fontFiles.Open(filePath) + if err != nil { + return nil, err + } + defer fp.Close() + + img, err := png.Decode(fp) + if err != nil { + return nil, err + } + + gs := [256]GlyphHW{} + for dy := 0; dy < 16; dy++ { + for dx := 0; dx < 16; dx++ { + glyph := GlyphHW(0) + for i := 0; i < bitsHW; i++ { + x := dx*glyphWidthHW + i%glyphWidthHW + y := dy*glyphHeightHW + i/glyphWidthHW + r, g, b, _ := img.At(x, y).RGBA() + if r == 0 && b == 0 && g == 0 { + glyph |= 1 << i + } + } + c := dy*16 + dx + gs[c] = glyph + } + } + return &gs, nil +} + +func parseGlyphsFW(filePath string) (*[31][189]GlyphFW, *[16][189]GlyphFW, error) { + fp, err := fontFiles.Open(filePath) + if err != nil { + return nil, nil, err + } + defer fp.Close() + + img, err := png.Decode(fp) + if err != nil { + return nil, nil, err + } + + gs1 := [31][189]GlyphFW{} + for dy := 0; dy < 62; dy++ { + for dx := 0; dx < 94; dx++ { + glyph := GlyphFW(0) + for i := 0; i < bitsFW; i++ { + x := dx*glyphWidthFW + i%glyphWidthFW + y := dy*glyphHeightFW + i/glyphWidthFW + r, g, b, _ := img.At(x, y).RGBA() + if r == 0 && b == 0 && g == 0 { + glyph |= 1 << i + } + } + c1 := dy / 2 + c2 := dx + (fwSecondByteEnd-fwSecondByteStart)*(dy%2) + gs1[c1][c2] = glyph + } + } + + yOffset := 31 * glyphHeightFW + gs2 := [16][189]GlyphFW{} + for dy := 0; dy < 16; dy++ { + for dx := 0; dx < 94; dx++ { + glyph := GlyphFW(0) + for i := 0; i < bitsFW; i++ { + x := dx*glyphWidthFW + i%glyphWidthFW + y := dy*glyphHeightFW + i/glyphWidthFW + yOffset + r, g, b, _ := img.At(x, y).RGBA() + if r == 0 && b == 0 && g == 0 { + glyph |= 1 << i + } + } + c1 := dy / 2 + c2 := dx + (fwSecondByteEnd-fwSecondByteStart)*(dy%2) + gs2[c1][c2] = glyph + } + } + + return &gs1, &gs2, nil +} + +func prepareFont(fileHW, fileFW string) (*Font, error) { + glyphsHW, err := parseGlyphsHW(fileHW) + if err != nil { + return nil, err + } + glyphsFW1, glyphsFW2, err := parseGlyphsFW(fileFW) + if err != nil { + return nil, err + } + return &Font{glyphsHW, glyphsFW1, glyphsFW2}, nil +} + +func main() { + if len(os.Args) <= 1 { + return + } + + font, err := prepareFont( + "assets/misaki_gothic_2nd_4x8.png", + "assets/misaki_mincho.png", + ) + if err != nil { + log.Fatalf("%+v", err) + } + + r, err := NewRenderer( + tcell.StyleDefault.Background(tcell.ColorReset).Foreground(tcell.ColorReset), + tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorOlive), + ) + if err != nil { + log.Fatalf("%+v", err) + } + defer r.Fini() + + banner, err := NewBanner(os.Args[1:]) + if err != nil { + log.Fatalf("%+v", err) + } + drawBanner(r, banner, font) + + for { + r.Show() + + ev := r.PollEvent() + switch ev := ev.(type) { + case *tcell.EventResize: + drawBanner(r, banner, font) + r.Sync() + case *tcell.EventKey: + if ev.Key() == tcell.KeyEscape || ev.Key() == tcell.KeyCtrlC || ev.Rune() == 'q' { + return + } + } + } +} diff --git a/screenshot.png b/screenshot.png Binary files differnew file mode 100644 index 0000000..c527879 --- /dev/null +++ b/screenshot.png |
