Created
May 13, 2020 00:17
-
-
Save jaburns/5b207c4d69de3ac25010cab23e71953d to your computer and use it in GitHub Desktop.
node.js code for embedded data in a png
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const testPng = fs.readFileSync('input.png'); | |
// ===== crc-32 ============================================== | |
// https://github.com/SheetJS/js-crc32/blob/master/crc32.js | |
function signed_crc_table() { | |
var c = 0, table = new Array(256); | |
for(var n =0; n != 256; ++n){ | |
c = n; | |
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); | |
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); | |
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); | |
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); | |
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); | |
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); | |
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); | |
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); | |
table[n] = c; | |
} | |
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table; | |
} | |
var T = signed_crc_table(); | |
function crc32_buf_8(buf) { | |
var C = -1, L = buf.length - 7; | |
for(var i = 0; i < L;) { | |
C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; | |
C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; | |
C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; | |
C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; | |
C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; | |
C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; | |
C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; | |
C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; | |
} | |
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; | |
return C ^ -1; | |
} | |
// =========================================================== | |
const readPNG = buff => | |
{ | |
let i = 8; | |
const chunks = []; | |
while( i < buff.length ) | |
{ | |
const len = buff.readUInt32BE(i); | |
i+= 4; | |
const type = buff.slice(i,i+4).toString('ascii'); | |
const typeAndData = buff.slice(i,i+4+len); | |
const data = buff.slice( i+4, i+4+len ); | |
i += 4 + len; | |
const crc = buff.readInt32BE(i); | |
i += 4; | |
const crcGen = crc32_buf_8( typeAndData ); | |
let textValue = null; | |
if( type === 'tEXt' ) | |
{ | |
const splitter = data.indexOf( 0 ); | |
textValue = { | |
key: data.slice( 0, splitter ).toString('ascii'), | |
value: data.slice( splitter+1, data.length ).toString('ascii'), | |
}; | |
} | |
chunks.push({ len, type, data, typeAndData, crc, crcGen, textValue }); | |
} | |
return chunks; | |
}; | |
// type Chunk = { text: string, data: Uint8Array } | |
const writePNG = chunks => | |
{ | |
let result = []; | |
result.push(Uint8Array.of( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a )); | |
chunks.forEach( chunk => | |
{ | |
const buff0 = Buffer.alloc( 4 ); | |
buff0.writeUInt32BE( chunk.data.length, 0 ); | |
const buff1 = Buffer.alloc( 4 + chunk.data.length ); | |
buff1.write( chunk.type, 0, 4, 'ascii' ); | |
chunk.data.copy( buff1, 4, 0, chunk.data.length ); | |
const buff2 = Buffer.alloc( 4 ); | |
buff2.writeInt32BE( crc32_buf_8( buff1 )); | |
result.push( buff0 ); | |
result.push( buff1 ); | |
result.push( buff2 ); | |
}); | |
return Buffer.concat(result); | |
}; | |
const buildTextChunk = ( key, value ) => | |
{ | |
const data = Buffer.alloc( key.length + value.length + 1 ); | |
data.write( key, 0, 'ascii' ); | |
data.writeUInt8( 0, key.length ); | |
data.write( value, key.length + 1, 'ascii' ); | |
return { type: 'tEXt', data }; | |
}; | |
const buildEndChunk = () => ({ type: 'IEND', data: Buffer.alloc( 0 ) }); | |
const inpng = readPNG( testPng ); | |
const outpng = writePNG( inpng | |
.filter( x => x.type !== 'tEXt' && x.type !== 'IEND' ) | |
.concat([ | |
buildTextChunk('custom::data', 'hello world!'), | |
buildEndChunk() | |
]) | |
); | |
console.log(inpng); | |
fs.writeFileSync( 'output.png', outpng ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment