JS 判断文件是否是图片

2,339 阅读2分钟

JS 判断文件是否为图片,原理就是检测文件的 Magic Number

对 JPEG、GIF、PNG 的 magic number 的检测如下:

// 使用magicNumber判断图片类型
// 一句话形容magic Number就是:文件的唯一标识
// 一些比较常见的图片及其magic number:
// 图片类型	扩展名	magic number(以其开头)
// 对 JPEG、GIF、PNG 的 magic number 的检测如下:
const isImage = (buf) => {
	const pngMagic = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
	const jpeg_jfif = [0x4a, 0x46, 0x49, 0x46];
	const jpeg_exif = [0x45, 0x78, 0x69, 0x66];
	const jpegMagic = [0xFF, 0xD8, 0xFF, 0xE0];
	const gifMagic0 = [0x47, 0x49, 0x46, 0x38, 0x37, 0x61];
	const getGifMagic1 = [0x47, 0x49, 0x46, 0x38, 0x39, 0x61];
	// 6 bytes
	const isGif = data => (arrayEquals(data, gifMagic0) || arrayEquals(data, getGifMagic1))
	// 4 bytes
	const isJpeg = data => (arrayEquals(data, jpegMagic) || arrayEquals(data, jpeg_jfif) || arrayEquals(data, jpeg_exif))
	// 8 bytes
	const isPng = data => arrayEquals(data, pngMagic)
	const arraycopy = (src, index, dist, distIndex, size) => {
		for (let i = 0; i < size; i++) {
			dist[distIndex + i] = src[index + i]
		}
	}
	const arrayEquals = (arr1, arr2) => {
		if (!arr1 || !arr2) {
			return false
		}
		if (arr1 instanceof Array && arr2 instanceof Array) {
			if (arr1.length != arr2.length) {
				return false
			}
			for (let i = 0; i < arr1.length; i++) {
				if (arr1[i] != arr2[i]) {
					return false
				}
			}
			return true
		}
		return false;
	}
	if (!buf || buf.length < 8) {
		return null;
	}
	let bytes = [];
	arraycopy(buf, 0, bytes, 0, 6);
	if (isGif(bytes)) {
		return "image/gif";
	}
	bytes = [];
	arraycopy(buf, 6, bytes, 0, 4);
	if (isJpeg(bytes)) {
		return "image/jpeg";
	}
	bytes = [];
	arraycopy(buf, 0, bytes, 0, 8);
	if (isPng(bytes)) {
		return "image/png";
	}
	return null;
}
const checkImage = file => {
	if (!file || !(file instanceof File)) throw '文件不存在'
	return new Promise((resolve, reject) => {
		let reader = new FileReader();
		reader.onload = (evt) => {
			//取前11Bytes转换成Uint8Array
			let fileBuf = new Uint8Array(evt.target.result.slice(0, 11));
			//调用之前的方法判断是不是图片
			//如果不是返回null,否则返回mimeType
			let mime = isImage(fileBuf);
			resolve(mime)
		};
		reader.onerror = ev => {
			resolve(null)
		}
		//读取文件为ArrayBuffer
		reader.readAsArrayBuffer(file);
	})
}

// 获取图片文件的信息
const getImgFileInfo = file => {
	if (!file || !(file instanceof File)) throw '文件不存在'
	return new Promise((resolve, reject) => {
		const url = window.URL || window.webkitURL
		// 手动创建一个Image对象
		const img = new Image()
		// 创建Image的对象的url       
		img.src = url.createObjectURL(file)
		// onload 加载完成后触发
		img.onload = () => resolve({ width: img.width, height: img.height })
		// onload 加载完成后触发
		img.onload = () => resolve({ success: true, width: img.width, height: img.height })
		// onerror
		img.onerror = () => resolve({ success: false })
	})
}

在 HTML 中使用如下:

function handleFileSelect(evt) {
	var files = evt.target.files;
	if (files[0]) {
		checkImage(files[0]).then(isImg => {
			if (isImg) {
				// 是图片文件 ....
			} else {
				// 不是图片文件 ....
			}
		})
	}
}