首頁  >  文章  >  web前端  >  透過Canvas及File API縮放並上傳圖片完整範例_html5教學技巧

透過Canvas及File API縮放並上傳圖片完整範例_html5教學技巧

WBOY
WBOY原創
2016-05-16 15:49:071538瀏覽

範例網址:Canvas Resize Demo
原文作者:Dr. Tom Trenka
原文日期: 2013年8月6日
翻譯日期:2013年8月8日

Tom Trenka 能為"我"的部落格寫一篇文章,對我來說是一個巨大的榮譽。 Tom是Dojo框架的最初貢獻者之一,也是我在SitePen公司的良師益友.我見證了他最頂級的天才能力,並且他總是第一個以前瞻性的解決方案預見了很多棘手的問題。他總是站在局外思考,打破常規但卻堅實可靠地解決邊緣問題。本文就是一個完美的例子。
最近我總是被問道要創造一個用戶介面API,允許用戶上傳圖片到伺服器上(伴隨其他的事情),並能在我們公司提供支援的大量網站的客戶端上使用。通常來說這都是很容易的事情-建立一個form表單,加入一個file類型的input輸入框,讓使用者從電腦裡選擇圖片,並在form標籤上設定enctype="multipart/form-data"表單屬性,然後上傳即可。非常簡單,不是嗎?事實上,這裡有一個足夠簡單的例子;點擊進入
但是如果你想要透過某些方式預先處理一下圖片再上傳,那該怎麼辦?比方說,你必須先壓縮圖片尺寸,或是需要圖片只能是某些種類的格式,如 png 或jpg,你怎麼辦?
用canvas來解決!

Canvas簡介
canvas 是一個HTML5新增的DOM元素,允許用戶在頁面上直接地繪製圖形,通常是使用JavaScript.而不同的格式標準也是不同的,例如SVG是光柵API(raster API) 而VML卻是向量API(vector API).可以考慮使用Adobe Illustrator(向量圖)作圖與使用Adobe Photoshop (光柵圖)作圖的區別。

在canvas(畫布)上能做的事情就是讀取和渲染圖像,並且允許你透過JavaScript操縱影像資料。已經有很多現存的文章來為你演示基本的圖像處理——主要關注與各種不同的圖像過濾技術( image filtering techniques)——但我們需要的僅僅是縮放圖片並轉換到特定的文件格式,而canvas完全可以做到這些事。

我們假定的需求,例如影像高度不超過100像素,不管原始影像有多高。基本的代碼如下所示:

複製代碼
代碼如下:

//參數,最大高度
var MAX_HEIGHT = 100;
// 渲染
function render(src){
// 建立一個Image 物件
var image = new Image();

var image = new Image();
// 綁定load 事件處理器,在載入完成後執行
image.onload = function(){
// 取得canvas DOM 物件
var canvas = document.getElementById("myCanvas");
// 若高度超標
if(image.height > MAX_HEIGHT) {
// 寬度等比例縮放*=
image.width *= MAX_HEIGHT / image.height;
image.height = MAX_HEIGHT;
}
// 取得canvas的2d 環境物件,
// 可以理解Context是管理員,canvas是房子
var ctx = canvas.getContext("2d");
// canvas清屏
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 重設canvas寬高
canvas.width = image.width;
canvas.height = image.height;
// 將影像繪製到canvas上
ctx.drawImage(image, 0, 0, image.width, image.height);
// !!! 注意,image 沒有加入到dom之中
};
// 設定src屬性,瀏覽器會自動載入。
// 記住必須先綁定事件,才能設定src屬性,否則會出同步問題。
image.src = src;
};
在上面的範例中,你可以使用canvas 的toDataURL() 方法取得影像的Base64編碼的值(可以類似理解為16進位字串,或二進位資料流).
注意: canvas 的toDataURL () 取得的URL以字串開頭,有22個無用的資料"data:image/png;base64,",需要在客戶端或服務端進行過濾.
原則上只要瀏覽器支持,URL位址的長度是沒有限制的,而1024的長度限制,是老一代IE所獨有的。

