[feat] new pngchunk encode/decoderr
This commit is contained in:
144
src/ts/pngChunk.ts
Normal file
144
src/ts/pngChunk.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { Buffer } from 'buffer';
|
||||
import crc32 from 'crc/crc32';
|
||||
import type { LocalWriter } from './storage/globalApi';
|
||||
|
||||
export const PngChunk = {
|
||||
read: (data:Uint8Array, chunkName:string[], arg:{checkCrc?:boolean} = {}) => {
|
||||
let pos = 8
|
||||
let chunks:{[key:string]:string} = {}
|
||||
while(pos < data.length){
|
||||
const len = data[pos] * 0x1000000 + data[pos+1] * 0x10000 + data[pos+2] * 0x100 + data[pos+3]
|
||||
const type = data.slice(pos+4,pos+8)
|
||||
const typeString = new TextDecoder().decode(type)
|
||||
console.log(typeString, len)
|
||||
if(arg.checkCrc){
|
||||
const crc = data[pos+8+len] * 0x1000000 + data[pos+9+len] * 0x10000 + data[pos+10+len] * 0x100 + data[pos+11+len]
|
||||
const crcCheck = crc32(data.slice(pos+4,pos+8+len))
|
||||
if(crc !== crcCheck){
|
||||
throw new Error('crc check failed')
|
||||
}
|
||||
}
|
||||
if(typeString === 'IEND'){
|
||||
break
|
||||
}
|
||||
if(typeString === 'tEXt'){
|
||||
const chunkData = data.slice(pos+8,pos+8+len)
|
||||
let key=''
|
||||
let value=''
|
||||
for(let i=0;i<10;i++){
|
||||
if(chunkData[i] === 0){
|
||||
key = new TextDecoder().decode(chunkData.slice(0,i))
|
||||
value = new TextDecoder().decode(chunkData.slice(i))
|
||||
break
|
||||
}
|
||||
}
|
||||
if(chunkName.includes(key)){
|
||||
chunks[key] = value
|
||||
}
|
||||
}
|
||||
pos += 12 + len
|
||||
}
|
||||
return chunks
|
||||
},
|
||||
|
||||
trim: (data:Uint8Array) => {
|
||||
let pos = 8
|
||||
let newData:Uint8Array[] = []
|
||||
while(pos < data.length){
|
||||
const len = data[pos] * 0x1000000 + data[pos+1] * 0x10000 + data[pos+2] * 0x100 + data[pos+3]
|
||||
const type = data.slice(pos+4,pos+8)
|
||||
const typeString = new TextDecoder().decode(type)
|
||||
if(typeString === 'IEND'){
|
||||
newData.push(data.slice(pos,pos+12+len))
|
||||
break
|
||||
}
|
||||
if(typeString === 'tEXt'){
|
||||
pos += 12 + len
|
||||
}
|
||||
else{
|
||||
newData.push(data.slice(pos,pos+12+len))
|
||||
pos += 12 + len
|
||||
}
|
||||
}
|
||||
newData.push(data.slice(pos))
|
||||
return Buffer.concat(newData)
|
||||
},
|
||||
|
||||
write: async (data:Uint8Array, chunks:{[key:string]:string}, options:{writer?:LocalWriter} = {}):Promise<void | Buffer> => {
|
||||
let pos = 8
|
||||
let newData:Uint8Array[] = []
|
||||
|
||||
async function pushData(data:Uint8Array){
|
||||
if(options.writer){
|
||||
await options.writer.write(data)
|
||||
}
|
||||
else{
|
||||
newData.push(data)
|
||||
}
|
||||
}
|
||||
|
||||
await pushData(data.slice(0,8))
|
||||
|
||||
while(pos < data.length){
|
||||
const len = data[pos] * 0x1000000 + data[pos+1] * 0x10000 + data[pos+2] * 0x100 + data[pos+3]
|
||||
const type = data.slice(pos+4,pos+8)
|
||||
const typeString = new TextDecoder().decode(type)
|
||||
if(typeString === 'IEND'){
|
||||
break
|
||||
}
|
||||
if(typeString === 'tEXt'){
|
||||
pos += 12 + len
|
||||
}
|
||||
else{
|
||||
await pushData(data.slice(pos,pos+12+len))
|
||||
pos += 12 + len
|
||||
}
|
||||
}
|
||||
for(const key in chunks){
|
||||
const keyData = new TextEncoder().encode(key)
|
||||
const value = Buffer.from(chunks[key])
|
||||
const lenNum = value.byteLength + keyData.byteLength + 1
|
||||
//idk, but uint32array is not working
|
||||
const length = new Uint8Array([
|
||||
lenNum / 0x1000000 % 0x100,
|
||||
lenNum / 0x10000 % 0x100,
|
||||
lenNum / 0x100 % 0x100,
|
||||
lenNum % 0x100
|
||||
])
|
||||
const type = new TextEncoder().encode('tEXt')
|
||||
await pushData(length)
|
||||
await pushData(type)
|
||||
await pushData(keyData)
|
||||
await pushData(new Uint8Array([0]))
|
||||
await pushData(value)
|
||||
const crc = crc32(Buffer.concat([type,keyData,new Uint8Array([0]),value]))
|
||||
await pushData(new Uint8Array([
|
||||
crc / 0x1000000 % 0x100,
|
||||
crc / 0x10000 % 0x100,
|
||||
crc / 0x100 % 0x100,
|
||||
crc % 0x100
|
||||
]))
|
||||
}
|
||||
//create IEND chunk
|
||||
{
|
||||
const length = new Uint8Array((new Uint32Array([0])).buffer)
|
||||
const type = new TextEncoder().encode('IEND')
|
||||
await pushData(length)
|
||||
await pushData(type)
|
||||
const crc = crc32(type)
|
||||
await pushData(new Uint8Array([
|
||||
crc / 0x1000000 % 0x100,
|
||||
crc / 0x10000 % 0x100,
|
||||
crc / 0x100 % 0x100,
|
||||
crc % 0x100
|
||||
]))
|
||||
}
|
||||
|
||||
if(options.writer){
|
||||
await options.writer.close()
|
||||
}
|
||||
else{
|
||||
return Buffer.concat(newData)
|
||||
}
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user