Last active
October 1, 2021 03:53
-
-
Save Sohojoe/f760b119be511c3b97e0f496b4dc1e1c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const base91 = require('node-base91') | |
const sharp = require('sharp'); | |
function short_rgb_to_rgba_buffer(pixels) { | |
var width = 16, height = 16; | |
// var frameData = Buffer.from(rgba) | |
var i = 0; | |
var frameData = Buffer.alloc(width * height * 4); | |
var frameData_idx = 0; | |
var rgba = []; | |
do { | |
short_r = pixels[i++]; | |
short_g = pixels[i++]; | |
short_b = pixels[i++]; | |
// r = short_r * 16 + short_r; | |
// g = short_g * 16 + short_g; | |
// b = short_b * 16 + short_b; | |
r = parseInt(""+short_r+short_r, 16); | |
g = parseInt(""+short_g+short_g, 16); | |
b = parseInt(""+short_b+short_b, 16); | |
frameData[frameData_idx++] = r; | |
frameData[frameData_idx++] = g; | |
frameData[frameData_idx++] = b; | |
frameData[frameData_idx++] = 0xff; // alpha, not used | |
} while (i < (16 * 16 * 3)); | |
return frameData; | |
} | |
function hexToRgb(hex) { | |
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") | |
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; | |
hex = hex.replace(shorthandRegex, function(m, r, g, b) { | |
return r + r + g + g + b + b; | |
}); | |
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); | |
return result ? { | |
r: parseInt(result[1], 16), | |
g: parseInt(result[2], 16), | |
b: parseInt(result[3], 16) | |
} : null; | |
} | |
function rgbToShortHex(rgb) { | |
var hexR = Math.round(rgb.r / 17).toString(16); | |
var hexG = Math.round(rgb.g / 17).toString(16); | |
var hexB = Math.round(rgb.b / 17).toString(16); | |
return "" + hexR + "" + hexG + "" + hexB; | |
} | |
function componentToHex(c) { | |
var hex = c.toString(16); | |
return hex.length == 1 ? "0" + hex : hex; | |
} | |
function rgbToHex(r, g, b) { | |
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); | |
} | |
function getShortHexColorCode(code) { | |
var rgb = hexToRgb(code); | |
return rgbToShortHex(rgb); | |
} | |
function rgb_to_short_rgb(pixels) { | |
var str = ''; | |
var i = 0; | |
for (var x = 0; x <= 15; x++) { | |
for (var y = 0; y <= 15; y++) { | |
var r = pixels[i++]; | |
var g = pixels[i++]; | |
var b = pixels[i++]; | |
str = str + getShortHexColorCode(rgbToHex(r,g,b)); | |
// str = str + rgbToHex(r,g,b); | |
} | |
} | |
return str; | |
} | |
async function joe_encode_async(pixels) { | |
var frameData = short_rgb_to_rgba_buffer(pixels); | |
const imageData = await sharp(frameData, { | |
raw: { | |
width: 16, | |
height: 16, | |
channels: 4 | |
} | |
}).toBuffer(); | |
var { data, info } = await sharp(frameData, { | |
raw: { | |
width: 16, | |
height: 16, | |
channels: 4 | |
} | |
// }).jpeg({ | |
// // quality: 100, | |
// mozjpeg: true, | |
// }).heif({ | |
// lossless: true, | |
// // compression: 'hevc', | |
// speed: 0 | |
// }).avif({ | |
// lossless: true, | |
// // compression: 'hevc', | |
// speed: 0 | |
// }) | |
}) | |
.removeAlpha() | |
.webp({ | |
lossless: true, | |
// nearLossless: true, | |
// smartSubsample: true, | |
}) | |
.toBuffer({ resolveWithObject: true }); | |
// console.log("--done--"); | |
return base91.encode(data); | |
} | |
async function joe_decode_async(str) { | |
decoded = base91.decode(str); | |
var { data, info } = await sharp(decoded) | |
// .removeAlpha() | |
.raw() | |
.toBuffer({ resolveWithObject: true }); | |
var crap_format = rgb_to_short_rgb(data) | |
// console.log("--info:" + info + " len:" + data.length); | |
// console.log("--info:" + info + " len:" + crap_format.length); | |
return (crap_format.toString()); | |
} | |
const star = ['390390390390390390390000000390390390390390390390', '390390390390390390000ff0ff0000390390390390390390', '390390390390390390000ff0ff0000390390390390390390', '390390390390390000ff0ff0ff0ff0000390390390390390', '000000000000000000ff0ff0ff0ff0000000000000000000', '000ff0ff0ff0ff0ff0ff0ff0ff0ff0ff0ff0ff0ff0ff0000', '390000ff0ff0ff0ff0000ff0ff0000ff0ff0ff0ff0000390', '390390000ff0ff0ff0000ff0ff0000ff0ff0ff0000390390', '390390390000ff0ff0000ff0ff0000ff0ff0000390390390', '390390390000ff0ff0ff0ff0ff0ff0ff0ff0000390390390', '390390000ff0ff0ff0ff0ff0ff0ff0ff0ff0ff0000390390', '390390000ff0ff0ff0ff0ff0ff0ff0ff0ff0ff0000390390', '390000ff0ff0ff0ff0ff0000000ff0ff0ff0ff0ff0000390', '390000ff0ff0ff0000000390390000000ff0ff0ff0000390', '000ff0ff0000000390390390390390390000000ff0ff0000', '000000000390390390390390390390390390390000000000'].join(''); | |
const zero = [ | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
'000000000000000000000000000000000000000000000000', | |
].join('') | |
const pinky = [ | |
'000000000000000211e8bf9cf9cf9ce8b211000000000000', | |
'000000000111d8be9bf9cf9cf9cf9cf9ce9bd8b111000000', | |
'000000111d8bf9cf9cf9cf9cf9cf9cf9cf9cf9cd8b101000', | |
'000101d9bffffeff9cf9cf9cfacffffeff9cf9ce9b100000', | |
'000111edeeffffffeff9cf9ceefeefffffeff9ce8b111000', | |
'00010100e11feefffff9ce8c11f11feefffff9cf9cd8b101', | |
'111d8b11f11feefffff9ce8c10f11feefffff9cf9ce9b101', | |
'101e8be9ceeffeff9cf9cf9ce9ceeffeffacf9cf9ce8b101', | |
'101e8bf9cfacf9cf9cf9cf9cf9cf9cf9cf9cf9cf9ce8b101', | |
'101e8bf9cf9cf9cf9cf9cf9cf9cf9cf9cf9cf9cf9ce8b101', | |
'101e8bf9cf9cf9cf9cf9cf9cf9cf9cf9cf9cf9cf9ce8b101', | |
'101e8bf9cf9cf9cf9cf9cf9cf9cf9cf9cf9cf9cf9ce8b101', | |
'101e8bf9cf9cf9cf9cf9cf9cf9cf9cf9cf9cf9cf9ce8b101', | |
'101e9bf9cf9cf9ce9bf9cf9cf9cf9ce9bf9cf9cf9ce9b101', | |
'101d8bf9cf9cd8b212d8bf9cf9cd8b212d8bf9cf9cd8b101', | |
'000111e9be9b111000111e9be9b111000111e9be9b111000', | |
].join(''); | |
const inky = [ | |
'0000000000000001217ec7fd7fd7fd7ec121000000000000', | |
'0000000001116dc7ed7fd7fd7fd7fd7fd7ed6dc111000000', | |
'0000000117dc7fe7fd7fd7fd7fd7fd7fd7fd7fd6dc011000', | |
'0000117dcfffeff8fd7fd7fd8fdeffeff8fd7fd7ed011000', | |
'000111deefeffffeff7fd7fddefeeffffeff7fd6ec111000', | |
'00001110e11feeffff7fd6ed11f11feeffff7fd7fd6dc011', | |
'0116dc01f11feefeff7fd6ed01f11feefeff7fd7fd7ed011', | |
'0116ed7edeefeff8fd7fd7fd7edeefeff8fd7fd7fd6ec011', | |
'0116ec7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd6ec011', | |
'0116ec7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd6ec011', | |
'0116ec7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd6ec011', | |
'0116ec7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd6ec011', | |
'0116ec7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd7fd6ec011', | |
'0117ed7fd7fd7fd7ec7fd7fd7fd7fd7ec7fd7fd7fd7ed011', | |
'0116dc7fd7fd6dc1226dc7fd7fd6dc1226dc7fd7fd6dc011', | |
'0001117ed7ed1110001117ed7ed1110001117ed7ed111000', | |
].join(''); | |
(async () => { | |
var encoded = await joe_encode_async(star); | |
console.log("--star len:" + encoded.length + " " + encoded ); | |
var decoded = await joe_decode_async(encoded); | |
console.log(star === decoded); | |
// console.log(star); | |
// console.log(decoded); | |
encoded = await joe_encode_async(zero); | |
console.log("--zero len:" + encoded.length + " " + encoded ); | |
decoded = await joe_decode_async(encoded); | |
console.log(zero === decoded); | |
encoded = await joe_encode_async(inky); | |
console.log("--inky len:" + encoded.length + " " + encoded ); | |
decoded = await joe_decode_async(encoded); | |
console.log(inky === decoded); | |
// console.log(inky); | |
// console.log(decoded); | |
encoded = await joe_encode_async(pinky); | |
console.log("--pinky len:" + encoded.length + " " + encoded ); | |
decoded = await joe_decode_async(encoded); | |
console.log(pinky === decoded); | |
// console.log(pinky); | |
// console.log(decoded); | |
// console.log("pinky:" + pinky.length); | |
})(); | |
// var encoded = joe_encode(ss); | |
// console.log(encoded[0]); | |
// console.log(joe_encode(ss)); | |
// console.log(joe_encode(ss).length) | |
console.log("--end sync code "); | |
// console.log(web_safe_colors) | |
// console.log(web_safe_colors.length) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submission for the PixelMap compression competition | |
Internally this uses a true lossless algorthem as uses 8 bit colors. | |
In using PixelMap I found it frustrating that it looses color. | |
So my motivation was to find a solution that can keep the orginal intent of the art. | |
In this submission I convert between the 4bit format so that it uses the reference 'star' | |
I think there maybe a bug in your 4bit conversion algo as it makes no sense that you divide by 17. | |
requires: | |
npm install sharp | |
npm install node-base91 | |
expected output: | |
node app.js | |
--end sync code | |
--star len:128 UaRz$(AAv(*wpBQPT?gwKAAAn`+>BAuAmBi@1u:%rBfZ0:_ewR4F%H8c$Z#J8RqK0P;T3sP:qy{H,^O;U6xWB54FVwq$}s5l4;zZ~l=[a=`a1ue+dLTEmw}xMmTji8{A | |
true | |
--zero len:41 UaRzrSAAv(*wpBQPT?>+BAAAn`+>BAQ"AYWLAY[~B | |
true | |
--inky len:231 UaRz*kBAv(*wpBQPT?K]UAAAn`+>BACEk+Vz@u3)T4$X[l3L4ZK}DfOVhhluvTI$&d9}$h`.,Lx[$tB"*t(n+^Gu2tTa>|]vkX1BIBB%=MIz>)5%#E{*3}BrxEAY@9PlctM,e}v+3`$+$P12zJY=Y:y_k17UNs*gfe=gjC=M49[Zo5YUKY|b$cmy=Kot]FnS0FNm]q$/l@MnoI55D0Tz,?W9q1Ykfu#M@#cInAA | |
true | |
--pinky len:233 UaRzPmBAv(*wpBQPT?2OVAAAn`+>BA=Dm+lz"O_.lOr0mPKGrJm+lz"OVFW[P$2L@EwmS{0nykq({EPW4F~~M5aiLRtB#FzlsreK@u>>[(6(dM,mlCxBDD;VX~>;>:|L{sZb7N&=AWH%:joIb@<f4A<)CUcmgYd1(Du6u_MGaz~OY0X,gw{{ON;]u}1u)igBmFOev.%D,P^G)m>+:r6}}TV[c3*SW!2YqH}%TenAA | |
true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
added documentation