Node.js – Escribir y codificar un archivo PNG utilizando únicamente los módulos FS y ZLIB.
Estoy tratando de generar una imagen .png a partir de una cadena de color hexadecimal (#RRGGBB), sin utilizar módulos como pngjs o jimp.
La cadena en hexadecimal se ve así:
let colors = “ff000000ff000000ffff00ff00ffffffff00”;
Según este artículo, todos los archivos png deben comenzar con la firma ‘b’\x89PNG\r\n\x1a\n’ y tener 3 “chunks” (IHDR, IDAT e IEND), cada uno con la siguiente estructura:
(Data Length, Chunk Type, Chunk Data y CRC)
Y según las especificaciones de png, se comprime con deflate de zlib, por lo que he creado este código:
const fs = require(“fs”);
const zlib = require(“zlib”);
let colors = “ff000000ff000000ffff00ff00ffffffff00”;
let data = b'\x89PNG\r\n\x1a\n'0d00IHDR030002008200000002400IDAT${colors}0000IEND
;
zlib.deflateRaw(data, (err, buffer) =>{
fs.writeFile(“output.png”, buffer, (err)=>{if (err) throw err;});
});
Para una mejor legibilidad, los datos divididos se ven así:
b’\x89PNG\r\n\x1a\n’ // firma
0d00 // longitud de los datos del chunk (13)
IHDR // tipo de chunk
/* datos del chunk */
0300 // ancho de la imagen (3)
0200 // alto de la imagen (2)
8 // profundidad de bits (8)
2 // tipo de color (2)
0 // método de compresión (0)
0 // método de filtro (0)
0 // método de entrelazado (0)
0000 // CRC (?)
2400 // longitud de los datos del chunk (36)
IDAT // tipo de chunk
ff000000ff000000ffff00ff00ffffffff00 // datos del chunk (#RRGGBB)
0000 // CRC (?)
IEND
Lo que esperaba obtener como resultado era la siguiente imagen (en su tamaño de 3×2), pero todo lo que tengo es un archivo png aparentemente inválido que mi visor de imágenes no admite.
¿Es realmente posible escribir un archivo png válido de esta manera? Si es así, ¿cómo se hace?
davy.ai
Es posible crear un archivo PNG válido de esta manera, pero el código proporcionado tiene algunos errores que deben corregirse.
En primer lugar, las longitudes de datos y los valores CRC para los trozos IHDR e IDAT son incorrectos. Deben calcularse en función de la longitud real de los datos del trozo y del tipo de trozo, respectivamente.
En segundo lugar, los colores en los datos del trozo deben convertirse de una cadena hexadecimal a bytes. Una forma de hacer esto es utilizando un bucle for para dividir la cadena en subcadenas de 2 caracteres, y luego convertir cada subcadena en un byte utilizando
parseInt()
.Aquí está el código corregido:
En resumen, para crear un archivo PNG válido a partir de una cadena hexadecimal de colores sin usar módulos externos, debes:
Haciendo esto, deberías poder generar una imagen PNG válida.