이미지 회전 · 뒤집기
90도·180도·임의 각도 회전, 좌우·상하 반전, EXIF 방향 자동 보정 — 100% 브라우저 처리, 무설치
1. 이미지 회전·뒤집기 도구 소개
| 기능 | 회전·뒤집기 |
|---|---|
| 지원 형식 | JPG, PNG, WebP, GIF, BMP |
| 처리 방식 | 브라우저 Canvas API |
| 서버 전송 | 없음 (100% 로컬) |
| 최소 각도 | 0.1° 단위 |
| 각도 범위 | −360° ~ +360° |
| EXIF 보정 | 자동 지원 |
| 배경 채우기 | 투명·흰색·검정·커스텀 |
이미지 회전은 디지털 사진 편집에서 가장 기초적이면서도 자주 필요한 작업 중 하나입니다. 스마트폰으로 가로로 찍었는데 세로로 저장된 사진, 스캔한 문서의 기울기 보정, SNS 업로드용 이미지 방향 조정 등 회전이 필요한 상황은 일상에서 매우 빈번합니다.
TodayTooltip의 이미지 회전 도구는 단순히 90도 단위 회전만 지원하는 대부분의 온라인 도구와 달리, 0.1도 단위의 임의 각도 회전을 지원합니다. 지평선이 약간 기울어진 풍경 사진, 스캔 시 종이가 조금 비뚤어진 문서, 예술적 효과를 위해 특정 각도로 기울이고 싶은 이미지 등 다양한 용도로 활용할 수 있습니다.
핵심 기능을 살펴보면 다음과 같습니다. 빠른 회전 버튼으로 90°/180°/270° 회전을 원클릭으로 처리할 수 있으며, 각도 입력란과 슬라이더를 연동하여 −180°~+180° 범위에서 실시간으로 미리보기를 확인하면서 정밀 조정이 가능합니다. 좌우 반전(수평 플립)과 상하 반전(수직 플립)도 독립적으로 적용할 수 있어, 셀카 보정이나 텍스트 반전 등 다양한 시나리오에 대응합니다.
특히 주목할 기능은 EXIF 방향 태그 자동 보정입니다. 스마트폰 카메라로 찍은 사진은 실제 픽셀 데이터는 눕혀진 채로 저장되고, EXIF 메타데이터의 Orientation 태그로만 올바른 방향을 지정하는 경우가 많습니다. 이 도구는 해당 태그를 읽어 이미지를 실제로 올바른 방향으로 회전시킨 뒤 처리합니다. 모든 처리는 JavaScript Canvas API를 통해 완전히 브라우저 안에서 수행되므로 이미지가 외부 서버로 전송되지 않습니다.
2. EXIF Orientation 태그의 역사 — 스마트폰 카메라와 방향 메타데이터 문제
EXIF(Exchangeable Image File Format)의 Orientation 태그는 현대 디지털 사진에서 수많은 혼란과 버그를 일으키는 근본 원인 중 하나입니다. 이 태그가 왜 존재하게 되었는지, 그리고 왜 아직도 문제를 일으키는지 이해하려면 디지털 카메라의 역사를 살펴볼 필요가 있습니다.
초창기 디지털 카메라(1990년대 후반)는 대부분 가로(landscape) 방향 촬영을 기본으로 설계되었습니다. 카메라 센서 자체가 가로로 배치되어 있었기 때문에, 세로(portrait) 방향으로 촬영하려면 카메라를 90도 회전해야 했습니다. 이 경우 이미지 센서는 여전히 가로 방향으로 픽셀을 캡처하기 때문에, 실제로 저장되는 픽셀 데이터는 90도 눕혀진 상태입니다.
JEIDA(일본전자공업진흥협회, 現 JEITA)는 1998년 EXIF 2.1 표준을 제정하면서 이 문제를 해결하기 위해 Orientation 태그(태그 ID: 0x0112)를 도입했습니다. 이 태그는 1~8까지의 값을 가지며, 각 값은 이미지가 올바르게 표시되기 위해 뷰어가 어떤 방향으로 표시해야 하는지를 지정합니다. 예를 들어, 값 6은 "시계방향으로 90도 회전해서 표시하라"는 의미입니다.
| 값 | 의미 | 변환 필요 동작 |
|---|---|---|
| 1 | 정상 (회전 없음) | 없음 |
| 2 | 수평 반전 | 좌우 뒤집기 |
| 3 | 180° 회전 | 180도 회전 |
| 4 | 수직 반전 | 상하 뒤집기 |
| 5 | 90° CW + 수평 반전 | 시계방향 90° + 좌우 뒤집기 |
| 6 | 90° CW (시계방향) | 시계방향 90° 회전 |
| 7 | 90° CW + 수직 반전 | 시계방향 90° + 상하 뒤집기 |
| 8 | 90° CCW (반시계방향) | 반시계방향 90° 회전 |
이 접근법은 이론적으로 우아한 해결책이었습니다. 픽셀 데이터를 실제로 재정렬하는 연산 비용 없이, 작은 메타데이터 값 하나로 방향 정보를 저장할 수 있었습니다. 그러나 실제로는 소프트웨어 생태계 전반에 걸쳐 수십 년간 혼란을 초래했습니다.
문제의 핵심은 일관성 없는 소프트웨어 지원입니다. 일부 뷰어와 브라우저는 이 태그를 읽고 자동으로 회전해서 표시하지만, 일부는 태그를 무시하고 픽셀 데이터를 그대로 표시합니다. 예를 들어, iOS Safari는 항상 EXIF Orientation을 존중하지만, 일부 구형 안드로이드 브라우저나 Windows 포토 뷰어 구버전은 태그를 무시했습니다. 결과적으로 아이폰으로 찍은 세로 사진이 어떤 기기에서는 올바르게 보이고 다른 기기에서는 옆으로 누워 보이는 현상이 발생했습니다.
웹 개발 측면에서 이 문제는 더욱 복잡합니다. HTML의 <img> 태그는 EXIF Orientation을 존중하도록 표준화된 것은 비교적 최근(Chrome 81, Firefox 26 이후)의 일입니다. 이전에는 JavaScript로 EXIF를 직접 파싱해서 CSS transform을 적용하거나, Canvas에 올바른 방향으로 그리는 수작업이 필요했습니다. 이 도구가 EXIF 자동 보정 기능을 제공하는 이유가 바로 여기에 있습니다. 이미지를 회전·편집하기 전에 먼저 EXIF Orientation에 따라 실제 픽셀을 올바른 방향으로 재배치함으로써, 이후 모든 처리가 "보이는 대로" 동작하도록 보장합니다.
3. 이미지 회전의 수학: 회전 행렬, 선형 변환, 어파인 변환
이미지 회전은 수학적으로 선형 대수의 회전 행렬(Rotation Matrix)로 완벽하게 기술됩니다. 단순해 보이는 회전 연산의 뒤에는 좌표 변환, 보간(interpolation), 캔버스 크기 재계산 등 여러 수학적 과정이 숨어 있습니다.
원점을 중심으로 각도 θ만큼 회전하는 2D 회전 행렬은 다음과 같이 정의됩니다:
[ sin θ, cos θ ]
이미지 상의 임의 점 (x, y)를 θ만큼 회전한 새 좌표 (x', y')는 다음과 같이 계산됩니다:
y' = x·sin θ + y·cos θ
위의 공식은 원점(0,0) 기준 회전입니다. 이미지 중심을 기준으로 회전하려면 어파인 변환(Affine Transformation)을 적용해야 합니다. 어파인 변환은 선형 변환(회전, 스케일, 전단)에 이동(translation)을 추가한 것으로, 3×3 행렬로 표현됩니다:
2단계: 회전 행렬 적용: rotate(θ)
3단계: 다시 원하는 중심으로 이동: translate(+cx', +cy')
Canvas API의 ctx.translate()와 ctx.rotate()가 바로 이 어파인 변환을 내부적으로 수행합니다. Canvas는 변환 행렬(CTM, Current Transformation Matrix)을 유지하며, 모든 그리기 연산은 이 행렬에 의해 변환된 좌표계에서 수행됩니다.
임의 각도로 회전할 때 가장 중요한 계산 중 하나는 회전된 이미지가 온전히 들어갈 새 캔버스 크기를 구하는 것입니다. 원래 너비 W, 높이 H인 이미지를 θ만큼 회전하면, 새 캔버스의 너비 W'와 높이 H'는 다음과 같이 계산됩니다:
H' = |W·sin θ| + |H·cos θ|
이 공식은 회전된 사각형의 경계 박스(bounding box)를 계산하는 것으로, 이미지의 네 꼭짓점이 회전 후 어떤 좌표를 가지는지 구하고 그 최솟값과 최댓값의 차이를 구하는 것과 동일합니다. 예를 들어 1920×1080 이미지를 45도 회전하면 약 2121×2121 픽셀 캔버스가 필요합니다.
회전 후 각 출력 픽셀의 색상값을 결정하는 방법이 보간(Interpolation)입니다. 가장 간단한 최근접 이웃(Nearest Neighbor) 방식은 계단 현상(aliasing)이 두드러지지만 빠릅니다. 양선형 보간(Bilinear Interpolation)은 인접한 4개 픽셀의 가중 평균을 사용하여 더 부드러운 결과를 제공하며, Canvas의 기본 렌더링 모드입니다. 양삼차 보간(Bicubic Interpolation)은 16개 픽셀을 사용하여 더 선명하고 부드럽지만 연산 비용이 높습니다. Photoshop이나 GIMP 같은 전문 도구가 고품질 회전에 양삼차 보간을 사용하는 이유입니다. 브라우저 Canvas API는 기본적으로 양선형 보간을 사용하여 속도와 품질의 균형을 맞춥니다.
4. 회전 시 발생하는 빈 공간(레터박스) 처리 전략 비교
임의 각도로 이미지를 회전하면 직사각형 이미지가 기울어지면서 사각형 캔버스의 모서리에 빈 공간이 생깁니다. 이 공간을 어떻게 처리하느냐에 따라 결과물의 용도와 시각적 느낌이 달라집니다.
가장 일반적인 방법으로, 회전된 이미지가 온전히 보이도록 캔버스 크기를 키우고 빈 공간을 지정한 배경색(또는 투명)으로 채웁니다. 이미지의 어떤 부분도 잘리지 않는다는 장점이 있습니다. 디자인 작업, 합성, 인쇄물 제작 등 이미지 전체가 중요한 경우에 적합합니다. 단점은 파일 크기가 커질 수 있다는 점과, 레이아웃에 사용할 경우 크기가 예측 불가능하게 변할 수 있다는 점입니다.
캔버스 크기를 원본과 동일하게 유지하고, 회전으로 인해 캔버스 밖으로 나가는 부분은 자릅니다. 결과물의 크기가 일정하다는 장점이 있습니다. 소셜 미디어 포스팅, 썸네일 생성 등 고정 크기가 필요한 경우에 유용합니다. 단, 이미지 가장자리 부분이 잘릴 수 있습니다.
회전된 이미지 안에 꼭 맞는 최대 직사각형을 찾아 그 부분만 잘라냅니다. 빈 공간 없이 이미지 내용만으로 가득 찬 직사각형 결과물을 얻을 수 있습니다. 내접 직사각형의 크기는 각도 θ에 따라 달라지며, 수학적으로는 다음과 같이 계산됩니다:
이 전략은 Lightroom의 "회전 후 자르기" 기능, Instagram의 사진 보정 등에서 사용됩니다.
| 전략 | 캔버스 크기 | 이미지 손실 | 빈 공간 | 적합한 용도 |
|---|---|---|---|---|
| 여백 추가 | 커짐 | 없음 | 있음 | 편집·합성·인쇄 |
| 원본 크기 유지 | 동일 | 가장자리 잘림 | 없음 | 고정 크기 레이아웃 |
| 내접 크롭 | 작아짐 | 가장자리 일부 | 없음 | SNS 업로드·보정 |
투명 배경: PNG 또는 WebP로 저장할 때만 의미가 있습니다. 웹 디자인, UI 아이콘, 합성 작업에서 레이어를 유지하고 싶을 때 사용합니다. JPG는 투명도를 지원하지 않으므로 JPG 저장 시 투명 영역은 기본값(보통 흰색)으로 채워집니다.
흰색 배경: 문서 스캔, 프레젠테이션 자료 등 흰색 배경이 자연스러운 경우에 적합합니다. 대부분의 인쇄물 용도에도 흰색이 무난합니다.
검정 배경: 영화·영상 관련 이미지, 다크 테마 UI, 우주·야경 사진 등에 어울립니다.
커스텀 색상: 브랜드 아이덴티티에 맞는 특정 색상이 필요할 때 사용합니다. 이 도구에서는 색상 피커로 원하는 색상을 직접 지정할 수 있습니다.
5. 이미지 미러링(플립)의 활용 — 셀카 보정, 텍스트 미러링 문제
이미지 뒤집기(플립, 미러링)는 회전과 달리 픽셀을 좌우 또는 상하 방향으로 대칭 이동시키는 연산입니다. 수학적으로는 스케일 변환의 특수한 경우로, 좌우 반전은 X축 스케일에 −1을 적용하고, 상하 반전은 Y축 스케일에 −1을 적용합니다.
스마트폰 전면 카메라는 거울처럼 동작합니다. 화면에서 보이는 미리보기는 좌우가 반전된 상태(거울 이미지)이지만, 실제로 저장되는 사진은 제조사 설정에 따라 다릅니다. 삼성 갤럭시의 경우 기본 설정에서 셀카를 "거울처럼" 저장하는 옵션이 있어, 촬영자가 익숙하게 보던 방향(거울 방향)으로 저장됩니다. 반면 아이폰은 촬영한 방향 그대로(비거울) 저장하는 것이 기본입니다. 이 차이 때문에 "내가 앱에서 보던 내 얼굴과 저장된 사진의 내 얼굴이 다르다"는 경험이 발생합니다. 좌우 반전 기능으로 이 문제를 즉시 해결할 수 있습니다.
이미지에 텍스트가 포함된 경우, 좌우 반전을 적용하면 텍스트도 함께 반전되어 읽을 수 없게 됩니다. 이른바 미러 텍스트(Mirror Text)가 만들어지는 것입니다. 의도적으로 거울 효과를 표현하는 예술 작업이 아니라면, 텍스트가 포함된 이미지는 반전 시 각별한 주의가 필요합니다. 일부 고급 이미지 편집 도구는 특정 레이어만 선택적으로 반전하는 기능을 제공하지만, 픽셀 단위로 처리하는 이 도구에서는 전체 이미지가 반전됩니다.
상하 반전(수직 플립)은 좌우 반전보다 일상적인 활용도는 낮지만 특수한 용도가 있습니다. 수면에 비친 반영 효과를 만들 때, 인스타그램 등 SNS에서 창의적인 시각 효과를 위해, 건축 렌더링에서 반사 표면 시뮬레이션 등에 사용됩니다. 또한 일부 스캐너가 문서를 거꾸로 스캔하는 경우 상하 반전으로 빠르게 보정할 수 있습니다.
플립과 회전은 독립적으로 또는 조합해서 적용할 수 있습니다. Canvas API에서는 ctx.scale(-1, 1)로 좌우 반전, ctx.scale(1, -1)로 상하 반전을 구현합니다. 중요한 것은 변환 순서입니다. 수학적으로 회전 행렬과 스케일 행렬의 곱셈은 교환법칙이 성립하지 않으므로, 회전 후 플립과 플립 후 회전은 다른 결과를 만들 수 있습니다. 이 도구에서는 항상 회전 먼저, 플립 나중의 순서로 적용됩니다.
6. 디지털 카메라와 EXIF 표준의 역사
EXIF(Exchangeable Image File Format)는 디지털 카메라에서 이미지 파일에 메타데이터를 저장하기 위한 표준 규격입니다. 현재는 사진 촬영 일시, GPS 위치, 카메라 모델, 노출 설정 등 수십 가지 정보를 담을 수 있는 정교한 포맷으로 발전했습니다.
EXIF의 역사는 1995년으로 거슬러 올라갑니다. 일본 전자 공업 진흥 협회(JEIDA, Japan Electronic Industry Development Association)가 디지털 카메라 제조사들 사이의 파일 포맷 호환성을 위해 최초의 EXIF 1.0 규격을 제정했습니다. 당시에는 주로 후지필름, 캐논, 니콘 등 일본 카메라 제조사들이 주도했습니다.
1998년 EXIF 2.1, 2002년 EXIF 2.2, 2010년 EXIF 2.3으로 지속적으로 개정되며 지원 태그와 기능이 크게 확장되었습니다. JEIDA는 이후 JEITA(Japan Electronics and Information Technology Industries Association)로 통합되어 현재도 규격 관리를 담당합니다.
| 태그 이름 | 태그 ID | 저장 정보 |
|---|---|---|
| DateTime | 0x0132 | 파일 수정 일시 |
| DateTimeOriginal | 0x9003 | 원본 촬영 일시 |
| Orientation | 0x0112 | 이미지 방향 (1~8) |
| Make / Model | 0x010F / 0x0110 | 카메라 제조사·모델명 |
| ExposureTime | 0x829A | 셔터 스피드 (초) |
| FNumber | 0x829D | 조리개 값 (F 수) |
| ISOSpeedRatings | 0x8827 | ISO 감도 |
| FocalLength | 0x920A | 초점 거리 (mm) |
| GPSLatitude / GPSLongitude | 0x8825 | GPS 위도·경도 |
| PixelXDimension / PixelYDimension | 0xA002 / 0xA003 | 이미지 해상도 |
스마트폰 카메라의 등장은 EXIF의 중요성을 한층 높였습니다. 아이폰이 2007년 등장한 이후 GPS 태그가 기본으로 내장되기 시작했고, 이후 HDR 처리 정보, 렌즈 보정 데이터, 깊이 맵(depth map) 등 점점 더 많은 정보가 EXIF에 추가되었습니다. 현재 아이폰의 사진 한 장에는 수백 개의 EXIF 태그가 포함될 수 있으며, 애플 고유의 확장 태그(MakerNote)까지 포함하면 데이터 양이 상당합니다.
개인정보 보호 관점에서 EXIF의 GPS 태그는 민감한 이슈입니다. 집에서 찍은 사진을 SNS에 올리면 정확한 집 위치가 메타데이터에 노출될 수 있습니다. 대부분의 SNS(Instagram, Twitter/X, Facebook)는 업로드 시 GPS 태그를 자동으로 제거하지만, 이미지를 직접 공유하거나 이메일로 전송할 때는 주의가 필요합니다.
7. 회전 손실: JPEG 손실 압축 vs JPEGTRAN 무손실 회전
JPEG 이미지를 회전하고 다시 저장할 때 화질이 저하된다는 이야기를 들어본 적 있을 것입니다. 이는 사실이지만, 그 메커니즘을 정확히 이해하면 손실을 최소화하거나 아예 피할 수 있습니다.
JPEG는 이미지를 8×8 픽셀 블록으로 나눈 뒤, 각 블록에 DCT(Discrete Cosine Transform, 이산 코사인 변환)를 적용하여 주파수 성분으로 변환합니다. 고주파 성분(미세한 디테일)을 버리는 양자화 과정에서 손실이 발생합니다. 압축률이 높을수록 더 많은 고주파 성분이 버려져 품질이 떨어집니다.
문제는 JPEG 이미지를 불러와서 픽셀 단위로 수정한 뒤 다시 JPEG로 저장하면, 두 번의 양자화가 이루어진다는 점입니다. 첫 번째 저장 시 이미 한 번 양자화된 데이터를 다시 DCT 변환하고 재양자화하므로 오차가 누적됩니다. 이것이 "JPEG를 열고 저장할 때마다 화질이 떨어진다"는 현상의 원인입니다.
jpegtran은 JPEG 이미지를 픽셀로 디코딩하지 않고 DCT 블록 수준에서 직접 조작하는 명령줄 도구입니다. 90도, 180도, 270도 회전은 DCT 블록 자체를 재배열하는 것으로 구현할 수 있으며, 이 경우 픽셀 값이 전혀 변경되지 않아 화질 손실이 없습니다. 이것이 "무손실 JPEG 회전"의 핵심입니다.
단, 무손실 회전의 조건이 있습니다. 이미지의 너비와 높이가 모두 8의 배수(더 엄밀하게는 크로마 서브샘플링에 따라 8 또는 16의 배수)여야 합니다. 크기가 조건을 만족하지 않으면 가장자리 블록을 처리하는 방식에서 약간의 손실이 불가피합니다. jpegtran은 -trim 옵션으로 조건 불만족 시 가장자리를 자르거나, -perfect 옵션으로 조건 불만족 시 아예 변환을 거부하도록 설정할 수 있습니다.
이 도구를 포함한 대부분의 브라우저 기반 이미지 처리 도구는 Canvas API를 사용하여 이미지를 처리합니다. JPEG를 Canvas에 그리는 과정에서 먼저 완전히 디코딩되어 RGBA 픽셀 배열로 변환됩니다. 이 상태에서 회전이 적용되고, 다시 JPEG로 인코딩되어 저장됩니다. 즉, Canvas 방식은 항상 재인코딩 과정에서 손실이 발생합니다.
화질 손실을 최소화하려면 품질(quality) 설정을 높이거나, 출력 형식을 PNG(무손실)로 선택하는 것이 좋습니다. 또는 원본이 JPEG인 경우, 단순히 90도 회전만 필요하다면 jpegtran 같은 전문 도구 사용을 고려하세요. 웹 기반 도구의 편의성과 무손실 처리의 품질 사이에서 적절한 선택이 필요합니다.
| 방법 | 지원 각도 | 화질 손실 | 사용 편의성 |
|---|---|---|---|
| Canvas API (이 도구) | 임의 각도 | 재인코딩 시 최소 손실 | 매우 높음 |
| jpegtran (CLI) | 90°/180°/270°만 | 없음 (무손실) | 낮음 (터미널 필요) |
| Photoshop (PNG 저장) | 임의 각도 | 없음 (PNG 저장 시) | 중간 |
| EXIF Orientation 편집 | 90°/180°/270°만 | 없음 (픽셀 미변경) | 중간 |
8. CSS transform:rotate vs Canvas 변환 vs SVG transform 비교
웹 환경에서 이미지를 회전하는 방법은 크게 세 가지가 있습니다. 각각 다른 목적과 장단점을 가지고 있으며, 용도에 따라 적절한 방법을 선택해야 합니다.
CSS의 transform: rotate(ndeg)는 DOM 요소를 시각적으로 회전시킵니다. 핵심은 시각적 변환이라는 점으로, 실제 이미지 픽셀 데이터는 전혀 변경되지 않습니다. GPU가 직접 처리하기 때문에 매우 빠르고 애니메이션에 적합합니다. 그러나 회전된 이미지를 파일로 저장하거나 캔버스에 그려야 하는 경우에는 사용할 수 없습니다. 또한 기본적으로 요소가 자신의 공간을 차지하는 방식이 회전 전과 동일하게 유지되어(레이아웃에 영향 없음), 다른 요소와 겹칠 수 있습니다. transform-origin 속성으로 회전 중심점을 지정할 수 있습니다.
Canvas는 픽셀 수준에서 이미지를 처리합니다. ctx.rotate()는 Canvas의 CTM(Current Transformation Matrix)을 변경하며, 이후 ctx.drawImage()로 그린 이미지는 실제 픽셀이 회전된 상태로 Canvas에 래스터화됩니다. 결과는 실제 픽셀 데이터이므로 파일로 내보내거나 추가 편집이 가능합니다. 이 도구가 Canvas API를 사용하는 이유입니다. 단점은 큰 이미지의 경우 메모리와 처리 시간이 많이 필요하다는 점과, 회전 시 보간으로 인해 미세한 화질 변화가 발생할 수 있다는 점입니다.
SVG의 transform="rotate(angle, cx, cy)"는 벡터 그래픽 맥락에서 이미지나 요소를 회전합니다. SVG 내부에 <image> 요소로 래스터 이미지를 삽입하고 transform을 적용할 수 있습니다. 벡터 요소(텍스트, 경로 등)의 경우 완벽한 무손실 회전이 가능합니다. 그러나 래스터 이미지를 SVG에 embed하는 방식은 파일 크기 효율이 낮고, 브라우저 렌더링 성능이 Canvas보다 떨어질 수 있습니다.
| 방법 | 픽셀 변경 | 파일 저장 | GPU 가속 | 임의 각도 | 주 용도 |
|---|---|---|---|---|---|
| CSS transform | 없음 | 불가 | 있음 | 가능 | UI 애니메이션 |
| Canvas API | 있음 | 가능 | 부분적 | 가능 | 이미지 편집·저장 |
| SVG transform | 없음 | SVG로만 | 있음 | 가능 | 벡터 그래픽 |
9. 다중 파일 일괄 회전 전략 — Web Workers 활용
수십~수백 장의 이미지를 동일한 각도로 회전해야 하는 경우, 브라우저의 단일 스레드에서 순차 처리하면 UI가 멈추는 문제가 발생합니다. Web Workers를 활용하면 백그라운드 스레드에서 병렬 처리하여 사용자 경험을 크게 개선할 수 있습니다.
Web Workers는 브라우저의 JavaScript 메인 스레드와 별도로 동작하는 백그라운드 스레드입니다. DOM에는 접근할 수 없지만, 데이터 처리, 파일 변환, 암호화 등 CPU 집약적인 작업에 적합합니다. Canvas의 OffscreenCanvas API를 통해 Worker 내부에서도 Canvas 조작이 가능해져 이미지 처리 작업을 완전히 Worker로 옮길 수 있습니다.
최적의 일괄 처리 방식은 파일 수와 이미지 크기에 따라 달라집니다. 소규모(10개 미만)는 순차 처리로 충분합니다. 중규모(10~50개)는 Worker Pool을 만들어 사용 가능한 CPU 코어 수(navigator.hardwareConcurrency)에 맞게 병렬 처리합니다. 대규모(50개 이상)는 스트리밍 처리와 ZIP 압축을 병행하여 메모리 사용을 최적화합니다. 모든 파일을 메모리에 올리지 않고 처리된 파일을 즉시 ZIP에 추가하는 방식입니다.
현재 이 도구는 단일 파일 처리에 최적화되어 있지만, 다중 파일 지원은 동일한 rotateImage() 함수를 반복 호출하는 방식으로 확장할 수 있습니다. 브라우저 환경에서는 메모리 제한이 중요하여, 큰 이미지 여러 장을 동시에 처리하면 크래시가 발생할 수 있으므로 순차 처리 또는 제한된 병렬 처리가 안전합니다.
mogrify -rotate 90 *.jpg 명령으로 현재 디렉토리의 모든 JPG를 일괄 회전할 수 있습니다. 90도 회전은 JPEG 품질 손실 없이 처리하는 방법도 있습니다.
10. 흔한 오해 5가지
11. 자주 묻는 질문 (FAQ)
for %f in (*.jpg) do magick "%f" -rotate 90 "rotated_%f"와 같이 일괄 처리할 수 있습니다.