fix: canvas image/video download - fix data URL parsing in cvDownloadPreview (v1.5.21, hot 1.5.23)
This commit is contained in:
+98
-1
@@ -47,4 +47,101 @@ function extractZip(buf, destDir) {
|
||||
return written;
|
||||
}
|
||||
|
||||
module.exports = { extractZip };
|
||||
// ---- 零依赖 ZIP 压缩(deflate/stored),供员工团队打包等复用 ----
|
||||
// CRC32 表(懒加载)
|
||||
let CRC_TABLE = null;
|
||||
function crc32(buf) {
|
||||
if (!CRC_TABLE) {
|
||||
CRC_TABLE = new Int32Array(256);
|
||||
for (let n = 0; n < 256; n++) {
|
||||
let c = n;
|
||||
for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
||||
CRC_TABLE[n] = c;
|
||||
}
|
||||
}
|
||||
let crc = ~0;
|
||||
for (let i = 0; i < buf.length; i++) crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ buf[i]) & 0xff];
|
||||
return (~crc) >>> 0;
|
||||
}
|
||||
|
||||
// MS-DOS 时间/日期(固定用一个合法值即可,不追求精确时间戳)
|
||||
function dosDateTime(d) {
|
||||
const date = d || new Date();
|
||||
const time = ((date.getHours() & 0x1f) << 11) | ((date.getMinutes() & 0x3f) << 5) | ((date.getSeconds() / 2) & 0x1f);
|
||||
const day = (((date.getFullYear() - 1980) & 0x7f) << 9) | (((date.getMonth() + 1) & 0x0f) << 5) | (date.getDate() & 0x1f);
|
||||
return { time: time & 0xffff, date: day & 0xffff };
|
||||
}
|
||||
|
||||
// files: [{ path, content(string|Buffer), mode?(unix 权限,如 0o755) }]
|
||||
// 返回一个 zip 的 Buffer。目录靠文件路径里的 "/" 隐含,无需单独目录项。
|
||||
function createZip(files) {
|
||||
const { time, date } = dosDateTime();
|
||||
const locals = [];
|
||||
const centrals = [];
|
||||
let offset = 0;
|
||||
for (const f of files) {
|
||||
const nameBuf = Buffer.from(String(f.path).replace(/^\/+/, ""), "utf8");
|
||||
const raw = Buffer.isBuffer(f.content) ? f.content : Buffer.from(String(f.content == null ? "" : f.content), "utf8");
|
||||
const crc = crc32(raw);
|
||||
// 尝试 deflate;若压不小就存储(method 0)
|
||||
let method = 8;
|
||||
let comp = zlib.deflateRawSync(raw, { level: 9 });
|
||||
if (comp.length >= raw.length) { method = 0; comp = raw; }
|
||||
|
||||
// 本地文件头
|
||||
const lh = Buffer.alloc(30);
|
||||
lh.writeUInt32LE(0x04034b50, 0);
|
||||
lh.writeUInt16LE(20, 4); // version needed
|
||||
lh.writeUInt16LE(0, 6); // flags
|
||||
lh.writeUInt16LE(method, 8);
|
||||
lh.writeUInt16LE(time, 10);
|
||||
lh.writeUInt16LE(date, 12);
|
||||
lh.writeUInt32LE(crc, 14);
|
||||
lh.writeUInt32LE(comp.length, 18);
|
||||
lh.writeUInt32LE(raw.length, 22);
|
||||
lh.writeUInt16LE(nameBuf.length, 26);
|
||||
lh.writeUInt16LE(0, 28); // extra len
|
||||
locals.push(lh, nameBuf, comp);
|
||||
|
||||
// 中央目录项
|
||||
const ch = Buffer.alloc(46);
|
||||
// unix 权限写进外部属性高 16 位(低位保留),默认 0644,可执行给 0755
|
||||
const unixMode = f.mode ? f.mode : 0o644;
|
||||
const externalAttr = (unixMode << 16) >>> 0;
|
||||
ch.writeUInt32LE(0x02014b50, 0);
|
||||
ch.writeUInt16LE(0x031e, 4); // version made by (unix)
|
||||
ch.writeUInt16LE(20, 6); // version needed
|
||||
ch.writeUInt16LE(0, 8); // flags
|
||||
ch.writeUInt16LE(method, 10);
|
||||
ch.writeUInt16LE(time, 12);
|
||||
ch.writeUInt16LE(date, 14);
|
||||
ch.writeUInt32LE(crc, 16);
|
||||
ch.writeUInt32LE(comp.length, 20);
|
||||
ch.writeUInt32LE(raw.length, 24);
|
||||
ch.writeUInt16LE(nameBuf.length, 28);
|
||||
ch.writeUInt16LE(0, 30); // extra len
|
||||
ch.writeUInt16LE(0, 32); // comment len
|
||||
ch.writeUInt16LE(0, 34); // disk number
|
||||
ch.writeUInt16LE(0, 36); // internal attr
|
||||
ch.writeUInt32LE(externalAttr, 38);
|
||||
ch.writeUInt32LE(offset, 42);
|
||||
centrals.push(ch, nameBuf);
|
||||
|
||||
offset += lh.length + nameBuf.length + comp.length;
|
||||
}
|
||||
|
||||
const localPart = Buffer.concat(locals);
|
||||
const centralPart = Buffer.concat(centrals);
|
||||
const eocd = Buffer.alloc(22);
|
||||
eocd.writeUInt32LE(0x06054b50, 0);
|
||||
eocd.writeUInt16LE(0, 4);
|
||||
eocd.writeUInt16LE(0, 6);
|
||||
eocd.writeUInt16LE(files.length, 8);
|
||||
eocd.writeUInt16LE(files.length, 10);
|
||||
eocd.writeUInt32LE(centralPart.length, 12);
|
||||
eocd.writeUInt32LE(localPart.length, 16); // central dir offset
|
||||
eocd.writeUInt16LE(0, 20);
|
||||
return Buffer.concat([localPart, centralPart, eocd]);
|
||||
}
|
||||
|
||||
module.exports = { extractZip, createZip };
|
||||
|
||||
Reference in New Issue
Block a user