채보 이미지
채보 이미지 처리기는 공개된 채보를 Cassiopeia의 정적 개요 렌더러로 그립니다. SVG와 등록된 래스터라이저를 통한 PNG를 지원하며, PNG 배포에는 해당 Fontsource 매니페스트와 파일이 들어 있습니다. 아래 애플리케이션은 공개 워커의 실제 응답을 보여 줍니다.
이미지 요청
섹션 제목: “이미지 요청”curl --fail-with-body \ 'https://haneoka.org/api/v1/songs/100070/charts/expert/image.svg?server=intl&locale=en&height=720&download=1' \ -o chart.svgPNG에는 .png를 씁니다. 명시적 형태는 /api/v1/servers/{server}/songs/{songId}/charts/{difficulty}/image.{format}입니다. 둘 다 현재 데이터를 고르며 release는 받지 않습니다. 곡 DTO가 실제로 제공하는 난이도를 고르세요.
| 매개변수 | 값 | 의미 |
|---|---|---|
server | 활성 리소스 서버 슬러그. 별칭의 기본값은 intl | 원본 카탈로그 |
difficulty | easy, normal, hard, expert, special, master | 경로 세그먼트. 그 곡에 있어야 한다 |
locale | ja, en, zh-TW, zh-CN, ko | 캡션 언어. 없으면 Accept-Language로 협상 |
height | 정수 360~1440, 기본값 720 | 헤더를 뺀 채보 패널 하나의 높이 |
download | 1 또는 0, 기본값 1 | Content-Disposition을 attachment로 할지 inline으로 할지 |
format | svg 또는 png | 파일 확장자와 응답 MIME |
쿼리 값이 반복되거나 비어 있으면 400으로 거부됩니다. 채보 데이터와 출력에는 렌더러 예산이 있으며, 너무 큰 입력이나 출력은 무한정 큰 이미지를 만들지 않고 413으로 거부됩니다.
크기와 조건부 요청
섹션 제목: “크기와 조건부 요청”결과 캔버스에는 헤더와 채보에 필요한 만큼의 패널이 들어갑니다. 패널 높이를 늘리면 패널 수와 최종 너비가 바뀝니다. X-Haneoka-Image-Width와 X-Haneoka-Image-Height를 읽고, 그 크기로 이미지 자리를 안정적으로 확보하세요. 이 값은 요청한 패널 높이가 아니라 SVG width/height나 PNG IHDR과 일치합니다.
응답에는 Content-Type, Content-Length, Content-Disposition, Content-Language, ETag, X-Haneoka-Server, X-Haneoka-Release-Id, X-Haneoka-Chart-Renderer가 포함됩니다. GET은 이미지를, HEAD는 본문 없이 헤더를 반환하며, If-None-Match는 Content-Length 없는 304를 반환할 수 있습니다. 공개 엔드포인트는 익명 CORS를 허용합니다. OPTIONS는 204를, 지원하지 않는 메서드는 Allow와 함께 405를 반환합니다.
const url = "https://haneoka.org/api/v1/songs/100070/charts/expert/image.png?locale=en&download=0";const response = await fetch(url, { credentials: "omit" });if (!response.ok) { const failure = await response.json(); throw new Error(`${response.status}: ${failure.error.code}`);}const width = Number(response.headers.get("X-Haneoka-Image-Width"));const height = Number(response.headers.get("X-Haneoka-Image-Height"));const imageUrl = URL.createObjectURL(await response.blob());// Set your image element's dimensions and src; revoke imageUrl on teardown.console.log(width, height, imageUrl);실패 처리
섹션 제목: “실패 처리”오류는 {error:{code,message,requestId}}, X-Request-Id, Cache-Control: no-store를 씁니다. 주요 코드는 invalid_height/invalid_locale/invalid_download/release_not_supported(400), song_not_found/difficulty_not_found/chart_not_found(404), format_not_supported(406), chart_too_large/chart_render_budget(413), chart_image_failed(502), release_unavailable(503)입니다. 배포된 PNG 글꼴이 없거나 잘못되면 chart_image_failed, 글꼴 예산 초과는 chart_render_budget이 됩니다. 래스터라이저가 등록되지 않은 배포는 501 png_renderer_unavailable을 보고할 수 있습니다. 요청 ID를 보관하고, 매개변수나 배포 원인을 고친 뒤 재시도하세요.
실제 요청 만들고 확인하기
섹션 제목: “실제 요청 만들고 확인하기”서버, 곡, 난이도, 형식, 언어, 패널 높이, 내려받기를 바꾸고 GET, HEAD, OPTIONS를 고르세요. 애플리케이션은 클릭했을 때만 실제 엔드포인트를 가져옵니다. GET이 성공하면 반환된 크기의 실제 이미지를 스크롤 가능한 미리보기에 보여 주고 같은 바이트를 내려받게 합니다. 오류 응답은 HTTP 상태와 실제 본문을 보여 주며, 쓸 수 없는 엔드포인트 대신 로컬 이미지를 보여 주지 않습니다.
JSON을 편집하고 요청합니다. 응답에는 실제 상태, 크기, 캐시 헤더가 표시되고, GET이 성공하면 이미지 미리보기와 응답 내려받기를 제공합니다.
예제를 준비하는 중…
예제 소스 보기 scoped는 명시적 서버 경로를 고릅니다. apiBase는 호환되는 다른 API를 고르고, acceptLanguage와 ifNoneMatch는 요청 헤더를 정합니다. ifNoneMatch의 $last는 마지막 응답 ETag를 씁니다. 이들은 애플리케이션 전송 설정이며, API 매개변수 자체는 아래에 있습니다. HEAD, OPTIONS, 304에는 새 이미지 본문이 없습니다. 캐시하는 쪽은 304에서 저장한 표현을 다시 쓰세요. 이 확인 도구는 헤더를 보여 줍니다. 지우기, 교체, 페이지 이탈 시 자신이 만든 Blob URL을 폐기합니다. 화면 표시에는 SDK나 GPU 가져오기가 필요 없고 이미지를 미리 불러오지 않습니다.
라우트와 쿼리의 완전한 계약
섹션 제목: “라우트와 쿼리의 완전한 계약”GET/HEAD로 선택적 server 쿼리가 붙은 /api/v1/songs/{songId}/charts/{difficulty}/image.{format}이나 /api/v1/servers/{server}/songs/{songId}/charts/{difficulty}/image.{format}을 쓰세요. 공개 읽기에는 계정이 필요 없습니다. 원본 데이터를 읽기 전에 OPTIONS에는 204를, 지원하지 않는 메서드에는 Allow와 함께 405를 반환합니다.
| 매개변수 | 타입·필수·기본값 | 정확한 검증과 효과 |
|---|---|---|
| songId | 필수 문자열 경로 세그먼트 | 1~256자. 첫 글자는 영숫자, 나머지는 영숫자와 . _ : ~ -. 세그먼트 하나로 인코딩한다. 구문이 잘못되었거나 곡이 없으면 404 song_not_found. |
| difficulty | 필수 소문자 경로 세그먼트 | easy/normal/hard/expert/special/master. DTO에 있어야 하며, 없으면 404 difficulty_not_found. |
| format | 필수 확장자 | 소문자 svg/png. 형식은 맞지만 지원하지 않는 소문자 확장자는 406 format_not_supported, 잘못된 라우트는 404가 될 수 있다. SVG MIME은 image/svg+xml, PNG는 image/png. |
| server | 명시적 형태에서는 필수 세그먼트, 별칭 쿼리의 기본값은 intl | 양 끝이 영숫자인, 소문자 영숫자와 하이픈으로 된 1~40자의 활성 슬러그. 별칭에서 server가 중복되면 400 invalid_server, 잘못되었거나 알 수 없는 슬러그는 404 server_not_found. 명시적 형태에 server 쿼리를 주면 경로와 같아야 한다. |
| locale | 선택 쿼리, 없으면 협상 | ja/en/zh-TW/zh-CN/ko. 비었거나 지원하지 않거나 중복이면 400 invalid_locale. 캡션 언어이며 server와 독립. |
| height | 선택 쿼리, 기본값 720 | 1 |
| download | 선택 쿼리, 기본값 1 | 문자열 0 또는 1을 한 번만. 0은 inline, 1은 attachment. 비었거나 다른 값이거나 중복이면 400 invalid_download. |
| release | 지원 안 함 | release 쿼리를 주면 400 release_not_supported. 현재 데이터만. 카탈로그 릴리스 고정은 별도 인터페이스. |
이 HTTP 엔드포인트에는 너비, 곡 제목, 밴드, 노트 속도, 재킷을 덮어쓰는 매개변수가 없습니다. 제목, 밴드, 채보 데이터는 현재 곡 DTO와 실제 채보에서 가져옵니다. 쿼리 이름은 대소문자를 구분합니다. 비어 있지 않은 요청 본문은 400 body_not_allowed입니다.
모든 헤더와 바이너리 의미
섹션 제목: “모든 헤더와 바이너리 의미”| 헤더 | 방향·기본값 | 의미 |
|---|---|---|
| Accept-Language | 선택 요청 | locale 쿼리가 없을 때 쓴다. 일반 BCP 47 협상을 지원한다. |
| If-None-Match | 선택 요청 | 이전 ETag. 강한·약한 태그나 *가 맞으면 Content-Length 없는 304. |
| Content-Type | 응답 | SVG(UTF-8) 또는 PNG, 오류면 JSON. |
| Content-Length | 200·HEAD 응답 | 인코딩된 이미지의 실제 바이트 수. 304에는 없다. |
| Content-Disposition | 응답 | 기본 attachment 또는 inline. 파일 이름에 Haneoka, 서버, 곡, 난이도, 언어, 확장자가 들어간다. |
| Content-Language | 응답 | 선택된 캡션 언어. |
| ETag | 응답 | 표현과 선택된 서버, 릴리스, 곡, 언어, 렌더러 식별자의 해시. |
| X-Haneoka-Server | 응답 | 선택된 레지스트리. |
| X-Haneoka-Release-Id | 응답 | 실제 현재 릴리스. |
| X-Haneoka-Chart-Renderer | 응답 | 정적 개요 렌더러 버전. |
| X-Haneoka-Image-Width/Height | 응답 | 헤더와 패널 배치를 포함한 최종 캔버스 크기. |
| Cache-Control | 성공 시 public, max-age=300, must-revalidate | 오류는 no-store. |
| Vary | 성공 시 Accept-Language | 협상한 캡션 언어로 캐시를 구분한다. |
| X-Request-Id | 디스패처 응답 | 상관 ID. JSON API 오류에는 requestId도 들어 있다. |
| Allow | 405 응답 | GET, HEAD, OPTIONS. |
익명 CORS는 출처 *, GET/HEAD/OPTIONS, 요청 헤더 Content-Type/Accept/Accept-Language/If-None-Match를 허용합니다. 노출되는 이미지 메타데이터에는 Content-Disposition, Content-Length, 렌더러, 릴리스, 서버, 크기, ETag가 있습니다. 브라우저가 읽을 수 있는 헤더는 이 노출 설정에 따릅니다. 헤더가 노출되지 않으면 JSON 오류의 requestId를 보관하세요. HEAD는 같은 표현 헤더를 반환하며 본문이 없습니다. Range는 이미지 API 옵션이 아닙니다. 렌더링된 표현 전체를 가져오거나 ETag로 재검증하세요.
정확한 예산과 오류 복구
섹션 제목: “정확한 예산과 오류 복구”처리기가 읽는 것은 최대 원시 채보 2 MiB와 선택적 재킷 1 MiB입니다. 재킷이 없거나 지원하지 않으면 빼고 채보는 그대로 그립니다. 렌더러 상한은 패널 256개, 출력 1,200만 픽셀, SVG 8 MiB입니다. PNG는 시그니처와 IHDR, 정확한 크기, 8 MiB 바이트 상한을 검증합니다. 이는 서비스 제한이며 추가 요청 항목이 아닙니다. PNG 배포에는 등록된 래스터라이저와 Fontsource 매니페스트와 파일이 들어 있습니다.
| 상태·코드 | 원인 | 조치 |
|---|---|---|
| 400 invalid_height/locale/download/server | 허용된 매개변수가 잘못됨, 중복, 비어 있음 | 요청을 고친다. |
| 400 release_not_supported/body_not_allowed | 지원하지 않는 release나 본문 | 본문 없이 현재 데이터를 읽는다. |
| 404 server_not_found/song_not_found/difficulty_not_found/chart_not_found | 레지스트리, 엔티티, 채보를 쓸 수 없음 | 카탈로그를 읽고 쓸 수 있는 항목을 고른다. |
| 405 method_not_allowed | 읽기가 아닌 메서드 | GET/HEAD/OPTIONS를 쓴다. |
| 406 format_not_supported | 형식은 맞지만 지원하지 않는 확장자 | svg/png를 쓴다. |
| 413 chart_too_large/chart_render_budget | 입력, 글꼴, 출력 예산 초과 | 더 작은 채보를 고르거나 제공 측 예산을 보고한다. 너무 큰 요청을 그대로 반복하지 않는다. |
| 501 png_renderer_unavailable | 배포에 PNG 래스터라이저가 없음 | SVG를 쓰거나 렌더러를 배포한다. |
| 502 chart_path_invalid/chart_invalid/release_invalid | 원본 식별자, 경로, 채보가 잘못됨 | requestId를 보관하고 현재 데이터를 보고한다. |
| 502 png_invalid/chart_image_failed | PNG 시그니처나 크기 오류, 이미지나 글꼴 실패 | 해당 배포나 글꼴 에셋을 고친다. |
| 503 release_unavailable | 활성 릴리스가 없음 | 횟수를 제한한 백오프로 나중에 재시도한다. |
오류는 공개 디스패처의 {error:{code,message,requestId}}, X-Request-Id, no-store입니다. 네이티브 fetch, CORS, 중단 오류는 이 엔벌로프 이전의 전송 실패이므로 따로 표시하세요. 공개 사용 가능 여부는 실제로 배포된 워커 응답으로 정해집니다. 인라인 애플리케이션은 이를 기록하며, 문서 배포를 API 배포로 취급하지 않습니다.