UNPKG

fsk-imgoptimize

Version:
171 lines (161 loc) 4.96 kB
var Writable = require('stream').Writable; var Readable = require('stream').Readable; var ImgOptimize = require('./imgOptimize.js'); var util = require('util'); var imgtypes = require('./constants.js'); util.inherits(GIFStream, ImgOptimize); function GIFStream(options) { if (!(this instanceof GIFStream)) { return new GIFStream(options); } ImgOptimize.call(this); } GIFStream.prototype.handleSignature = function() { this.addHandle(6, this.parseSignature.bind(this)); }; GIFStream.prototype.parseSignature = function(data) { var sign = data.toString(); if (sign === 'GIF89a' || sign === 'GIF79a') { this.push(data); this.addHandle(7, this.parseLSD.bind(this)); } else { throw new Error('unvalid file type'); } }; //LSD===Logical Screen Description 逻辑屏幕描述块 GIFStream.prototype.parseLSD = function(data) { this.push(data); var packedField = data.readUIntBE(4, 1); var g = packedField.toString(2).charAt(1); //g === 1时表示有全局颜色表 读取后三位计算全局颜色表的大小 if (g === '1') { var globalColorTableSize = (2 << (packedField & 7 )) * 3; this.addHandle(globalColorTableSize, this.parseGCT.bind(this)); } else { this.addHandle(1, this.parseOther.bind(this)); } } //GCT === global color table 全局颜色表 GIFStream.prototype.parseGCT = function(data) { this.push(data); this.addHandle(1, this.parseOther.bind(this)); }; GIFStream.prototype.parseOther = function(data) { var sign = data.readUIntBE(0, data.length); switch (sign) { case 33 : this.addHandle(1, this.parseExtChunk.bind(this)); break; case 44: this.push(data); this.addHandle(9, this.parseImg.bind(this)); break; case 59: this.push(data); this.end(); default: break; } }; GIFStream.prototype.parseExtChunk = function(data) { var sign = data.readUIntBE(0, data.length); switch (sign) { case 1: //扩展文本标识 this.push(new Buffer([0x21])); this.push(data); this.addHandle(13, this.parseTextExt.bind(this)); break; case 255: //应用扩展 this.push(new Buffer([0x21])); this.push(data); this.addHandle(12, this.parseAppExt.bind(this)); break; case 249: //图形控制扩展 this.push(new Buffer([0x21])); this.push(data); this.addHandle(6, this.parseGraphicControl.bind(this)); break; case 254: //注释 //注释标识之后紧跟着就是 注释子数据块 //所以可以直接读取自数据块 并且忽略掉注释的数据 this.handleSubBlock(true); break; default: break; } }; GIFStream.prototype.parseTextExt = function(data) { this.push(data); this.handleSubBlock(false); } GIFStream.prototype.parseAppExt = function(data){ this.push(data); this.handleSubBlock(); } GIFStream.prototype.handleSubBlock = function(ignore) { var self = this; this._queue.push({ length: 1, callback: function(data) { if (!ignore) { self.push(data); } else { // console.log(data.readUIntBE(0, 1)); } var length = data.readUIntBE(0, 1); //如果length为0 则认为数据子块结束 继续读取下一个数据块 //否则继续调用handleSubBlock读取下一段数据子块 if(length) { self._queue.push({ length: length, callback: function(content) { if (!ignore) { self.push(content); } self.handleSubBlock(ignore); } }); } else { self.addHandle(1, this.parseOther.bind(this)); } } }); }; GIFStream.prototype.parseGraphicControl = function(data) { this.push(data); this.addHandle(1, this.parseOther.bind(this)); } GIFStream.prototype.parseImg = function(data) { this.push(data); var packedField = data.readUIntBE(8, 1); var l = packedField.toString(2).charAt(1); //若标识为1 则说明有局部颜色列表 解析之 if ( l === '1') { var LocalColorTableSize = (2 << (packed & 7)) * 3; this.addHandle(LocalColorTableSize, this.parseLCT.bind(this)); } else { //等于说明没有局部颜色列表 直接读取LZW数据 this.addHandle(1, this.parseLZW.bind(this)); } } //LCT == local color table 局部颜色列表 GIFStream.prototype.parseLCT = function(data) { this.push(data); //解析完LCT继续读LZW this.addHandle(1, this.parseLZW.bind(this)); }; GIFStream.prototype.parseLZW = function(data) { this.push(data); this.handleSubBlock(); }; module.exports = GIFStream; // var fs = require('fs'); // fs.createReadStream('a.gif').pipe(new GIFStream()).pipe(fs.createWriteStream('9.gif')); // // var buf = new Buffer([ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 ]) // fs.readFile('9.gif', function(err, data) { // var pos = 0; // while (pos < data.length){ // console.log(data.slice(pos, pos + 16)); // pos += 16; // } // });