1+ <!DOCTYPE html>
2+ < html >
3+
4+ < head >
5+ < title > ASCII Unicode Conversion Maps Creator</ title >
6+ < script type ="importmap ">
7+ {
8+ "imports" : {
9+ "vue" : "http://unpkg.com/vue@3/dist/vue.esm-browser.js" ,
10+ "opentype" : "http://unpkg.com/opentype.js/dist/opentype.module.js"
11+ }
12+ }
13+ </ script >
14+ < style >
15+ header {
16+ display : flex;
17+ flex-direction : row;
18+ flex-wrap : wrap;
19+ padding : 4em ;
20+ }
21+
22+ # glyfs {
23+ display : flex;
24+ flex-direction : row;
25+ flex-wrap : wrap;
26+ gap : 1em ;
27+ }
28+
29+ .glyf {
30+ border : 1px solid black;
31+ min-width : 40px ;
32+ }
33+
34+ canvas {
35+ width : 8em ;
36+ height : 4em ;
37+ }
38+
39+ .glyfHeader {
40+ background-color : blue;
41+ color : white;
42+ }
43+
44+ .glyfContent {
45+ display : flex;
46+ flex-direction : row;
47+ }
48+
49+ .glyfContentRight {
50+ display : flex;
51+ flex-direction : column;
52+ }
53+
54+ .serial {
55+ background-color : lightgreen;
56+ color : black;
57+ }
58+
59+ .mapinput {
60+ height : 1em ;
61+ font-size : 50px ;
62+ }
63+ </ style >
64+ </ head >
65+
66+ < body >
67+ < div id ="app ">
68+ < h1 > ASCII Unicode Conversion Map Editor</ h1 >
69+ < header >
70+ < div >
71+ < label for ="read "> Choose Font</ label >
72+ < input type ="file " @change ="onChangeFont " id ="read " />
73+ </ div >
74+ < div >
75+ < label for ="read "> Choose Map</ label > < input type ="file " @change ="onChangeMap " id ="map " />
76+ </ div >
77+ < div >
78+ < textarea id ="mapcontents " v-model ="mapValue "> </ textarea >
79+ < button @click ="copyMap "> Copy Map</ button >
80+ </ div >
81+ </ header >
82+ < div id ="glyfs ">
83+ < div class ="glyf " v-for ="(char, index) in asciiChars " :key ="char ">
84+ < div class ="glyfHeader "> < span class ="serial "> {{ ASCII_START + index }}</ span > {{ char }}</ div >
85+ < div class ="glyfContent ">
86+ < canvas :ref ="(el) => storeGlyfCanvas(char, el) "> </ canvas >
87+ < div class ="glyfContentRight ">
88+ < input v-model ="mappings[char] " size ="1 " class ="mapinput "
89+ @change ="e => changeMapping(char, e.target.value) " />
90+ < span > {{ getCharCode(mappings[char]) }}</ span >
91+ </ div >
92+ </ div >
93+ </ div >
94+ </ div >
95+ </ div >
96+
97+ < script type ="module ">
98+ import { createApp , reactive , ref } from 'vue'
99+ import { parse } from 'opentype'
100+ const ASCII_START = 33 ;
101+ const ASCII_END = 256 ;
102+ createApp ( {
103+ setup ( ) {
104+ const asciiChars = [ ] ;
105+ for ( let i = ASCII_START ; i < ASCII_END ; i ++ ) {
106+ asciiChars . push ( String . fromCharCode ( i ) ) ;
107+ }
108+ const glyfCanvases = reactive ( { } )
109+ const storeGlyfCanvas = ( char , el ) => glyfCanvases [ char ] = el ;
110+ const mapValue = ref ( "" ) ;
111+ const mappings = reactive ( { } ) ;
112+ return {
113+ asciiChars,
114+ glyfCanvases,
115+ storeGlyfCanvas,
116+ ASCII_START ,
117+ mapValue,
118+ mappings,
119+ }
120+ } ,
121+ methods : {
122+ async copyMap ( ) {
123+ try {
124+ await navigator . clipboard . writeText ( this . mapValue ) ;
125+ alert ( 'Copied map to clipboard. Consider contributing to community at https://github.com/libindic/unicode-conversion-maps' ) ;
126+ } catch ( $e ) {
127+ alert ( 'Cannot copy. Manually copy from text area ' ) ;
128+ }
129+ } ,
130+ changeMapping ( char , value ) {
131+ this . mapValue = this . mapValue
132+ . split ( '\n' )
133+ . map ( line => {
134+ if ( line . startsWith ( '#' ) ) return line ;
135+ let [ lhs , rhs ] = line . split ( '=' ) . map ( w => w . trim ( ) )
136+ if ( lhs === char ) {
137+ return `${ lhs } =${ value } `
138+ } else {
139+ return line
140+ }
141+ } )
142+ . join ( '\n' )
143+ } ,
144+ getCharCode ( text ) {
145+ if ( ! text ) return "" ;
146+ return text . split ( '' )
147+ . map ( k =>
148+ `U${ k
149+ . charCodeAt ( 0 )
150+ . toString ( 16 )
151+ . toUpperCase ( )
152+ . padStart ( 4 , '0' )
153+ } `)
154+ . join ( '+' )
155+ } ,
156+ readMapFile ( text ) {
157+ const lines = text . split ( '\n' ) ;
158+ lines . forEach ( line => {
159+ if ( line . startsWith ( '#' ) ) return ;
160+ let [ lhs , rhs ] = line . split ( '=' ) . map ( w => w . trim ( ) )
161+ this . mappings [ lhs ] = rhs ;
162+ } )
163+ } ,
164+ onChangeMap ( e ) {
165+ const file = e . target . files [ 0 ] ;
166+ const reader = new FileReader ( ) ;
167+ reader . onload = ( e ) => {
168+ this . mapValue = e . target . result ;
169+ this . readMapFile ( e . target . result ) ;
170+ }
171+ reader . onerror = ( e ) => {
172+ console . log ( "err" , e ) ;
173+ } ;
174+ reader . readAsText ( file ) ;
175+ } ,
176+ renderGlyph ( char , glyph ) {
177+ const canvas = this . glyfCanvases [ char ]
178+ glyph . draw ( canvas . getContext ( "2d" ) , 50 , 75 , 100 ) ;
179+ } ,
180+ onChangeFont ( e ) {
181+ const file = e . target . files [ 0 ] ;
182+ const reader = new FileReader ( ) ;
183+ reader . onload = ( e ) => {
184+ const font = parse ( e . target . result ) ;
185+ const scale = 1000 / font . unitsPerEm ;
186+ const glyphDict = { }
187+ Object . entries ( font . glyphs . glyphs ) . forEach ( ( [ index , glyph ] ) => {
188+ glyphDict [ glyph . unicode ] = glyph ;
189+ } ) ;
190+ console . log ( this . asciiChars ) ;
191+ for ( let i = ASCII_START ; i < ASCII_END ; i ++ ) {
192+
193+ const char = this . asciiChars [ i - ASCII_START ] ;
194+ if ( i in glyphDict ) {
195+ this . renderGlyph ( char , glyphDict [ i ] )
196+ }
197+ }
198+ } ;
199+ reader . onerror = ( e ) => {
200+ console . log ( "err" , e ) ;
201+ } ;
202+ reader . readAsArrayBuffer ( file ) ;
203+ } ,
204+ } ,
205+ } ) . mount ( '#app' )
206+ </ script >
207+
208+ </ body >
209+
210+ </ html >
0 commit comments