yt-dlp support
This commit is contained in:
415
node_modules/node-webpmux/webp.js
generated
vendored
Normal file
415
node_modules/node-webpmux/webp.js
generated
vendored
Normal file
@@ -0,0 +1,415 @@
|
||||
// For more information on the WebP format, see https://developers.google.com/speed/webp/docs/riff_container
|
||||
const { WebPReader, WebPWriter } = require('./parser.js');
|
||||
const IO = require('./io.js');
|
||||
const emptyImageBuffer = Buffer.from([
|
||||
0x52, 0x49, 0x46, 0x46, 0x24, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, 0x56, 0x50, 0x38, 0x20,
|
||||
0x18, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x9d, 0x01, 0x2a, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00,
|
||||
0x34, 0x25, 0xa4, 0x00, 0x03, 0x70, 0x00, 0xfe, 0xfb, 0xfd, 0x50, 0x00
|
||||
]);
|
||||
const constants = {
|
||||
TYPE_LOSSY: 0,
|
||||
TYPE_LOSSLESS: 1,
|
||||
TYPE_EXTENDED: 2
|
||||
};
|
||||
const encodeResults = {
|
||||
// These are errors from binding.cpp
|
||||
LIB_NOT_READY: -1, // <interface>.initEnc() was not called. This happens internally during <interface>.encodeImage() and thus should never happen.
|
||||
LIB_INVALID_CONFIG: -2, // invalid options passed in via set[Image/Frame]Data. This should never happen.
|
||||
SUCCESS: 0,
|
||||
// These errors are from native code and can be found in upstream libwebp/src/encode.h, WebPEncodingError enum
|
||||
VP8_ENC_ERROR_OUT_OF_MEMORY: 1, // memory error allocating objects
|
||||
VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY: 2, // memory error while flushing bits
|
||||
VP8_ENC_ERROR_NULL_PARAMETER: 3, // a pointer parameter is NULL
|
||||
VP8_ENC_ERROR_INVALID_CONFIGURATION: 4, // configuration is invalid
|
||||
VP8_ENC_ERROR_BAD_DIMENSION: 5, // picture has invalid width/height
|
||||
VP8_ENC_ERROR_PARTITION0_OVERFLOW: 6, // partition is bigger than 512k
|
||||
VP8_ENC_ERROR_PARTITION_OVERFLOW: 7, // partition is bigger than 16M
|
||||
VP8_ENC_ERROR_BAD_WRITE: 8, // error while flushing bytes
|
||||
VP8_ENC_ERROR_FILE_TOO_BIG: 9, // file is bigger than 4G
|
||||
VP8_ENC_ERROR_USER_ABORT: 10, // abort request by user
|
||||
VP8_ENC_ERROR_LAST: 11 // list terminator. always last.
|
||||
};
|
||||
const imageHints = {
|
||||
DEFAULT: 0,
|
||||
PICTURE: 1, // digital picture, such as a portrait. Indoors shot
|
||||
PHOTO: 2, // outdoor photograph with natural lighting
|
||||
GRAPH: 3 // discrete tone image (graph, map-tile, etc)
|
||||
};
|
||||
const imagePresets = {
|
||||
DEFAULT: 0,
|
||||
PICTURE: 1, // digital picture, such as a portrait. Indoors shot
|
||||
PHOTO: 2, // outdoor photograph with natural lighting
|
||||
DRAWING: 3, // hand or line drawing, with high-contrast details
|
||||
ICON: 4, // small-sized, colorful images
|
||||
TEXT: 5 // text-like
|
||||
};
|
||||
|
||||
class Image {
|
||||
constructor() { this.data = null; this.loaded = false; this.path = ''; }
|
||||
async initLib() { return Image.initLib(); }
|
||||
clear() { this.data = null; this.path = ''; this.loaded = false; }
|
||||
// Convenience getters/setters
|
||||
get width() { let d = this.data; return !this.loaded ? undefined : d.extended ? d.extended.width : d.vp8l ? d.vp8l.width : d.vp8 ? d.vp8.width : undefined; }
|
||||
get height() { let d = this.data; return !this.loaded ? undefined : d.extended ? d.extended.height : d.vp8l ? d.vp8l.height : d.vp8 ? d.vp8.height : undefined; }
|
||||
get type() { return this.loaded ? this.data.type : undefined; }
|
||||
get hasAnim() { return this.loaded ? this.data.extended ? this.data.extended.hasAnim : false : false; }
|
||||
get hasAlpha() { return this.loaded ? this.data.extended ? this.data.extended.hasAlpha : this.data.vp8 ? this.data.vp8.alpha : this.data.vp8l ? this.data.vp8l.alpha : false : false; }
|
||||
get anim() { return this.hasAnim ? this.data.anim : undefined; }
|
||||
get frames() { return this.anim ? this.anim.frames : undefined; }
|
||||
get iccp() { return this.data.extended ? this.data.extended.hasICCP ? this.data.iccp.raw : undefined : undefined; }
|
||||
set iccp(raw) {
|
||||
if (!this.data.extended) { this._convertToExtended(); }
|
||||
if (raw === undefined) { this.data.extended.hasICCP = false; delete this.data.iccp; }
|
||||
else { this.data.iccp = { raw }; this.data.extended.hasICCP = true; }
|
||||
}
|
||||
get exif() { return this.data.extended ? this.data.extended.hasEXIF ? this.data.exif.raw : undefined : undefined; }
|
||||
set exif(raw) {
|
||||
if (!this.data.extended) { this._convertToExtended(); }
|
||||
if (raw === undefined) { this.data.extended.hasEXIF = false; delete this.data.exif; }
|
||||
else { this.data.exif = { raw }; this.data.extended.hasEXIF = true; }
|
||||
}
|
||||
get xmp() { return this.data.extended ? this.data.extended.hasXMP ? this.data.xmp.raw : undefined : undefined; }
|
||||
set xmp(raw) {
|
||||
if (!this.data.extended) { this._convertToExtended(); }
|
||||
if (raw === undefined) { this.data.extended.hasXMP = false; delete this.data.xmp; }
|
||||
else { this.data.xmp = { raw }; this.data.extended.hasXMP = true; }
|
||||
}
|
||||
// Private member functions
|
||||
_convertToExtended() {
|
||||
if (!this.loaded) { throw new Error('No image loaded'); }
|
||||
this.data.type = constants.TYPE_EXTENDED;
|
||||
this.data.extended = {
|
||||
hasICCP: false,
|
||||
hasAlpha: false,
|
||||
hasEXIF: false,
|
||||
hasXMP: false,
|
||||
width: this.data.vp8 ? this.data.vp8.width : this.data.vp8l ? this.data.vp8l.width : 1,
|
||||
height: this.data.vp8 ? this.data.vp8.height : this.data.vp8l ? this.data.vp8l.height : 1
|
||||
};
|
||||
}
|
||||
async _demuxFrame(d, frame) {
|
||||
let { hasICCP, hasEXIF, hasXMP } = this.data.extended ? this.data.extended : { hasICCP: false, hasEXIF: false, hasXMP: false }, hasAlpha = ((frame.vp8) && (frame.vp8.alpha)), writer = new WebPWriter();
|
||||
if (typeof d === 'string') { writer.writeFile(d); }
|
||||
else { writer.writeBuffer(); }
|
||||
writer.writeFileHeader();
|
||||
if ((hasICCP) || (hasEXIF) || (hasXMP) || (hasAlpha)) {
|
||||
writer.writeChunk_VP8X({
|
||||
hasICCP,
|
||||
hasEXIF,
|
||||
hasXMP,
|
||||
hasAlpha: ((frame.vp8l) && (frame.vp8l.alpha)) || hasAlpha,
|
||||
width: frame.width,
|
||||
height: frame.height
|
||||
});
|
||||
}
|
||||
if (frame.vp8l) { writer.writeChunk_VP8L(frame.vp8l); }
|
||||
else if (frame.vp8) {
|
||||
if (frame.vp8.alpha) { writer.writeChunk_ALPH(frame.alph); }
|
||||
writer.writeChunk_VP8(frame.vp8);
|
||||
} else { throw new Error('Frame has no VP8/VP8L?'); }
|
||||
if ((hasICCP) || (hasEXIF) || (hasXMP) || (hasAlpha)) {
|
||||
if (this.data.extended.hasICCP) { writer.writeChunk_ICCP(this.data.iccp); }
|
||||
if (this.data.extended.hasEXIF) { writer.writeChunk_EXIF(this.data.exif); }
|
||||
if (this.data.extended.hasXMP) { writer.writeChunk_XMP(this.data.xmp); }
|
||||
}
|
||||
return writer.commit();
|
||||
}
|
||||
async _save(writer, { width = undefined, height = undefined, frames = undefined, bgColor = [ 255, 255, 255, 255 ], loops = 0, delay = 100, x = 0, y = 0, blend = true, dispose = false, exif = false, iccp = false, xmp = false } = {}) {
|
||||
let _width = width !== undefined ? width : this.width - 1, _height = height !== undefined ? height : this.height - 1, isAnim = this.hasAnim || frames !== undefined;
|
||||
if ((_width < 0) || (_width > (1 << 24))) { throw new Error('Width out of range'); }
|
||||
else if ((_height < 0) || (_height > (1 << 24))) { throw new Error('Height out of range'); }
|
||||
else if ((_height * _width) > (Math.pow(2, 32) - 1)) { throw new Error(`Width * height too large (${_width}, ${_height})`); }
|
||||
if (isAnim) {
|
||||
if ((loops < 0) || (loops >= (1 << 24))) { throw new Error('Loops out of range'); }
|
||||
else if ((delay < 0) || (delay >= (1 << 24))) { throw new Error('Delay out of range'); }
|
||||
else if ((x < 0) || (x >= (1 << 24))) { throw new Error('X out of range'); }
|
||||
else if ((y < 0) || (y >= (1 << 24))) { throw new Error('Y out of range'); }
|
||||
} else { if ((_width == 0) || (_height == 0)) { throw new Error('Width/height cannot be 0'); } }
|
||||
writer.writeFileHeader();
|
||||
switch (this.type) {
|
||||
case constants.TYPE_LOSSY: writer.writeChunk_VP8(this.data.vp8); break;
|
||||
case constants.TYPE_LOSSLESS: writer.writeChunk_VP8L(this.data.vp8l); break;
|
||||
case constants.TYPE_EXTENDED:
|
||||
{
|
||||
let hasICCP = iccp === true ? !!this.iccp : iccp,
|
||||
hasEXIF = exif === true ? !!this.exif : exif,
|
||||
hasXMP = xmp === true ? !!this.xmp : xmp;
|
||||
writer.writeChunk_VP8X({
|
||||
hasICCP, hasEXIF, hasXMP,
|
||||
hasAlpha: ((this.data.alph) || ((this.data.vp8l) && (this.data.vp8l.alpha))),
|
||||
hasAnim: isAnim,
|
||||
width: _width,
|
||||
height: _height
|
||||
});
|
||||
if (hasICCP) { writer.writeChunk_ICCP(iccp !== true ? iccp : this.data.iccp); }
|
||||
if (isAnim) {
|
||||
let _frames = frames || this.frames;
|
||||
writer.writeChunk_ANIM({ bgColor, loops });
|
||||
for (let i = 0, l = _frames.length; i < l; i++) {
|
||||
let fr = _frames[i],
|
||||
_delay = fr.delay == undefined ? delay : fr.delay,
|
||||
_x = fr.x == undefined ? x :fr.x,
|
||||
_y = fr.y == undefined ? y : fr.y,
|
||||
_blend = fr.blend == undefined ? blend : fr.blend,
|
||||
_dispose = fr.dispose == undefined ? dispose : fr.dispose, img;
|
||||
if ((_delay < 0) || (_delay >= (1 << 24))) { throw new Error(`Delay out of range on frame ${i}`); }
|
||||
else if ((_x < 0) || (_x >= (1 << 24))) { throw new Error(`X out of range on frame ${i}`); }
|
||||
else if ((_y < 0) || (_y >= (1 << 24))) { throw new Error(`Y out of range on frame ${i}`); }
|
||||
if (fr.path) { img = new Image(); await img.load(fr.path); img = img.data; }
|
||||
else if (fr.buffer) { img = new Image(); await img.load(fr.buffer); img = img.data; }
|
||||
else if (fr.img) { img = fr.img.data; }
|
||||
else { img = fr; }
|
||||
writer.writeChunk_ANMF({
|
||||
x: _x,
|
||||
y: _y,
|
||||
delay: _delay,
|
||||
blend: _blend,
|
||||
dispose: _dispose,
|
||||
img
|
||||
});
|
||||
}
|
||||
if ((_width == 0) || (_height == 0)) { writer.updateChunk_VP8X_size(_width == 0 ? writer.width : _width, _height == 0 ? writer.height : _height); }
|
||||
} else {
|
||||
if (this.data.vp8) {
|
||||
if (this.data.alph) { writer.writeChunk_ALPH(this.data.alph); }
|
||||
writer.writeChunk_VP8(this.data.vp8);
|
||||
} else if (this.data.vp8l) { writer.writeChunk_VP8L(this.data.vp8l); }
|
||||
}
|
||||
if (hasEXIF) { writer.writeChunk_EXIF(exif !== true ? exif : this.data.exif); }
|
||||
if (hasXMP) { writer.writeChunk_XMP(xmp !== true ? xmp : this.data.xmp); }
|
||||
}
|
||||
break;
|
||||
default: throw new Error('Unknown image type');
|
||||
}
|
||||
return writer.commit();
|
||||
}
|
||||
// Public member functions
|
||||
async load(d) {
|
||||
let reader = new WebPReader();
|
||||
if (typeof d === 'string') { if (!IO.avail) { await IO.err(); } reader.readFile(d); this.path = d; }
|
||||
else { reader.readBuffer(d); }
|
||||
this.data = await reader.read();
|
||||
this.loaded = true;
|
||||
}
|
||||
convertToAnim() {
|
||||
if (!this.data.extended) { this._convertToExtended(); }
|
||||
if (this.hasAnim) { return; }
|
||||
if (this.data.vp8) { delete this.data.vp8; }
|
||||
if (this.data.vp8l) { delete this.data.vp8l; }
|
||||
if (this.data.alph) { delete this.data.alph; }
|
||||
this.data.extended.hasAnim = true;
|
||||
this.data.anim = {
|
||||
bgColor: [ 255, 255, 255, 255],
|
||||
loops: 0,
|
||||
frames: []
|
||||
};
|
||||
}
|
||||
async demux({ path = undefined, buffers = false, frame = -1, prefix = '#FNAME#', start = 0, end = 0 } = {}) {
|
||||
if (!this.hasAnim) { throw new Error("This image isn't an animation"); }
|
||||
let _end = end == 0 ? this.frames.length : end, bufs = [];
|
||||
if (start < 0) { start = 0; }
|
||||
if (_end >= this.frames.length) { _end = this.frames.length - 1; }
|
||||
if (start > _end) { let n = start; start = _end; _end = n; }
|
||||
if (frame != -1) { start = _end = frame; }
|
||||
for (let i = start; i <= _end; i++) {
|
||||
let t = await this._demuxFrame(path ? (`${path}/${prefix}_${i}.webp`).replace(/#FNAME#/g, IO.basename(this.path, '.webp')) : undefined, this.anim.frames[i]);
|
||||
if (buffers) { bufs.push(t); }
|
||||
}
|
||||
if (buffers) { return bufs; }
|
||||
}
|
||||
async replaceFrame(frameIndex, d) {
|
||||
if (!this.hasAnim) { throw new Error("WebP isn't animated"); }
|
||||
if (typeof frameIndex !== 'number') { throw new Error('Frame index expects a number'); }
|
||||
if ((frameIndex < 0) || (frameIndex >= this.frames.length)) { throw new Error(`Frame index out of bounds (0 <= index < ${this.frames.length})`); }
|
||||
let r = new Image(), fr = this.frames[frameIndex];
|
||||
await r.load(d);
|
||||
switch (r.type) {
|
||||
case constants.TYPE_LOSSY:
|
||||
case constants.TYPE_LOSSLESS:
|
||||
break;
|
||||
case constants.TYPE_EXTENDED:
|
||||
if (r.hasAnim) { throw new Error('Merging animations not currently supported'); }
|
||||
break;
|
||||
default: throw new Error('Unknown WebP type');
|
||||
}
|
||||
switch (fr.type) {
|
||||
case constants.TYPE_LOSSY:
|
||||
if (fr.vp8.alpha) { delete fr.alph; }
|
||||
delete fr.vp8;
|
||||
break;
|
||||
case constants.TYPE_LOSSLESS:
|
||||
delete fr.vp8l;
|
||||
break;
|
||||
default: throw new Error('Unknown frame type');
|
||||
}
|
||||
switch (r.type) {
|
||||
case constants.TYPE_LOSSY:
|
||||
fr.vp8 = r.data.vp8;
|
||||
fr.type = constants.TYPE_LOSSY;
|
||||
break;
|
||||
case constants.TYPE_LOSSLESS:
|
||||
fr.vp8l = r.data.vp8l;
|
||||
fr.type = constants.TYPE_LOSSLESS;
|
||||
break;
|
||||
case constants.TYPE_EXTENDED:
|
||||
if (r.data.vp8) {
|
||||
fr.vp8 = r.data.vp8;
|
||||
if (r.data.vp8.alpha) { fr.alph = r.data.alph; }
|
||||
fr.type = constants.TYPE_LOSSY;
|
||||
} else if (r.data.vp8l) { fr.vp8l = r.data.vp8l; fr.type = constants.TYPE_LOSSLESS; }
|
||||
break;
|
||||
}
|
||||
fr.width = r.width;
|
||||
fr.height = r.height;
|
||||
}
|
||||
async save(path = this.path, { width = this.width, height = this.height, frames = this.frames, bgColor = this.hasAnim ? this.anim.bgColor : [ 255, 255, 255, 255 ], loops = this.hasAnim ? this.anim.loops : 0, delay = 100, x = 0, y = 0, blend = true, dispose = false, exif = !!this.exif, iccp = !!this.iccp, xmp = !!this.xmp } = {}) {
|
||||
let writer = new WebPWriter();
|
||||
if (path !== null) { if (!IO.avail) { await IO.err(); } writer.writeFile(path); }
|
||||
else { writer.writeBuffer(); }
|
||||
return this._save(writer, { width, height, frames, bgColor, loops, delay, x, y, blend, dispose, exif, iccp, xmp });
|
||||
}
|
||||
async getImageData() {
|
||||
if (!Image.libwebp) { throw new Error('Must call Image.initLib() before using getImageData'); }
|
||||
if (this.hasAnim) { throw new Error('Calling getImageData on animations is not supported'); }
|
||||
let buf = await this.save(null);
|
||||
return Image.libwebp.decodeImage(buf, this.width, this.height);
|
||||
}
|
||||
async setImageData(buf, { width = 0, height = 0, preset = undefined, quality = undefined, exact = undefined, lossless = undefined, method = undefined, advanced = undefined } = {}) {
|
||||
if (!Image.libwebp) { throw new Error('Must call Image.initLib() before using setImageData'); }
|
||||
if (this.hasAnim) { throw new Error('Calling setImageData on animations is not supported'); }
|
||||
if ((quality !== undefined) && ((quality < 0) || (quality > 100))) { throw new Error('Quality out of range'); }
|
||||
if ((lossless !== undefined) && ((lossless < 0) || (lossless > 9))) { throw new Error('Lossless preset out of range'); }
|
||||
if ((method !== undefined) && ((method < 0) || (method > 6))) { throw new Error('Method out of range'); }
|
||||
let ret = Image.libwebp.encodeImage(buf, width > 0 ? width : this.width, height > 0 ? height : this.height, { preset, quality, exact, lossless, method, advanced }), img = new Image(), keepEx = false, ex;
|
||||
if (ret.res !== encodeResults.SUCCESS) { return ret.res; }
|
||||
await img.load(Buffer.from(ret.buf));
|
||||
switch (this.type) {
|
||||
case constants.TYPE_LOSSY: delete this.data.vp8; break;
|
||||
case constants.TYPE_LOSSLESS: delete this.data.vp8l; break;
|
||||
case constants.TYPE_EXTENDED:
|
||||
ex = this.data.extended;
|
||||
delete this.data.extended;
|
||||
if ((ex.hasICCP) || (ex.hasEXIF) || (ex.hasXMP)) { keepEx = true; }
|
||||
if (this.data.vp8) { delete this.data.vp8; }
|
||||
if (this.data.vp8l) { delete this.data.vp8l; }
|
||||
if (this.data.alph) { delete this.data.alph; }
|
||||
break;
|
||||
}
|
||||
switch (img.type) {
|
||||
case constants.TYPE_LOSSY:
|
||||
if (keepEx) { this.data.type = constants.TYPE_EXTENDED; ex.hasAlpha = false; ex.width = img.width; ex.height = img.height; this.data.extended = ex; }
|
||||
else { this.data.type = constants.TYPE_LOSSY; }
|
||||
this.data.vp8 = img.data.vp8;
|
||||
break;
|
||||
case constants.TYPE_LOSSLESS:
|
||||
if (keepEx) { this.data.type = constants.TYPE_EXTENDED; ex.hasAlpha = img.data.vp8l.alpha; ex.width = img.width; ex.height = img.height; this.data.extended = ex; }
|
||||
else { this.data.type = constants.TYPE_LOSSLESS; }
|
||||
this.data.vp8l = img.data.vp8l;
|
||||
break;
|
||||
case constants.TYPE_EXTENDED:
|
||||
this.data.type = constants.TYPE_EXTENDED;
|
||||
if (keepEx) { ex.hasAlpha = img.data.alph || ((img.data.vp8l) && (img.data.vp8l.alpha)); ex.width = img.width; ex.height = img.height; this.data.extended = ex; }
|
||||
else { this.data.extended = img.data.extended; }
|
||||
if (img.data.vp8) { this.data.vp8 = img.data.vp8; }
|
||||
if (img.data.vp8l) { this.data.vp8l = img.data.vp8l; }
|
||||
if (img.data.alph) { this.data.alph = img.data.alph; }
|
||||
break;
|
||||
}
|
||||
return encodeResults.SUCCESS;
|
||||
}
|
||||
async getFrameData(frameIndex) {
|
||||
if (!Image.libwebp) { throw new Error('Must call Image.initLib() before using getFrameData'); }
|
||||
if (!this.hasAnim) { throw new Error('Calling getFrameData on non-animations is not supported'); }
|
||||
if (typeof frameIndex !== 'number') { throw new Error('Frame index expects a number'); }
|
||||
if ((frameIndex < 0) || (frameIndex >= this.frames.length)) { throw new Error('Frame index out of range'); }
|
||||
let fr = this.frames[frameIndex], buf = await this._demuxFrame(null, fr);
|
||||
return Image.libwebp.decodeImage(buf, fr.width, fr.height);
|
||||
}
|
||||
async setFrameData(frameIndex, buf, { width = 0, height = 0, preset = undefined, quality = undefined, exact = undefined, lossless = undefined, method = undefined, advanced = undefined } = {}) {
|
||||
if (!Image.libwebp) { throw new Error('Must call Image.initLib() before using setFrameData'); }
|
||||
if (!this.hasAnim) { throw new Error('Calling setFrameData on non-animations is not supported'); }
|
||||
if (typeof frameIndex !== 'number') { throw new Error('Frame index expects a number'); }
|
||||
if ((frameIndex < 0) || (frameIndex >= this.frames.length)) { throw new Error('Frame index out of range'); }
|
||||
if ((quality !== undefined) && ((quality < 0) || (quality > 100))) { throw new Error('Quality out of range'); }
|
||||
if ((lossless !== undefined) && ((lossless < 0) || (lossless > 9))) { throw new Error('Lossless preset out of range'); }
|
||||
if ((method !== undefined) && ((method < 0) || (method > 6))) { throw new Error('Method out of range'); }
|
||||
let fr = this.frames[frameIndex], ret = Image.libwebp.encodeImage(buf, width > 0 ? width : fr.width, height > 0 ? height : fr.height, { preset, quality, exact, lossless, method, advanced }), img = new Image();
|
||||
if (ret.res !== encodeResults.SUCCESS) { return ret.res; }
|
||||
await img.load(Buffer.from(ret.buf));
|
||||
switch (fr.type) {
|
||||
case constants.TYPE_LOSSY: delete fr.vp8; if (fr.alph) { delete fr.alph; } break;
|
||||
case constants.TYPE_LOSSLESS: delete fr.vp8l; break;
|
||||
}
|
||||
fr.width = img.width;
|
||||
fr.height = img.height;
|
||||
switch (img.type) {
|
||||
case constants.TYPE_LOSSY: fr.type = img.type; fr.vp8 = img.data.vp8; break;
|
||||
case constants.TYPE_LOSSLESS: fr.type = img.type; fr.vp8l = img.data.vp8l; break;
|
||||
case constants.TYPE_EXTENDED:
|
||||
if (img.data.vp8) {
|
||||
fr.type = constants.TYPE_LOSSY;
|
||||
fr.vp8 = img.data.vp8;
|
||||
if (img.data.vp8.alpha) { fr.alph = img.data.alph; }
|
||||
} else if (img.data.vp8l) {
|
||||
fr.type = constants.TYPE_LOSSLESS;
|
||||
fr.vp8l = img.data.vp8l;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return encodeResults.SUCCESS;
|
||||
}
|
||||
// Public static functions
|
||||
static async initLib() {
|
||||
if (!Image.libwebp) {
|
||||
const libWebP = require('./libwebp.js');
|
||||
Image.libwebp = new libWebP();
|
||||
await Image.libwebp.init();
|
||||
}
|
||||
}
|
||||
static async save(d, opts) {
|
||||
if ((opts.frames) && ((opts.width === undefined) || (opts.height === undefined))) { throw new Error('Must provide both width and height when passing frames'); }
|
||||
return (await Image.getEmptyImage(!!opts.frames)).save(d, opts);
|
||||
}
|
||||
static async getEmptyImage(ext) {
|
||||
let img = new Image();
|
||||
await img.load(emptyImageBuffer);
|
||||
if (ext) { img.exif = undefined; }
|
||||
return img;
|
||||
}
|
||||
static async generateFrame({ path = undefined, buffer = undefined, img = undefined, x = undefined, y = undefined, delay = undefined, blend = undefined, dispose = undefined } = {}) {
|
||||
let _img = img;
|
||||
if (((!path) && (!buffer) && (!img)) ||
|
||||
((path) && (buffer) && (img))) { throw new Error('Must provide either `path`, `buffer`, or `img`'); }
|
||||
if (!img) {
|
||||
_img = new Image();
|
||||
if (path) { await _img.load(path); }
|
||||
else { await _img.load(buffer); }
|
||||
}
|
||||
if (_img.hasAnim) { throw new Error('Merging animations is not currently supported'); }
|
||||
return {
|
||||
img: _img,
|
||||
x,
|
||||
y,
|
||||
delay,
|
||||
blend,
|
||||
dispose
|
||||
};
|
||||
}
|
||||
static from(webp) {
|
||||
let img = new Image();
|
||||
img.data = webp.data;
|
||||
img.loaded = webp.loaded;
|
||||
img.path = webp.path;
|
||||
return img;
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
TYPE_LOSSY: constants.TYPE_LOSSY,
|
||||
TYPE_LOSSLESS: constants.TYPE_LOSSLESS,
|
||||
TYPE_EXTENDED: constants.TYPE_EXTENDED,
|
||||
encodeResults,
|
||||
hints: imageHints,
|
||||
presets: imagePresets,
|
||||
Image
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user