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 相关文章推荐
JavaScript window.location对象
Nov 14 Javascript
javascript中replace( )方法的使用
Apr 24 Javascript
jquery结婚电子请柬特效源码分享
Aug 21 Javascript
编写高质量JavaScript代码的基本要点
Mar 02 Javascript
JS异步文件上传(兼容IE8+)
Apr 02 Javascript
vuex 项目结构目录及一些简单配置介绍
Apr 08 Javascript
使用vue2.0创建的项目的步骤方法
Sep 25 Javascript
js中null与空字符串&quot;&quot;的区别讲解
Jan 17 Javascript
小程序云开发如何实现图片上传及发表文字
May 17 Javascript
详解小程序BackgroundAudioManager踩坑之旅
Dec 08 Javascript
vue+flask实现视频合成功能(拖拽上传)
Mar 04 Vue.js
吃通javascript正则表达式
Apr 21 Javascript
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
怎么使 Mysql 数据同步
2006/10/09 PHP
php 函数使用方法与函数定义方法
2010/05/09 PHP
解析smarty模板中类似for的功能实现
2013/06/18 PHP
thinkPHP模型初始化实例分析
2015/12/03 PHP
PHP面向对象之领域模型+数据映射器实例(分析)
2017/06/21 PHP
用户注册常用javascript代码
2009/08/29 Javascript
JavaScript 组件之旅(三):用 Ant 构建组件
2009/10/28 Javascript
javascript中的__defineGetter__和__defineSetter__介绍
2014/08/15 Javascript
kindeditor编辑器点中图片滚动条往上顶的bug
2015/07/05 Javascript
javascript每日必学之继承
2016/02/23 Javascript
bootstrap和jQuery.Gantt的css冲突 如何解决
2016/05/29 Javascript
jQuery基本选择器之标签名选择器
2016/09/03 Javascript
Vue2实现组件props双向绑定
2016/12/02 Javascript
AngularJS中$apply方法和$watch方法用法总结
2016/12/13 Javascript
说说AngularJS中的$parse和$eval的用法
2017/09/14 Javascript
关于vue中的ajax请求和axios包问题
2018/04/19 Javascript
vue2.0+SVG实现音乐播放圆形进度条组件
2019/09/21 Javascript
OpenLayers3实现测量功能
2020/09/25 Javascript
Python实现好友全头像的拼接实例(推荐)
2017/06/24 Python
Python简单读取json文件功能示例
2017/11/30 Python
Python 通配符删除文件的实例
2018/04/24 Python
python解决字符串倒序输出的问题
2018/06/25 Python
python 实现将txt文件多行合并为一行并将中间的空格去掉方法
2018/12/20 Python
解决Python正则表达式匹配反斜杠''\''问题
2019/07/17 Python
Python实现自动访问网页的例子
2020/02/21 Python
Pandas中DataFrame交换列顺序的方法实现
2020/12/14 Python
瑞士男士时尚网上商店:Babista
2020/05/14 全球购物
用JAVA SOCKET编程,读服务器几个字符,再写入本地显示
2012/11/25 面试题
C#实现对任一张表的数据进行增,删,改,查要求,运用Webservice,体现出三层架构
2014/07/11 面试题
聊城大学毕业生自荐书
2014/02/01 职场文书
《山谷中的谜底》教学反思
2014/04/26 职场文书
纪念一二九运动演讲稿
2014/09/16 职场文书
2015年体育教师个人工作总结
2015/05/12 职场文书
Python自动化测试PO模型封装过程详解
2021/06/22 Python
Django中session进行权限管理的使用
2021/07/09 Python
分享一个vue实现的记事本功能案例
2022/04/11 Vue.js