You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.1 KiB
118 lines
3.1 KiB
"use strict";
|
|
|
|
var jpeg = require("jpeg-js")
|
|
var png = require("pngparse")
|
|
var gif = require("omggif")
|
|
var bufferEqual = require("buffer-equal")
|
|
var isnumber = require("isnumber")
|
|
|
|
module.exports = read
|
|
module.exports.Image = Image
|
|
module.exports.Frame = Frame
|
|
|
|
var gifHeader = new Buffer("GIF8")
|
|
var pngHeader = new Buffer([137, 80, 78, 71])
|
|
|
|
function read(buffer, callback) {
|
|
// detect type, convert to format
|
|
// braindead logic: check if GIF or PNG, if not, assume JPG
|
|
var head = buffer.slice(0, 4)
|
|
if (bufferEqual(head, gifHeader)) {
|
|
return parseGif(buffer, callback)
|
|
}
|
|
if (bufferEqual(head, pngHeader)) {
|
|
return parsePng(buffer, callback)
|
|
}
|
|
return parseJpg(buffer, callback)
|
|
}
|
|
|
|
function parseGif(buffer, callback) {
|
|
var image
|
|
try {
|
|
image = new gif.GifReader(buffer)
|
|
} catch (e) {
|
|
return callback(e)
|
|
}
|
|
var img = new Image(image.height, image.width)
|
|
var frameCount = image.numFrames()
|
|
for (var i = 0; i < frameCount; i++) {
|
|
var frameInfo = image.frameInfo(i)
|
|
var rgba = new Buffer(frameInfo.width * frameInfo.height * 4)
|
|
image.decodeAndBlitFrameRGBA(i, rgba)
|
|
img.addFrame(rgba, frameInfo.delay * 10)
|
|
}
|
|
return callback(null, img)
|
|
}
|
|
|
|
function parsePng(buffer, callback) {
|
|
png.parse(buffer, function (err, image) {
|
|
if (err) {
|
|
return callback(err)
|
|
}
|
|
var rgba = image.data
|
|
if (image.channels === 1) {
|
|
rgba = new Buffer(image.height * image.width * 4)
|
|
for (var i = 0; i < image.data.length; i++) {
|
|
var idx = i * 4
|
|
rgba[idx] = rgba[idx + 1] = rgba[idx + 2] = image.data[i]
|
|
rgba[idx + 3] = 0xff
|
|
}
|
|
}
|
|
if (image.channels === 2) {
|
|
rgba = new Buffer(image.height * image.width * 4)
|
|
for (var i = 0; i < image.data.length; i += 2) {
|
|
var idx = (i/2) * 4
|
|
rgba[idx] = rgba[idx + 1] = rgba[idx + 2] = image.data[i]
|
|
rgba[idx + 3] = image.data[i + 1]
|
|
}
|
|
}
|
|
if (image.channels === 3) {
|
|
rgba = new Buffer(image.height * image.width * 4)
|
|
for (var i = 0; i < image.data.length; i += 3) {
|
|
var idx = (i/3) * 4
|
|
rgba[idx] = image.data[i]
|
|
rgba[idx + 1] = image.data[i + 1]
|
|
rgba[idx + 2] = image.data[i + 2]
|
|
rgba[idx + 3] = 0xff
|
|
}
|
|
}
|
|
var img = new Image(image.height, image.width)
|
|
img.addFrame(rgba)
|
|
return callback(null, img)
|
|
})
|
|
}
|
|
|
|
function parseJpg(buffer, callback) {
|
|
var image
|
|
try {
|
|
image = jpeg.decode(buffer)
|
|
} catch (e) {
|
|
return callback(e)
|
|
}
|
|
var img = new Image(image.height, image.width)
|
|
img.addFrame(image.data)
|
|
return callback(null, img)
|
|
}
|
|
|
|
function Image(height, width) {
|
|
if (!(this instanceof Image)) {
|
|
return new Image(height, width)
|
|
}
|
|
if (!isnumber(height) || !isnumber(width)) {
|
|
throw new Error("Image height and width must be numbers.")
|
|
}
|
|
this.height = +height
|
|
this.width = +width
|
|
this.frames = []
|
|
}
|
|
Image.prototype.addFrame = function (rgba, delay) {
|
|
this.frames.push(new Frame(rgba, delay))
|
|
}
|
|
|
|
function Frame(rgba, delay) {
|
|
if (!(this instanceof Frame)) {
|
|
return new Frame(rgba, delay)
|
|
}
|
|
this.data = rgba
|
|
this.delay = delay
|
|
}
|
|
|