![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/015.gif)
📱테스트 환경
"react": "18.2.0"
"react-dom": "18.2.0"
"typescript": "^5.1.6"
😢 내가 겪은 문제
SEO 에 사용할 이미지를 하나만 사용하면 사용할 일 없었겠지만, 같은 페이지라도 query 값에 따라 보여지는 SEO 이미지가 달라야했다..
예를 들어서 localhost:8000/result 에는 A 이미지가 보여야 했다면
localhost:8000/result?id=123 에는 B 이미지가 보여야했다.
그리고 예시로 든 URL 에 result 가 들어있는것만봐도 결과값을 이용해서 썸네일을 만들고 싶었다... ^^
대충 이런식의 썸네일을 만드려고 했다. 규격이 800x400 인 이유는 카톡 썸네일 기준이기 때문이다.
내가 보기엔 이거 할 줄 알면 canvas 로 못만들거 없어진다. ( canvas 이용한 것 중에 이게 제일 어려웠다. )
일단 canvas 에 대해 알아보자면
캔버스(Canvas)는 HTML5에서 제공되는 그래픽 그리기를 위한 요소로
JavaScript를 사용하여 그림을 그리고 다양한 그래픽 요소를 조작할 수 있는 기능을 제공해준다.
캔버스를 사용하면 웹 페이지에서 동적인 그래픽 및 애니메이션을 생성할 수 있습니다. ( 사실상 다 만들 수 있다는 소리다. )
나도 이때문에 canvas 이용해서 하라고 해서 개고생하면서 열심히 만들었따 ..
일단 전체코드이다.
getThumbnail.tsx
export const getThumbnail = async () => {
const image: any = getImage();
const canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 400;
canvas.style.display = "none";
document.body.appendChild(canvas);
const context = canvas.getContext("2d");
if (context) {
context.fillStyle = "#7491ff";
context.fillRect(0, 0, canvas.width, canvas.height);
context.font = "700 40px Arial"; // font-weight font-size font
const paddingX = 40;
const paddingY = 40;
const img = new Image();
img.src = location.origin + image.src;
await new Promise((resolve) => {
img.onload = resolve;
img.onerror = resolve;
});
const imgWidth = 80; // 이미지의 너비
const imgHeight = 80; // 이미지의 높이
const imgX = paddingX;
const imgY = paddingY;
context.drawImage(img, imgX, imgY, imgWidth, imgHeight);
const additionalText = "첫번째 줄 텍스트";
context.fillStyle = "white";
context.font = "700 50px Arial";
const additionalTextY = paddingY + 150;
context.fillText(additionalText, paddingX, additionalTextY);
context.fillStyle = "white";
context.font = "700 135px Arial";
const nameText = "두번쨰 줄 텍스트";
const nameTextY = additionalTextY + 170;
context.fillText(nameText, paddingX + 10, nameTextY);
const img2 = new Image();
img2.src = fileURL;
await new Promise((resolve) => {
img2.onload = resolve;
img2.onerror = resolve; // Handle error, since we don't want to reject the main promise
});
const img2Width = 400; // 이미지의 너비
const img2Height = 400; // 이미지의 높이
const img2X = canvas.width - img2Width;
const img2Y = canvas.height - img2Height;
context.drawImage(img2, img2X, img2Y, img2Width, img2Height);
const dataURL = canvas.toDataURL();
return dataURL;
}
};
중요한 코드를 쪼개서 이해해보도록자면
const canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 400;
canvas.style.display = "none";
document.body.appendChild(canvas);
const context = canvas.getContext("2d");
- 가로 800, 높이 400 짜리를 canvas 를 생성하고, display 는 none 로 설정한다.
display none 처리를 안하면 body 에 추가할껀데 화면에 계속 보이기 때문이다. - body 에 canvas 엘리먼트를 추가한다.
- 캔버스의 2D 컨텍스트를 가져온다.
2D 컨텍스트는 캔버스 위에 그래픽을 그리고 조작하는 데 사용되는 도구 모음이라고 생각하면 된다.
const img = new Image();
img.src = location.origin + image.src;
await new Promise((resolve) => {
img.onload = resolve;
img.onerror = resolve;
});
- 약간 선택사항(?) 같은데 .. img.src 에 location.origin + image.src 해주는 이유는
image 는 로컬에 저장 ( ../public/png/image.png) 되어있어서 이렇게 호출 해 주었다. 다른 방법이다 더 좋은 방법이 있다면 맞게 수정하면 될 것이다. ( 알려주면 더 좋다. ) - 여기가 중요한데, img 를 로드하기전에 썸네일을 다 만들어버리면 의미가없다. 그렇기 때문에 비동기 처리가 필요하다.
그렇기 때문에 이미지가 로드되거나 로드 중에 오류가 발생할 때까지 대기하는 비동기 작업을 수행할 수 있도록 한다.
중요한 코드는 이정도 인 것 같다.
나머지는 주석도 달려있고, 읽어보기만 해도 쉽게 이해할 수 있을 것이다.
나처럼 SEO 대응해서 썸네일 만들일이 많을지는 경험상 잘 모르겠따. 나도 처음해보는거라서.
Canvas 를 이용해서 이런것도 할 수 있구나 ~ 안되는게 없구나 ~ 이런식으로 하면 되겠구나 ~
정도로 이해하고 하고 넘어갈 수 있다면 좋을 것 같다.
'Javascript > Next' 카테고리의 다른 글
[NextJS] Mobile Web 에서 이메일 시스템 모달창 띄우기 (0) | 2023.08.30 |
---|---|
[NextJS] 모바일인지 PC 인지 구별하는 방법 (0) | 2023.08.30 |
[NextJS] .map() 함수 사용 & Components Map 하는 방법 (4) | 2023.08.29 |
[NextJS] onPress vs onClick 차이점 (0) | 2023.08.28 |
[NextJS] String -> Number , Number -> String (0) | 2023.08.28 |