<aside> 🐱

URL 하나로 크기와 텍스트를 지정하면 고양이 이미지를 즉시 반환하는 플레이스홀더 서비스입니다. https://placecat.1yoouoo.com/400/600처럼 요청하면 400x600 고양이 이미지가 생성될 수 있으며, 54,000장의 이미지 풀과 Edge Runtime으로 초고속 응답을 제공합니다.

</aside>

현재는 서비스 종료.

문제 상황

플레이스홀더 서비스는 이미 picsum.photos 같은 좋은 사이트가 있지만 고양이 특화 버전은 없었습니다. ㅎ

해결 방법

Edge Runtime + next/og 기반 동적 이미지 생성

Next.js의 OG 이미지 생성을 일반 API로 확장사용했습니다. 이미지를 미리 생성해두지 않고, 요청 시점에 CDN에서 고양이 이미지를 fetch해 Base64로 인코딩한 뒤 JSX로 합성합니다.

export const runtime = 'edge'; // Edge Runtime 선언

export async function renderImageResponse(
  imageUrl: string,
  width: number,
  height: number,
  text: string = '',
) {
  // CDN에서 fetch 후 base64 변환
  const imageBuffer = await (await fetch(imageUrl)).arrayBuffer();
  const dataUrl = `data:image/jpeg;base64,${Buffer.from(imageBuffer).toString('base64')}`;

  return new ImageResponse(
    (
      <div style={{ position: 'relative', width: '100%', height: '100%' }}>
        <img src={dataUrl} style={{ position: 'absolute', width: '100%', height: '100%', objectFit: 'cover' }} />
        {text && <div style={{ position: 'absolute' }}>{text}</div>}
      </div>
    ),
    { width, height },
  );
}

동적 3단계 라우팅

URL을 줄이면서도 유연하게 동작하도록 라우팅 상단에서 리다이렉트를 처리했습니다.

// /400       → /400/400/png   (정사각형)
// /400/600   → /400/600/png   (기본 포맷)
// /400/600/png → 이미지 생성

// app/[width]/route.tsx
export async function GET(request, { params }) {
  const { width } = await params;
  redirect(`/${width}/${width}/png`); // 높이 생략 시 정사각형
}

한글/영문 문자폭 구분 폰트 크기 자동 계산

텍스트 오버레이 시 이미지 크기에 맞는 폰트 크기를 자동으로 계산합니다. 한글은 영문보다 실질 폭이 넓기 때문에 문자 종류마다 가중치를 다르게 적용했습니다.

const calculateCharWidth = (char: string): number => {
  if (/[\\uAC00-\\uD7AF]/.test(char)) return 1.0;   // 한글: 넓음
  if (/[A-Z!@#$%^&*]/.test(char))   return 0.75;  // 영문 대문자/특수문자
  return 0.5;                                       // 영문 소문자/숫자
};

// 이미지 종횡비에 따른 추가 조정
const aspectRatio = width / height;
const aspectFactor = aspectRatio > 2 ? 0.85 : aspectRatio < 0.5 ? 1.1 : 1.0;

어떤 텍스트를 넘겨도 이미지를 벗어나지 않고, 어떤 비율의 이미지에도 적절하게 맞춰집니다.

미들웨어 조기 검증

라우트에 도달하기 전, 미들웨어에서 마이너스 크기나 비정상 포맷 요청을 미리차단합니다.