Improved GIF recorder

Fix GIF flickering issue
This commit is contained in:
JannisX11 2023-04-09 01:17:46 +02:00
parent b3418264e1
commit 40764f8234
6 changed files with 41 additions and 34 deletions

View File

@ -108,6 +108,7 @@ BARS.defineActions(() => {
<li><a class="open-in-browser" href="https://bgrins.github.io/spectrum">Spectrum</a></li>
<li><a class="open-in-browser" href="https://github.com/stijlbreuk/vue-color-picker-wheel">Vue Color Picker Wheel</a></li>
<li><a class="open-in-browser" href="https://github.com/jnordberg/gif.js">gif.js</a></li>
<li><a class="open-in-browser" href="https://github.com/mattdesl/gifenc">gifenc</a></li>
<li><a class="open-in-browser" href="https://stuk.github.io/jszip/">JSZip</a></li>
<li><a class="open-in-browser" href="https://github.com/rotemdan/lzutf8.js">LZ-UTF8</a></li>
<li><a class="open-in-browser" href="https://jquery.com">jQuery</a></li>

View File

@ -263,14 +263,8 @@ const Screencam = {
}
if (options.format == 'gif') {
gif = new GIF({
repeat: options.repeat,
quality: options.quality,
background: options.background ? options.background : {r: 30, g: 0, b: 255},
transparent: options.background ? undefined : 0x1e01ff,
width: canvas_width,
height: canvas_height
});
gif = GIFEnc.GIFEncoder();
} else if (options.format == 'apng') {
let [canvas] = createEmptyCanvas();
apng_encoder = new APNGencoder(canvas);
@ -301,7 +295,6 @@ const Screencam = {
if (!options.silent) {
Blockbench.setStatusBarText(tl('status_bar.recording_gif'));
if (gif) gif.on('progress', Blockbench.setProgress);
}
// Use renderer without anti aliasing to avoid texture bleeding and color flickering
@ -332,7 +325,7 @@ const Screencam = {
NoAAPreview.render();
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (options.format != 'gif' && options.background) {
if (options.background) {
ctx.fillStyle = options.background;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
@ -345,10 +338,7 @@ const Screencam = {
Math.round(NoAAPreview.width * options.pixelate),
Math.round(NoAAPreview.height * options.pixelate)
);
if (options.format == 'gif') {
gif.addFrame(canvas, {delay: interval});
} else if (options.format == 'png_sequence' || options.format == 'apng') {
if (options.format == 'png_sequence' || options.format == 'gif' || options.format == 'apng') {
frame_canvases.push(canvas);
}
})
@ -361,20 +351,6 @@ const Screencam = {
}
}, interval)
if (options.format == 'gif') {
gif.on('finished', blob => {
delete Screencam.processing_gif;
var reader = new FileReader();
reader.onload = () => {
if (!options.silent) {
Blockbench.setProgress();
Blockbench.setStatusBarText();
}
Screencam.returnScreenshot(reader.result, cb, blob);
}
reader.readAsDataURL(blob);
});
}
frame.classList.add('recording');
}
@ -400,7 +376,28 @@ const Screencam = {
Screencam.processing_gif = gif;
}
if (options.format == 'gif') {
gif.render();
let i = 0;
let format = 'rgb4444';
for (let canvas of frame_canvases) {
let data = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height).data;
let palette = GIFEnc.quantize(data, 256, {format, oneBitAlpha: true});
let index = GIFEnc.applyPalette(data, palette, format);
gif.writeFrame(index, canvas.width, canvas.height, {palette, delay: interval, transparent: true});
i++;
Blockbench.setProgress(i / frame_canvases.length);
await new Promise(resolve => setTimeout(resolve, 0));
}
gif.finish();
Blockbench.setProgress();
Blockbench.setStatusBarText();
let buffer = gif.bytesView();
let blob = new Blob([buffer], {type: 'image/gif'});
let url = URL.createObjectURL(blob);
Screencam.returnScreenshot(url, cb, blob);
} else if (options.format == 'apng') {
@ -409,7 +406,7 @@ const Screencam = {
apng_encoder.addFrame(canvas);
i++;
Blockbench.setProgress(i / frame_canvases.length);
await new Promise(resolve => setTimeout(resolve, 1));
await new Promise(resolve => setTimeout(resolve, 0));
}
apng_encoder.finish();
@ -429,7 +426,7 @@ const Screencam = {
archive.file(i.toDigitString(digits) + '.png', data_url.replace('data:image/png;base64,', ''), {base64: true});
i++;
Blockbench.setProgress(i / frame_canvases.length);
await new Promise(resolve => setTimeout(resolve, 1));
await new Promise(resolve => setTimeout(resolve, 0));
}
archive.generateAsync({type: 'blob'}).then(content => {
Blockbench.export({

File diff suppressed because one or more lines are too long

7
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "Blockbench",
"version": "4.7.0-beta.1",
"version": "4.7.0-beta.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -3507,6 +3507,11 @@
"get-intrinsic": "^1.1.1"
}
},
"gifenc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/gifenc/-/gifenc-1.0.3.tgz",
"integrity": "sha512-xdr6AdrfGBcfzncONUOlXMBuc5wJDtOueE3c5rdG0oNgtINLD+f2iFZltrBRZYzACRbKr+mSVU/x98zv2u3jmw=="
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",

View File

@ -116,6 +116,7 @@
"dependencies": {
"@electron/remote": "^2.0.1",
"electron-color-picker": "^0.2.0",
"electron-updater": "^5.2.1"
"electron-updater": "^5.2.1",
"gifenc": "^1.0.3"
}
}

View File

@ -20,4 +20,7 @@ window.CustomThemeOptions = [
ContrastTheme
]
import { GIFEncoder, quantize, applyPalette } from 'gifenc'
window.GIFEnc = { GIFEncoder, quantize, applyPalette };
window.appVersion = BBVERSION;