캔버스로 일부 이미지의 크기를 조정하려고하지만 부드럽게하는 방법에 대해 잘 모르겠습니다. 포토샵, 브라우저 등에서 그들이 사용하는 몇 가지 알고리즘 (예 : bicubic, bilinear)이 있지만 이것이 캔버스에 내장되어 있는지 여부는 모르겠습니다.
여기 내 바이올린이 있습니다. http://jsfiddle.net/EWupT/
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width=300
canvas.height=234
ctx.drawImage(img, 0, 0, 300, 234);
document.body.appendChild(canvas);
첫 번째는 일반적인 크기 조정 이미지 태그이고 두 번째는 캔버스입니다. 캔버스가 부드럽 지 않은지 확인하십시오. ‘부드러움’을 얻으려면 어떻게해야합니까?
답변
더 나은 결과를 얻기 위해 아래 단계를 사용할 수 있습니다. 대부분의 브라우저는 이미지 크기를 조정할 때 이중 입방체 가 아닌 선형 보간법 을 사용하는 것 같습니다 .
( 업데이트 사양에 품질 속성이 추가되었으며 imageSmoothingQuality
현재 Chrome에서만 사용할 수 있습니다.)
평활화 또는 가장 가까운 이웃을 선택하지 않는 한 브라우저는 앨리어싱을 피하기 위해이 기능을 저역 통과 필터로 축소 한 후 항상 이미지를 보간합니다.
Bi-linear는 2×2 픽셀을 사용하여 보간을 수행하는 반면, bi-cubic은 4×4를 사용하므로 단계별로 수행하면 결과 이미지에서 볼 수 있듯이 이중 선형 보간을 사용하는 동안 bi-cubic 결과에 근접 할 수 있습니다.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = new Image();
img.onload = function () {
// set size proportional to image
canvas.height = canvas.width * (img.height / img.width);
// step 1 - resize to 50%
var oc = document.createElement('canvas'),
octx = oc.getContext('2d');
oc.width = img.width * 0.5;
oc.height = img.height * 0.5;
octx.drawImage(img, 0, 0, oc.width, oc.height);
// step 2
octx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5);
// step 3, resize to final size
ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5,
0, 0, canvas.width, canvas.height);
}
img.src = "//i.imgur.com/SHo6Fub.jpg";
<img src="//i.imgur.com/SHo6Fub.jpg" width="300" height="234">
<canvas id="canvas" width=300></canvas>
크기 조정의 정도에 따라 차이가 적을 경우 2 단계를 건너 뛸 수 있습니다.
데모에서 새로운 결과가 이미지 요소와 매우 유사하다는 것을 알 수 있습니다.
답변
Trung Le Nguyen Nhat의 바이올린 이 전혀 정확하지 않기 때문에 (마지막 단계에서 원본 이미지 만 사용함)
성능 비교와 함께 내 자신의 일반 바이올린을 작성했습니다.
기본적으로 다음과 같습니다.
img.onload = function() {
var canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d"),
oc = document.createElement('canvas'),
octx = oc.getContext('2d');
canvas.width = width; // destination canvas size
canvas.height = canvas.width * img.height / img.width;
var cur = {
width: Math.floor(img.width * 0.5),
height: Math.floor(img.height * 0.5)
}
oc.width = cur.width;
oc.height = cur.height;
octx.drawImage(img, 0, 0, cur.width, cur.height);
while (cur.width * 0.5 > width) {
cur = {
width: Math.floor(cur.width * 0.5),
height: Math.floor(cur.height * 0.5)
};
octx.drawImage(oc, 0, 0, cur.width * 2, cur.height * 2, 0, 0, cur.width, cur.height);
}
ctx.drawImage(oc, 0, 0, cur.width, cur.height, 0, 0, canvas.width, canvas.height);
}
답변
관심있는 모든 사람을 위해 이미지 / 캔버스의 고품질 크기 조정을 처리하기 위해 재사용 가능한 Angular 서비스를 만들었습니다. https://gist.github.com/transitive-bullshit/37bac5e741eaec60e983
이 서비스에는 둘 다 고유 한 장단점이 있기 때문에 두 가지 솔루션이 포함됩니다. lanczos 컨볼 루션 방식은 속도가 느리지 만 품질이 더 높은 반면, 단계적 축소 방식은 합리적으로 안티 앨리어싱 된 결과를 생성하고 훨씬 빠릅니다.
사용 예 :
angular.module('demo').controller('ExampleCtrl', function (imageService) {
// EXAMPLE USAGE
// NOTE: it's bad practice to access the DOM inside a controller,
// but this is just to show the example usage.
// resize by lanczos-sinc filter
imageService.resize($('#myimg')[0], 256, 256)
.then(function (resizedImage) {
// do something with resized image
})
// resize by stepping down image size in increments of 2x
imageService.resizeStep($('#myimg')[0], 256, 256)
.then(function (resizedImage) {
// do something with resized image
})
})
답변
이러한 코드 스 니펫 중 일부는 짧고 작동하지만 따르고 이해하는 것이 사소한 것은 아닙니다.
저는 스택 오버플로의 “복사-붙여 넣기”를 좋아하지 않기 때문에 개발자가 소프트웨어에 푸시하는 코드를 이해하기를 바랍니다. 아래 내용이 유용하기를 바랍니다.
데모 : JS 및 HTML Canvas 데모 피들러로 이미지 크기 조정.
이 크기 조정을 수행하는 3 가지 방법을 찾을 수 있으며, 코드가 작동하는 방식과 이유를 이해하는 데 도움이됩니다.
https://jsfiddle.net/1b68eLdr/93089/
코드에서 사용할 수있는 데모 및 TypeScript 메서드의 전체 코드는 GitHub 프로젝트에서 찾을 수 있습니다.
https://github.com/eyalc4/ts-image-resizer
이것이 최종 코드입니다.
export class ImageTools {
base64ResizedImage: string = null;
constructor() {
}
ResizeImage(base64image: string, width: number = 1080, height: number = 1080) {
let img = new Image();
img.src = base64image;
img.onload = () => {
// Check if the image require resize at all
if(img.height <= height && img.width <= width) {
this.base64ResizedImage = base64image;
// TODO: Call method to do something with the resize image
}
else {
// Make sure the width and height preserve the original aspect ratio and adjust if needed
if(img.height > img.width) {
width = Math.floor(height * (img.width / img.height));
}
else {
height = Math.floor(width * (img.height / img.width));
}
let resizingCanvas: HTMLCanvasElement = document.createElement('canvas');
let resizingCanvasContext = resizingCanvas.getContext("2d");
// Start with original image size
resizingCanvas.width = img.width;
resizingCanvas.height = img.height;
// Draw the original image on the (temp) resizing canvas
resizingCanvasContext.drawImage(img, 0, 0, resizingCanvas.width, resizingCanvas.height);
let curImageDimensions = {
width: Math.floor(img.width),
height: Math.floor(img.height)
};
let halfImageDimensions = {
width: null,
height: null
};
// Quickly reduce the dize by 50% each time in few iterations until the size is less then
// 2x time the target size - the motivation for it, is to reduce the aliasing that would have been
// created with direct reduction of very big image to small image
while (curImageDimensions.width * 0.5 > width) {
// Reduce the resizing canvas by half and refresh the image
halfImageDimensions.width = Math.floor(curImageDimensions.width * 0.5);
halfImageDimensions.height = Math.floor(curImageDimensions.height * 0.5);
resizingCanvasContext.drawImage(resizingCanvas, 0, 0, curImageDimensions.width, curImageDimensions.height,
0, 0, halfImageDimensions.width, halfImageDimensions.height);
curImageDimensions.width = halfImageDimensions.width;
curImageDimensions.height = halfImageDimensions.height;
}
// Now do final resize for the resizingCanvas to meet the dimension requirments
// directly to the output canvas, that will output the final image
let outputCanvas: HTMLCanvasElement = document.createElement('canvas');
let outputCanvasContext = outputCanvas.getContext("2d");
outputCanvas.width = width;
outputCanvas.height = height;
outputCanvasContext.drawImage(resizingCanvas, 0, 0, curImageDimensions.width, curImageDimensions.height,
0, 0, width, height);
// output the canvas pixels as an image. params: format, quality
this.base64ResizedImage = outputCanvas.toDataURL('image/jpeg', 0.85);
// TODO: Call method to do something with the resize image
}
};
}}
답변
모든 색상 데이터를 유지하면서 백분율을 낮출 수있는 라이브러리를 만들었습니다.
https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js
브라우저에 포함 할 수있는 파일입니다. 결과는 포토샵 또는 이미지 마술처럼 보이며, 모든 색상 데이터를 보존하고, 주변의 픽셀을 가져 와서 다른 픽셀을 떨어 뜨리는 대신 픽셀을 평균화합니다. 평균을 추측하기 위해 공식을 사용하지 않고 정확한 평균을 취합니다.
답변
K3N 답변을 기반으로 누구나 원하는 코드를 일반적으로 다시 작성합니다.
var oc = document.createElement('canvas'), octx = oc.getContext('2d');
oc.width = img.width;
oc.height = img.height;
octx.drawImage(img, 0, 0);
while (oc.width * 0.5 > width) {
oc.width *= 0.5;
oc.height *= 0.5;
octx.drawImage(oc, 0, 0, oc.width, oc.height);
}
oc.width = width;
oc.height = oc.width * img.height / img.width;
octx.drawImage(img, 0, 0, oc.width, oc.height);
JSFIDDLE 데모 업데이트
답변
아무도 제안하지 않는 이유를 이해하지 못합니다 createImageBitmap
.
createImageBitmap(
document.getElementById('image'),
{ resizeWidth: 300, resizeHeight: 234, resizeQuality: 'high' }
)
.then(imageBitmap =>
document.getElementById('canvas').getContext('2d').drawImage(imageBitmap, 0, 0)
);
아름답게 작동합니다 (이미지 및 캔버스에 대한 ID를 설정했다고 가정).