Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Overlay module for gifs #1616

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 161 additions & 32 deletions src/modules/Overlay/Module.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = function Dynamic(options, UI, util) {

const pixelSetter = require('../../util/pixelSetter.js');
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
options.x = options.x || defaults.x;
options.y = options.y || defaults.y;
Expand Down Expand Up @@ -28,39 +28,167 @@ module.exports = function Dynamic(options, UI, util) {
var baseStepOutput = this.getOutput(options.offset);

var getPixels = require('get-pixels');
const ndarray = require('ndarray');

getPixels(input.src, function(err, pixels) {
// parse the inputs
parseCornerCoordinateInputs({
iw: pixels.shape[0],
ih: pixels.shape[1]
},
{
x: { valInp: options.x, type: 'horizontal' },
y: { valInp: options.y, type: 'vertical' },
}, function(opt, input) {
options.x = parseInt(input.x.valInp);
options.y = parseInt(input.y.valInp);
});
let frames = [];
let counter = 0;

////////////////////////////////////////////
const isGIF = input.src.includes('image/gif');
if (isGIF && pixels != null) {
// console.log(pixels);
// const { shape } = pixels;
// const [
// noOfFrames,
// width,
// height,
// channels
// ] = pixels.shape;
const noOfFrames = pixels.shape[0];
const width = pixels.shape[1];
const height = pixels.shape[2];
const channels = pixels.shape[3];
// console.log('yooo');

numFrames = noOfFrames;
renderableFrames = noOfFrames; // Total number of renderable frames (mutable)
perFrameShape = [width, height, channels]; // Shape of ndarray of each frame

const numPixelsInFrame = width * height;

/* Coalesce the GIF frames (Some GIFs store delta information in between frames
i.e. Only the pixels which change between frames are stored. All these frames need to be
"Coalesced" to get final GIF frame.
More Info: https://www.npmjs.com/package/gif-extract-frames#why
*/

// Credit for the below code: https://www.npmjs.com/package/gif-extract-frames
// We couldn't use the library because it uses ES6 features which cannot be browserified
for (let i = 0; i < numFrames; ++i) {
if (i > 0) {
const currIndex = pixels.index(i, 0, 0, 0);
const prevIndex = pixels.index(i - 1, 0, 0, 0);

for (let j = 0; j < numPixelsInFrame; ++j) {
const curr = currIndex + j * channels;

if (pixels.data[curr + channels - 1] === 0) {
const prev = prevIndex + j * channels;

for (let k = 0; k < channels; ++k) {
pixels.data[curr + k] = pixels.data[prev + k];
}
}
}
}
}

for (let f = 0; f < numFrames; f++) {
frames.push(
new ndarray(
new Uint8Array(
perFrameShape[0] *
perFrameShape[1] *
perFrameShape[2]
),
perFrameShape
)
);

for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
for (let c = 0; c < channels; c++) {
frames[f].set(x, y, c, pixels.get(f, x, y, c));
}
}
}
}
// parse the inputs
parseCornerCoordinateInputs({
iw: perFrameShape[0],
ih: perFrameShape[1]
},
{
x: { valInp: options.x, type: 'horizontal' },
y: { valInp: options.y, type: 'vertical' },
}, function(opt, input) {
options.x = parseInt(input.x.valInp);
options.y = parseInt(input.y.valInp);
});
}
else if(pixels != null) {
frames.push(pixels);
// parse the inputs
parseCornerCoordinateInputs({
iw: pixels.shape[0],
ih: pixels.shape[1]
},
{
x: { valInp: options.x, type: 'horizontal' },
y: { valInp: options.y, type: 'vertical' },
}, function(opt, input) {
options.x = parseInt(input.x.valInp);
options.y = parseInt(input.y.valInp);
});
}



options.secondImagePixels = frames;

// function changePixel(r1, g1, b1, a1, x, y) {

// // overlay
// var p = options.secondImagePixels;
// if (x >= options.x
// && x - options.x < p.shape[0]
// && y >= options.y
// && y - options.y < p.shape[1])
// return [
// p.get(x - options.x, y - options.y, 0),
// p.get(x - options.x, y - options.y, 1),
// p.get(x - options.x, y - options.y, 2),
// p.get(x - options.x, y - options.y, 3)
// ];
// else
// return [r1, g1, b1, a1];
// }

function extraManipulation(first_pixels, setRenderState, generateOutput) {

if(pixels != null ){
setRenderState(false);
var p = frames[counter];
counter++;
for (let x = 0; x < first_pixels.shape[0]; x++) {
for (let y = 0; y < first_pixels.shape[1]; y++) {
if (x >= options.x
&& x - options.x < p.shape[0]
&& y >= options.y
&& y - options.y < p.shape[1]){
pixelSetter(
x,
y,
[
p.get(x, y, 0),
p.get(x, y, 1),
p.get(x, y, 2),
p.get(x, y, 3)
],
first_pixels
);
}
}
}
const getDataUri = require('../../util/getDataUri');

setRenderState(true);
generateOutput();


}

options.secondImagePixels = pixels;

function changePixel(r1, g1, b1, a1, x, y) {

// overlay
var p = options.secondImagePixels;
if (x >= options.x
&& x - options.x < p.shape[0]
&& y >= options.y
&& y - options.y < p.shape[1])
return [
p.get(x - options.x, y - options.y, 0),
p.get(x - options.x, y - options.y, 1),
p.get(x - options.x, y - options.y, 2),
p.get(x - options.x, y - options.y, 3)
];
else
return [r1, g1, b1, a1];
}

function output(image, datauri, mimetype, wasmSuccess) {
Expand All @@ -78,7 +206,8 @@ module.exports = function Dynamic(options, UI, util) {
return require('../_nomodule/PixelManipulation.js')(baseStepOutput, {
output: output,
ui: options.step.ui,
changePixel: changePixel,
// changePixel: changePixel,
extraManipulation: extraManipulation,
format: baseStepOutput.format,
image: baseStepImage,
inBrowser: options.inBrowser,
Expand Down