-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbmpgen.html
More file actions
70 lines (70 loc) · 5.07 KB
/
Copy pathbmpgen.html
File metadata and controls
70 lines (70 loc) · 5.07 KB
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
---
layout: page
title: BMP generator
permalink: /bmpgen
---
<style>html {font-family: sans-serif}
.dotline {text-decoration:underline dotted}</style>
<textarea placeholder="paste your thing here" id="textinput" name="john"></textarea><br />
<label>or upload: <input type=file id="fileinput" name="george"/></label><br />
<button onclick="try {gen('text')} catch (e) {lyk('generation failure: ',e)}">generate from text</button>
<button onclick="try {gen('file')} catch (e) {lyk('generation failure: ',e)}">generate from file</button><br />
<a id="aoutput" name="rachel" download>output will go here</a><br />
<ul> options:
<li><label>dimensions ([W,L])<input id="par1" name="larry" /></label></li>
<li><label>resolution ([W,L])<input id="par2" name="jerry" /></label></li>
<li><label>8-bit color array ([B,G,R,X] repeated 1-256 times)<input id="par3" name="garry" /></label></li>
<li><label>force 8 bits<input type="checkbox" id="force8" name="joseph" /></label></li>
<li><label for="rawmode" title="classic functionality - treats input as raw data rather than rgb data"><span class="dotline">raw mode</span></label>
<input type="checkbox" checked id="rawmode" name="maria" /></li>
</ul>
<script>// baby
const lyk = (m,e) => {window.alert(m+e.message); throw e}
async function genfull(file, dims = null, res = [2835,2835], cca = null, f8 = false, raw = false) {
// once upon a time, there was a boy
const byte = ((base) => new Uint8Array(base.buffer))
const feet = ((baby) => new Uint8Array([baby,baby>>8,baby>>16,baby>>24])) // unhappy birthday to you
const bury = ((king) => new Uint8Array([king,king>>8])) // royal work of art
if (file.size > 0xFFFFFFFF) {throw new RangeError("too much data")}
if (file.size > 0xFFFFFAFF) {console.warn("this file is especially large. successful conversion cannot be guaranteed.")}
else if (file.size > 0x7FFFFFFF) {console.warn("this file is very large. conversion may not work in certain environments.")}
let bytes = new Uint8Array(await file.arrayBuffer()); if (!raw) {bytes.reverse()}
let isz = bytes.byteLength/* no way in theyll im naming it is */; let bd
switch (0) {
case f8&&isz%3: bd=3;break
case f8&&isz%2: bd=2;break
default: bd = 1; if (cca?.length) {var c = new Uint8Array(cca)} else {var c = new Uint8Array(1024); for (let i = 0; i < 256; i++) {c.set([i,i,i,0],4*i)}}}
try {let d = [...c]}
catch {var c = new Uint8Array(0)}
function getdivs(k) {const res = []; for (let i = 2; i <= Math.sqrt(k); i++) {if (k%i==0) {res.push(i)}}; return res}
//function tohalf(a) {const res = []; for (let i = 0; i < 2; i++) {res.push(a.slice(i,Math.ceil(a.length/2)))}; return res}
if (dims?.at(0) && dims?.at(1) && dims?.every(x => typeof x == 'number')) {var dim = dims.slice(0,2)}
else {const ks = isz/bd; const hd = getdivs(ks).map(x=>ks/x)/*.reduce((a,v) => a*v,1)*/; var dim = [hd.at(-1),ks/hd.at(-1)]}
const k=(bd==3?12:4); const bpr = k-bd*dim[0]%k;
const p = new Uint8Array(bpr); const cc = c.byteLength
isz += bpr*dim[1]; const o = 54+cc; const fs = isz+o;
if (fs > 0xFFFFFFFF) {console.log(fs); throw new RangeError("file would be too large")}
const Head1 = new Uint8Array([66,77,...feet(fs),0,0,0,0,...feet(o)])
const Head2 = new Uint8Array([40,0,0,0,...feet(dim[0]),...feet(dim[1]),1,0,...bury(bd*8),0,0,0,0,...feet(isz),...feet(res[0]),...feet(res[1]),...feet(cc/4),0,0,0,0])
// should mention dimensions are/were defined semi-arbitrarily due to operating from raw rgb
const full = new Uint8Array(fs); console.log(Head1,Head2,bytes)
full.set(Head1,0); full.set(Head2,14);
full.set(c,54)
for (let i = o, j = 0, k=0,row = new Array(dim[0]),rrow; k<dim[1]; i+=dim[0]+bpr,j+=dim[0],k++)
{rrow = bytes.slice(j,j+dim[0]); for (let z = 0; z < dim[0]; z+=bd) {row[z/bd] = Array.from(rrow.slice(z,z+bd))};
full.set(new Uint8Array(raw ? row.flat() : row.reverse().flat()),i); full.set(p,dim[0]+i)}
// i'm so tired of trying so hard and not getting it right
return full}
function gen(method) {
if (method == 'text') {var ok = new File([document.getElementById('textinput').value],"johnresult.txt")}
if (method == 'file') {var ok = document.getElementById('fileinput').files[0]}
const pars = []; try {for (let i = 1,x; i <= 3; i++) {x = document.getElementById(`par${i}`).value; pars.push(x.length ? JSON.parse(x) : undefined)}}
catch (e) {window.alert("error in param parsing: "+e.message); throw e}
const chkcheck = (box) => document.getElementById(box).checked
if (pars[2] != null && [pars[2].length%4,pars[2].length-3,1025-pars[2].length].some(x => x<=0)) {throw new SyntaxError('invalid color table')}
const outer = document.getElementById('aoutput')
try {genfull(ok,...pars,!chkcheck('force8'),chkcheck('rawmode')).then(fdata => outer.href = URL.createObjectURL(new Blob([fdata],{type:"image/bmp"}))).catch(e => console.error("something went issue",e))}
catch (e) {window.alert("an error occured: "+e.message); throw e}
Object.assign(outer,{download: ok.name.split(".").slice(0,-1).join(".").concat(".bmp"), innerHTML: "download output"})
window.alert(`file ready for download. the output quality correlates to the input quality.`)}
</script>