728x90

https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html

 

Creating Compatible Web Content

Creating Compatible Web Content This chapter covers best practices in creating web content that is compatible with Safari on the desktop and Safari on iOS. Many of these guidelines simply improve the reliability, performance, look, and user experience of y

developer.apple.com

 

제 아이폰을 포함해 맥북 에서 사파리에서 너무 큰 이미지를 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