請問,如何取得我們需要的影像呢?
好孩子,很高興你能這麼問。你並不能透過File 輸入框來直接處理,你從這個檔案輸入框元素所能取得的只是使用者所選檔案的path路徑。按照常規想像,你可以透過這個path路徑資訊來載入圖像,但是,在瀏覽器裡面這是不切實際的。 (譯者註:瀏覽器廠商必須確保自己的瀏覽器絕對安全,才能獲得市場,至少避免媒體的攻擊,如果允許這樣做,那惡意網址可以通過拼湊文件路徑來嘗試獲取某些敏感信息).
為了實現這個需求,我們可以使用HTML5的File API 來讀取用戶磁碟上的文件,並用這個file來作為圖像的來源(src,source).

File API簡介
新的File API介面是在不違反任何安全沙盒規則下,讀取並列出使用者檔案目錄的途徑- 透過沙盒(sandbox)限制,惡意網站並不能將病毒寫入用戶磁碟,當然更不能執行。
我們要使用的檔案讀取物件叫做 FileReader,FileReader允許開發者讀取檔案的內容(具體瀏覽器的實作方式可能大不相同)。

假設我們已經取得了映像檔的path路徑,那麼依賴前面的程式碼,使用FileReader來載入和渲染影像就變得很容易了:

複製程式碼
程式碼如下:

// 載入圖片檔案(url路徑)
function loadImage(src){
/ / 過濾掉非image 類型的檔案
if(!src.type.match(/image.*/)){
if(window.console){
console.log("選擇的檔案類型不是圖片: ", src.type);
} else {
window.confirm("只能選取圖片檔案");
}
return;
}
//建立FileReader 物件並呼叫render 函數來完成渲染.
var reader = new FileReader();
// 綁定load事件自動回呼函數
reader.onload = function(e){
/ / 呼叫前面的render 函數
render(e.target.result);
};
// 讀取檔案內容
reader.readAsDataURL(src);
};

請問,如何取得文件呢?
小白兔,要有耐心!我們的下一步就是取得文件,當然有好多方法可以實現啦。例如:你可以用文字方塊讓使用者輸入檔案路徑,但很顯然大多數使用者都不是開發者,根本對輸入什麼值不了解.
為了使用者使用方便,我們採用 Drag and Drop API介面。

使用Drag and Drop API
拖曳介面(Drag and Drop)非常簡單-在大多數的DOM元素上,你都可以透過綁定事件處理器來實作. 只要使用者從磁碟上拖曳一個檔案到dom物件上並放開滑鼠,那我們就可以讀取這個檔案。程式碼如下:

複製程式碼
程式碼如下:

function infunction infunction 🎜>// 取得DOM元素物件
var target = document.getElementById("drop-target");
// 阻止dragover(拖曳到DOM元素上方) 事件傳遞
target.addEventListener("dragover ", function(e){e.preventDefault();}, true);
// 拖曳並放開滑鼠的事件
target.addEventListener("drop", function(e){
// 阻止預設事件,以及事件傳播
e.preventDefault();
// 呼叫前面的載入影像函數,參數為dataTransfer物件的第一個檔案
loadImage(e.dataTransfer.files[ 0]);
}, true);
var setheight = document.getElementById("setheight");
var maxheight = document.getElementById("maxheight");
setheight.addList( click", function(e){
//
var value = maxheight.value;
if(/^d $/.test(value)){
MAX_HEIGHT = parseInt(value);
}
e.preventDefault();
},true);
var btnsend = document.getElementById("btnsend");
btnsend.addEventListener("clicke", function("clicke" ){
//
sendImage();
},true);
};


