工做中遇到了關於圖片的處理方法,作個記錄分享給小夥伴們。javascript
作法:html
canvas
base64
的格式下面先提供代碼,並對代碼作進一步的講解:html5
picWaterMark = ({ // 1
url = '',
textAlign = 'left',
font = "30px Microsoft Yahei",
fillStyle = 'rgba(255, 255, 255, 0.8)',
content = '請勿外傳',
callback = null,
} = {}) => {
const img = new Image(); // 2
img.src = url;
img.crossOrigin = 'anonymous'; // 3
img.onload = function () {
const canvas = document.createElement('canvas');
canvas.width = img.width; // 4
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, imageWidth, imageHeight);
ctx.textAlign = textAlign; // 5
ctx.font = font;
ctx.fillStyle = fillStyle;
ctx.fillText(content, 10, 20);
let base64Url = '';
base64Url = canvas.toDataURL("image/jpeg", 0.5); // 6
callback && callback(base64Url); // 7
}
}
複製代碼
代碼中註釋的數字,是我下文要說明的內容哈。java
傳參我這裏定義成一個對象,小夥伴能夠自行定義哈,對於上面的傳參值,小夥伴們也能夠直接寫死在代碼中。ios
base64
格式的圖片或者圖片的 url
。建立一個圖片對象用來存放咱們要改造的圖片。canvas
解決跨域問題。跨域
當在 canvas
中繪製一張外鏈圖片時,咱們會遇到一個跨域問題。打開瀏覽器調試會發現如下錯誤:瀏覽器
img.html:23 Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.安全
這是受限於 CORS 策略,會存在跨域問題,雖然可使用圖像,可是繪製到畫布上會污染畫布,一旦畫布被污染,就沒法提取畫布上的數據。服務器
好比沒法使用使用畫布 toBlob()
,toDataURL()
,或 getImageData()
方法;當使用這些方法的時候 會拋出上面的安全錯誤。
加上第三點的代碼就能解決這個問題。
這裏若是將原圖的長寬縮小,是能夠對圖片進行壓縮處理的。
有了這份參考手冊和上面的代碼作參考,對於自定義水印內容應該是沒有難度了。
將畫布數據提取出來,toDataURL
的第二個參數是對圖片進行壓縮,是個選填值,小夥伴能夠根據須要自行定義。
生成新的圖像數據後進行接下來的操做。
若是咱們使用的 input
, 設置 type='file'
,進行圖片上傳,須要將文件數據轉化成 base64
的形式。
const Page: FC = () => {
// 將圖片轉化爲 base64 的格式
const transformFileToDataUrl = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = e => {
const { result } = e.target;
resolve({
result,
});
};
});
}
const fileChange = files => {
const file = files.target.files[0];
transformFileToDataUrl(file).then(data => {
console.log(data.result);
})
};
return (
<input type='file' onChange={fileChange} /> ) } 複製代碼
html5
+ canvas
進行移動端手機照片上傳時,發現ios手機上傳豎拍照片會逆時針旋轉90度,橫拍照片無此問題;Android手機沒這個問題。
所以解決這個問題的思路是:獲取到照片拍攝的方向角,對非橫拍的ios照片進行角度旋轉修正。
利用 exif.js
讀取照片的拍攝信息。可到官網 查看詳細文檔。
這裏主要用到 Orientation
屬性。
Orientation
屬性說明以下:
旋轉角度 | 參數 |
---|---|
0° | 1 |
順時針90° | 6 |
逆時針90° | 8 |
180° | 3 |
根據旋轉角度進行修正。
修改上述 transformFileToDataUrl()
的方法,以下:
// 將圖片轉化爲 base64 的格式
const transformFileToDataUrl = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = e => {
const { result } = e.target;
EXIF.getData(file, function () {
EXIF.getAllTags(this);
const orientation = EXIF.getTag(this, "Orientation");
resolve({
result,
orientation
});
});
};
});
}
複製代碼
export const dataURLtoFile = (dataurl, filename) => {
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
複製代碼
如下代碼爲網絡上 copy 過來,侵刪。
入參先寫在前頭:
data
是個對象,裏面放兩個字段,dataUrl
: base64 圖片數據格式,orientation
: 可能須要用到的旋轉字段,若是不須要設置固定值爲 1
便可。true
true
export const compress = (
data, // { dataUrl: '', orientation: 默認值爲1 }
callback,
compressionRatio = 20,
compress = true,
cross = false,
) => {
/** * 壓縮圖片 * @param data file文件 數據會一直向下傳遞 * @param callback 下一步回調 * @compressionRatio 壓縮比例 * @compress 是否壓縮 */
// const imgCompassMaxSize = 200 * 1024; // 超過 200k 就壓縮
// const imgFile = data.file;
const orientation = data.orientation || 1;
const img = new window.Image();
img.src = data.dataUrl;
if (cross) {
// img.setAttribute("crossOrigin", 'Anonymous')
img.crossOrigin = "*";
}
img.onload = function () {
let drawWidth, drawHeight, width, height;
drawWidth = this.naturalWidth;
drawHeight = this.naturalHeight;
// 改變一下圖片大小
let maxSide = Math.max(drawWidth, drawHeight);
if (maxSide > 1024) {
let minSide = Math.min(drawWidth, drawHeight);
minSide = (minSide / maxSide) * 1024;
maxSide = 1024;
if (drawWidth > drawHeight) {
drawWidth = maxSide;
drawHeight = minSide;
} else {
drawWidth = minSide;
drawHeight = maxSide;
}
}
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = width = drawWidth;
canvas.height = height = drawHeight;
// 判斷圖片方向,重置 canvas 大小,肯定旋轉角度,iphone 默認的是 home 鍵在右方的橫屏拍攝方式
switch (orientation) {
// 1 不須要旋轉
case 1: {
// ctx.drawImage(img, 0, 0, drawWidth, drawHeight);
ctx.clearRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
break;
}
// iphone 橫屏拍攝,此時 home 鍵在左側 旋轉180度
case 3: {
ctx.clearRect(0, 0, width, height);
ctx.translate(0, 0);
ctx.rotate(Math.PI);
ctx.drawImage(img, -width, -height, width, height);
break;
}
// iphone 豎屏拍攝,此時 home 鍵在下方(正常拿手機的方向) 旋轉90度
case 6: {
canvas.width = height;
canvas.height = width;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.translate(0, 0);
ctx.rotate((90 * Math.PI) / 180);
ctx.drawImage(img, 0, -height, width, height);
break;
}
// iphone 豎屏拍攝,此時 home 鍵在上方 旋轉270度
case 8: {
canvas.width = height;
canvas.height = width;
ctx.clearRect(0, 0, width, height);
ctx.translate(0, 0);
ctx.rotate((-90 * Math.PI) / 180);
ctx.drawImage(img, -width, 0, width, height);
break;
}
default: {
ctx.clearRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
break;
}
}
let compressedDataUrl;
if (compress) {
compressedDataUrl = canvas.toDataURL(
"image/jpeg",
compressionRatio / 100
);
} else {
compressedDataUrl = canvas.toDataURL("image/jpeg");
}
data.compressedDataUrl = compressedDataUrl;
delete data.orientation;
callback(compressedDataUrl, data);
};
};
複製代碼
//兩個參數:所須要截圖的元素id,截圖後要執行的函數, canvas爲截圖後返回的最後一個canvas
html2canvas(document.getElementById('id')).then(function(canvas) {document.body.appendChild(canvas);});
複製代碼
html2canvas
能夠設置一些參數,入參請看官網
若是是在移動端進行截屏嘗試的話,可能會存在大屏手機沒法截屏的狀況。
這是由於 canvas 有面積大小的限制,因此建議減小 canvas
的高度來保證 html2canvas
的正常使用。
舉個例子,在釘釘微應用的開發中,官方有提供一個圖片預覽的方法。
截屏出來的 base64
數據在 ios 上可以正常的展現,可是在安卓機子上確失效。
建議:base64
的數據先上傳到服務器上,用返回回來的 url 進行圖片預覽來達到目的。