-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMCBE.html
122 lines (117 loc) · 5.76 KB
/
MCBE.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<script async src="gas.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>ttf转mcpack</title>
<meta name="description" content="mc glyph generator">
<link rel="icon" type="image/svg+xml" href="icon.svg">
<link rel="apple-touch-icon" href="icon.png">
<meta name="theme-color" content="#214"/>
<link rel="stylesheet" href="s.css">
</head>
<body>
<style>
:root{tab-size:2;image-rendering:pixelated;}
#ta{width:100%;font-family:monospace;}
canvas{width:min(720px,100%);background:#0004 0 0/12.5% url("data:image/svg+xml,%3Csvg viewBox='0 0 2 2' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolygon points='0,0 1,0 1,2 2,2 2,1 0,1' fill='%238884'/%3E%3C/svg%3E");}
</style>
<h1>MCBE字体</h1>
<hr>
<label>字体文件: <input type="file" id="file" class="zab" accept=".ttf,.ttc,.otf,.otc,.woff,.woff2"></label>
<pre id="flog"></pre>
<textarea id="ta" class="zab" spellcheck="false">// 配置文件,默认即可
{
name:'font resource pack',
img:64,
font:'56px _your_loaded_font_file_ttf,sans-serif',// make smaller when too many magenta char
list:[-1,...Array(256).keys()].filter(i=>i<0xd8||0xf5<i),// xx<0 ? default8 : glyph_xx
threads:4,// If less than or equal to 0, the main thread is used.(higher browser compatibility)
preview:0x00
}</textarea>
<button id="btn" class="zab bgca">export</button>
<div id="elog"></div>
<canvas></canvas>
<ul>
<li>这个网站会通过浏览器调用CPU在本地运算,文件不会上传到,请放心使用</li>
</ul>
<script src="mcmf.js"></script>
<script type="module">
import TA from 'https://mcbeeringi.github.io/ta/ta.mjs';
import {zip,dl} from 'https://mcbeeringi.github.io/petit/zip.mjs';
const
d8=`ÀÁÂÈÊËÍÓÔÕÚßãõğİıŒœŞşŴŵžȇ§© !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αβΓπΣσμτΦΘΩδ∞∅∈∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ `,
ctx=document.querySelector('canvas').getContext('2d'),
cfgget=_=>{try{return Function(`return(${ta.value});`)()}catch(e){}},
cfgset=(ctx,cfg)=>(ctx.canvas.width=ctx.canvas.height=cfg.img*16,ctx.fillStyle='#fff',ctx.font=cfg.font),
draw=(ctx,p,dbg)=>(
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height),
[...Array(256)].forEach((a=ctx.canvas.width/16,i,s,m,h,b)=>(
s=p<0?d8[i]:String.fromCodePoint(p<<8|i),
m=ctx.measureText(s),
h=m.actualBoundingBoxAscent+(b=Math.max(m.fontBoundingBoxDescent||0,m.actualBoundingBoxDescent+1))+1,
a<h&&ctx.scale(1,a/h,dbg&&(dbg=ctx.fillStyle,ctx.fillStyle='#f0f')),
ctx.fillText(s,(i%16)*a+m.actualBoundingBoxLeft+1,((i/16|0)+1)*Math.max(h,a)-b,a-m.actualBoundingBoxLeft-1),
a<h&&ctx.scale(1,h/a,dbg&&(ctx.fillStyle=dbg))
))
),
i2p=i=>i<0?`font/default8.png`:`font/glyph_${i.toString(16).toUpperCase().padStart(2,0)}.png`,
flist=[],
fload=async(x,w=document,_)=>(w.fonts.add(await new FontFace(x.name,`url(${_=URL.createObjectURL(x)})`).load()),URL.revokeObjectURL(_)),
pcent=e=>Math.round(e.value/e.max*100),
main=async w=>(w=cfgget())&&(
w={cfg:w,prg:document.createElement('progress'),log:document.createElement('pre')},
w.prg.max=w.cfg.list.length,
w.log.textContent='please wait...',
elog.append(w.prg,w.log),
self.OffscreenCanvas&&0<w.cfg.threads?(
w.wurl=URL.createObjectURL(new Blob(['onmessage=m=>Object.getPrototypeOf(async _=>_).constructor("w",m.data.main)(m.data);'])),
w.files=(await Promise.all([...Array(w.cfg.threads)].map(async(x,i,a)=>(
x=new Worker(w.wurl),
await new Promise(f=>(
x.onmessage=f,
x.postMessage({flist,cfg:w.cfg,main:`
self.d8=${JSON.stringify(d8)};self.draw=${draw};self.i2p=${i2p};self.fload=${fload};await Promise.all(w.flist.map(x=>fload(x,self)));
(${cfgset})(self.ctx=new OffscreenCanvas(1,1).getContext('2d'),w.cfg);
onmessage=async m=>postMessage(await Promise.all(m.data.map(async x=>(draw(ctx,x),x={name:i2p(x)},postMessage(x),x.buffer=await ctx.canvas.convertToBlob(),x))));
postMessage(0);
`})
)),
w.prg.value=0,
await new Promise(f=>(
x.onmessage=m=>Array.isArray(m.data)?(f(m.data),x.terminate()):(w.prg.value=+w.prg.value+1,w.log.textContent=`${pcent(w.prg)}% ${m.data.name}`),
a=Math.ceil(w.cfg.list.length/a.length),x.postMessage(w.cfg.list.slice(a*i,a*(i+1)))
))
)))).flat(),
URL.revokeObjectURL(w.wurl)
):(
cfgset(ctx,w.cfg),
w.files=await Promise.all(w.cfg.list.map((x,i)=>new Promise(f=>setTimeout(async _=>(
draw(ctx,x),x={name:i2p(x)},w.prg.value=i+1,w.log.textContent=`${pcent(w.prg)}% ${x.name}`,
x.buffer=await new Promise(f=>ctx.canvas.toBlob(f)),f(x)
)))))
),
w.prg.removeAttribute('value'),w.log.textContent='please wait...',
w.files.push(
{name:'manifest.json',buffer:new Blob([mcmf({n:w.cfg.name,d:w.cfg.font})])},
{name:'pack_icon.png',buffer:await new Promise((f,r,x)=>(
cfgset(x=document.createElement('canvas').getContext('2d'),{...w.cfg,img:w.cfg.img/8}),
x.textBaseline='middle',x.textAlign='center',x.fillText('Aa',w.cfg.img,w.cfg.img),x.canvas.toBlob(f)
))}
),
w.log.textContent='packing...',
dl(w.zip={name:w.cfg.name+'.mcpack',buffer:await zip(w.files)}),
console.log(w),w.prg.remove(),w.log.remove()
);
TA.editor(ta);
ta.oninput=_=>(_=cfgget())&&(
cfgset(ctx,_),draw(ctx,_.preview,1));
(file.onchange=async _=>(
file.files[0]&&(_=new File([file.files[0]],'_'+file.files[0].name.replace(/\W/g,'_')),flist.push(_),await fload(_),ta.value=ta.value.replace(/_\w+/,_.name),flog.textContent=`loaded_fonts:${flist.map(x=>'\n\t'+x.name).join('')}`),
ta.oninput()
))();
btn.onclick=_=>main();
</script>
</body>
<html>