JavaScript 및 Canvas API를 사용하여 브라우저에서 SVG 이미지 변환
12768 단어 javascript
50(왼쪽) 및 100(오른쪽) 픽셀의 SVG(위) 및 PNG(아래) 이미지.
그러나 최근 SVG의 유용성이 한계에 이르렀다는 것을 알게 되었습니다(SVG의 잘못은 아니지만).
문제
나는 실험 중 하나로 Game of Life 보드를 조립해 왔으며 사용하고 있던 검은색 정사각형을 텍스처가 조금 더 많은 것으로 교체하고 싶었습니다.
크기가 다른 왼쪽의 오래된 검정색 타일과 오른쪽의 새로운 "질감 있는"타일을 비교합니다.
이 게임은 Canvas API으로 조작할 수 있는
<canvas>
요소를 사용하며 셀을 그리는 원래 코드는 다음과 같습니다(프로젝트는 Vue.js로 빌드되었으며 소스는 GitHub에서 사용할 수 있습니다).drawCell(x, y, state) {
let context = this.$refs.canvas.getContext('2d');
switch (state) {
case DEAD:
context.fillStyle = 'white';
break;
case ALIVE:
context.fillStyle = 'black';
break;
}
// fill the grid square but leave the grid outline
context.fillRect(
(x * this.cellSize) + 1,
(y * this.cellSize) + 1,
this.cellSize - 2,
this.cellSize - 2
);
}
이미지 복제
첫 번째 단계로 이 방법을 다음과 같이 훨씬 더 짧은 방법으로 대체했습니다.
drawCell(x, y, state) {
let context = this.$refs.canvas.getContext('2d');
context.drawImage(this.images[state], (x * this.cellSize), (y * this.cellSize), this.cellSize, this.cellSize);
}
drawImage(Image, x, y, height, width)
는 PNG, JPEG 및 SVG를 포함하여 이전에 로드된 모든 이미지 데이터를 허용합니다.안타깝게도 사용자가 셀 크기를 제어할 수 있기 때문에 내가 사용한 모든 PNG 이미지는 이미지 크기 조정으로 인해 발생하는 일반적인 문제에 노출될 수 있으므로 SVG를 사용하기로 했습니다.
구성 요소
mounted
메서드를 사용하여 두 이미지를 미리 로드했습니다.async mounted() {
this.images = {
'alive': await loadImage("./img/alive.svg"),
'dead': await loadImage("./img/dead.svg"),
}
this.initialiseMap();
}
loadImage
는 이미지를 비동기식으로 로드할 수 있도록 하는 간단한 기능이므로 구성 요소가 이미지를 렌더링하려고 시도하기 전에 이미지를 사용할 수 있도록 합니다.function loadImage(url, height, width) {
return new Promise((resolve, reject) => {
let image = new Image();
image.onload = () => {
resolve(image);
}
image.onerror = reject;
image.src = url;
});
}
접지 정지
불행하게도 이 구현으로 인해 전체 그리기 주기가 급격히 줄어들었고 각 세대를 다시 그리는 데 수십 초가 걸렸습니다. 오래된 채워진 사각형 방법이 상당히 큰 보드에서도 번개처럼 빠르다는 점을 고려하면 이것은 상당한 좌절이었습니다.
SVG를 미리 로드하여 최악의 성능 문제를 방지하고 싶었지만 각 셀의 크기 조정 및 그리기는 여전히 비용이 많이 드는 작업인 것 같습니다.
나는 평평한 검은 타일을 가질 운명이었습니까? 한 가지 더 시도해 볼 것이 있었습니다.
SVG를 PNG로 변환
drawImage
가 로드된 모든 이미지 데이터를 허용할 수 있다는 것을 기억하십니까? 이 데이터는 파일에서 직접 가져올 필요가 없습니다. 다른 canvas
요소에서 이미지 데이터를 추출하고 drawImage
를 포함하여 다른 이미지를 사용할 수 있는 곳에 사용할 수 있습니다.내
loadImage
기능을 업데이트했습니다.function loadImageAsPNG(url, height, width) {
return new Promise((resolve, reject) => {
let sourceImage = new Image();
sourceImage.onload = () => {
let png = new Image();
let cnv = document.createElement('canvas'); // doesn't actually create an element until it's appended to a parent,
// so will be discarded once this function has done it's job
cnv.height = height;
cnv.width = width;
let ctx = cnv.getContext('2d');
ctx.drawImage(sourceImage, 0, 0, height, width);
png.src = cnv.toDataURL(); // defaults to image/png
resolve(png);
}
image.onerror = reject;
image.src = url;
});
}
여기서
toDataURL(type, encoderOptions)
메서드는 MIME 유형 문자열(image/png, image/jpeg 등)을 허용하고 다른 Image
의 소스로 사용할 수 있는 base-64 인코딩 이미지 데이터를 반환합니다. 요청한 MIME 유형을 지원하지 않거나 제공하지 않으면 PNG를 반환합니다. 두 번째 매개변수는 JPEG와 같은 "손실"유형의 이미지 품질을 제어하는 데 사용됩니다. 이것은 0과 1 사이의 숫자를 사용하며 기본값은 0.92입니다.마지막으로
toDataURL
도 최신 WebP 유형을 출력할 수 있지만 Chrome에서만 출력할 수 있습니다(다른 브라우저에서는 기본적으로 PNG로 설정되기 때문에 괜찮습니다).마지막 생각들
이것은 이상적이지 않습니다. drawImage는 여전히 비용이 많이 드는 기능이고 더 큰 보드는 여전히 상당히 느리기 때문에 다른 최적화를 찾아야 합니다.
그러나 브라우저에서 한 이미지 유형에서 다른(지원되는) 유형으로 변환해야 하는 경우 Canvas API 및 해당
toDataURL
메서드에 대해 생각해 보십시오. toDataURL
는 사용자가 그린 캔버스에서 이미지 데이터를 가져오고(앱에서 지원하는 경우) 파일로 저장하기 위해 서버로 보내는 데에도 사용할 수 있습니다.
Reference
이 문제에 관하여(JavaScript 및 Canvas API를 사용하여 브라우저에서 SVG 이미지 변환), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/horus_kol/convert-svg-images-in-the-browser-using-javascript-and-the-canvas-api-2kge텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)