Skip to content

Instantly share code, notes, and snippets.

@Sohojoe
Last active October 1, 2021 03:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sohojoe/f760b119be511c3b97e0f496b4dc1e1c to your computer and use it in GitHub Desktop.
Save Sohojoe/f760b119be511c3b97e0f496b4dc1e1c to your computer and use it in GitHub Desktop.
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)
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
@Sohojoe
Copy link
Author

Sohojoe commented Oct 1, 2021

added documentation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment