首页 > 其他分享 >[JS真好玩] 图片文件没后缀,怎么判断图片类型?

[JS真好玩] 图片文件没后缀,怎么判断图片类型?

时间:2022-10-26 15:06:50浏览次数:73  
标签:info 文件 buffer 真好玩 JS file var type 图片


这是我的专栏​​《JS真好玩》​​,将教你用JS实现一些有趣的东西。JS可以直接在浏览器运行,也可以在Node中运行,你可以跟我学习用JS做好玩儿的事情。感谢大家关注~文章求赞噢!祝大家早日变成一名「前端极客」!

欢迎阅读:本专栏最受欢迎文章​​《用JS找到哪个小坏蛋给我连点2次赞》​​。

背景

最近我在处理图片,遇到个问题:从网上下载的图片,都没有后缀标明文件类型。我希望写代码识别他们的后缀,并自动改名字。

关于图片存储

文件用后缀标明文件类型,是给计算机的「文件管理器」和人类看的。「文件管理器」可以直接读取文件名,知道用什么软件打开文件,「人类」也可以直观的从文件名中知道类型。

但文件名后缀不是决定文件类型的(所以人类可以任意修改后缀,没有限制)。文件中,通常有 Magic Number 标识文件类型。这个 Magic Number 通常位于文件的头部。一个文件其实就是一个长的二进制序列,头部就是这些二进制序列的前几个字节。

以下来自维基百科对 ​​Magic Number​​ 的一些案例:

  • ​GIF​​​ image files have the​​ASCII​​​ code for "GIF89a" (​​47​​​​49​​​​46​​​​38​​​​39​​​​61​​​) or "GIF87a" (​​47​​​​49​​​​46​​​​38​​​​37​​​​61​​)
  • ​JPEG​​​ image files begin with​​FF​​​​D8​​​ and end with​​FF​​​​D9​​​. JPEG/​​JFIF​​​ files contain the​​ASCII​​​ code for "JFIF" (​​4A​​​​46​​​​49​​​​46​​​) as a​​null terminated string​​​. JPEG/​​Exif​​​ files contain the​​ASCII​​​ code for "Exif" (​​45​​​​78​​​​69​​​​66​​​) also as a null terminated string, followed by more​​metadata​​ about the file.
  • ​PNG​​​ image files begin with an 8-​​byte​​​ signature which identifies the file as a PNG file and allows detection of common file transfer problems:​​\211​​​​P​​​​N​​​​G​​​​\r​​​​\n​​​​\032​​​​\n​​​ (​​89​​​​50​​​​4E​​​​47​​​​0D​​​​0A​​​​1A​​​​0A​​​). That signature contains various​​newline​​​ characters to permit detecting unwarranted automated newline conversions, such as transferring the file using​​FTP​​ with theASCII​transfer mode​​ instead of thebinarymode.

上面提到的"GIF89a" (​​47​​​ ​​49​​​ ​​46​​​ ​​38​​​ ​​39​​​ ​​61​​​),引号里是ASCII,括号里是16进制,你可以去我写的工具里轻松转换:​​tool.hullqin.cn/byte-parser…​​​ ,工具介绍文章在​​《手写解析uin8数组的工具:解析二进制字节,太快太方便了!》​

方案一:imageinfo

安装

npm i imageinfo

在NodeJS中使用

const imageinfo = require('imageinfo');
const img = fs.readFileSync('图片文件路径');
const info = imageinfo(img);
console.log(info);
console.log(info.format);
console.log("Data is type:", info.mimeType);
console.log(" Size:", img.length, "bytes");
console.log(" Dimensions:", info.width, "x", info.height);

得到​​info​​​后,使用​​info.format.toLowerCase()​​就能获得文件后缀。

这个库比较简洁,只能识别png jpg gif swf。如果文件未识别到图片类型,info就是false了,要注意特殊处理这种情况。

源码

imageinfo源码非常简单:

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;
};

可以看到它定义了一些头部标识,然后通过​​checkSig​​​去匹配。我们再看看​​checkSig​​:

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;
}

也很简单,就是拿文件头部几个字节和之前定义的头部标识进行逐个匹配,全匹配成功,返回true,否则就返回false。

方案二:file-type

这个库不像​​imagetype​​​走简洁路线,​​file-type​​功能更强大,能识别的类型更多。同时支持NodeJS环境和浏览器环境。

官方介绍如下:

The file type is detected by checking the magic number of the buffer.

This package is for detecting binary-based file formats, not text-based formats like ​​.txt​​​, ​​.csv​​​, ​​.svg​​, etc.

意思是,这个库通过检查文件二进制序列的 magic number 来判断文件类型。不支持 txt csv svg这些文本类型文件的判断。

安装

npm i file-type

使用

NodeJS使用:

import {fileTypeFromFile} from 'file-type';

console.log(await fileTypeFromFile('Unicorn.png'));
//=> {ext: 'png', mime: 'image/png'}

浏览器使用:

import {fileTypeFromStream} from 'file-type';

const url = 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg';

const response = await fetch(url);
const fileType = await fileTypeFromStream(response.body);

console.log(fileType);

更多API,可阅读官方文档: ​​file-type​

写在最后

我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,联系我,交个朋友),转发本文前需获得作者HullQin授权。我独立开发了​​《联机桌游合集》​​​,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费无广告。还独立开发了​​《合成大西瓜重制版》​​​。还开发了​​《Dice Crush》​​​参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这2个专栏里分享:​​《教你做小游戏》​​​、​​《极致用户体验》​​。


标签:info,文件,buffer,真好玩,JS,file,var,type,图片
From: https://blog.51cto.com/hullqin/5797921

相关文章

  • Nodejs相关ORM框架分析
    概述写这篇blog的原因,想找个node的ORM框架用用,确很难找到一篇对比分析这些ORM框架的文章,唯一找到了一篇,居然是通过star数来论英雄,我觉着很难服众,于是就找几个看看。后来又......
  • 在linux系统中安装Nodejs 的简单步骤说明
    一、首先我们要下载Nodejs安装包 1、可以从官网上https://nodejs.org/zh-cn/download/ ,下载合适自己的安装包。大家可以根据自己的服务器下载不同的安装包,通过uname......
  • Nodejs:ESModule和commonjs,傻傻分不清
    最近写nodejs脚本的时候遇到了commonjs和ESModule的问题,正好之前用得稀里糊涂的,这次好好学习一下。ESModule导出仅导出namedexports:命名导出,每次可以导出一个或......
  • js 加减乘除取余运算
    1.取整//丢弃小数部分,保留整数部分parseInt(5/2)//22.向上取整//向上取整,有小数就整数部分加1Math.ceil(5/2)//33.向下取整//向下取整,丢弃小数部分......
  • [RxJS] merge - build count down example
    import{interval,fromEvent,of,merge,empty}from'rxjs';import{scan,mapTo,takeWhile,takeUntil,tap,startWith,switchMap}from'rxjs/operators';/......
  • JSON Crack 数据可视化工具
    JSONCrack简介JSONCrack是一个很方便的JSON数据可视化工具。该项目不是简单的展示JSON数据,而是将其转化为类似思维导图的形式,支持放大/缩小、展开/收缩、搜索节......
  • pytorch+Unet图像分割:将图片中的盐体找出来
    向AI转型的程序员都关注了这个号????????????机器学习AI算法工程  公众号:datayx 什么是图像分割问题呢?简单的来讲就是给一张图像,检测是用框出框出物体,而图像分割分出一......
  • 通过百度文字识别的API来实现把图片内容写入到txt文件当中【多测师】
    1、首先去百度注册一个账户,然后选择对应的识别类型创建对应的应用,获取AppID,APIKey,SecretKey,请参考百度官方接入文档http://ai.baidu.com/docs#/Begin/top2、官方使用文档......
  • JSP笔记以及理解
    时间:2020/4/21前言:课件笔记、JSP的缺点笔记来源:老师的课件一、课件笔记1JSP(Javaserverpages)是一种用于开发动态网页的技术,文件后缀名是.jsp在JSP页面中可以嵌套Java代码,为......
  • Vue 结合Sortablejs实现table行排序
    场景在一个列表展示页面上,使用了表格组件,原有组件本身不支持拖拽功能,需求要求在列表的基础上支持行拖拽排序。因此引入了www.sortablejs.com插件。问题引入Sortablejs后......