跟canvas
有關的處理,時常在最後我們需要預覽、上傳、下載影像
這個單元就來說說這些動作該如何實現。
當我們有input
允許使用者上傳檔案時,可以設定該input
只accept影像檔案。
確保使用者使用這個input
只能上傳影像,就能確保這個檔案可以用於canvas
JSbin Demo
HTML
<div class="container">
<input type="file" name="images" accept="image/*" multiple>
</div>
JavaScript
// 取得input
const input = document.querySelector('input')
// 當使用者修改內容(選擇檔案)
input.addEventListener('change', function(event){
const files = this.files // 取得所有 file
const container = this.parentNode // 設定一個preview容器
// 處理每一個檔案
Array.prototype.forEach.call(files, file => {
filePreview(file, container)
})
})
// 這個將會把file的預覽圖加入指定container
function filePreview(file, container) {
const url = URL.createObjectURL(file) // 建立檔案url
const image = new Image
image.style.width = '150px'
image.style.height = 'auto'
image.alt = file.name
image.addEventListener('load', function(event) {
container.appendChild(this)
})
image.src = url
}
下載很簡單,首先將canvas轉成一個ObjectURL接著定於連結即可
JSbin Demo
// 這裡首先建立並繪製一個canvas
// 這個 canvas 可以是任何你想指定的canvas
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = 150
canvas.height = 150
ctx.strokeStyle = 'rgba(255, 0, 0, .5)'
ctx.arc(75, 75, 50, 0, Math.PI*2, false)
ctx.lineWidth = '5'
ctx.stroke()
document.body.appendChild(canvas)
// 使用canvas的toBlob方法將其轉為blob
const blob = canvas.toBlob(blob => {
// 有了blob我們就可以使三 URL.createObjectURL建立url
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.innerText = 'Download'
link.href = url // 將url 設定給 a tage 的 href
link.download = 'circle.png' // 設定 download name
document.body.appendChild(link) // 加到指定元素之中,即可點擊下載
})
比起預覽、下載,上傳動作相對複雜,但也不算太困難
這裡的上傳是指,將一個canvas轉為檔案,之後使用Ajax(fetch)將該檔送至後端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Canvas Demo</title>
</head>
<body>
<script>
// 建立一個範例用圖
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = 150
canvas.height = 150
ctx.strokeStyle = 'rgba(255, 0, 0, .5)'
ctx.arc(75, 75, 50, 0, Math.PI * 2, false)
ctx.lineWidth = '5'
ctx.stroke()
// 建立 file
const dataURL = canvas.toDataURL('image/png')
const blobBin = atob(dataURL.split(',')[1])
const array = []
for (let i = 0; i < blobBin.length; i++) {
array.push(blobBin.charCodeAt(i))
}
const file = new Blob([new Uint8Array(array)], { type: 'image/png' })
// 將file 加至 formData
const formData = new FormData()
formData.append('file', file, 'test.png')
// send ajax request
fetch('/upload.php', {
method: 'POST',
body: formData
}).then(res => res.text())
.then(resText => console.log(resText))
</script>
</body>
</html>
// upload.php
<?php
if (isset($_FILES["file"])) {
$file = $_FILES["file"];
$name = $file["name"];
$tmp_name = $file['tmp_name'];
$error = $file['error'];
move_uploaded_file($tmp_name, './' . $name);
echo 'file uploaded';
} else {
echo 'no file upload.';
}
而這個範例直接展示了如何將瀏覽器中的canvas
轉為file上傳到伺服器
而不用透過使用者下載然後點選input在上傳檔案。
由於最後個範例牽扯到一點點的php code,所以不方便上Demo
有興趣測試的朋友請複製程式到local測試
將html部分直接取名為index.php 或 index.html
php部分取名為upload.php,執行index.html後便會在跟專案得到一張圖片
不是直接執行index.html
而示開一個local php server執行