我們還可以做一些其他的處理,例如顯示預覽圖。但如果不想壓縮圖片的話,那很可能沒什麼用。我們將採用Ajax透過HTTP 的post方式上傳圖片資料。下面的例子是使用Dojo框架來完成請求的,當然你也可以採用其他的Ajax技術來實現.
Dojo 程式碼如下:

複製代碼
代碼如下:

// 譯者並不懂Dojo,所以將在後面附上jQuery的實現
// Remember that DTK 1.7 is AMD!
require(["dojo/request"], function(request){
// 設定請求URL,參數,以及回呼。
request.post("image-handler.php", {
data: {
imageName: "myImage.png",
imageData: encodeURIComponent(document.getElementById("canvas").toDataURL("image/png"))
}
}
} ).then(function(text){
console.log("The server returned: ", text);
});
});


jQuery 實作如下:
複製程式碼
程式碼如下:


/// 上傳圖片,jQuery版
function sendImage(){
// 取得canvas DOM 物件
var canvas = document.getElementById("myCanvas");
// 取得Base64編碼後的影像數據,格式是字串
// "data:image/png;base64,"開頭,需要在客戶端或伺服器端將其去掉,後面的部分可以直接寫入檔案。
var dataurl = canvas.toDataURL("image/png");
// 為安全對URI進行編碼
// data:image/png;64, 開頭
var imagedata = encodeURIComponent( dataurl);
//var url = $("#form").attr("action");
// 1. 如果form表單不好處理,可以使用某個hidden隱藏域來設定請求地址
//
var url = $("input[name='action']").val() ;
// 2. 也可以直接用某個dom物件的屬性來取得
//
// var url = $("#imageaction").attr("action");
// 因為是string,所以伺服器需要對資料進行轉碼,寫檔案操作等。
// 個人約定,所有http參數名字全部小寫
console.log(dataurl);
//console.log(imagedata);
var data = {
imagename: "myImage .png",
imagedata: imagedata
};
jQuery.ajax( {
url : url,
data : data,
type : "POST",
data : data,
type : "POST",
/ / 期待的回傳值類型
dataType: "json",
complete : function(xhr,result) {
//console.log(xhr.responseText);
var $tip2 = $( "#tip2");
if(!xhr){
$tip2.text('網路連線失敗!');
return false;
}
var text = xhr.responseText ;
if(!text){
$tip2.text('網路錯誤!');
return false;
}
var json = eval("(" text ")" );
if(!json){
$tip2.text('解析錯誤!');
return false;
} else {
$tip2.text(json.message) ;
}
//console.dir(json);
//console.log(xhr.responseText);
}
});
};


OK,搞定!你還需要做的,就是創建一個只管的使用者介面,並允許你控制圖片的大小。上傳到伺服器端的數據,並不需要處理enctype為multi-part/form-data 的情況,僅僅一個簡單的POST表單處理程序就可以了.
好了,下面附上完整的代碼示例:
複製程式碼
程式碼如下:


字串路徑= request.getContextPath() ;
String basePath = request.getScheme() "://" request.getServerName() ":" request.getServerPort() 路徑"/";
%>



透過Canvas及File API縮放並上傳圖片







