Skip to content

Instantly share code, notes, and snippets.

@mollerse
Last active November 29, 2019 15:14
Show Gist options
  • Save mollerse/a64218593a12809adb9d3814adf63e58 to your computer and use it in GitHub Desktop.
Save mollerse/a64218593a12809adb9d3814adf63e58 to your computer and use it in GitHub Desktop.

Gratulerer med dagen, Marco!

Her er kildekoden til kortet ditt. For å kjøre den:

git clone https://gist.github.com/a64218593a12809adb9d3814adf63e58.git
cd a64218593a12809adb9d3814adf63e58
npm i get-pixels ndarray ndarray-fill ndarray-scratch zeros
npx budo marco.js

Så gå til localhost:9966 i nettlesern

const getPixels = require("get-pixels");
const pool = require("ndarray-scratch");
const fill = require("ndarray-fill");
const zeros = require("zeros");
const RISOCOLORS = [
{ name: "BLACK", color: [0, 0, 0] },
{ name: "BURGUNDY", color: [145, 78, 114] },
{ name: "BLUE", color: [0, 120, 191] },
{ name: "GREEN", color: [0, 169, 92] },
{ name: "MEDIUMBLUE", color: [50, 85, 164] },
{ name: "BRIGHTRED", color: [241, 80, 96] },
{ name: "RISOFEDERALBLUE", color: [61, 85, 136] },
{ name: "PURPLE", color: [118, 91, 167] },
{ name: "TEAL", color: [0, 131, 138] },
{ name: "FLATGOLD", color: [187, 139, 65] },
{ name: "HUNTERGREEN", color: [64, 112, 96] },
{ name: "RED", color: [255, 102, 94] },
{ name: "BROWN", color: [146, 95, 82] },
{ name: "YELLOW", color: [255, 232, 0] },
{ name: "MARINERED", color: [210, 81, 94] },
{ name: "ORANGE", color: [255, 108, 47] },
{ name: "FLUORESCENTPINK", color: [255, 72, 176] },
{ name: "LIGHTGRAY", color: [136, 137, 138] },
{ name: "METALLICGOLD", color: [172, 147, 110] },
{ name: "CRIMSON", color: [228, 93, 80] },
{ name: "FLUORESCENTORANGE", color: [255, 116, 119] },
{ name: "CORNFLOWER", color: [98, 168, 229] },
{ name: "SKYBLUE", color: [73, 130, 207] },
{ name: "SEABLUE", color: [0, 116, 162] },
{ name: "LAKE", color: [35, 91, 168] },
{ name: "INDIGO", color: [72, 77, 122] },
{ name: "MIDNIGHT", color: [67, 80, 96] },
{ name: "MIST", color: [213, 228, 192] },
{ name: "GRANITE", color: [165, 170, 168] },
{ name: "CHARCOAL", color: [112, 116, 124] },
{ name: "SMOKYTEAL", color: [95, 130, 137] },
{ name: "STEEL", color: [55, 94, 119] },
{ name: "SLATE", color: [94, 105, 94] },
{ name: "TURQUOISE", color: [0, 170, 147] },
{ name: "EMERALD", color: [25, 151, 93] },
{ name: "GRASS", color: [57, 126, 88] },
{ name: "FOREST", color: [81, 110, 90] },
{ name: "SPRUCE", color: [74, 99, 93] },
{ name: "MOSS", color: [104, 114, 77] },
{ name: "SEAFOAM", color: [98, 194, 177] },
{ name: "KELLYGREEN", color: [103, 179, 70] },
{ name: "LIGHTTEAL", color: [0, 157, 165] },
{ name: "IVY", color: [22, 155, 98] },
{ name: "PINE", color: [35, 126, 116] },
{ name: "LAGOON", color: [47, 97, 101] },
{ name: "VIOLET", color: [157, 122, 210] },
{ name: "ORCHID", color: [170, 96, 191] },
{ name: "PLUM", color: [132, 89, 145] },
{ name: "RAISIN", color: [119, 93, 122] },
{ name: "GRAPE", color: [108, 93, 128] },
{ name: "SCARLET", color: [246, 80, 88] },
{ name: "TOMATO", color: [210, 81, 94] },
{ name: "CRANBERRY", color: [209, 81, 122] },
{ name: "MAROON", color: [158, 76, 110] },
{ name: "RASPBERRYRED", color: [209, 81, 122] },
{ name: "BRICK", color: [167, 81, 84] },
{ name: "LIGHTLIME", color: [227, 237, 85] },
{ name: "SUNFLOWER", color: [255, 181, 17] },
{ name: "MELON", color: [255, 174, 59] },
{ name: "APRICOT", color: [246, 160, 77] },
{ name: "PAPRIKA", color: [238, 127, 75] },
{ name: "PUMPKIN", color: [255, 111, 76] },
{ name: "BRIGHTOLIVEGREEN", color: [180, 159, 41] },
{ name: "BRIGHTGOLD", color: [186, 128, 50] },
{ name: "COPPER", color: [189, 100, 57] },
{ name: "MAHOGANY", color: [142, 89, 90] },
{ name: "BISQUE", color: [242, 205, 207] },
{ name: "BUBBLEGUM", color: [249, 132, 202] },
{ name: "LIGHTMAUVE", color: [230, 181, 201] },
{ name: "DARKMAUVE", color: [189, 140, 166] },
{ name: "WINE", color: [145, 78, 114] },
{ name: "GRAY", color: [146, 141, 136] },
{ name: "CORAL", color: [255, 142, 145] },
{ name: "WHITE", color: [255, 255, 255] },
{ name: "AQUA", color: [94, 200, 229] },
{ name: "MINT", color: [130, 216, 213] },
{ name: "CLEARMEDIUM", color: [242, 242, 242] },
{ name: "FLUORESCENTYELLOW", color: [255, 233, 22] },
{ name: "FLUORESCENTRED", color: [255, 76, 101] },
{ name: "FLUORESCENTGREEN", color: [68, 214, 44] }
];
function normalize(min, max, v) {
return (v - min) / (max - min);
}
function random2(u, l) {
return l + (u - l) * Math.random();
}
function random2i(u, l) {
return random2(u, l) | 0;
}
function bin(v) {
if (v <= 0.25) {
return 0.25;
} else if (v <= 0.5) {
return 0.5;
} else if (v <= 0.75) {
return 0.75;
} else if (v <= 1.0) {
return 1.0;
}
}
function getChannel(pixels, channel) {
let singleChannel;
switch (channel) {
case "R":
singleChannel = pixels.pick(null, null, 0);
break;
case "G":
singleChannel = pixels.pick(null, null, 1);
break;
case "B":
singleChannel = pixels.pick(null, null, 2);
break;
case "A":
singleChannel = pixels.pick(null, null, 3);
break;
}
return singleChannel;
}
function atkinsonDither(pixels, w, h) {
console.log("ATKINSON");
for (let i = 0; i < w; i++) {
for (let j = 0; j < h; j++) {
let currentPixel = pixels.get(i, j);
let newPixel = currentPixel < 129 ? 0 : 255;
let err = Math.floor((currentPixel - newPixel) / 8);
pixels.set(i, j, newPixel);
pixels.set(i + 1, j, pixels.get(i + 1, j) + err);
pixels.set(i + 2, j, pixels.get(i + 2, j) + err);
pixels.set(i - 1, j + 1, pixels.get(i - 1, j + 1) + err);
pixels.set(i, j + 1, pixels.get(i, j + 1) + err);
pixels.set(i + 1, j + 1, pixels.get(i + 1, j + 1) + err);
pixels.set(i, j + 2, pixels.get(i, j + 2) + err);
}
}
return pixels;
}
function floydSteinbergDither(pixels, w, h) {
console.log("FLOYD");
for (let i = 0; i < w; i++) {
for (let j = 0; j < h; j++) {
let currentPixel = pixels.get(i, j);
let newPixel = currentPixel < 129 ? 0 : 255;
let err = Math.floor((currentPixel - newPixel) / 16);
pixels.set(i, j, newPixel);
pixels.set(i + 1, j, pixels.get(i + 1, j) + 7 * err);
pixels.set(i - 1, j + 1, pixels.get(i - 1, j + 1) + 3 * err);
pixels.set(i, j + 1, pixels.get(i, j + 1) + 5 * err);
pixels.set(i + 1, j + 1, pixels.get(i + 1, j + 1) + err);
}
}
return pixels;
}
function basicDither(pixels, w, h) {
console.log("BASIC");
for (let i = 0; i < w; i++) {
for (let j = 0; j < h; j++) {
let currentPixel = pixels.get(i, j);
let newPixel = currentPixel < 129 ? 0 : 255;
pixels.set(i, j, newPixel);
}
}
return pixels;
}
function bayerDither(pixels, w, h) {
console.log("BAYER");
const BAYER_4X4_MAP = [
[15, 135, 45, 165],
[195, 75, 225, 105],
[60, 180, 30, 150],
[240, 120, 210, 90]
];
for (let i = 0; i < w; i++) {
for (let j = 0; j < h; j++) {
let currentPixel = pixels.get(i, j);
let mod = Math.floor((currentPixel + BAYER_4X4_MAP[i % 4][j % 4]) / 2);
let newPixel = mod < 129 ? 0 : 255;
pixels.set(i, j, newPixel);
}
}
return pixels;
}
function dither(pixels, type) {
let [w, h] = pixels.shape;
switch (type) {
case "FLOYD":
return floydSteinbergDither(pixels, w, h);
case "ATKINSON":
return atkinsonDither(pixels, w, h);
case "BAYER":
return bayerDither(pixels, w, h);
default:
return basicDither(pixels, w, h);
}
}
function color(base, alpha, invert) {
let [r, g, b] = RISOCOLORS.find(({ name }) => name === base).color;
let v = invert ? 1 - normalize(0, 255, alpha) : normalize(0, 255, alpha);
return `rgba(${r}, ${g}, ${b}, ${bin(v)})`;
}
function drawLayer(
ctx,
w,
h,
layerPixels,
c,
invert = false,
[xshift, yshift] = [0, 0]
) {
let cc = c.replace(/\s/g, "").toUpperCase();
ctx.save();
ctx.translate(xshift * w, yshift * h);
for (let i = 0; i < w; i++) {
for (let j = 0; j < h; j++) {
ctx.fillStyle = color(cc, layerPixels.get(i, j), invert);
ctx.fillRect(i, j, 1, 1);
}
}
ctx.restore();
}
function drawText(ctx, w, h, text) {
let original = ctx.globalCompositeOperation;
ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = "black";
ctx.font = `bold ${0.125 * w}px arial`;
ctx.fillText(text, 0.065 * w, 0.95 * h);
ctx.globalCompositeOperation = original;
}
function drawImage(ctx, w, h, quadrant = [0, 0], layers = []) {
ctx.save();
ctx.translate(quadrant[0] * w, quadrant[1] * h);
layers.forEach(l => l());
ctx.restore();
}
function run(img) {
let w = img.shape[0];
let h = img.shape[1];
let atkinson = dither(getChannel(pool.clone(img), "R"), "ATKINSON");
let floyd = dither(getChannel(pool.clone(img), "R"), "FLOYD");
let bayer = dither(getChannel(pool.clone(img), "R"), "BAYER");
let basic = dither(getChannel(pool.clone(img), "R"), "BASIC");
let flat = zeros([img.shape[0], img.shape[1]], img.dtype);
fill(flat, () => 255);
let canvas = document.createElement("canvas");
canvas.setAttribute("width", w * 2 * 2);
canvas.setAttribute("height", h * 3 * 2);
let ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
let draw = drawImage.bind(null, ctx, w, h);
let layer = drawLayer.bind(null, ctx, w, h);
let text = drawText.bind(null, ctx, w, h);
ctx.scale(2, 2);
ctx.globalCompositeOperation = "overlay";
draw(
[0, 0],
[
() => layer(bayer, "BLUE", true),
() => text("GRATULERER"),
() =>
layer(atkinson, "RED", true, [
random2(-0.01, 0.01),
random2(-0.01, 0.01)
])
]
);
draw(
[1, 0],
[
() => layer(bayer, "FLUORESCENTGREEN", true),
() => text("GRATULERER"),
() =>
layer(atkinson, "BURGUNDY", false, [
random2(-0.01, 0.01),
random2(-0.01, 0.01)
])
]
);
ctx.globalCompositeOperation = "screen";
draw(
[0, 1],
[
() => layer(flat, "BLACK", false),
() => layer(atkinson, "FLUORESCENTRED", true),
() => text("GRATULERER"),
() => layer(basic, "FLUORESCENTRED", true)
]
);
ctx.globalCompositeOperation = "overlay";
draw(
[1, 1],
[
() => layer(basic, "Wine", true, [0.025, 0.025]),
() => text("GRATULERER"),
() => layer(bayer, "Bright Olive Green", true)
]
);
draw(
[1, 2],
[
() => layer(flat, "mint", false),
() => text("GRATULERER"),
() => layer(basic, "Fluorescent Yellow", true)
]
);
draw(
[0, 2],
[
() => layer(bayer, "Slate", true),
() => text("GRATULERER"),
() => layer(atkinson, "Orchid", true, [-0.025, -0.025])
]
);
}
getPixels("src-compressed.jpg", function(err, img) {
run(img);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment