JavaScript實(shí)現(xiàn)旋轉(zhuǎn)圖像的三種方法介紹
有時(shí)我們需要旋轉(zhuǎn)網(wǎng)頁(yè)上的圖像,比如顯示正在加載中的動(dòng)畫。在文檔掃描Web應(yīng)用中,我們需要旋轉(zhuǎn)傾斜的或掃描方向錯(cuò)誤的文檔圖像。
在本文中,我們將討論使用JavaScript旋轉(zhuǎn)圖像的三種方法:
- CSS的Transform屬性
- HTML5的Canvas
- Dynamic Web TWAIN,一個(gè)文檔掃描SDK
編寫一個(gè)HTML5頁(yè)面以旋轉(zhuǎn)圖像
讓我們編寫一個(gè)HTML5頁(yè)面來(lái)旋轉(zhuǎn)圖像。
新建HTML文件
創(chuàng)建一個(gè)包含以下模板的新HTML文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rotate an Image with JavaScript</title>
<style>
.home {
display: flex;
align-items: center;
flex-direction: column;
}
</style>
</head>
<body>
<div class="home">
<h2>Rotate an Image</h2>
</div>
<script></script>
</body>
</html>
加載圖片
添加用于選擇文件的input元素,并使用按鈕觸發(fā)它。圖片將被加載到兩個(gè)img元素中,一個(gè)用于顯示旋轉(zhuǎn)的結(jié)果,另一個(gè)用于存儲(chǔ)原始圖像。
HTML:
<button id="loadFileButton">Load a File</button>
<input style="display:none;" type="file" id="file" onchange="loadImageFromFile();" accept=".jpg,.jpeg,.png,.bmp" />
<div class="imageContainer">
<img id="image"/>
<img id="imageHidden"/>
</div>
<style>
.imageContainer {
max-width: 50%;
}
#image {
max-width: 100%;
}
#imageHidden {
display: none;
}
</style>
JavaScript:
function loadImageFromFile(){
let fileInput = document.getElementById("file");
let files = fileInput.files;
if (files.length == 0) {
return;
}
let file = files[0];
fileReader = new FileReader();
fileReader.onload = function(e){
document.getElementById("image").src = e.target.result;
document.getElementById("imageHidden").src = e.target.result;
};
fileReader.onerror = function () {
console.warn('oops, something went wrong.');
};
fileReader.readAsDataURL(file);
}
使用CSS旋轉(zhuǎn)圖像
我們可以使用CSS屬性transform來(lái)旋轉(zhuǎn)HTML元素,用法如下:
element.style.transform = 'rotate(45deg)';
我們還可以指定transform-origin這個(gè)屬性來(lái)設(shè)置旋轉(zhuǎn)變換的原點(diǎn)。默認(rèn)情況下,變換的原點(diǎn)是圖像中心。
下面是頁(yè)面中的具體實(shí)現(xiàn)。
添加用于指定旋轉(zhuǎn)角度的input元素。
HTML:
<label for="degree">Degree (0-360):</label> <input type="number" id="degree" name="degree" min="0" max="360" value="0"/>
監(jiān)聽input元素的change事件,用CSS旋轉(zhuǎn)圖像。
document.getElementById("degree").addEventListener("change",function(e){
const degree = e.target.value;
rotateImage(degree);
})
function rotateImage(degree){
const image = document.getElementById("image");
const imageHidden = document.getElementById("imageHidden");
if (!image.src) {
return; //no image selected
}
image.src = imageHidden.src;
image.style.transform = 'rotate(' + degree + 'deg)';
}
使用CSS不會(huì)實(shí)際上改變圖像數(shù)據(jù),因此處理速度很快。但是它可能存在overflow的問題,會(huì)遮蓋住其他元素。我們可以將其容器的overflow CSS屬性設(shè)置為auto,以避免遮住其他元素,但圖像將被剪切。
使用Canvas旋轉(zhuǎn)圖像
HTML5提供了一個(gè)canvas標(biāo)簽,我們可以用它操作圖像數(shù)據(jù)。我們可以使用它來(lái)獲得實(shí)際旋轉(zhuǎn)后的圖像。
向頁(yè)面添加一個(gè)隱藏的canvas元素。
<canvas id="canvasHidden"></canvas>
<style>
#canvasHidden {
display: none;
}
</style>
添加一個(gè)select元素以選擇要使用的旋轉(zhuǎn)方法。
<label>
Method:
<select id="methodSelect">
<option>CSS</option>
<option>Canvas</option>
</select>
</label>
當(dāng)所選方法為"Canvas"時(shí),使用canvas旋轉(zhuǎn)圖像。
if (method == 0) {
image.src = imageHidden.src;
image.style.transform = 'rotate(' + degree + 'deg)';
}else if (method == 1){
image.style.transform = '';
rotateImageWithCanvas(degree);
}
下面我們討論具體如何使用canvas旋轉(zhuǎn)圖像。
獲取新的旋轉(zhuǎn)圖像的大小。
旋轉(zhuǎn)后,圖像將具有新的大小。我們需要設(shè)置canvas的大小以匹配新的圖像的大小。假設(shè)我們需要圍繞圖像的中心旋轉(zhuǎn)圖像,我們可以使用以下函數(shù)來(lái)計(jì)算新的大小。
首先,得到四個(gè)角點(diǎn),并計(jì)算它們?cè)谛D(zhuǎn)后的位置。然后,基于這些點(diǎn)獲得正外接矩形。
function getBoundingRect(width,height,degree) {
let rad = Degree2Rad(degree);
let points = [{x:0,y:0},{x:width,y:0},{x:width,y:height},{x:0,y:height}];
let minX = undefined;
let minY = undefined;
let maxX = 0;
let maxY = 0;
for (let index = 0; index < points.length; index++) {
const point = points[index];
const rotatedPoint = getRotatedPoint(point.x,point.y,width/2,height/2,rad);
if (minX == undefined) {
minX = rotatedPoint.x;
}else{
minX = Math.min(rotatedPoint.x,minX);
}
if (minY == undefined) {
minY = rotatedPoint.y;
}else{
minY = Math.min(rotatedPoint.y,minY);
}
maxX = Math.max(rotatedPoint.x,maxX);
maxY = Math.max(rotatedPoint.y,maxY);
}
let rectWidth = maxX - minX;
let rectHeight = maxY - minY;
let rect = {
x: minX,
y: minY,
width: rectWidth,
height: rectHeight
}
return rect;
}
function Degree2Rad(degree){
return degree*Math.PI/180
}
//https://gamedev.stackexchange.com/questions/86755/how-to-calculate-corner-positions-marks-of-a-rotated-tilted-rectangle
function getRotatedPoint(x,y,cx,cy,theta){
let tempX = x - cx;
let tempY = y - cy;
// now apply rotation
let rotatedX = tempX*Math.cos(theta) - tempY*Math.sin(theta);
let rotatedY = tempX*Math.sin(theta) + tempY*Math.cos(theta);
// translate back
x = rotatedX + cx;
y = rotatedY + cy;
let point = {x:x,y:y};
return point;
}
將canvas的大小設(shè)置為旋轉(zhuǎn)圖像的大小。
const canvas = document.getElementById("canvasHidden");
const imgWidth = imageHidden.naturalWidth;
const imgHeight = imageHidden.naturalHeight;
const rect = getBoundingRect(imgWidth,imgHeight,degree);
canvas.width = rect.width;
canvas.height = rect.height;
獲取canvas的context以執(zhí)行操作。
const ctx = canvas.getContext("2d");
使用translate將新的(0,0)原點(diǎn)位置設(shè)置為canvas的中心。
ctx.translate(canvas.width/2,canvas.height/2);
使用rotate設(shè)置變換矩陣。
ctx.rotate(Degree2Rad(degree));
使用drawImage繪制圖像內(nèi)容。
ctx.drawImage(imageHidden, -imgWidth/2, -imgHeight/2);
我們需要指定在目標(biāo)canvas中放置源圖像左上角的x軸和y軸坐標(biāo)。在這里,由于新原點(diǎn)是canvas的中心,我們需要使用-imgWidth/2和-imgHeight/2。
顯示旋轉(zhuǎn)后的圖像。
image.src = canvas.toDataURL();
使用Dynamic Web TWAIN旋轉(zhuǎn)圖像
Dynamic Web TWAIN是一個(gè)文檔掃描SDK,可以在瀏覽器中掃描文檔。它提供了各種圖像處理方法。我們可以使用其RotateEx方法旋轉(zhuǎn)圖像。
使用它的優(yōu)點(diǎn)是,它可以用于批量處理大量圖像,因?yàn)樘幚硎鞘褂帽镜剡M(jìn)程完成的。
以下是使用它的步驟:
在頁(yè)面中引入Dynamic Web TWAIN。
<script src="https://unpkg.com/dwt@18.4.2/dist/dynamsoft.webtwain.min.js"></script>
添加Dynamic Web TWAIN作為新的旋轉(zhuǎn)方法。
<label>
Method:
<select id="methodSelect">
<option>CSS</option>
<option>Canvas</option>
<option>Dynamic Web TWAIN</option>
</select>
</label>
當(dāng)選擇它作為旋轉(zhuǎn)方法時(shí),初始化一個(gè)Web TWAIN的實(shí)例并使用它來(lái)旋轉(zhuǎn)圖像。可以在此處申請(qǐng)其許可證。
let DWObject;
Dynamsoft.DWT.AutoLoad = false;
Dynamsoft.DWT.ProductKey = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="; //one-day trial
Dynamsoft.DWT.ResourcesPath = "https://unpkg.com/dwt@18.4.2/dist";
async function rotateImage(degree){
const method = document.getElementById("methodSelect").selectedIndex;
const image = document.getElementById("image");
const imageHidden = document.getElementById("imageHidden");
if (!image.src) {
return;
}
if (method == 0) {
image.src = imageHidden.src;
image.style.transform = 'rotate(' + degree + 'deg)';
}else if (method == 1){
image.style.transform = '';
rotateImageWithCanvas(degree);
}else if (method == 2){
image.style.transform = '';
if (!DWObject) {
await init();
}
rotateImageWithDWT(degree);
}
}
function init(){
return new Promise((resolve, reject) => {
const title = document.querySelector("h2").innerText;
document.querySelector("h2").innerText = "Loading Dynamic Web TWAIN...";
Dynamsoft.DWT.CreateDWTObjectEx(
{
WebTwainId: 'dwtcontrol'
},
function(obj) {
DWObject = obj;
document.querySelector("h2").innerText = title;
resolve();
},
function(err) {
console.log(err);
document.querySelector("h2").innerText = "Failed to load Dynamic Web TWAIN";
reject(err);
}
);
})
}
function rotateImageWithDWT(degree){
return new Promise(async (resolve, reject) => {
if (DWObject) {
DWObject.RemoveAllImages();
let file = document.getElementById("file").files[0];
let buffer = await file.arrayBuffer();
DWObject.LoadImageFromBinary(buffer,
function(){
const method = document.getElementById("interpolationMethodSelect").selectedOptions[0].value;
DWObject.RotateEx(0,degree,false,method,
function(){
document.getElementById("image").src = DWObject.GetImageURL(0);
},
function(errorCode, errorString){
reject(errorString);
});
},
function(errorCode, errorString){
reject(errorString);
})
}else{
reject();
}
})
}
在旋轉(zhuǎn)過(guò)程中需要添加新的像素,稱為插值。Dynamic Web TWAIN為此提供了幾種算法。
可以添加一個(gè)select元素用于選擇使用哪種算法。
<div class="dwtcontrols">
<label>
Interpolation Method:
<select id="interpolationMethodSelect">
<option value="1">Nearest Neighbour</option>
<option value="2">Bilinear</option>
<option value="3">Bicubic</option>
<option value="5" selected>Best Quality</option>
</select>
</label>
</div>
Web TWAIN還具有檢測(cè)文檔圖像傾斜角度的功能。我們可以用它來(lái)確定需要的旋轉(zhuǎn)角度。
DWObject.GetSkewAngle(
0,
function(angle) {
document.getElementById("degree").value = 360+angle;
rotateImage(360+angle);
},
function(errorCode, errorString) {
console.log(errorString);
}
);
源代碼
可以在以下倉(cāng)庫(kù)中找到所有代碼:
github.com/tony-xlh/Rotate-Image-JavaScript
以上就是JavaScript實(shí)現(xiàn)旋轉(zhuǎn)圖像的三種方法介紹的詳細(xì)內(nèi)容,更多關(guān)于JavaScript旋轉(zhuǎn)圖像的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于RequireJS和JQuery的模塊化編程日常問題解析
本文是小編日常收集整理些有關(guān)RequireJS和JQuery的模塊化編程,感興趣的朋友一起學(xué)習(xí)吧2016-04-04
js實(shí)現(xiàn)鼠標(biāo)感應(yīng)圖片展示的方法
這篇文章主要介紹了js實(shí)現(xiàn)鼠標(biāo)感應(yīng)圖片展示的方法,實(shí)例分析了javascript鼠標(biāo)事件及樣式的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02
Layui實(shí)現(xiàn)數(shù)據(jù)表格默認(rèn)全部顯示(不要分頁(yè))
今天小編就為大家分享一篇Layui實(shí)現(xiàn)數(shù)據(jù)表格默認(rèn)全部顯示(不要分頁(yè)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-10-10
javascript實(shí)現(xiàn)簡(jiǎn)單頁(yè)面倒計(jì)時(shí)
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)簡(jiǎn)單頁(yè)面倒計(jì)時(shí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03
bootstrap表單按回車會(huì)自動(dòng)刷新頁(yè)面的解決辦法
這篇文章主要介紹了bootstrap表單按回車會(huì)自動(dòng)刷新頁(yè)面的問題及解決辦法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03

