繁体   English   中英

画布旋转,toDataUrl,然后裁切破坏了图像质量

[英]Canvas Rotate, toDataUrl, and then Crop is ruining image quality

我有一张图片,允许用户在任何方向上旋转90度。 每次旋转时,我都会使用canvas执行图像处理,然后保存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>

请记住,我正在裁剪图像的自然宽度和高度。 因此,很奇怪的是,如果我不裁剪,则图像质量不会改变,但是当我裁剪时,图像质量会改变。

画布绘制是有损的,旋转图像会引起像素的硬修改。 因此,的确,如果始终从最后一个状态开始,最终将为图像添加越来越多的伪像。

只需将原始图像存储在某个地方,并始终从那里开始,而不使用修改后的版本。

 // 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"> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM