2021-02-25 00:24:09 +01:00
|
|
|
import {writeFileSync} from "fs";
|
|
|
|
|
2021-02-03 04:02:14 +01:00
|
|
|
const SWFReader = require('@gizeta/swf-reader');
|
|
|
|
|
2021-02-03 19:02:10 +01:00
|
|
|
const _encoder = require('png-stream/encoder');
|
2021-02-03 04:02:14 +01:00
|
|
|
|
2021-02-03 19:02:10 +01:00
|
|
|
const _encoder2 = _interopRequireDefault(_encoder);
|
2021-02-03 04:02:14 +01:00
|
|
|
|
2021-02-03 19:02:10 +01:00
|
|
|
const _zlib = require('zlib');
|
2021-02-03 04:02:14 +01:00
|
|
|
|
2021-02-03 19:02:10 +01:00
|
|
|
const _zlib2 = _interopRequireDefault(_zlib);
|
2021-02-03 04:02:14 +01:00
|
|
|
|
2021-02-03 19:02:10 +01:00
|
|
|
const _streamToArray = require('stream-to-array');
|
2021-02-03 04:02:14 +01:00
|
|
|
|
2021-02-03 19:02:10 +01:00
|
|
|
const _streamToArray2 = _interopRequireDefault(_streamToArray);
|
2021-02-03 04:02:14 +01:00
|
|
|
|
2021-02-03 19:02:10 +01:00
|
|
|
const _stream = require('stream');
|
2021-02-03 04:02:14 +01:00
|
|
|
|
2021-02-03 19:02:10 +01:00
|
|
|
const _stream2 = _interopRequireDefault(_stream);
|
|
|
|
|
|
|
|
const _decoder = require('jpg-stream/decoder');
|
|
|
|
|
|
|
|
const _decoder2 = _interopRequireDefault(_decoder);
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
function _interopRequireDefault(obj: any)
|
|
|
|
{
|
|
|
|
return obj && obj.__esModule ? obj : { default: obj };
|
2021-02-03 19:02:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const _concatFrames = require('concat-frames');
|
|
|
|
|
|
|
|
const _concatFrames2 = _interopRequireDefault(_concatFrames);
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
const _slicedToArray = function ()
|
|
|
|
{
|
|
|
|
function sliceIterator(arr: any, i: any)
|
|
|
|
{
|
|
|
|
const _arr = [];
|
|
|
|
let _n = true;
|
|
|
|
let _d = false;
|
|
|
|
let _e = undefined;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
for(var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true)
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
_arr.push(_s.value);
|
2021-02-17 00:30:41 -05:00
|
|
|
if(i && _arr.length === i) break;
|
2021-02-03 19:02:10 +01:00
|
|
|
}
|
2021-02-17 00:30:41 -05:00
|
|
|
}
|
|
|
|
catch (err)
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
_d = true;
|
|
|
|
_e = err;
|
2021-02-17 00:30:41 -05:00
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if(!_n && _i['return']) _i['return']();
|
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
if(_d) throw _e;
|
2021-02-03 19:02:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return _arr;
|
|
|
|
}
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
return function (arr: any, i: any)
|
|
|
|
{
|
|
|
|
if(Array.isArray(arr))
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
return arr;
|
2021-02-17 00:30:41 -05:00
|
|
|
}
|
|
|
|
else if(Symbol.iterator in Object(arr))
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
return sliceIterator(arr, i);
|
2021-02-17 00:30:41 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw new TypeError('Invalid attempt to destructure non-iterable instance');
|
2021-02-03 19:02:10 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}();
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
export function readSwfAsync(data: string | Buffer): Promise<any>
|
|
|
|
{
|
|
|
|
return new Promise<any>(((resolve, reject) =>
|
|
|
|
{
|
|
|
|
SWFReader.read(data, function (err: Error, swf: any)
|
|
|
|
{
|
|
|
|
if(err)
|
|
|
|
{
|
2021-02-03 04:02:14 +01:00
|
|
|
reject(err);
|
|
|
|
}
|
|
|
|
resolve(swf);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2021-02-03 19:02:10 +01:00
|
|
|
const pngMagic = Buffer.from('0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A'.split(' ').map(Number));
|
|
|
|
const gifMagic = Buffer.from('0x47 0x49 0x46 0x38 0x39 0x61'.split(' ').map(Number));
|
2021-02-25 00:24:09 +01:00
|
|
|
const jpegMagic = Buffer.from('0xFF 0xD8'.split(' ').map(Number));
|
2021-02-17 00:30:41 -05:00
|
|
|
const recognizeHeader = function recognizeHeader(buffer: Buffer)
|
|
|
|
{
|
|
|
|
if(pngMagic.equals(buffer.slice(0, pngMagic.length))) return 'png';
|
|
|
|
if(gifMagic.equals(buffer.slice(0, gifMagic.length))) return 'gif';
|
2021-02-25 00:24:09 +01:00
|
|
|
if(jpegMagic.equals(buffer.slice(0, jpegMagic.length))) return 'jpeg';
|
|
|
|
|
|
|
|
throw new Error('unknown format: ' + buffer.slice(0, 8));
|
2021-02-03 19:02:10 +01:00
|
|
|
};
|
2021-02-03 04:02:14 +01:00
|
|
|
|
2021-02-25 00:24:09 +01:00
|
|
|
export async function readImagesJPEG3or4(code: number, tagData: any): Promise<any>
|
2021-02-17 00:30:41 -05:00
|
|
|
{
|
|
|
|
const characterId = tagData.characterId,
|
2021-02-03 19:02:10 +01:00
|
|
|
imageData = tagData.imageData;
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
const imgType = recognizeHeader(imageData);
|
|
|
|
if(imgType !== 'jpeg')
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
return {
|
|
|
|
code: code,
|
|
|
|
characterId: characterId,
|
|
|
|
imgType: imgType,
|
|
|
|
imgData: imageData
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
const bitmapAlphaData = tagData.bitmapAlphaData;
|
2021-02-03 19:02:10 +01:00
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
return new Promise(function (resolve, reject)
|
|
|
|
{
|
|
|
|
const enc = new _encoder2.default(undefined, undefined, { colorSpace: 'rgba' });
|
|
|
|
_zlib2.default.unzip(bitmapAlphaData, function (err: any, alphaBufPre: any)
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
// INVARIANT: alphaBuf is either null or a non-empty buffer
|
|
|
|
let alphaBuf: any = null;
|
2021-02-17 00:30:41 -05:00
|
|
|
if(err)
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
/*
|
|
|
|
Due to a bug present in node zlib (https://github.com/nodejs/node/issues/17041)
|
|
|
|
unzipping an empty buffer can raise "unexpected end of file" error.
|
|
|
|
We fix this here so that our impl does not depend on the version of node
|
|
|
|
being used.
|
|
|
|
Theoretically every zlib.unzip call needs to be guarded, but for this package,
|
|
|
|
other two zlib.unzip call happens at sites that an empty uncompressed Buffer
|
|
|
|
does not make sense. So I think the current fix is good enough.
|
|
|
|
*/
|
2021-02-25 00:24:09 +01:00
|
|
|
if(bitmapAlphaData && bitmapAlphaData.length > 0)
|
2021-02-17 00:30:41 -05:00
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
return reject(new Error(err));
|
|
|
|
}
|
|
|
|
// leaving alphaBuf as null
|
2021-02-17 00:30:41 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
// ensure alphaBuf is only assigned an non-empty Buffer
|
2021-02-17 00:30:41 -05:00
|
|
|
if(alphaBufPre.length > 0) alphaBuf = alphaBufPre;
|
2021-02-03 19:02:10 +01:00
|
|
|
}
|
2021-02-17 00:30:41 -05:00
|
|
|
const bufferStream = new _stream2.default.PassThrough();
|
2021-02-03 19:02:10 +01:00
|
|
|
bufferStream.end(imageData);
|
2021-02-17 00:30:41 -05:00
|
|
|
bufferStream.pipe(new _decoder2.default()).pipe((_concatFrames2.default)(function (_ref: any)
|
|
|
|
{
|
|
|
|
const _ref2 = _slicedToArray(_ref, 1),
|
2021-02-03 19:02:10 +01:00
|
|
|
frame = _ref2[0];
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
const input = frame.pixels;
|
|
|
|
const pCount = frame.width * frame.height;
|
|
|
|
const output = Buffer.alloc(pCount * 4);
|
|
|
|
if(alphaBuf !== null && alphaBuf.length !== pCount)
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
console.error('expect alphaBuf to have size ' + pCount + ' while getting ' + alphaBuf.length);
|
|
|
|
}
|
2021-02-17 00:30:41 -05:00
|
|
|
const getAlphaBuf = alphaBuf === null ? function (_ignored: any)
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
return 0xff;
|
2021-02-17 00:30:41 -05:00
|
|
|
} : function (i: any)
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
return alphaBuf[i];
|
|
|
|
};
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
for(let i = 0; i < pCount; ++i)
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
output[4 * i] = input[3 * i];
|
|
|
|
output[4 * i + 1] = input[3 * i + 1];
|
|
|
|
output[4 * i + 2] = input[3 * i + 2];
|
|
|
|
output[4 * i + 3] = getAlphaBuf(i);
|
|
|
|
}
|
|
|
|
enc.format.width = frame.width;
|
|
|
|
enc.format.height = frame.height;
|
|
|
|
enc.end(output);
|
|
|
|
}));
|
|
|
|
});
|
2021-02-17 00:30:41 -05:00
|
|
|
(_streamToArray2.default)(enc).then(function (parts: any)
|
|
|
|
{
|
|
|
|
const buffers = parts.map(function (part: any)
|
|
|
|
{
|
2021-02-03 19:02:10 +01:00
|
|
|
return Buffer.isBuffer(part) ? part : Buffer.from(part);
|
|
|
|
});
|
|
|
|
resolve({
|
|
|
|
code: code,
|
|
|
|
characterId: characterId,
|
|
|
|
imgType: 'png',
|
|
|
|
imgData: Buffer.concat(buffers)
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2021-02-03 04:02:14 +01:00
|
|
|
}
|
|
|
|
|
2021-02-15 17:13:43 +01:00
|
|
|
export interface ImageTagData {
|
|
|
|
code: number,
|
|
|
|
characterId: number,
|
|
|
|
imgType: string,
|
|
|
|
imgData: Buffer,
|
|
|
|
bitmapWidth: number,
|
|
|
|
bitmapHeight: number
|
|
|
|
}
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
export function readImagesDefineBitsLossless(tag: any)
|
|
|
|
{
|
2021-02-03 04:02:14 +01:00
|
|
|
const characterId = tag.characterId,
|
|
|
|
bitmapFormat = tag.bitmapFormat,
|
|
|
|
bitmapWidth = tag.bitmapWidth,
|
|
|
|
bitmapHeight = tag.bitmapHeight,
|
|
|
|
bitmapColorTableSize = tag.bitmapColorTableSize,
|
|
|
|
zlibBitmapData = tag.zlibBitmapData;
|
|
|
|
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
return new Promise(function (resolve, reject)
|
|
|
|
{
|
|
|
|
const enc = new _encoder2.default(bitmapWidth, bitmapHeight, { colorSpace: 'rgba' });
|
2021-02-03 04:02:14 +01:00
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
_zlib2.default.unzip(zlibBitmapData, function (err: any, dataBuf: any)
|
|
|
|
{
|
|
|
|
if(err)
|
|
|
|
{
|
2021-02-03 04:02:14 +01:00
|
|
|
return reject(new Error(err));
|
|
|
|
}
|
2021-02-17 00:30:41 -05:00
|
|
|
const output = Buffer.alloc(bitmapWidth * bitmapHeight * 4);
|
|
|
|
let index = 0;
|
|
|
|
let ptr = 0;
|
|
|
|
if(bitmapFormat === 5)
|
|
|
|
{
|
2021-02-03 04:02:14 +01:00
|
|
|
// 32-bit ARGB image
|
2021-02-17 00:30:41 -05:00
|
|
|
for(let y = 0; y < bitmapHeight; ++y)
|
|
|
|
{
|
|
|
|
for(let x = 0; x < bitmapWidth; ++x)
|
|
|
|
{
|
|
|
|
const alpha = dataBuf[ptr];
|
2021-02-15 17:13:43 +01:00
|
|
|
output[index] = dataBuf[ptr + 1] * (255 / alpha);
|
|
|
|
output[index + 1] = dataBuf[ptr + 2] * (255 / alpha);
|
|
|
|
output[index + 2] = dataBuf[ptr + 3] * (255 / alpha);
|
2021-02-03 04:02:14 +01:00
|
|
|
output[index + 3] = alpha;
|
|
|
|
index += 4;
|
|
|
|
ptr += 4;
|
|
|
|
}
|
|
|
|
}
|
2021-02-17 00:30:41 -05:00
|
|
|
}
|
|
|
|
else if(bitmapFormat === 3)
|
|
|
|
{
|
2021-02-03 04:02:14 +01:00
|
|
|
// 8-bit colormapped image
|
2021-02-17 00:30:41 -05:00
|
|
|
const colorMap = [];
|
|
|
|
for(let i = 0; i < bitmapColorTableSize + 1; ++i)
|
|
|
|
{
|
2021-02-03 04:02:14 +01:00
|
|
|
colorMap.push([dataBuf[ptr], dataBuf[ptr + 1], dataBuf[ptr + 2], dataBuf[ptr + 3]]);
|
|
|
|
ptr += 4;
|
|
|
|
}
|
2021-02-17 00:30:41 -05:00
|
|
|
for(let _y2 = 0; _y2 < bitmapHeight; ++_y2)
|
|
|
|
{
|
|
|
|
for(let _x2 = 0; _x2 < bitmapWidth; ++_x2)
|
|
|
|
{
|
|
|
|
const idx = dataBuf[ptr];
|
|
|
|
const color = idx < colorMap.length ? colorMap[idx] : [0, 0, 0, 0];
|
2021-02-03 04:02:14 +01:00
|
|
|
output[index] = color[0];
|
|
|
|
output[index + 1] = color[1];
|
|
|
|
output[index + 2] = color[2];
|
|
|
|
output[index + 3] = color[3];
|
|
|
|
ptr += 1;
|
|
|
|
index += 4;
|
|
|
|
}
|
|
|
|
// skip padding
|
|
|
|
ptr += (4 - bitmapWidth % 4) % 4;
|
|
|
|
}
|
2021-02-17 00:30:41 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-02-03 04:02:14 +01:00
|
|
|
return reject(new Error('unhandled bitmapFormat: ' + bitmapFormat));
|
|
|
|
}
|
|
|
|
enc.end(output);
|
|
|
|
});
|
|
|
|
|
2021-02-17 00:30:41 -05:00
|
|
|
(_streamToArray2.default)(enc).then(function (parts: any)
|
|
|
|
{
|
|
|
|
const buffers = parts.map(function (part: any)
|
|
|
|
{
|
2021-02-03 04:02:14 +01:00
|
|
|
return Buffer.isBuffer(part) ? part : Buffer.from(part);
|
|
|
|
});
|
|
|
|
resolve({
|
|
|
|
code: 36,
|
|
|
|
characterId: characterId,
|
|
|
|
imgType: 'png',
|
2021-02-15 17:13:43 +01:00
|
|
|
imgData: Buffer.concat(buffers),
|
|
|
|
bitmapWidth: bitmapWidth,
|
|
|
|
bitmapHeight: bitmapHeight
|
2021-02-03 04:02:14 +01:00
|
|
|
});
|
|
|
|
});
|
2021-02-17 00:30:41 -05:00
|
|
|
}).catch(function (e)
|
|
|
|
{
|
2021-02-03 04:02:14 +01:00
|
|
|
console.error(e);
|
|
|
|
});
|
2021-02-25 00:24:09 +01:00
|
|
|
}
|