HTML Canvas crop 기능 구현 시 Safari 에서의 문제점
728x90
제 아이폰을 포함해 맥북 에서 사파리에서 너무 큰 이미지를 Crop 하려고 할때 에러가 발생하여 이 기능을 어떻게 해결 하였는지 적어 보려 합니다.
위의 사이트는 IOS 공식 문서입니다.
Safari 브라우저에서 제 핸드폰 으로 찍은 사진을 크롭 하려고 했습니다.
const createImage = url =>
new Promise((resolve, reject) => {
const image = new Image();
image.addEventListener('load', () => resolve(image));
image.addEventListener('error', error => reject(error));
image.setAttribute('crossOrigin', 'anonymous'); // needed to avoid cross-origin issues on CodeSandbox
image.src = url;
});
function getRadianAngle(degreeValue) {
return (degreeValue * Math.PI) / 180;
}
/**
* @param imageSrc
* @param {Object} pixelCrop - pixelCrop Object provided by react-easy-crop
* @param {number} rotation - optional rotation parameter
*/
export default async function getCroppedImg(imageSrc, pixelCrop, rotation = 0) {
const image: any = await createImage(imageSrc);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const maxSize = Math.max(image.width, image.height);
// const safeArea = 2 * ((maxSize / 2) * Math.sqrt(2));
// Mac os safari 의 아이폰 메모리 이슈로 4천이 넘어가면 캔버스 최대 크기픽셀 을 연산 할수가 없음
const safeArea = 4000;
// set each dimensions to double largest dimension to allow for a safe area for the
// image to rotate in without being clipped by canvas context
canvas.width = safeArea;
canvas.height = safeArea;
// translate canvas context to a central location on image to allow rotating around the center.
ctx.translate(safeArea / 2, safeArea / 2);
ctx.rotate(getRadianAngle(rotation));
ctx.translate(-safeArea / 2, -safeArea / 2);
// draw rotated image and store data.
ctx.fillStyle = '#DCDCDC';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(
<
| HTMLImageElement
| SVGImageElement
| HTMLVideoElement
| HTMLCanvasElement
| ImageBitmap
>image,
safeArea / 2 - image.width * 0.5,
safeArea / 2 - image.height * 0.5,
);
const data = ctx.getImageData(0, 0, safeArea, safeArea);
// set canvas width to final desired crop size - this will clear existing context
canvas.width = pixelCrop.width;
canvas.height = pixelCrop.height;
// paste generated rotate image with correct offsets for x,y crop values.
ctx.putImageData(
data,
Math.round(0 - safeArea / 2 + image.width * 0.5 - pixelCrop.x),
Math.round(0 - safeArea / 2 + image.height * 0.5 - pixelCrop.y),
);
// As Base64 string
// return canvas.toDataURL('image/jpeg');
// As a blob
return new Promise(resolve => {
canvas.toBlob(file => {
resolve(file);
}, 'image/png');
});
}
문제는 회전을 고려하여 안전한 영역을 잡기위해 safeArea 라는 변수를 두어
const maxSize = Math.max(image.width, image.height);
const safeArea = 2 * ((maxSize / 2) * Math.sqrt(2));
다음과 같이 계산 하였는데 이 safeArea 의 value 가 너무 커져서 문제가 되었습니다.
제 아이폰12 Mini 기준 세로로 가로로 찍었을때 3000 x 4000 으로 나와 최대 값을 4000 으로 고정 했습니다.
최대값을 4000으로 고정 하기 전에는 연산량이 너무 커 에러를 발생하는 것으로 보입니다.
4000으로 수정뒤 다시 crop 한 결과
아직 추측 일 뿐이지만 정상작동하는 것으로 보입니다.
확실한 해결 책이나 어떤 이유 때문에 오작동 하는지 아시는 분은 댓글 달아주시면 감사합니다
728x90
'Javascript' 카테고리의 다른 글
javascript lodash 를 이용한 deep copy (0) | 2021.08.07 |
---|