搜尋
首頁web前端js教程JavaScript關於圖片處理與合成的方法詳解

JavaScript關於圖片處理與合成的方法詳解

Mar 05, 2018 am 09:05 AM
javascriptjs合成

圖片處理現在已經成為我們生活中的剛需,想必大家也常有了這方面的需求。實際前端業務中,也常常會有很多的項目需要用到圖片加工處理。由於過去一段時間公司的業務需求,讓我在這方面累積了一些乾貨,趁著年後這段時間總結成一系列文章與大家分享,希望能對各位努力中的前端童鞋帶來啟發和幫助。

本系列分成以下4個部分:

  1. 基礎類型圖片處理技術的縮放與裁切;

  2. 基礎類型圖片處理技術之圖片合成;

  3. 基礎類型圖片處理技術之文字合成;

  4. 演算法類型圖片處理技術;

透過這些積累,我封裝了幾個項目中常用的功能:

圖片合成: Example Git 圖片裁剪: Example Git 人像摳除: Example Git

嘮叨完這些老套路後,我們開始起飛!

首先,我在這裡將前端圖片處理暫且分成兩種類型:基礎類型與演算法類型;

基礎類型的圖片處理技術: 圖片縮放,旋轉,添加邊框,圖片合成,拼圖等業務都屬於基礎類型的圖片處理,其區分點在於無需使用像素級別的演算法,而是透過計算改變圖片的尺寸及位置等來改造圖片。例如常用的貼紙功能:

演算法類型的圖片處理: 這類型的圖片處理複雜度較高,特點是透過像素層級演算法對圖片的像素點進行RGBA通道值等進行改造,例如我們使用photshop或美圖秀等工具對圖片進行的美顏/ 濾鏡/ 黑白/ 摳圖/ 模糊等操作,這類型的重點主要在於演算法和效能層面。例如常用的妝容功能:

本系列首先從基礎型別處理開啟我們的旅程。基礎類型的圖片處理在實際專案中有著大量的使用場景,主要是運用canvas的能力來完成,不存在效能和相容性問題,能夠達到線上運行標準。我在這裡將基礎類型的圖片處理大致的分成以下幾種類型,這些類型基本上能涵蓋日常所有業務場景:

  • 圖片的縮放;

  • #圖片的裁切;

  • 圖片的合成;

#圖片與圖片的合成,例如貼紙,邊框,浮水印等;為圖片添加文字;為圖片添加基礎幾何圖形;

Tips: 我已將該類型的圖片處理場景封裝成了一個插件,基本上能應付所有這類型圖片處理的需求,GIT地址(歡迎探討);

在介紹具體的功能前,由於圖片的繪製完全的依賴於圖片的加載,因此先來了解一些前置知識。

1、圖片的跨域

首先,圖片載入並繪製涉及了圖片的跨域問題,因此如果是一張在線的圖片,需要在圖片伺服器上設定跨域頭,並且在前端載入圖片之前將<img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/054/025/cf56c86a64cb807fa8da6a08631d05a1-2.jpg?x-oss-process=image/resize,p_40" class="lazy" alt="JavaScript關於圖片處理與合成的方法詳解" >標籤的crossOrigin設定為*,否則繪製到畫布的時候會報跨域的錯誤。

Tips: 這裡累積了一些小坑,可以跟大家分享下:

  1. #crossOrigin需要嚴格設置,既只有是線上圖片時,才設置,而本地路徑或base64時,則一定不能設置,否則在某些系統下會報錯,導致圖片加載失敗;

  2. ##當當項目為本機套件環境時,例如內建於

    App時,crossOrigin值無效,webview的安全機制會導致無論該值設定與否,都會報跨域的錯誤。解決方法是:需要將所有圖片轉換成base64才能正確繪製;

  3. #crossOrigin值一定要在圖片載入之前設置,即為<img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/054/025/cf56c86a64cb807fa8da6a08631d05a1-2.jpg?x-oss-process=image/resize,p_40" class="lazy" alt="JavaScript關於圖片處理與合成的方法詳解" >賦值src之前進行設置,否則無效;

2、圖片的載入

由於

canvas的繪製需要的是已經載入完成的圖片,我們需要確保繪製的素材圖片是已經載入完成的,因此我們需要使用<img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/054/025/cf56c86a64cb807fa8da6a08631d05a1-2.jpg?x-oss-process=image/resize,p_40" class="lazy" alt="JavaScript關於圖片處理與合成的方法詳解" >onload事件,可以使用html中已存在的圖片,或是用js建立一個圖片物件:


