我有一张图片,允许用户在任何方向上旋转90度。每次旋转时,我都会使用画布执行图像处理,然后保存canvas.toDataURL("image/png", 1)
返回的数据。
问题是每次旋转图像时图像质量都会下降。
我的最终目标是旋转矩形图像而不损失图像质量,并保存新的数据URL。
function rotateAndSave(image: HTMLImageElement, degrees: number): string {
const imageWidth = image.naturalWidth;
const imageHeight = image.naturalHeight;
const startedHorizontalEndedVertical = imageWidth > imageHeight;
const canvasSize = startedHorizontalEndedVertical ? imageWidth : imageHeight;
const canvas = document.createElement("canvas");
canvas.width = canvasSize;
canvas.height = canvasSize;
const ctx = canvas.getContext("2d");
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// center and rotate canvas
const translateCanvas = canvasSize / 2;
ctx.translate(translateCanvas, translateCanvas);
ctx.rotate(degrees * Math.PI / 180);
// draw from center
const translateImageX = startedHorizontalEndedVertical ? -translateCanvas : (-imageWidth / 2);
const translateImageY = startedHorizontalEndedVertical ? (-imageHeight / 2) : -translateCanvas;
ctx.drawImage(image, translateImageX, translateImageY);
// I got 'cropPlusExport' from another stackoverflow question.
function cropPlusExport(img, cropX, cropY, cropWidth, cropHeight) {
// create a temporary canvas sized to the cropped size
const canvas1 = document.createElement('canvas');
canvas1.width = cropWidth;
canvas1.height = cropHeight;
const ctx1 = canvas1.getContext('2d');
ctx1.setTransform(1, 0, 0, 1, 0, 0);
ctx1.clearRect(0, 0, canvas1.width, canvas1.height);
// use the extended from of drawImage to draw the
// cropped area to the temp canvas
ctx1.drawImage(img, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
return canvas1.toDataURL("image/png", 1);
}
// Start Cropping
let squareImage = new Image();
squareImage.src = canvas.toDataURL("image/png", 1);
squareImage.onload = () => {
const sx = startedHorizontalEndedVertical ? ((canvasSize - imageHeight) / 2) : 0;
const sy = startedHorizontalEndedVertical ? 0 : ((canvasSize - imageWidth) / 2);
const sw = imageHeight;
const sh = imageWidth;
const data = cropPlusExport(squareImage, sx, sy, sw, sh);
// Update DOM via angular binding...
const dataUrl = data.split(",")[1];
this.imageSource = dataUrl;
squareImage = null;
}
示例html
<div class="view">
<img [src]="imageSource" />
</div>
请记住,我正在裁剪图像的自然宽度和高度。所以,奇怪的是,如果我不裁剪,则图像质量不会改变,但是当我裁剪时,图像质量会改变。
答案 0 :(得分:1)
画布绘制是有损的,旋转图像会引起像素的硬修改。因此,的确,如果始终从最后一个状态开始,最终将在图像中添加越来越多的伪像。
只需将原始图像存储在某个地方,并始终从那里开始,而不要使用修改后的版本。
// will fire in a loop
img.onload = e => elem.rotateAndSave(1);
const elem = {
// store a copy of the original image
originalimage: img.cloneNode(),
angle: 0,
rotateAndSave(degrees) {
// always use the stored original image
const image = this.originalimage;
// keep track of current transform
this.angle += degrees;
const imageWidth = image.naturalWidth;
const imageHeight = image.naturalHeight;
const startedHorizontalEndedVertical = imageWidth > imageHeight;
const canvasSize = startedHorizontalEndedVertical ? imageWidth : imageHeight;
const canvas = document.createElement("canvas");
canvas.width = canvasSize;
canvas.height = canvasSize;
const ctx = canvas.getContext("2d");
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// center and rotate canvas
const translateCanvas = canvasSize / 2;
ctx.translate(translateCanvas, translateCanvas);
ctx.rotate(this.angle * Math.PI / 180);
// draw from center
const translateImageX = startedHorizontalEndedVertical ? -translateCanvas : (-imageWidth / 2);
const translateImageY = startedHorizontalEndedVertical ? (-imageHeight / 2) : -translateCanvas;
ctx.drawImage(image, translateImageX, translateImageY);
// I got 'cropPlusExport' from another stackoverflow question.
function cropPlusExport(img, cropX, cropY, cropWidth, cropHeight) {
// create a temporary canvas sized to the cropped size
const canvas1 = document.createElement('canvas');
canvas1.width = cropWidth;
canvas1.height = cropHeight;
const ctx1 = canvas1.getContext('2d');
ctx1.setTransform(1, 0, 0, 1, 0, 0);
ctx1.clearRect(0, 0, canvas1.width, canvas1.height);
// use the extended from of drawImage to draw the
// cropped area to the temp canvas
ctx1.drawImage(img, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
return canvas1.toDataURL("image/png", 1);
}
// Start Cropping
let squareImage = new Image();
squareImage.src = canvas.toDataURL("image/png", 1);
squareImage.onload = () => {
const sx = startedHorizontalEndedVertical ? ((canvasSize - imageHeight) / 2) : 0;
const sy = startedHorizontalEndedVertical ? 0 : ((canvasSize - imageWidth) / 2);
const sw = imageHeight;
const sh = imageWidth;
const data = cropPlusExport(squareImage, sx, sy, sw, sh);
// Update DOM via angular binding...
img.src = data;
}
}
};
<img crossorigin src="https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg" id="img">