//參數,最大高度
var MAX_HEIGHT = 100 ;
// 渲染
function render(src){
// 建立一個Image 物件
var image = new Image();
// 綁定載入事件處理器,載入完成後來執行
image.onload = function(){
// 取得canvas DOM 物件
var canvas = document.getElementById("myCanvas") ;
// 如果高度超標
if( image.height > MAX_HEIGHT) {
// 寬度等縮放*=
image.width *= MAX_HEIGHT / image.height;
image.height = MAX_HEIGHT;
}
image.height = MAX_HEIGHT;
}
}
/取得canvas的2d環境對象,
//可以理解Context是管理員,canvas是房子
var ctx = canvas.getContext("2d");
// canvas 清屏
ctx.clearRect (0, 0, canvas.width, canvas.height);
//重設canvas寬高
canvas.width = image.width;
canvas.height = image.height;
/ / 將影像強度到canvas上
ctx.drawImage(image, 0, 0, image.width, image.height);
//!!! 請注意,圖片未加入 dom
};
};
// 設定src 屬性,瀏覽器會自動載入。
// 記住必須先綁定事件,才能設定 src 屬性,否則會出同步問題。
image.src = src;
};
// 載入圖片檔案(url路徑)
function loadImage(src){
//過濾掉非映像類型的檔案
if(!src.type.match(/image.*/ )){
if(window.console){
console.log("選取的檔案類型不是圖片: ", src.type);
} else {
window.confirm("只能選擇圖片檔案");
}
回傳;
}
// 建立FileReader 物件並呼叫render 函數來完成渲染。
var reader = new FileReader();
// 結合load事件自動回呼函數
reader.onload = function(e){
//呼叫前面的render函數
render( e.target.result);
};
//讀取檔案內容
reader.readAsDataURL(src);
};
// 上傳圖片,jQuery 版
function sendImage(){
// 取得canvas DOM 物件
var canvas = document.getElementById("myCanvas");
//取得Base64編碼後的圖片數據,格式為字串
// "data:image/png;base64,"開頭,需要在客戶端或伺服器端將其前面,後面的部分可以直接
var dataurl = canvas.toDataURL("image/png"); 寫入檔案。
// 為安全對URI進行編碼
// data:image/png;base64, 底層
var imagedata =encodeURIComponent(dataurl);
//var url = $("#form" ).attr("action");
// 1.如果表單表單不好處理,可以使用某個隱藏域來設定請求位址
// >
var url = $("input[name='action']").val();
// 2. 也可以直接用某個dom物件的屬性來取得
//
// var url = $("#imageaction").attr("action");
//因為是字串,所以伺服器需要對資料進行轉碼,寫檔案操作等。
// 個人約定,所有http名稱參數全部小寫
console.log(dataurl);
//console.log(imagedata);
var data = {
imagename: "myImage .png",
imagedata: imagedata
};
jQuery.ajax( {
url : url,
data : data,
type : "POST",
data : data,
type : "POST",
/ /期待的回傳值類型
dataType: "json",
完整:function(xhr,result) {
//console.log(xhr.responseText);
var $tip2 = $( "#tip2");
if(!xhr){
$tip2.text('網路連線失敗!');
return false;}
var text = xhr.responseText;
if(!text){
$tip2 .text('網路錯誤!');
回傳false
}
var json = eval("(" text ")");
if(!json){
$ tip2.text('解析錯誤!');
return false
} else {
$tip2.text(json.message);
/ /console.dir(json );
//console.log(xhr.responseText)
}
}); }; function init(){ //獲取DOM元素物件var target = document.getElementById("drop-target");
// 阻止dragover(拖曳到DOM元素上方) 事件傳遞
target.addEventListener("dragover", function(e){e.preventDefault( );}, true);
// 拖曳並放開滑鼠的事件
target.addEventListener("drop", function(e){
// 阻止預設事件,以及事件傳播
e.preventDefault();
// 呼叫前面的載入影像函數,參數為dataTransfer物件的第一個檔案
loadImage(e.dataTransfer.files[0]);
}, true) ;
var setheight = document.getElementById("setheight");
var maxheight = document.getElementById("maxheight");
setheight.addEventListener("click", function(e){
//
var value = maxheight.value;
if(/^d $/.test(value)){
MAX_HEIGHT = parseInt(value);
}
e.preventDefault( );
},true);
var btnsend = document.getElementById("btnsend");
btnsend.addEventListener("click", function(e){
//
sendImage ();
},true);
};
window.addEventListener("DOMContentLoaded", function() {
//
init();
},false) ;




透過Canvas及File API縮放並上傳圖片


從資料夾拖曳一張照片到下方的盒子裡, canvas 和JavaScript將會自動的進行縮放.






拖曳圖片檔案到這裡...






縮圖:








陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn