[in progress] a color utility i'm making for my pixel art painting process
www.val.town/x/jennschiffer/pixelstats
1import * as path from "@std/path";
2import { Application, Router } from "@oak/oak";
3import { getPixels } from "@unpic/pixels";
4
5const app = new Application();
6
7/** FILES **/
8const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
9const publicDir = path.join(moduleDir, "public");
10
11function getPublicFile(...filePath: string[]): Promise < Uint8Array > {
12 return Deno.readFile(path.join(publicDir, ...filePath));
13}
14
15/** ROUTES **/
16const router = new Router();
17
18// index
19router.get("/", async (ctx, next) => {
20 ctx.response.body = await getPublicFile("index.html");
21 ctx.response.type = "text/html";
22 await next();
23});
24
25// process
26router.post("/process-pixels", async (ctx, next) => {
27 const file = (await ctx.request.body.formData()).get("image");
28
29 if (file instanceof File) {
30
31 try {
32 // create image from file uploaded
33 const uploadedFileBuffer = await file.arrayBuffer();
34 const { width, height, data } = await getPixels(uploadedFileBuffer);
35 const colors = getPixelColors(data);
36
37 const processed = JSON.stringify({
38 message: "success: pixels processed",
39 fileName: file.name,
40 fileSize: file.size,
41 fileType: file.type,
42 width,
43 height,
44 data,
45 colors,
46 });
47
48 ctx.response.status = 200;
49 ctx.response.body = { processed }
50
51 } catch (err) {
52 ctx.response.status = 400;
53 ctx.response.body = { message: 'Error: Failed to create getPixels' }
54 }
55 } else {
56 ctx.response.status = 400;
57 ctx.response.body = { message: 'Error: File not uploaded' }
58 }
59 await next();
60})
61
62// routes & static files
63app.use(router.routes());
64app.use(router.allowedMethods());
65app.use(async (context, next) => {
66 const root = `${Deno.cwd()}/public`
67 try {
68 await context.send({ root })
69 } catch {
70 next()
71 }
72})
73
74
75/** CONSOLE/LISTEN **/
76function printStartupMessage({ hostname, port, secure }: {
77 hostname: string;
78 port: number;
79 secure ? : boolean;
80}): void {
81 const address = new URL(
82 `http${secure ? "s" : ""}://${
83 hostname === "0.0.0.0" ? "localhost" : hostname
84 }:${port}/`,
85 ).href;
86 console.log(`Listening at ${address}`);
87}
88app.addEventListener("listen", printStartupMessage);
89await app.listen({ port: 8000 });
90
91
92/** HELPER FUNCTIONS */
93// generate pixel colors json from image buffer
94function getPixelColors(data: Uint8Array): object {
95 let i = 0;
96 const pixelsArray = [];
97
98 while (i < data.length) {
99 pixelsArray.push([data[i], data[i + 1], data[i + 2], data[i + 3]].join());
100 i = i + 4;
101 }
102
103 // eg. 2400 colors for a 60 x 40 image
104 const colorsDistribution = {};
105 for (const pixel of pixelsArray) {
106 if (colorsDistribution[pixel]) {
107 colorsDistribution[pixel] += 1;
108 } else {
109 colorsDistribution[pixel] = 1;
110 }
111 }
112
113 const colorsDistributionSorted = Object.fromEntries(
114 Object.entries(colorsDistribution).sort(([, a], [, b]) => b - a),
115 );
116
117 return { pixelsArray, colorsDistribution, colorsDistributionSorted };
118}