Comparing version 1.0.0 to 2.0.0
331
demo/demo.js
@@ -0,211 +1,228 @@ | ||
import { parseGIF, decompressFrames } from '../lib/index.js' | ||
// user canvas | ||
var c = document.getElementById('c'); | ||
var ctx = c.getContext('2d'); | ||
var c = document.getElementById('c') | ||
var ctx = c.getContext('2d') | ||
// gif patch canvas | ||
var tempCanvas = document.createElement('canvas'); | ||
var tempCtx = tempCanvas.getContext('2d'); | ||
var tempCanvas = document.createElement('canvas') | ||
var tempCtx = tempCanvas.getContext('2d') | ||
// full gif canvas | ||
var gifCanvas = document.createElement('canvas'); | ||
var gifCtx = gifCanvas.getContext('2d'); | ||
var gifCanvas = document.createElement('canvas') | ||
var gifCtx = gifCanvas.getContext('2d') | ||
var url = document.getElementById('url'); | ||
var url = document.getElementById('url') | ||
// default gif | ||
url.value = '/demo/horses.gif'; | ||
url.value = '/demo/horses.gif' | ||
document.getElementById('loadGIF').onclick = loadGIF | ||
document.getElementById('playpause').onclick = playpause | ||
document.getElementById('edgedetect').onchange = () => { | ||
bEdgeDetect = !bEdgeDetect | ||
} | ||
document.getElementById('grayscale').onchange = () => { | ||
bGrayscale = !bGrayscale | ||
} | ||
document.getElementById('invert').onchange = () => { | ||
bInvert = !bInvert | ||
} | ||
document.getElementById('pixels').onchange = e => { | ||
pixelPercent = e.target.value | ||
} | ||
// load the default gif | ||
loadGIF(); | ||
var gif; | ||
loadGIF() | ||
var gif | ||
// load a gif with the current input url value | ||
function loadGIF(){ | ||
var oReq = new XMLHttpRequest(); | ||
oReq.open("GET", url.value, true); | ||
oReq.responseType = "arraybuffer"; | ||
function loadGIF() { | ||
var oReq = new XMLHttpRequest() | ||
oReq.open('GET', url.value, true) | ||
oReq.responseType = 'arraybuffer' | ||
oReq.onload = function (oEvent) { | ||
var arrayBuffer = oReq.response; // Note: not oReq.responseText | ||
if (arrayBuffer) { | ||
gif = new GIF(arrayBuffer); | ||
var frames = gif.decompressFrames(true); | ||
console.log(gif); | ||
// render the gif | ||
renderGIF(frames); | ||
} | ||
}; | ||
oReq.onload = function(oEvent) { | ||
var arrayBuffer = oReq.response // Note: not oReq.responseText | ||
if (arrayBuffer) { | ||
gif = parseGIF(arrayBuffer) | ||
var frames = decompressFrames(gif, true) | ||
// render the gif | ||
renderGIF(frames) | ||
} | ||
} | ||
oReq.send(null); | ||
oReq.send(null) | ||
} | ||
var playing = false; | ||
var bEdgeDetect = false; | ||
var bInvert = false; | ||
var bGrayscale = false; | ||
var pixelPercent = 100; | ||
var loadedFrames; | ||
var frameIndex; | ||
var playing = false | ||
var bEdgeDetect = false | ||
var bInvert = false | ||
var bGrayscale = false | ||
var pixelPercent = 100 | ||
var loadedFrames | ||
var frameIndex | ||
function playpause(){ | ||
playing = !playing; | ||
if(playing){ | ||
renderFrame(); | ||
} | ||
function playpause() { | ||
playing = !playing | ||
if (playing) { | ||
renderFrame() | ||
} | ||
} | ||
function renderGIF(frames){ | ||
loadedFrames = frames; | ||
frameIndex = 0; | ||
function renderGIF(frames) { | ||
loadedFrames = frames | ||
frameIndex = 0 | ||
c.width = frames[0].dims.width; | ||
c.height = frames[0].dims.height; | ||
c.width = frames[0].dims.width | ||
c.height = frames[0].dims.height | ||
gifCanvas.width = c.width; | ||
gifCanvas.height = c.height; | ||
gifCanvas.width = c.width | ||
gifCanvas.height = c.height | ||
if(!playing){ | ||
playpause(); | ||
} | ||
if (!playing) { | ||
playpause() | ||
} | ||
} | ||
var frameImageData; | ||
var frameImageData | ||
function drawPatch(frame){ | ||
var dims = frame.dims; | ||
if(!frameImageData || dims.width != frameImageData.width || dims.height != frameImageData.height){ | ||
tempCanvas.width = dims.width; | ||
tempCanvas.height = dims.height; | ||
frameImageData = tempCtx.createImageData(dims.width, dims.height); | ||
} | ||
// set the patch data as an override | ||
frameImageData.data.set(frame.patch); | ||
function drawPatch(frame) { | ||
var dims = frame.dims | ||
// draw the patch back over the canvas | ||
tempCtx.putImageData(frameImageData, 0, 0); | ||
if ( | ||
!frameImageData || | ||
dims.width != frameImageData.width || | ||
dims.height != frameImageData.height | ||
) { | ||
tempCanvas.width = dims.width | ||
tempCanvas.height = dims.height | ||
frameImageData = tempCtx.createImageData(dims.width, dims.height) | ||
} | ||
gifCtx.drawImage(tempCanvas, dims.left, dims.top); | ||
} | ||
// set the patch data as an override | ||
frameImageData.data.set(frame.patch) | ||
var edge = function(data, output){ | ||
// draw the patch back over the canvas | ||
tempCtx.putImageData(frameImageData, 0, 0) | ||
var odata = output.data; | ||
var width = gif.raw.lsd.width; | ||
var height = gif.raw.lsd.height; | ||
gifCtx.drawImage(tempCanvas, dims.left, dims.top) | ||
} | ||
var conv = [-1, -1, -1, | ||
-1, 8, -1, | ||
-1, -1, -1]; | ||
var halfside = Math.floor(3/2); | ||
var edge = function(data, output) { | ||
var odata = output.data | ||
var width = gif.lsd.width | ||
var height = gif.lsd.height | ||
for(var y=0; y<height; y++){ | ||
for(var x=0; x<width; x++){ | ||
var conv = [-1, -1, -1, -1, 8, -1, -1, -1, -1] | ||
var halfside = Math.floor(3 / 2) | ||
var r=0, g=0, b=0; | ||
for(var cy=0; cy<3; cy++){ | ||
for(var cx=0; cx<3; cx++){ | ||
for (var y = 0; y < height; y++) { | ||
for (var x = 0; x < width; x++) { | ||
var r = 0, | ||
g = 0, | ||
b = 0 | ||
for (var cy = 0; cy < 3; cy++) { | ||
for (var cx = 0; cx < 3; cx++) { | ||
var scy = y - halfside + cy | ||
var scx = x - halfside + cx | ||
var scy = (y - halfside + cy); | ||
var scx = (x - halfside + cx); | ||
if (scy >= 0 && scy < height && scx >= 0 && scx < width) { | ||
var src = (scy * width + scx) * 4 | ||
var f = cy * 3 + cx | ||
r += data[src] * conv[f] | ||
g += data[src + 1] * conv[f] | ||
b += data[src + 2] * conv[f] | ||
} | ||
} | ||
} | ||
if(scy >= 0 && scy < height && scx >= 0 && scx < width){ | ||
var src = (scy * width + scx) * 4; | ||
var f= cy * 3 + cx; | ||
r += data[src] * conv[f]; | ||
g += data[src + 1] * conv[f]; | ||
b += data[src + 2] * conv[f]; | ||
} | ||
} | ||
} | ||
var i = (y * width + x) * 4 | ||
odata[i] = r | ||
odata[i + 1] = g | ||
odata[i + 2] = b | ||
odata[i + 3] = 255 | ||
} | ||
} | ||
var i = (y * width + x) * 4; | ||
odata[i] = r; | ||
odata[i + 1] = g; | ||
odata[i + 2] = b; | ||
odata[i + 3] = 255; | ||
} | ||
} | ||
return output; | ||
return output | ||
} | ||
var invert = function(data) { | ||
for (var i = 0; i < data.length; i += 4) { | ||
data[i] = 255 - data[i]; // red | ||
data[i + 1] = 255 - data[i + 1]; // green | ||
data[i + 2] = 255 - data[i + 2]; // blue | ||
data[i + 3] = 255; | ||
} | ||
}; | ||
for (var i = 0; i < data.length; i += 4) { | ||
data[i] = 255 - data[i] // red | ||
data[i + 1] = 255 - data[i + 1] // green | ||
data[i + 2] = 255 - data[i + 2] // blue | ||
data[i + 3] = 255 | ||
} | ||
} | ||
var grayscale = function(data) { | ||
for (var i = 0; i < data.length; i += 4) { | ||
var avg = (data[i] + data[i +1] + data[i +2]) / 3; | ||
data[i] = avg; // red | ||
data[i + 1] = avg; // green | ||
data[i + 2] = avg; // blue | ||
data[i + 3] = 255; | ||
} | ||
}; | ||
for (var i = 0; i < data.length; i += 4) { | ||
var avg = (data[i] + data[i + 1] + data[i + 2]) / 3 | ||
data[i] = avg // red | ||
data[i + 1] = avg // green | ||
data[i + 2] = avg // blue | ||
data[i + 3] = 255 | ||
} | ||
} | ||
function manipulate(){ | ||
var imageData = gifCtx.getImageData(0, 0, gifCanvas.width, gifCanvas.height); | ||
var other = gifCtx.createImageData(gifCanvas.width, gifCanvas.height); | ||
function manipulate() { | ||
var imageData = gifCtx.getImageData(0, 0, gifCanvas.width, gifCanvas.height) | ||
var other = gifCtx.createImageData(gifCanvas.width, gifCanvas.height) | ||
if(bEdgeDetect){ | ||
imageData = edge(imageData.data, other); | ||
} | ||
if (bEdgeDetect) { | ||
imageData = edge(imageData.data, other) | ||
} | ||
if(bInvert){ | ||
invert(imageData.data); | ||
} | ||
if (bInvert) { | ||
invert(imageData.data) | ||
} | ||
if(bGrayscale){ | ||
grayscale(imageData.data); | ||
} | ||
if (bGrayscale) { | ||
grayscale(imageData.data) | ||
} | ||
// do pixelation | ||
var pixelsX = 5 + Math.floor(pixelPercent / 100 * (c.width - 5)); | ||
var pixelsY = (pixelsX * c.height) / c.width; | ||
// do pixelation | ||
var pixelsX = 5 + Math.floor((pixelPercent / 100) * (c.width - 5)) | ||
var pixelsY = (pixelsX * c.height) / c.width | ||
if(pixelPercent != 100){ | ||
ctx.mozImageSmoothingEnabled = false; | ||
ctx.webkitImageSmoothingEnabled = false; | ||
ctx.imageSmoothingEnabled = false; | ||
} | ||
if (pixelPercent != 100) { | ||
ctx.mozImageSmoothingEnabled = false | ||
ctx.webkitImageSmoothingEnabled = false | ||
ctx.imageSmoothingEnabled = false | ||
} | ||
ctx.putImageData(imageData, 0, 0); | ||
ctx.drawImage(c, 0, 0, c.width, c.height, 0, 0, pixelsX, pixelsY); | ||
ctx.drawImage(c, 0, 0, pixelsX, pixelsY, 0, 0, c.width, c.height); | ||
ctx.putImageData(imageData, 0, 0) | ||
ctx.drawImage(c, 0, 0, c.width, c.height, 0, 0, pixelsX, pixelsY) | ||
ctx.drawImage(c, 0, 0, pixelsX, pixelsY, 0, 0, c.width, c.height) | ||
} | ||
function renderFrame(){ | ||
// get the frame | ||
var frame = loadedFrames[frameIndex]; | ||
function renderFrame() { | ||
// get the frame | ||
var frame = loadedFrames[frameIndex] | ||
var start = new Date().getTime(); | ||
var start = new Date().getTime() | ||
gifCtx.clearRect(0, 0, c.width, c.height); | ||
gifCtx.clearRect(0, 0, c.width, c.height) | ||
// draw the patch | ||
drawPatch(frame); | ||
// draw the patch | ||
drawPatch(frame) | ||
// perform manipulation | ||
manipulate(); | ||
// perform manipulation | ||
manipulate() | ||
// update the frame index | ||
frameIndex++; | ||
if(frameIndex >= loadedFrames.length){ | ||
frameIndex = 0; | ||
} | ||
// update the frame index | ||
frameIndex++ | ||
if (frameIndex >= loadedFrames.length) { | ||
frameIndex = 0 | ||
} | ||
var end = new Date().getTime(); | ||
var diff = end - start; | ||
var end = new Date().getTime() | ||
var diff = end - start | ||
if(playing){ | ||
// delay the next gif frame | ||
setTimeout(function(){ | ||
requestAnimationFrame(renderFrame); | ||
//renderFrame(); | ||
}, Math.max(0, Math.floor(frame.delay - diff))); | ||
} | ||
if (playing) { | ||
// delay the next gif frame | ||
setTimeout(function() { | ||
requestAnimationFrame(renderFrame) | ||
//renderFrame(); | ||
}, Math.max(0, Math.floor(frame.delay - diff))) | ||
} | ||
} |
{ | ||
"name": "gifuct-js", | ||
"version": "1.0.0", | ||
"description": "Easy to use efficient .GIF parsing in the browser", | ||
"main": "index.js", | ||
"version": "2.0.0", | ||
"description": "Easy to use efficient .GIF parsing in javascript", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"build": "babel src --out-dir lib", | ||
"build-demo": "webpack demo/demo.js -o demo/demo.build.js --mode=\"none\"" | ||
}, | ||
@@ -25,10 +26,11 @@ "repository": { | ||
"devDependencies": { | ||
"browserify": "^10.2.6", | ||
"gulp": "^3.9.0", | ||
"gulp-jshint": "^1.11.2", | ||
"gulp-rename": "^1.2.2", | ||
"gulp-uglify": "^1.2.0", | ||
"vinyl-buffer": "^1.0.0", | ||
"vinyl-source-stream": "^1.1.0" | ||
"@babel/cli": "^7.10.5", | ||
"@babel/core": "^7.11.4", | ||
"@babel/preset-env": "^7.11.0", | ||
"webpack": "^4.44.1", | ||
"webpack-cli": "^3.3.12" | ||
}, | ||
"dependencies": { | ||
"js-binary-schema-parser": "^2.0.0" | ||
} | ||
} |
# gifuct-js | ||
A Simple to use javascript .GIF decoder. | ||
@@ -12,24 +13,23 @@ | ||
*Installation:* | ||
_Installation:_ | ||
bower install --save gifuct-js | ||
*Decoding:* | ||
npm install gifuct-js | ||
_Decoding:_ | ||
This decoder uses **[js-binary-schema-parser][5]** to parse the gif files (you can examine the schema in the source). This means the gif file must firstly be converted into a `Uint8Array` buffer in order to decode it. Some examples: | ||
* *Angularjs* | ||
- _fetch_ | ||
import { parseGIF, decompressFrames } from 'gifuct-js' | ||
return $http.get(gifURL, { | ||
responseType: 'arraybuffer' | ||
}).then(function(result){ | ||
var gif = new GIF(result.data); | ||
// return the frame data as the promise result | ||
return gif.decompressFrames(true); | ||
}); | ||
* *XMLHttpRequest* | ||
var promisedGif = fetch(gifURL) | ||
.then(resp => resp.arrayBuffer()) | ||
.then(buff => parseGIF(buff)) | ||
.then(gif => decompressFrames(gif, true)); | ||
- _XMLHttpRequest_ | ||
import { parseGIF, decompressFrames } from 'gifuct-js' | ||
var oReq = new XMLHttpRequest(); | ||
@@ -42,4 +42,4 @@ oReq.open("GET", gifURL, true); | ||
if (arrayBuffer) { | ||
var gif = new GIF(arrayBuffer); | ||
var frames = gif.decompressFrames(true); | ||
var gif = parseGIF(arrayBuffer); | ||
var frames = decompressFrames(gif, true); | ||
// do something with the frame data | ||
@@ -51,18 +51,11 @@ } | ||
* *fetch* | ||
_Result:_ | ||
var promisedGif = fetch(gifURL) | ||
.then(resp => resp.arrayBuffer()) | ||
.then(buff => new GIF(buff)) | ||
.then(gif => gif.decompressFrames(true)); | ||
The result of the `decompressFrames(gif, buildPatch)` function returns an array of all the GIF image frames, and their meta data. Here is a an example frame: | ||
*Result:* | ||
The result of the `decompressFrames(buildPatch)` function returns an array of all the GIF image frames, and their meta data. Here is a an example frame: | ||
{ | ||
// The color table lookup index for each pixel | ||
pixels: [...], | ||
pixels: [...], | ||
// the dimensions of the gif frame (see disposal method) | ||
dims: { | ||
dims: { | ||
top: 0, | ||
@@ -84,12 +77,12 @@ left: 10, | ||
} | ||
*Automatic Patch Generation:* | ||
_Automatic Patch Generation:_ | ||
If the `buildPatch` param of the `dcompressFrames()` function is `true`, the parser will not only return the parsed and decompressed gif frames, but will also create canvas ready `Uint8ClampedArray` arrays of each gif frame image, so that they can easily be drawn using `ctx.putImageData()` for example. This requirement is common, however it was made optional because it makes assumptions about transparency. The [demo][4] makes use of this option. | ||
*Disposal Method:* | ||
_Disposal Method:_ | ||
The `pixel` data is stored as a list of indexes for each pixel. These each point to a value in the `colorTable` array, which contain the color that each pixel should be drawn. Each frame of the gif may not be the full size, but instead a patch that needs to be drawn over a particular location. The `disposalType` defines how that patch should be drawn over the gif canvas. In most cases, that value will be `1`, indicating that the gif frame should be simply drawn over the existing gif canvas without altering any pixels outside the frames patch dimensions. More can be read about this [here][6]. | ||
*Transparency:* | ||
_Transparency:_ | ||
@@ -112,5 +105,7 @@ If a `transparentIndex` is defined for a frame, it means that any pixel within the pixel data that matches this index should not be drawn. When drawing the patch using canvas, this means setting the alpha value for this pixel to `0`. | ||
[Unassigned][9] | ||
[Matt Way][9] & [Nick Drewe][10] | ||
[1]: http://ruffle.us | ||
[Wethrift.com][11] | ||
[1]: https://www.producthunt.com/posts/ruffle | ||
[2]: http://slbkbs.org/jsgif/ | ||
@@ -123,2 +118,4 @@ [3]: https://github.com/buzzfeed/libgif-js | ||
[8]: https://gist.github.com/devunwired/4479231 | ||
[9]: http://unassigned.co | ||
[9]: https://twitter.com/_MattWay | ||
[10]: https://twitter.com/nickdrewe | ||
[11]: https://wethrift.com |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
3773445
5
18
1407
0
0
1
116
2
+ Addedjs-binary-schema-parser@2.0.3(transitive)