# 图片相关
# 1、获取图片的原生尺寸
参数支持传入url或者一个HTMLImageElement, 返回Promise
function getImgRawSize(img) {
let _image = img;
return new Promise((resolve, reject) => {
if (!_image) {
reject(new Error('Please provide img param!'));
return;
}
if (_image instanceof HTMLImageElement) {
if (_image.naturalWidth) {
// 推荐使用 naturalWidth ,因为该值返回的是原始值,不会被属性影响
resolve({
width: _image.naturalWidth,
height: _image.naturalHeight
});
return;
}
if (_image.complete) {
// 如果没有 naturalWidth 且图片已加载完成,那么很大几率是不支持
// 为了防止被属性影响,我们要用空白的标签重新加载
img = img.src;
} else {
// 没有的话直接用
_image = img;
}
}
if (typeof img === 'string') {
_image = new Image();
_image.src = img;
}
_image.onload = function () {
resolve({
width: _image.naturalWidth || _image.width,
height: _image.naturalHeight || _image.height
});
};
_image.onerror = function (event) {
reject(event);
};
});
}
# 2、旋转图片
function rotateBase64Img(src, edg, callback) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var imgW; //图片宽度
var imgH; //图片高度
var size; //canvas初始大小
if (edg % 90 != 0) {
console.error('旋转角度必须是90的倍数!');
throw '旋转角度必须是90的倍数!';
}
edg < 0 && (edg = (edg % 360) + 360);
const quadrant = (edg / 90) % 4; //旋转象限
const cutCoor = { sx: 0, sy: 0, ex: 0, ey: 0 }; //裁剪坐标
var image = new Image();
image.crossOrigin = 'anonymous';
image.src = src;
image.onload = function() {
imgW = image.width;
imgH = image.height;
size = imgW > imgH ? imgW : imgH;
canvas.width = size * 2;
canvas.height = size * 2;
switch (quadrant) {
case 0:
cutCoor.sx = size;
cutCoor.sy = size;
cutCoor.ex = size + imgW;
cutCoor.ey = size + imgH;
break;
case 1:
cutCoor.sx = size - imgH;
cutCoor.sy = size;
cutCoor.ex = size;
cutCoor.ey = size + imgW;
break;
case 2:
cutCoor.sx = size - imgW;
cutCoor.sy = size - imgH;
cutCoor.ex = size;
cutCoor.ey = size;
break;
case 3:
cutCoor.sx = size;
cutCoor.sy = size - imgW;
cutCoor.ex = size + imgH;
cutCoor.ey = size + imgW;
break;
}
ctx.translate(size, size);
ctx.rotate((edg * Math.PI) / 180);
ctx.drawImage(image, 0, 0);
var imgData = ctx.getImageData(
cutCoor.sx,
cutCoor.sy,
cutCoor.ex,
cutCoor.ey
);
if (quadrant % 2 == 0) {
canvas.width = imgW;
canvas.height = imgH;
} else {
canvas.width = imgH;
canvas.height = imgW;
}
ctx.putImageData(imgData, 0, 0);
callback(canvas.toDataURL('image/png'));
};
}
# 3、图片压缩
下面是一个图片压缩的方法。或者可以借助一些三方库, 比如
compressorjs (opens new window)
应当会比下面的方法考虑更加全面一些
function compress(file, compress, callback) {
const reader = new FileReader()
reader.onload = function(evt) {
if (compress === false) {
callback(file)
return
}
// 启用压缩的分支
const img = new Image()
img.onload = function() {
const ratio = detectVerticalSquash(img)
const orientation = getOrientation(dataURItoBuffer(img.src))
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const maxW = compress.width
const maxH = compress.height
let w = img.width
let h = img.height
let dataURL
if (w < h && h > maxH) {
w = parseInt((maxH * img.width) / img.height)
h = maxH
} else if (w >= h && w > maxW) {
h = parseInt((maxW * img.height) / img.width)
w = maxW
}
canvas.width = w
canvas.height = h
if (orientation > 0) {
orientationHelper(canvas, ctx, orientation)
}
ctx.drawImage(img, 0, 0, w, h / ratio)
if (/image\/jpeg/.test(file.type) || /image\/jpg/.test(file.type)) {
dataURL = canvas.toDataURL('image/jpeg', compress.quality)
} else {
dataURL = canvas.toDataURL(file.type)
}
if (/;base64,null/.test(dataURL) || /;base64,$/.test(dataURL)) {
// 压缩出错,以文件方式上传的,采用原文件上传
console.warn(
'Compress fail, dataURL is ' +
dataURL +
'. Next will use origin file to upload.'
)
callback(file)
} else {
const blob = dataURItoBlob(dataURL)
blob.name = file.name
callback(blob)
}
}
img.src = evt.target.result
}
reader.readAsDataURL(file)
}
function getOrientation(buffer) {
const view = new DataView(buffer)
if (view.getUint16(0, false) != 0xffd8) return -2
const length = view.byteLength
let offset = 2
while (offset < length) {
const marker = view.getUint16(offset, false)
offset += 2
if (marker == 0xffe1) {
if (view.getUint32((offset += 2), false) != 0x45786966) return -1
const little = view.getUint16((offset += 6), false) == 0x4949
offset += view.getUint32(offset + 4, little)
const tags = view.getUint16(offset, little)
offset += 2
for (let i = 0; i < tags; i++)
if (view.getUint16(offset + i * 12, little) == 0x0112)
return view.getUint16(offset + i * 12 + 8, little)
} else if ((marker & 0xff00) != 0xff00) break
else offset += view.getUint16(offset, false)
}
return -1
}
function detectVerticalSquash(img) {
// 拍照在IOS7或以下的机型会出现照片被压扁的bug
let data
const ih = img.naturalHeight
const canvas = document.createElement('canvas')
canvas.width = 1
canvas.height = ih
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0)
try {
data = ctx.getImageData(0, 0, 1, ih).data
} catch (err) {
console.log('Cannot check verticalSquash: CORS?')
return 1
}
let sy = 0
let ey = ih
let py = ih
while (py > sy) {
const alpha = data[(py - 1) * 4 + 3]
if (alpha === 0) {
ey = py
} else {
sy = py
}
py = (ey + sy) >> 1 // py = parseInt((ey + sy) / 2)
}
const ratio = py / ih
return ratio === 0 ? 1 : ratio
}
# 4、图片的延迟加载的一些方式
function loadImage(obj, url, callback) {
var img = new Image();
img.src = url;
// 判断图片是否在缓存中
if (img.complete) {
callback.call(img, obj);
return;
}
// 图片加载到浏览器的缓存中回调函数
img.onload = function () {
callback.call(img, obj);
};
}
function showImage(obj) {
obj.src = this.src;
}
var imgs = document.querySelectorAll('img');
for (var i = 0; i < imgs.length; i++) {
var url = imgs[i].dataset.src;
loadImage(imgs[i], url, showImage);
}
就是先用img元素占位, 可以给一个默认的占位的图片, 这个资源可以比较小,真实的url可以保存在data-src中, 然后在一些load或者mount的钩子回调中执行这样子的一个操作。提供一种思路吧。 或者上划加载更多的懒加载方式,或者判断位置的那种可见再加载。