1.delete crc32.js delete png-metadata.js
Signed-off-by: zhoulisheng <635547767@qq.com>
This commit is contained in:
parent
bdc7156b27
commit
ca22bad4c4
6
OAT.xml
6
OAT.xml
|
@ -6,15 +6,13 @@
|
|||
<filteritem type="filename" name="hvigorfile.js" desc="hvigor构建脚本,DevEco Studio自动生成,不手动修改"/>
|
||||
<filteritem type="filename" name="*.json5" desc="hvigor配置文件,DevEco Studio自动生成,不手动修改"/>
|
||||
<filteritem type="filepath" name="imageknife/src/main/ets/components/imageknife/pngj/UPNG.js" desc="使用开源库UPNG,使用其默认版权头,无需修改"/>
|
||||
<filteritem type="filepath" name="imageknife/src/main/ets/components/imageknife/pngj/crc32.js" desc="使用开源库crc-32,使用其默认版权头,无需修改"/>
|
||||
<filteritem type="filepath" name="imageknife/src/main/ets/components/imageknife/pngj/png-metadata.js" desc="使用开源https://dev.exiv2.org/projects/exiv2/wiki/The_Metadata_in_PNG_files,使用其默认版权头,无需修改"/>
|
||||
|
||||
</filefilter>
|
||||
<filefilter name="defaultPolicyFilter" desc="Filters for compatibility,license header policies">
|
||||
<filteritem type="filename" name="hvigorfile.js" desc="hvigor构建脚本,DevEco Studio自动生成,不手动修改"/>
|
||||
<filteritem type="filename" name="*.json5" desc="hvigor配置文件,DevEco Studio自动生成,不手动修改"/>
|
||||
<filteritem type="filepath" name="imageknife/src/main/ets/components/imageknife/pngj/UPNG.js" desc="使用开源库UPNG,使用其默认版权头,无需修改"/>
|
||||
<filteritem type="filepath" name="imageknife/src/main/ets/components/imageknife/pngj/crc32.js" desc="使用开源库crc-32,使用其默认版权头,无需修改"/>
|
||||
<filteritem type="filepath" name="imageknife/src/main/ets/components/imageknife/pngj/png-metadata.js" desc="使用开源https://dev.exiv2.org/projects/exiv2/wiki/The_Metadata_in_PNG_files,使用其默认版权头,无需修改"/>
|
||||
|
||||
</filefilter>
|
||||
<filefilter name="defaultPolicyFilter" desc="Filters for copyright header policies">
|
||||
</filefilter>
|
||||
|
|
|
@ -14,16 +14,6 @@
|
|||
*/
|
||||
import router from '@system.router';
|
||||
import { Pngj } from '@ohos/imageknife'
|
||||
import {
|
||||
RESOLUTION_UNITS,
|
||||
insertMetadata,
|
||||
readMetadata,
|
||||
writeMetadata,
|
||||
textEncode,
|
||||
textDecode,
|
||||
extractChunks,
|
||||
encodeChunks
|
||||
} from '@ohos/imageknife'
|
||||
import resourceManager from '@ohos.resourceManager';
|
||||
import { FileUtils } from '@ohos/imageknife'
|
||||
import featureability from '@ohos.ability.featureAbility'
|
||||
|
@ -165,38 +155,6 @@ struct PngjTestCasePage {
|
|||
}.width('100%')
|
||||
.height(60).backgroundColor(Color.Pink)
|
||||
|
||||
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
Button('测试readMetadata')
|
||||
.onClick(() => {
|
||||
globalThis.ImageKnife.getImageKnifeContext()
|
||||
.resourceManagergetMedia($r('app.media.pngSample').id)
|
||||
.then(data => {
|
||||
let arrayBuffer = this.typedArrayToBuffer(data);
|
||||
let metadata = readMetadata(arrayBuffer);
|
||||
console.log("readMetadata metadata=" + JSON.stringify(metadata))
|
||||
this.hint5 = JSON.stringify(metadata);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('测试readMetadata err=' + err)
|
||||
})
|
||||
}).margin({ top: 5, left: 10 })
|
||||
Button('测试writeMetadata')
|
||||
.onClick(() => {
|
||||
globalThis.ImageKnife.getImageKnifeContext()
|
||||
.resourceManagergetMedia($r('app.media.pngSample').id)
|
||||
.then(data => {
|
||||
let arrayBuffer = this.typedArrayToBuffer(data);
|
||||
// let pngBuffer = writeMetadata(arrayBuffer);
|
||||
// console.log("writeMetadata metadata="+JSON.stringify(metadata))
|
||||
// this.hint5 = JSON.stringify(metadata);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('测试writeMetadata err=' + err)
|
||||
})
|
||||
}).margin({ top: 5, left: 10 })
|
||||
}.width('100%')
|
||||
.height(60).backgroundColor(Color.Pink)
|
||||
|
||||
Text(this.hint1)
|
||||
.width('100%')
|
||||
.height(120)
|
||||
|
|
|
@ -83,9 +83,6 @@ export * from './src/main/ets/components/imageknife/pngj/Pngj'
|
|||
export {handler} from './src/main/ets/components/imageknife/pngj/PngWork'
|
||||
export * from './src/main/ets/components/imageknife/pngj/UPNG'
|
||||
|
||||
export {
|
||||
RESOLUTION_UNITS, insertMetadata, readMetadata, writeMetadata, textEncode, textDecode, extractChunks, encodeChunks
|
||||
} from './src/main/ets/components/imageknife/pngj/png-metadata'
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported CRC32 */
|
||||
export var Crc32;
|
||||
(function(factory){
|
||||
/*jshint ignore:start */
|
||||
/*eslint-disable */
|
||||
|
||||
factory(Crc32 = {});
|
||||
|
||||
/*eslint-enable */
|
||||
/*jshint ignore:end */
|
||||
}(function (CRC32) {
|
||||
CRC32.version = '1.2.0';
|
||||
/* see perf/crc32table.js */
|
||||
/*global Int32Array */
|
||||
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_bstr(bstr, seed) {
|
||||
var C = seed ^ -1, L = bstr.length - 1;
|
||||
for (var i = 0; i < L; ) {
|
||||
C = (C >>> 8) ^ T[(C ^ bstr.charCodeAt(i++))&0xFF];
|
||||
C = (C >>> 8) ^ T[(C ^ bstr.charCodeAt(i++))&0xFF];
|
||||
}
|
||||
if (i === L) C = (C >>> 8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf(buf, seed) {
|
||||
if (buf.length > 10000) return crc32_buf_8(buf, seed);
|
||||
var C = seed ^ -1, L = buf.length - 3;
|
||||
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];
|
||||
}
|
||||
while (i < L + 3) C = (C >>> 8) ^ T[(C ^ buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf_8(buf, seed) {
|
||||
var C = seed ^ -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;
|
||||
}
|
||||
|
||||
function crc32_str(str, seed) {
|
||||
var C = seed ^ -1;
|
||||
for (var i = 0, L = str.length, c, d; i < L; ) {
|
||||
c = str.charCodeAt(i++);
|
||||
if (c < 0x80) {
|
||||
C = (C >>> 8) ^ T[(C ^ c)&0xFF];
|
||||
} else if (c < 0x800) {
|
||||
C = (C >>> 8) ^ T[(C ^ (192 | ((c >> 6) & 31)))&0xFF];
|
||||
C = (C >>> 8) ^ T[(C ^ (128 | (c & 63)))&0xFF];
|
||||
} else if (c >= 0xD800 && c < 0xE000) {
|
||||
c = (c & 1023) + 64;
|
||||
d = str.charCodeAt(i++) & 1023;
|
||||
C = (C >>> 8) ^ T[(C ^ (240 | ((c >> 8) & 7)))&0xFF];
|
||||
C = (C >>> 8) ^ T[(C ^ (128 | ((c >> 2) & 63)))&0xFF];
|
||||
C = (C >>> 8) ^ T[(C ^ (128 | ((d >> 6) & 15) | ((c & 3) << 4)))&0xFF];
|
||||
C = (C >>> 8) ^ T[(C ^ (128 | (d & 63)))&0xFF];
|
||||
} else {
|
||||
C = (C >>> 8) ^ T[(C ^ (224 | ((c >> 12) & 15)))&0xFF];
|
||||
C = (C >>> 8) ^ T[(C ^ (128 | ((c >> 6) & 63)))&0xFF];
|
||||
C = (C >>> 8) ^ T[(C ^ (128 | (c & 63)))&0xFF];
|
||||
}
|
||||
}
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
CRC32.table = T;
|
||||
// $FlowIgnore
|
||||
CRC32.bstr = crc32_bstr;
|
||||
// $FlowIgnore
|
||||
CRC32.buf = crc32_buf;
|
||||
// $FlowIgnore
|
||||
CRC32.str = crc32_str;
|
||||
}));
|
|
@ -1,423 +0,0 @@
|
|||
/**
|
||||
* library to read and write PNG Metadata
|
||||
*
|
||||
* References:
|
||||
* w3 PNG Chunks specification: https://www.w3.org/TR/PNG-Chunks.html
|
||||
* The Metadata in PNG files: https://dev.exiv2.org/projects/exiv2/wiki/The_Metadata_in_PNG_files
|
||||
*/
|
||||
|
||||
import { Crc32 } from './crc32'
|
||||
|
||||
|
||||
// Used for fast-ish conversion between uint8s and uint32s/int32s.
|
||||
// Also required in order to remain agnostic for both Node Buffers and
|
||||
// Uint8Arrays.
|
||||
let uint8 = new Uint8Array(4)
|
||||
let int32 = new Int32Array(uint8.buffer)
|
||||
let uint32 = new Uint32Array(uint8.buffer)
|
||||
|
||||
export const RESOLUTION_UNITS = { UNDEFINED: 0, METERS: 1, INCHES: 2 };
|
||||
|
||||
/**
|
||||
* https://github.com/aheckmann/sliced
|
||||
* An Array.prototype.slice.call(arguments) alternative
|
||||
* @param {Object} args something with a length
|
||||
* @param {Number} slice
|
||||
* @param {Number} sliceEnd
|
||||
* @api public
|
||||
*/
|
||||
function sliced(args, slice, sliceEnd) {
|
||||
var ret = [];
|
||||
var len = args.length;
|
||||
|
||||
if (0 === len) return ret;
|
||||
|
||||
var start = slice < 0
|
||||
? Math.max(0, slice + len)
|
||||
: slice || 0;
|
||||
|
||||
if (sliceEnd !== undefined) {
|
||||
len = sliceEnd < 0
|
||||
? sliceEnd + len
|
||||
: sliceEnd
|
||||
}
|
||||
|
||||
while (len-- > start) {
|
||||
ret[len - start] = args[len];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/hughsk/png-chunk-text
|
||||
* Returns a chunk object containing the metadata for a given key and value:
|
||||
* @param keyword
|
||||
* @param content
|
||||
* @param chunkName
|
||||
* @returns {{data: Uint8Array, name: 'tEXt'}}
|
||||
*/
|
||||
export function textEncode(keyword, content, chunkName = 'tEXt') {
|
||||
keyword = String(keyword)
|
||||
content = String(content)
|
||||
|
||||
if (content.length && (!/^[\x00-\xFF]+$/.test(keyword) || !/^[\x00-\xFF]+$/.test(content))) {
|
||||
throw new Error('Only Latin-1 characters are permitted in PNG tEXt chunks. You might want to consider base64 encoding and/or zEXt compression')
|
||||
}
|
||||
|
||||
if (keyword.length >= 80) {
|
||||
throw new Error('Keyword "' + keyword + '" is longer than the 79-character limit imposed by the PNG specification')
|
||||
}
|
||||
|
||||
let totalSize = keyword.length + content.length + 1
|
||||
let output = new Uint8Array(totalSize)
|
||||
let idx = 0
|
||||
let code
|
||||
|
||||
for (let i = 0; i < keyword.length; i++) {
|
||||
if (!(code = keyword.charCodeAt(i))) {
|
||||
throw new Error('0x00 character is not permitted in tEXt keywords')
|
||||
}
|
||||
|
||||
output[idx++] = code
|
||||
}
|
||||
|
||||
output[idx++] = 0
|
||||
|
||||
for (let j = 0; j < content.length; j++) {
|
||||
if (!(code = content.charCodeAt(j))) {
|
||||
throw new Error('0x00 character is not permitted in tEXt content')
|
||||
}
|
||||
|
||||
output[idx++] = code
|
||||
}
|
||||
|
||||
return {
|
||||
name: chunkName,
|
||||
data: output
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/hughsk/png-chunk-text
|
||||
* Reads a Uint8Array or Node.js Buffer instance containing a tEXt PNG chunk's data and returns its keyword/text:
|
||||
* @param data
|
||||
* @returns {{text: string, keyword: string}}
|
||||
*/
|
||||
export function textDecode(data) {
|
||||
if (data.data && data.name) {
|
||||
data = data.data
|
||||
}
|
||||
|
||||
let naming = true
|
||||
let text = ''
|
||||
let name = ''
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let code = data[i]
|
||||
|
||||
if (naming) {
|
||||
if (code) {
|
||||
name += String.fromCharCode(code)
|
||||
} else {
|
||||
naming = false
|
||||
}
|
||||
} else {
|
||||
if (code) {
|
||||
text += String.fromCharCode(code)
|
||||
} else {
|
||||
throw new Error('Invalid NULL character found. 0x00 character is not permitted in tEXt content')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
keyword: name,
|
||||
text: text
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/hughsk/png-chunks-extract
|
||||
* Extract the data chunks from a PNG file.
|
||||
* Useful for reading the metadata of a PNG image, or as the base of a more complete PNG parser.
|
||||
* Takes the raw image file data as a Uint8Array or Node.js Buffer, and returns an array of chunks. Each chunk has a name and data buffer:
|
||||
* @param data {Uint8Array}
|
||||
* @returns {[{name: String, data: Uint8Array}]}
|
||||
*/
|
||||
export function extractChunks(data) {
|
||||
if (data[0] !== 0x89) throw new Error('Invalid .png file header')
|
||||
if (data[1] !== 0x50) throw new Error('Invalid .png file header')
|
||||
if (data[2] !== 0x4E) throw new Error('Invalid .png file header')
|
||||
if (data[3] !== 0x47) throw new Error('Invalid .png file header')
|
||||
if (data[4] !== 0x0D) throw new Error('Invalid .png file header: possibly caused by DOS-Unix line ending conversion?')
|
||||
if (data[5] !== 0x0A) throw new Error('Invalid .png file header: possibly caused by DOS-Unix line ending conversion?')
|
||||
if (data[6] !== 0x1A) throw new Error('Invalid .png file header')
|
||||
if (data[7] !== 0x0A) throw new Error('Invalid .png file header: possibly caused by DOS-Unix line ending conversion?')
|
||||
|
||||
let ended = false
|
||||
let chunks = []
|
||||
let idx = 8
|
||||
|
||||
while (idx < data.length) {
|
||||
// Read the length of the current chunk,
|
||||
// which is stored as a Uint32.
|
||||
uint8[3] = data[idx++]
|
||||
uint8[2] = data[idx++]
|
||||
uint8[1] = data[idx++]
|
||||
uint8[0] = data[idx++]
|
||||
|
||||
// Chunk includes name/type for CRC check (see below).
|
||||
let length = uint32[0] + 4
|
||||
let chunk = new Uint8Array(length)
|
||||
chunk[0] = data[idx++]
|
||||
chunk[1] = data[idx++]
|
||||
chunk[2] = data[idx++]
|
||||
chunk[3] = data[idx++]
|
||||
|
||||
// Get the name in ASCII for identification.
|
||||
let name = (
|
||||
String.fromCharCode(chunk[0]) +
|
||||
String.fromCharCode(chunk[1]) +
|
||||
String.fromCharCode(chunk[2]) +
|
||||
String.fromCharCode(chunk[3])
|
||||
)
|
||||
|
||||
// The IHDR header MUST come first.
|
||||
if (!chunks.length && name !== 'IHDR') {
|
||||
throw new Error('IHDR header missing')
|
||||
}
|
||||
|
||||
// The IEND header marks the end of the file,
|
||||
// so on discovering it break out of the loop.
|
||||
if (name === 'IEND') {
|
||||
ended = true
|
||||
chunks.push({
|
||||
name: name,
|
||||
data: new Uint8Array(0)
|
||||
})
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
// Read the contents of the chunk out of the main buffer.
|
||||
for (let i = 4; i < length; i++) {
|
||||
chunk[i] = data[idx++]
|
||||
}
|
||||
|
||||
// Read out the CRC value for comparison.
|
||||
// It's stored as an Int32.
|
||||
uint8[3] = data[idx++]
|
||||
uint8[2] = data[idx++]
|
||||
uint8[1] = data[idx++]
|
||||
uint8[0] = data[idx++]
|
||||
|
||||
let crcActual = int32[0]
|
||||
let crcExpect = Crc32.buf(chunk)
|
||||
if (crcExpect !== crcActual) {
|
||||
throw new Error(
|
||||
'CRC values for ' + name + ' header do not match, PNG file is likely corrupted'
|
||||
)
|
||||
}
|
||||
|
||||
// The chunk data is now copied to remove the 4 preceding
|
||||
// bytes used for the chunk name/type.
|
||||
let chunkData = new Uint8Array(chunk.buffer.slice(4))
|
||||
|
||||
chunks.push({
|
||||
name: name,
|
||||
data: chunkData
|
||||
})
|
||||
}
|
||||
|
||||
if (!ended) {
|
||||
throw new Error('.png file ended prematurely: no IEND header was found')
|
||||
}
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/hughsk/png-chunks-encode
|
||||
* Return a fresh PNG buffer given a set of PNG chunks. Useful in combination with png-chunks-encode to easily modify or add to the data of a PNG file.
|
||||
* Takes an array of chunks, each with a name and data:
|
||||
* @param chunks {[{name: String, data: Uint8Array}]}
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
export function encodeChunks(chunks) {
|
||||
let totalSize = 8
|
||||
let idx = totalSize
|
||||
let i
|
||||
|
||||
for (i = 0; i < chunks.length; i++) {
|
||||
totalSize += chunks[i].data.length
|
||||
totalSize += 12
|
||||
}
|
||||
|
||||
let output = new Uint8Array(totalSize)
|
||||
|
||||
output[0] = 0x89
|
||||
output[1] = 0x50
|
||||
output[2] = 0x4E
|
||||
output[3] = 0x47
|
||||
output[4] = 0x0D
|
||||
output[5] = 0x0A
|
||||
output[6] = 0x1A
|
||||
output[7] = 0x0A
|
||||
|
||||
for (i = 0; i < chunks.length; i++) {
|
||||
let chunk = chunks[i]
|
||||
let name = chunk.name
|
||||
let data = chunk.data
|
||||
let size = data.length
|
||||
let nameChars = [
|
||||
name.charCodeAt(0),
|
||||
name.charCodeAt(1),
|
||||
name.charCodeAt(2),
|
||||
name.charCodeAt(3)
|
||||
]
|
||||
|
||||
uint32[0] = size
|
||||
output[idx++] = uint8[3]
|
||||
output[idx++] = uint8[2]
|
||||
output[idx++] = uint8[1]
|
||||
output[idx++] = uint8[0]
|
||||
|
||||
output[idx++] = nameChars[0]
|
||||
output[idx++] = nameChars[1]
|
||||
output[idx++] = nameChars[2]
|
||||
output[idx++] = nameChars[3]
|
||||
|
||||
for (let j = 0; j < size; ) {
|
||||
output[idx++] = data[j++]
|
||||
}
|
||||
|
||||
let crcCheck = nameChars.concat(sliced(data, undefined, undefined));
|
||||
int32[0] = Crc32.buf(crcCheck)
|
||||
output[idx++] = uint8[3]
|
||||
output[idx++] = uint8[2]
|
||||
output[idx++] = uint8[1]
|
||||
output[idx++] = uint8[0]
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
/**
|
||||
* read 4 bytes number from UInt8Array.
|
||||
* @param uint8array
|
||||
* @param offset
|
||||
* @returns {number}
|
||||
*/
|
||||
function readUint32(uint8array, offset) {
|
||||
let byte1, byte2, byte3, byte4;
|
||||
byte1 = uint8array[offset++];
|
||||
byte2 = uint8array[offset++];
|
||||
byte3 = uint8array[offset++];
|
||||
byte4 = uint8array[offset];
|
||||
return 0 | (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
|
||||
}
|
||||
|
||||
/**
|
||||
* write 4 bytes number to UInt8Array.
|
||||
* @param uint8array
|
||||
* @param num
|
||||
* @param offset
|
||||
*/
|
||||
function writeUInt32(uint8array, num, offset) {
|
||||
uint8array[offset] = (num & 0xff000000) >> 24;
|
||||
uint8array[offset + 1] = (num & 0x00ff0000) >> 16;
|
||||
uint8array[offset + 2] = (num & 0x0000ff00) >> 8;
|
||||
uint8array[offset + 3] = (num & 0x000000ff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object with PNG metadata. only tEXt and pHYs chunks are parsed
|
||||
* @param buffer {Buffer}
|
||||
* @returns {{tEXt: {keyword: value}, pHYs: {x: number, y: number, units: RESOLUTION_UNITS}, [string]: true}}
|
||||
*/
|
||||
export function readMetadata(buffer) {
|
||||
let result = {};
|
||||
const chunks = extractChunks(buffer);
|
||||
chunks.forEach(chunk => {
|
||||
switch (chunk.name) {
|
||||
case 'tEXt':
|
||||
if (!result['tEXt']) {
|
||||
result['tEXt'] = {};
|
||||
}
|
||||
let textChunk = textDecode(chunk.data);
|
||||
result['tEXt'][textChunk.keyword] = textChunk.text;
|
||||
break
|
||||
case 'pHYs':
|
||||
result['pHYs'] = {
|
||||
// Pixels per unit, X axis: 4 bytes (unsigned integer)
|
||||
"x": readUint32(chunk.data, 0),
|
||||
// Pixels per unit, Y axis: 4 bytes (unsigned integer)
|
||||
"y": readUint32(chunk.data, 4),
|
||||
"unit": chunk.data[8],
|
||||
}
|
||||
break
|
||||
case 'gAMA':
|
||||
case 'cHRM':
|
||||
case 'sRGB':
|
||||
case 'IHDR':
|
||||
case 'iCCP':
|
||||
default:
|
||||
result[chunk.name] = true;
|
||||
}
|
||||
})
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* create new Buffer with metadata. only tEXt and pHYs chunks are supported.
|
||||
* @param buffer {Buffer}
|
||||
* @param metadata {{tEXt: {keyword: value}, pHYs: {x: number, y: number, units: RESOLUTION_UNITS}}}
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
export function writeMetadata(buffer, metadata) {
|
||||
const chunks = extractChunks(buffer);
|
||||
insertMetadata(chunks, metadata);
|
||||
ArrayBuffer
|
||||
let out = encodeChunks(chunks).buffer;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
export function insertMetadata(chunks, metadata) {
|
||||
if (metadata.clear) {
|
||||
for (let i = chunks.length - 1; i--; ) {
|
||||
switch (chunks[i].name) {
|
||||
case 'IHDR':
|
||||
case 'IDAT':
|
||||
case 'IEND':
|
||||
break;
|
||||
default:
|
||||
chunks.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (metadata.tEXt) {
|
||||
for (var keyword in metadata.tEXt) {
|
||||
chunks.splice(-1, 0, textEncode(keyword, metadata.tEXt[keyword]))
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata.pHYs) {
|
||||
const data = new Uint8Array(9);
|
||||
writeUInt32(data, metadata.pHYs.x, 0)
|
||||
writeUInt32(data, metadata.pHYs.y, 4)
|
||||
data[8] = metadata.pHYs.units; // inches
|
||||
|
||||
let pHYs = chunks.find(chunk => chunk.name === "pHYs");
|
||||
if (pHYs) {
|
||||
pHYs.data = data;
|
||||
}
|
||||
else {
|
||||
chunks.splice(1, 0, { name: "pHYs", data: data })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue