node.js解决获取图片真实文件类型的问题


Posted in Javascript onDecember 20, 2014

遇到一个需求:假定有一个图片文件,真实的类型为jpg,而有人偷懒把jpg直接复制一张,存为同名的png文件,这样在as3读取文件时不会遇到问题,但手机c++在读取文件时却遇到问题了 - -!

现在就需要写一个程序,遍历所有文件夹下的文件,查找文件格式“不正常”的文件。我们的资源主要是gif、png、jpg,最开始,我到网上找到一篇文章:根据二进制流及文件头获取文件类型mime-type,然后读取文件二进制的头信息,获取其真实的文件类型,对与通过后缀名获得的文件类型进行比较。

var fd = fs.openSync(new_file_path, 'r');

var buffer = new Buffer(8);
var mineType = mime.lookup(new_file_path);

var fileType = mime.extension(mineType);
fs.readSync(fd, buffer, 0, 8, 0);

var newBuf = buffer.slice(0, 4);

var head_1 = newBuf[0].toString(16);

var head_2 = newBuf[1].toString(16);

var head_3 = newBuf[2].toString(16);

var head_4 = newBuf[3].toString(16);

var head_iden = head_1 + head_2;
var tempFileType = FILE_TYPE_CONFIG[head_iden];

if (!tempFileType) {

    head_iden += head_3;
    tempFileType = FILE_TYPE_CONFIG[head_iden];
    if (!tempFileType) {

        var msg = "Unknow fileType " + new_file_path + '-' + fileType;

        showLog(msg);

        continue;

    }

}
if (tempFileType != fileType) {

    var msg = "Error fileType" + new_file_path + '-' + fileType + '|' + tempFileType + '--正确的图像文件格式';

    showLog(msg);
    g_errorFileTypArr.push(msg);

}

后来搜索node image相关的信息时,找到这篇文章:node.js module ranking>> (images)

然后筛选到一个模块“node-imageinfo”,写了一个例子进行测试(故意把jpg文件直接修改后缀名为png):

node.js解决获取图片真实文件类型的问题

node.js解决获取图片真实文件类型的问题

它的源码,有兴趣可以研究一下:

