JPEG XL 브라우저 변환, WebGPU가 꼭 필요할까?

Rapier로 브라우저에서 사진을 JPEG XL로 바꾸려는데, 방문자 브라우저가 모두 WebGPU를 지원하는 건 아니다. GPU 없이도 변환이 될까, 배포할 때는 무엇을 함께 올려야 할까?

JPEG XL 브라우저 변환, WebGPU가 꼭 필요할까?
세 줄 요약
  • Rapier JXL의 기본 인코더는 CPU에서 작동하며 WebGPU는 필수 조건이 아니다.
  • 파일을 받는 toJXL 함수를 쓰려면 정지 이미지용 또는 전체 기능용 워커를 함께 배포해야 한다.
  • JXL 생성에 성공해도 브라우저의 이미지 표시 지원과 입력 사진의 색상·품질은 따로 확인해야 한다.

WebGPU가 없어도 CPU로 인코딩할 수 있다

Rapier JXL은 JavaScript로 작성된 JPEG XL 인코더다. 기본 함수인 encode는 CPU에서 실행된다. 비동기 함수 encodeAsync는 가능한 환경에서 사진 처리의 일부를 WebGPU로 옮기며, GPU 어댑터가 없거나 GPU 장치 연결이 끊기거나 GPU 오류가 나면 CPU 경로로 돌아간다.

API 문서는 품질 점수를 목표로 파일 크기를 찾는 encodeToScore에도 GPU를 선택적으로 전달하도록 한다. 따라서 WebGPU를 지원하지 않는다는 이유만으로 이 라이브러리의 변환 기능 전체를 막을 필요는 없다.

GPU 가속 효과는 장비와 처리 조건에 따라 읽어야 한다. 개발자의 비교 실험에서는 NVIDIA T4, 사진 24장, 품질 75·effort 1 조건에서 CPU와 GPU 처리 중앙값이 6.7초와 2.1초였다. 같은 문서의 품질 90 결과는 6.8초와 2.9초다. 이 수치는 GPU 경로의 가능성을 보여 주지만 사용자의 노트북이나 휴대전화 처리 시간을 뜻하지는 않는다.

파일 변환에는 toJXL과 워커를 연결한다

이미지 파일을 입력받는 페이지에는 rapier-jxl/image의 toJXL을 쓸 수 있다. 픽셀 배열을 직접 준비하는 코어 호출과 달리 파일을 받아 image/jxl 형식의 Blob을 반환하는 진입점이다.

프로젝트에 패키지를 설치하고, 정지 이미지용 워커를 페이지가 접근할 수 있는 경로에 배포한다. README의 파일 변환 예제는 다음 두 단계를 사용한다.

npm install rapier-jxl
# 패키지의 dist/rapier-still-worker.js를 웹에서 접근할 경로에 배포
import { toJXL } from 'rapier-jxl/image';

// file은 사용자가 선택한 File 객체다.
const jxl = await toJXL(file, {
  worker: './rapier-still-worker.js'
});
console.log(jxl.type); // image/jxl

위 코드는 패키지 import를 처리하는 웹 프로젝트에서 호출하는 예다. 반환된 Blob을 내려받는 버튼이나 미리보기 UI는 애플리케이션에서 연결해야 한다. worker 옵션에는 실행 중인 Worker 객체 또는 워커 파일의 URL이 필요하며, 애니메이션까지 처리하려면 전체 워커인 rapier-worker.js를 선택한다.

약 29KB는 픽셀 인코더의 크기다

Rapier가 소개하는 작은 코어와 웹 변환기에 필요한 전체 파일은 범위가 다르다. 10월 26일 확인한 README의 크기 표는 각 파일을 gzip 레벨 9로 압축한 값을 다음처럼 구분한다.

구성gzip 크기역할
코어28,920바이트타입이 지정된 RGBA 픽셀을 인코딩한다.
이미지 호출용 모듈1,184바이트입력을 워커에 보내고 JXL Blob을 받는다.
정지 이미지 워커149,572바이트사진·JPEG 변환 등을 포함하며 애니메이션은 제외한다.
전체 워커214,332바이트정지 이미지 기능에 애니메이션 등을 더한다.

약 29KB짜리 코어를 가져왔다고 파일 선택부터 저장까지 갖춘 변환기가 완성되는 것은 아니다. 일반 사진 변환이라면 이미지 호출용 모듈과 정지 이미지 워커를 기준으로 필요한 구성을 잡는 편이 정확하다.

파일을 만들 수 있다는 것과 화면에 표시된다는 것은 다르다

Rapier의 API 문서는 JXL을 표시하려면 브라우저의 기본 지원이나 별도의 디코더가 필요하다고 설명한다. 인코더를 페이지에 넣어도 브라우저의 img 요소에 새 형식 지원이 자동으로 생기는 것은 아니다.

브라우저 내장 Canvas 출력도 확인할 지점이다. MDN의 toBlob 설명에 따르면 요청한 형식을 지원하지 않으면 PNG로 출력한다. image/jxl을 요청하거나 파일 이름을 .jxl로 붙였다는 사실만으로 실제 JXL 인코딩이 됐다고 판단하면 안 된다.

입력 JPEG의 처리 방식도 선택에 영향을 준다. toJXL은 지원하는 JPEG를 원본 바이트로 복원 가능한 경로로 처리한다. transcode: false를 주면 JPEG를 픽셀로 풀어 다시 인코딩하는 경로가 된다. 원본 보존이 목적이라면 두 경로를 혼동하지 않아야 한다.

코드를 넣지 않고 변환을 먼저 해보려면 제작자가 제공하는 Rapier 변환 페이지를 이용할 수 있다. 제작자는 파일을 기기 안에서 처리한다고 설명한다. 웹 앱에 통합할 때는 워커 경로, 결과 Blob, 대상 브라우저의 표시와 색상을 실제 입력 파일로 확인하는 순서가 적절하다.