function loadImage(image, loader, error){
 // 创建 image 对象加载图片;
 let img = new Image();
 
 // 当为线上图片时,需要设置 crossOrigin 属性;
 if(image.indexOf(&#39;http&#39;) == 0)img.crossOrigin = &#39;*&#39;;
 img.onload = () => {
 loaded(img);
 
 // 使用完后清空该对象,释放内存;
 setTimeout(()=>{
  img = null;
 },1000);
 };
 img.onerror = () => {
 error(&#39;img load error&#39;);
 };
 img.src = image;
}

介紹圖片載入的前置知識後,我們先來看看最簡單的圖片處理---縮放與裁切!

Tips: 相信大家閱讀本文時,如果對
canvas不太了解,可以查詢下對應的API文件即可,本文不再對 canvas基礎API做詳細解說。

一、圖片的縮放

图片的缩放最常见的场景是做图片的压缩。在保证图片清晰的前提下通过合理地缩小图片尺寸,能大大的降低图片的大小。在实际应用场景中,有着广泛的用途。例如图片上传时,用户自主上传的图片可能是一张非常大的尺寸,例如现在手机所拍摄的照片尺寸经常能达到1920*2560的尺寸,大小可能超过5M。而在项目中,我们可能并不需要用到这么大的尺寸,此时对图片的压缩能大大的优化加载速度和节省带宽;

1、新建一个canvas画布,将宽高设置为需要压缩到的尺寸;

该画布既为图片缩放后的尺寸,此处有个点是需要保证图片的比例不变, 因此需要通过计算得出画布的宽与高:


let imgRatio = img.naturalWidth / img.naturalHeight;

// 创建一个画布容器;
let cvs = document.createElement(&#39;canvas&#39;);

// 获取容器中的画板;
let ctx = cvs.getContext(&#39;2d&#39;);
cvs.width = 1000;
cvs.height = cvs.width / imgRatio;

2、将图片画入后再导出成base64;

这里使用2个最常用的方法:

ctx.drawImage(image, dx, dy, dw, dh): 这个方法其实最多可以接收9个参数, 实现压缩,只需要使用其中的5个参数即可, 其余参数在其它部分使用到时再做详解;

image : 需要绘制的图片源,需要接收已经 加载完成 的HTMLImageElementHTMLCanvasElement或者HTMLVideoElement; dx / dy : 相对于画布左上角的绘制起始点坐标; dw / dh : 绘制的宽度和高度,宽高比例并不锁定,可使图片变形;

cvs.toDataURL(type, quality): 该方法用于将画布上的内容导出成 base64 格式的图片,可配置2个参数;

type: 图片格式, 一般可以使用 image/png 或者 image/jpeg, 当图片不包含透明时,建议使用jpeg,可使导出的图片大小减小很多; quality: 图片质量,可使用0~1之间的任意值;经过测试,该值设置成0.9时较为合适,可以有效减小图片文件大小且基本不影响图片清晰度,导出后的 base64 既为压缩后的图片;

Tips: 此处有个坑, 想导出jpg格式的图片必须用image/jpeg,不能使用image/jpg


// 将原图等比例绘制到缩放后的画布上;
ctx.drawImage(image, 0, 0, cvs.width, cvs.height);

// 将绘制后的图导出成 base64 的格式;
let b64 = cvs.toDataURL(&#39;image/jpeg&#39;, 0.9);

3.多种格式的图片转换成base64;

我们常用的图片上传功能,我们使用的是原生的<input type="file">标签,此时获取到的是File格式的图片,图片的格式各异且尺寸很大,我们应该压缩处理后再使用。

使用FileReader:


let file = e.files[0]; 
if(window.FileReader) { 
 let fr = new FileReader(); 
 fr.onloadend = e => {
 let b64 = e.target.result;
 
 // b64即为base64格式的用户上传图;
 }; 
 fr.readAsDataURL(file);
}

base64的图片使用刚才的canvas方式进行压缩的处理;

Tips: 这里有个小坑是,图片的EXIF信息中的方向值会影响图片的展示,在IOS会出现图片的宽高与图片的方向不匹配的问题,因此需要进行特殊处理,矫正图片的方向。方案:

1、可以使用 exif.js 来获取图片信息中的Orientation属性,利用canvas的旋转绘制来矫正;

2、这里有个 canvasResize.js 插件,可以解决从 Filebase64 的所有问题。

二、图片的裁剪

在实际项目中,由于图片的宽高比例各式各样,而展示和使用一般需要一个较为固定的比例,此时便需要将图片裁剪成我们需要的宽高比例,使用到的方式其实和图片的缩放基本一致,主要是通过调整 drawImagedx, dy参数来实现。原理其实是,将drawImage的绘制起始点(dx, dy)向上偏移,此时由于canvas已被我们设置成期望裁剪后的尺寸,而超出画布的部分不会绘制,从而达到裁剪的目的;通过灵活的设置值,基本可以完成各种图片裁剪需求,简单示例图(黑色框代表创建的画布的尺寸):

此处以需要将一张600*800的长方形图竖直居中裁剪为600*600的正方形图为例, 简单封装成一个功能函数:


// 使用方式:
let b64 = cropImage(img, {
 width : 600,
 height : 600,
});

// 居中裁剪
function cropImage(img, ops){
 // 图片原始尺寸;
 let imgOriginWidth = img.naturalWidth,
 imgOriginHeight = img.naturalHeight;
 
 // 图片长宽比,保证图片不变形;
 let imgRatio = imgOriginWidth / imgOriginHeight;
 
 // 图片裁剪后的宽高, 默认值为原图宽高;
 let imgCropedWidth = ops.width || imgOriginWidth,
 imgCropedHeight = ops.height || imgOriginHeight;
 
 // 计算得出起始坐标点的偏移量, 由于是居中裁剪,因此等于 前后差值 / 2;
 let dx = (imgCropedWidth - imgOriginWidth) / 2,
 dy = (imgCropedHeight - imgOriginHeight) / 2;

 // 创建画布,并将画布设置为裁剪后的宽高;
 let cvs = document.createElement(&#39;canvas&#39;);
 let ctx = cvs.getContext(&#39;2d&#39;);
 cvs.width = imgCropedWidth;
 cvs.height = imgCropedHeight;
 
 // 绘制并导出图片;
 ctx.drawImage(img, dx, dy, imgCropedWidth, imgCropedWidth / imgRatio);
 return cvs.toDataURL(&#39;image/jpeg&#39;, 0.9);
}

三、图片的旋转

图片的旋转的原理同样也是将图片绘制到画布上进行旋转后再导出。其实使用到的是canvasrotate方法;


let cvs = document.createElement(&#39;canvas&#39;);
let ctx = cvs.getContext(&#39;2d&#39;);

// 将参照点移动到画板的中心点;
ctx.translate(ctx.width/2, ctx.height/2);
// 旋转画板;
ctx.rotate = 90;
// 绘制图片;
ctx.drawImage(img);
// 导出得到旋转后的图片;
cvs.toDataURL();

这里有个比较特别的部分,就是这里旋转的是画布的画板部分,并不是整个画布容器,而画布容器外面不会被绘制,因此这里就会出现一个图像四个角被裁剪掉的问题:

解决的方式就是:

将画布容器放大,变成:

上面这个例子中,由于图片是正方形,因此将容器的宽高放大1.5倍便可保证图片不会被裁剪,而现实中的图片由于宽高比例不定,因此这个放大系数是一个动态的值:

Tips: 由于我们将画板基点移动到画布中心了,因此在绘制的时候,要相对于基点调整 dxdy;


// 创建画布,获取画板;
...

// 放大系数为
let iw = img.width, ih = img.height;
let ir = iw > ih ? iw / ih : ih / iw;

cvs.width = iw * ir * 1.5;
cvs.height = ih * ir * 1.5;
// 将参照点移动到画板的中心点;
ctx.translate(cvs.width/2, cvs.height/2);
// 旋转画板;
ctx.rotate = 90;

// 绘制图片;
ctx.drawImage(img, -cvs.width/2, -cvs.height/2);

// 导出图片;
...

总结

本文主要介绍了一些前端图片处理的前置知识:

图片处理技术分类;

基础类型图片处理技术;算法类型图片处理技术; 图片的跨域;图片的加载;

还有讲解了属于基础类型图片处理中最简单的两类:

图片的缩放;图片的裁剪;图片的旋转;

相信大家已经对图片的处理有了个大致的了解了。下篇文章,我们将继续深入研究基础类型中的图片合成,也是各种干货满满,美不胜收。

相关推荐:

PHP图片处理之多张图片合成一张的实例

关于微信小程序中图片处理的问题汇总

PHP图片处理类 phpThumb参数用法介绍

以上是JavaScript關於圖片處理與合成的方法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Python和JavaScript的未來:趨勢和預測Python和JavaScript的未來:趨勢和預測Apr 27, 2025 am 12:21 AM

Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

Python vs. JavaScript:開發環境和工具Python vs. JavaScript:開發環境和工具Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C/C在JavaScript口譯員和編譯器中的作用C/C在JavaScript口譯員和編譯器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具