function readUInt32(buffer, offset, bigEndian) {

    if (buffer.readUInt32) {

        return buffer.readUInt32(offset, bigEndian);

    }
    var value;

    if (bigEndian) {

        if (buffer.readUInt32BE) {

            return buffer.readUInt32BE(offset);

        }

        value = (buffer[offset] << 24) + (buffer[offset+1] << 16) + (buffer[offset+2] << 8) + buffer[offset+3];

    }

    else {

        if (buffer.readUInt32LE) {

            return buffer.readUInt32LE(offset);

        }

        value = buffer[offset] + (buffer[offset+1] << 8) + (buffer[offset+2] << 16) + (buffer[offset+3] << 24);

    }

    return value;

}
function readUInt16(buffer, offset, bigEndian) {

    if (buffer.readUInt16) {

        return buffer.readUInt16(offset, bigEndian);

    }
    var value;

    if (bigEndian) {

        if (buffer.readUInt16BE) {

            return buffer.readUInt16BE(offset);

        }

        value = (buffer[offset] << 8) + buffer[offset+1];

    }

    else {

        if (buffer.readUInt16LE) {

            return buffer.readUInt16LE(offset);

        }

        value = buffer[offset] + (buffer[offset+1] << 8);

    }

    return value;

}
function readBit(buffer, offset, bitOffset) {

    if (bitOffset > 7) {

        offset += Math.floor(bitOffset / 8);

        bitOffset = bitOffset % 8;

    }
    var b = buffer[offset];

    if (bitOffset < 7) {

        b >>>= (7 - bitOffset);

    }
    var val = b & 0x01;

    return val;

}
function readBits(buffer, offset, bitOffset, bitLen, signed) {

    var val = 0;

    

    var neg = false;

    if (signed) {

        if (readBit(buffer, offset, bitOffset) > 0) {

            neg = true;

        }

        bitLen--;

        bitOffset++;

    }
    var bytes = [];

    for (var i = 0; i < bitLen; i++) {

        var b = readBit(buffer, offset, bitOffset + i);

        if (i>0 && (bitLen - i) % 8 == 0) {

            bytes.push(val);

            val = 0;

        }

        val <<= 1;

        val |= b;

    }

    bytes.push(val);
    val = new Buffer(bytes);

    val.negative = neg?true:false;

    return val;

}
function imageInfoPng(buffer) {

    var imageHeader = [0x49, 0x48, 0x44, 0x52],

        pos = 12;
    if (!checkSig(buffer, pos, imageHeader)) {

        return false;

    }
    pos += 4;

    return {

        type: 'image',

        format: 'PNG',

        mimeType: 'image/png',

        width: readUInt32(buffer, pos, true),

        height: readUInt32(buffer, pos+4, true),

    };

}
function imageInfoJpg(buffer) {

    var pos = 2,

        len = buffer.length,

        sizeSig = [0xff, [0xc0, 0xc2]];
    while (pos < len) {

        if (checkSig(buffer, pos, sizeSig)) {

            pos += 5;

            return {

                type: 'image',

                format: 'JPG',

                mimeType: 'image/jpeg',

                width: readUInt16(buffer, pos+2, true),

                height: readUInt16(buffer, pos, true),

            };

        }
        pos += 2;

        var size = readUInt16(buffer, pos, true);

        pos += size;

    }

}
function imageInfoGif(buffer) {

    var pos = 6;
    return {

        type: 'image',

        format: 'GIF',

        mimeType: 'image/gif',

        width: readUInt16(buffer, pos, false),

        height: readUInt16(buffer, pos+2, false),

    };

}
function imageInfoSwf(buffer) {

    var pos = 8,

        bitPos = 0,

        val;
    if (buffer[0] === 0x43) {

        try {

            // If you have zlib available ( npm install zlib ) then we can read compressed flash files

            buffer = require('zlib').inflate(buffer.slice(8, 100));

            pos = 0;

        }

        catch (ex) {

            // Can't get width/height of compressed flash files... yet (need zlib)

            return {

                type: 'flash',

                format: 'SWF',

                mimeType: 'application/x-shockwave-flash',

                width: null,

                height: null,

            }

        }

    }
    var numBits = readBits(buffer, pos, bitPos, 5)[0];

    bitPos += 5;

    

    val = readBits(buffer, pos, bitPos, numBits, true);

    var xMin = (numBits > 9 ? readUInt16(val, 0, true) : val[0]) * (val.negative ? -1 : 1);

    bitPos += numBits;
    val = readBits(buffer, pos, bitPos, numBits, true);

    var xMax = (numBits > 9 ? readUInt16(val, 0, true) : val[0]) * (val.negative ? -1 : 1);

    bitPos += numBits;
    val = readBits(buffer, pos, bitPos, numBits, true);

    var yMin = (numBits > 9 ? readUInt16(val, 0, true) : val[0]) * (val.negative ? -1 : 1);

    bitPos += numBits;
    val = readBits(buffer, pos, bitPos, numBits, true);

    var yMax = (numBits > 9 ? readUInt16(val, 0, true) : val[0]) * (val.negative ? -1 : 1);
    return {

        type: 'flash',

        format: 'SWF',

        mimeType: 'application/x-shockwave-flash',

        width: Math.ceil((xMax - xMin) / 20),

        height: Math.ceil((yMax - yMin) / 20),

    };

}
function checkSig(buffer, offset, sig) {

    var len = sig.length;

    for (var i = 0; i < len; i++) {

        var b = buffer[i+offset],

            s = sig[i],

            m = false;
        if ('number' == typeof s) {

            m = s === b;

        }

        else {

            for (var k in s) {

                var o = s[k];

                if (o === b) {

                    m = true;

                }

            }

        }
        if (!m) {

            return false;

        }

    }
    return true;

}
module.exports = function imageInfo(buffer, path) {

    var pngSig = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];

    var jpgSig = [0xff, 0xd8, 0xff];

    var gifSig = [0x47, 0x49, 0x46, 0x38, [0x37, 0x39], 0x61];

    var swfSig = [[0x46, 0x43], 0x57, 0x53];
    if (checkSig(buffer, 0, pngSig)) return imageInfoPng(buffer);

    if (checkSig(buffer, 0, jpgSig)) return imageInfoJpg(buffer);

    if (checkSig(buffer, 0, gifSig)) return imageInfoGif(buffer);

    if (checkSig(buffer, 0, swfSig)) return imageInfoSwf(buffer);
    return false;

};
Javascript 相关文章推荐
找出字符串中出现次数最多的字母和出现次数精简版
Nov 07 Javascript
jQuery插件pagination实现分页特效
Apr 12 Javascript
jQuery实现的纵向下拉菜单实例详解【附demo源码下载】
Jul 09 Javascript
JavaScript 随机验证码的生成实例代码
Sep 22 Javascript
d3.js实现简单的网络拓扑图实例代码
Nov 06 Javascript
Javascript实现页面滚动时导航智能定位
May 06 Javascript
ExtJs异步无法向外传值和赋值的完美解决办法
Jun 14 Javascript
JS使用tween.js动画库实现轮播图并且有切换功能
Jul 17 Javascript
使用layui日期控件laydate对开始和结束时间进行联动控制的方法
Sep 06 Javascript
vue中组件通信详解(父子组件, 爷孙组件, 兄弟组件)
Jul 27 Javascript
为什么JavaScript中0.1 + 0.2 != 0.3
Dec 03 Javascript
vue el-table实现递归嵌套的示例代码
Aug 14 Vue.js
javascript使用for循环批量注册的事件不能正确获取索引值的解决方法
Dec 20 #Javascript
Node.js实现批量去除BOM文件头
Dec 20 #Javascript
javascript删除一个html元素节点的方法
Dec 20 #Javascript
Node.js中调用mysql存储过程示例
Dec 20 #Javascript
零基础搭建Node.js、Express、Ejs、Mongodb服务器及应用开发入门
Dec 20 #Javascript
jQuery多媒体插件jQuery Media Plugin使用详解
Dec 19 #Javascript
jquery图片播放浏览插件prettyPhoto使用详解
Dec 19 #Javascript
You might like
环境会对咖啡种植有什么影响
2021/03/03 咖啡文化
php运行报错Call to undefined function curl_init()的最新解决方法
2016/11/20 PHP
给大家分享几个常用的PHP函数
2017/01/15 PHP
JAVASCRIPT IE 与 FF中兼容问题小结
2009/02/18 Javascript
javascript中利用数组实现的循环队列代码
2010/01/24 Javascript
jquery创建一个新的节点对象(自定义结构/内容)的好方法
2013/01/21 Javascript
jquery移动点击的项目到列表最顶端的方法
2015/06/24 Javascript
jquery+css3实现会动的小圆圈效果
2016/01/27 Javascript
Jquery跨域获得Json的简单实例
2016/05/18 Javascript
微信小程序点击控件修改样式实例详解
2017/07/07 Javascript
JavaScript判断浏览器和hack滚动条的写法
2017/07/23 Javascript
JS 中LocalStorage和SessionStorage的使用
2017/08/17 Javascript
webpack处理 css\less\sass 样式的方法
2017/08/21 Javascript
微信小程序 按钮滑动的实现方法
2017/09/27 Javascript
基于jQuery Ajax实现下拉框无刷新联动
2017/12/06 jQuery
vue 通过下拉框组件学习vue中的父子通讯
2017/12/19 Javascript
微信小程序如何使用canvas二维码保存至手机相册
2019/07/15 Javascript
vue+ESLint 配置保存 自动格式化代码
2020/03/17 Javascript
VSCode搭建React Native环境
2020/05/07 Javascript
js实现省级联动(数据结构优化)
2020/07/17 Javascript
利用Python命令行传递实例化对象的方法
2016/11/02 Python
python将txt文件读入为np.array的方法
2018/10/30 Python
在keras下实现多个模型的融合方式
2020/05/23 Python
opencv 查找连通区域 最大面积实例
2020/06/04 Python
Python用来做Web开发的优势有哪些
2020/08/05 Python
python中实现词云图的示例
2020/12/19 Python
丝芙兰法国官网:SEPHORA法国
2016/09/01 全球购物
介绍下Java的输入输出流
2014/01/22 面试题
Delphi工程师笔试题
2013/09/21 面试题
七一党日活动总结
2014/07/08 职场文书
银行职员工作失误检讨书
2014/10/14 职场文书
保密工作整改报告
2014/11/06 职场文书
投标单位介绍信
2015/05/05 职场文书
优秀班主任工作总结2015
2015/05/25 职场文书
2016年校园重阳节广播稿
2015/12/18 职场文书
导游词之四川熊猫基地
2020/01/13 职场文书