Skip to content

Commit

Permalink
/history.gif
Browse files Browse the repository at this point in the history
  • Loading branch information
Chetan Padia committed Oct 10, 2024
1 parent 80ef32d commit 509ef98
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 31 deletions.
2 changes: 1 addition & 1 deletion database/rules.bolt
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ type CurrentTimestamp extends Number {

createOnly(value) {
prior(value) == null && value != null
}
}
4 changes: 4 additions & 0 deletions firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
{
"source": "/image.png",
"function": "imagePng"
},
{
"source": "/history.gif",
"function": "historyGif"
}
],
"headers": [
Expand Down
2 changes: 2 additions & 0 deletions functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
},
"main": "dist/functions/src/index.js",
"dependencies": {
"canvas": "^2.11.2",
"firebase-admin": "^8.13.0",
"firebase-functions": "^3.21.0",
"modern-gif": "^2.0.3",
"pngjs": "^3.3.3"
},
"devDependencies": {
Expand Down
71 changes: 52 additions & 19 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import * as functions from 'firebase-functions';
import { PNG } from 'pngjs';
import { Canvas, Square } from '../../database/.types';
import { Color as PaletteColor, Palette } from './palette';
import * as functions from "firebase-functions";
import { PNG } from "pngjs";
import { Canvas, Square } from "../../database/.types";
import { Color as PaletteColor, Palette } from "./palette";

import * as admin from 'firebase-admin';
import * as admin from "firebase-admin";
import { encodeHistoryAsGif } from "./encodeGif";
admin.initializeApp();

const IMAGE_ID = 'the-one-and-only';
const IMAGE_ID = "the-one-and-only";
const database = admin.database();

function zeroPad(n: number|string, padding: number): string {
return ('0'.repeat(padding) + n).slice(-padding);
function zeroPad(n: number | string, padding: number): string {
return ("0".repeat(padding) + n).slice(-padding);
}

function colorIndexFrom(depth: Canvas['depth'], canvas: Canvas['canvas'], x: number, y: number): number|undefined {
function colorIndexFrom(
depth: Canvas["depth"],
canvas: Canvas["canvas"],
x: number,
y: number
): number | undefined {
const xPath = zeroPad(x.toString(2), depth);
const yPath = zeroPad(y.toString(2), depth);
let square: Square<any>|number|undefined = canvas;
for (let i=0; i<depth; i++) {
square = square !== undefined && square[xPath[i] + yPath[i]] || undefined;
let square: Square<any> | number | undefined = canvas;
for (let i = 0; i < depth; i++) {
square = (square !== undefined && square[xPath[i] + yPath[i]]) || undefined;
}
return square as number;
}
Expand All @@ -34,14 +40,14 @@ function setColor(png: PNG, x: number, y: number, color: PaletteColor) {
export const imagePng = functions.https.onRequest(async (request, response) => {
try {
const [depthSnapshot, canvasSnapshot] = await Promise.all([
database.ref('canvas').child(IMAGE_ID).child('depth').once('value'),
database.ref('canvas').child(IMAGE_ID).child('canvas').once('value'),
database.ref("canvas").child(IMAGE_ID).child("depth").once("value"),
database.ref("canvas").child(IMAGE_ID).child("canvas").once("value"),
]);
const depth = depthSnapshot.val() as Canvas['depth'];
const canvas = canvasSnapshot.val() as Canvas['canvas'];
const depth = depthSnapshot.val() as Canvas["depth"];
const canvas = canvasSnapshot.val() as Canvas["canvas"];

const size = Math.pow(2, depth);
const image = new PNG({width: size, height: size});
const image = new PNG({ width: size, height: size });
for (let y = 0; y < size; y++) {
for (let x = 0; x < size; x++) {
const colorIndex = colorIndexFrom(depth, canvas, x, y);
Expand All @@ -51,8 +57,35 @@ export const imagePng = functions.https.onRequest(async (request, response) => {
}
}
const packedImage = image.pack();
packedImage.pipe(response).type('image/png')
packedImage.pipe(response).type("image/png");
} catch (error) {
response.status(500).send(error)
response.status(500).send(error);
}
});

export const historyGif = functions.https.onRequest(
async (request, response) => {
try {
const [depthSnapshot, historySnapshot] = await Promise.all([
database.ref("canvas").child(IMAGE_ID).child("depth").once("value"),
database.ref("canvas").child(IMAGE_ID).child("history").once("value"),
]);
const depth = depthSnapshot.val() as Canvas["depth"];
const history = Object.values(
historySnapshot.val() as Canvas["history"]
).sort((a, b) => a.timestamp - b.timestamp);

const size = Math.pow(2, depth);
const imageData = await encodeHistoryAsGif(size, size, history, {
speed: 10000,
lastFrameDelay: 5000,
minFrameDelay: 1,
maxFrameDelay: 500,
scale: 1,
});
response.type("image/gif").end(imageData, "binary");
} catch (error) {
response.status(500).send(error);
}
}
);
1 change: 0 additions & 1 deletion functions/src/palette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export const Palette: Color[] = [
{r: 0x22, g: 0x22, b: 0x22, a: 0xFF },
{r: 0xFF, g: 0xA7, b: 0xD1, a: 0xFF },
{r: 0xE5, g: 0x00, b: 0x00, a: 0xFF },

{r: 0xE5, g: 0x95, b: 0x00, a: 0xFF },
{r: 0xA0, g: 0x6A, b: 0x42, a: 0xFF },
{r: 0xE5, g: 0xD9, b: 0x00, a: 0xFF },
Expand Down
Loading

0 comments on commit 509ef98

Please sign in to comment.