libvips 사용법: 터미널에서 이미지 처리하기

libvips 사용법: 터미널에서 이미지 처리하기

웹 개발을 하다 보면 이미지를 다뤄야 하는 일이 정말 많죠. 사진을 리사이징하고, WebP나 AVIF로 변환하고, 썸네일을 만들고, 메타데이터를 확인하고… 이런 작업을 할 때 많은 분이 ImageMagick을 떠올리실 텐데요.

사실 더 빠르고 메모리도 훨씬 적게 쓰는 도구가 있습니다. 바로 libvips인데요. Node.js의 Sharp 라이브러리가 내부적으로 사용하는 이미지 처리 엔진이 바로 이 libvips입니다. Mastodon, Ruby on Rails, MediaWiki 같은 프로젝트에서도 이미지 처리에 libvips를 사용하고 있어요.

이번 글에서는 libvips가 제공하는 세 가지 CLI 도구의 사용법을 하나씩 살펴보겠습니다.

libvips란?

libvips는 이미지 처리에 특화된 라이브러리입니다. 300개 이상의 이미지 처리 연산을 지원하고, JPEG, PNG, WebP, AVIF, HEIF, TIFF, GIF 등 거의 모든 이미지 포맷을 다룰 수 있어요.

libvips가 빠른 이유는 이미지를 한꺼번에 메모리에 올려놓고 처리하는 게 아니라 파이프라인 방식으로 작은 조각(region)씩 처리하기 때문입니다. 덕분에 아주 큰 이미지도 메모리를 적게 쓰면서 빠르게 처리할 수 있죠. 멀티스레드 처리도 잘 되어 있어서 CPU 코어 수에 비례해서 성능이 올라갑니다.

libvips를 설치하면 세 가지 CLI 도구가 함께 설치됩니다.

  • vips — 300개 이상의 이미지 처리 연산을 실행하는 범용 도구
  • vipsthumbnail — 썸네일 생성에 특화된 도구
  • vipsheader — 이미지 메타데이터를 확인하는 도구

설치

운영체제별로 패키지 매니저를 사용해서 설치할 수 있습니다.

macOS에서는 Homebrew로 설치하면 됩니다.

brew install vips

Ubuntu/Debian에서는 apt로 설치합니다.

sudo apt install libvips-tools

설치가 완료되면 버전을 확인해볼까요?

vips --version
결과
vips-8.16.1

vipsheader로 이미지 정보 확인하기

이미지를 처리하기 전에 먼저 원본 이미지가 어떤 상태인지 파악하는 게 좋겠죠. vipsheader는 이미지 파일의 메타데이터를 빠르게 확인하는 도구입니다.

파일명만 넘기면 기본 정보를 보여줍니다.

vipsheader photo.jpg
결과
photo.jpg: 4032x3024 uchar, 3 bands, srgb, jpegload

가로 4032px, 세로 3024px, 8비트 RGB, sRGB 색공간의 JPEG 이미지라는 것을 한눈에 알 수 있습니다.

더 자세한 정보가 필요하면 -a 옵션을 사용합니다.

vipsheader -a photo.jpg
결과
photo.jpg: 4032x3024 uchar, 3 bands, srgb, jpegload
width: 4032
height: 3024
bands: 3
format: uchar
coding: none
interpretation: srgb
xres: 2.835
yres: 2.835
orientation: 1

특정 필드만 보고 싶다면 -f 옵션으로 지정할 수 있어요.

vipsheader -f width -f height photo.jpg
결과
width: 4032
height: 3024

여러 이미지의 크기를 한꺼번에 확인할 때 편리합니다.

vipsheader -f width -f height *.jpg

vipsthumbnail로 썸네일 만들기

vipsthumbnail은 이름 그대로 썸네일을 만드는 데 특화된 도구입니다. 내부적으로 축소 경로가 최적화되어 있어서 vips resize보다 더 빠르게 동작합니다.

가장 기본적인 사용법은 파일명만 넘기는 것입니다.

vipsthumbnail photo.jpg

아무 옵션 없이 실행하면 128x128 크기로 축소한 tn_photo.jpg 파일이 생성됩니다.

크기 지정

-s 옵션(또는 --size)으로 원하는 크기를 지정할 수 있습니다.

# 가로 세로 중 긴 쪽이 300px이 되도록 축소
vipsthumbnail photo.jpg -s 300

# 가로 800px, 세로는 비율에 맞춰 자동 조정
vipsthumbnail photo.jpg -s 800x

# 세로 600px, 가로는 비율에 맞춰 자동 조정
vipsthumbnail photo.jpg -s x600

# 정확히 400x300 크기의 바운딩 박스에 맞추기
vipsthumbnail photo.jpg -s 400x300

크기 뒤에 특수 문자를 붙여서 동작을 제어할 수도 있습니다.

# 원본보다 큰 경우만 축소 (확대하지 않음)
vipsthumbnail photo.jpg -s 300>

# 원본보다 작은 경우만 확대 (축소하지 않음)
vipsthumbnail photo.jpg -s 300<

# 비율 무시하고 강제로 맞추기
vipsthumbnail photo.jpg -s 400x300!

출력 파일 지정

기본적으로 tn_원본파일명.jpg 형식으로 저장되는데, -o 옵션으로 출력 경로와 포맷을 바꿀 수 있습니다.

# WebP로 출력
vipsthumbnail photo.jpg -s 300 -o thumb_%s.webp

# 다른 디렉토리에 저장
vipsthumbnail photo.jpg -s 300 -o ./thumbnails/%s.jpg

%s는 원본 파일의 확장자를 제외한 이름으로 치환됩니다. 출력 파일의 확장자에 따라 포맷이 자동으로 결정되기 때문에 .webp로 끝나면 WebP 파일이, .avif로 끝나면 AVIF 파일이 만들어집니다.

포맷 옵션도 함께 지정할 수 있어요.

# 품질 85의 JPEG으로 출력
vipsthumbnail photo.jpg -s 300 -o thumb_%s.jpg[Q=85]

# 품질 80의 WebP로 출력
vipsthumbnail photo.jpg -s 300 -o thumb_%s.webp[Q=80]

스마트 크롭

썸네일을 만들 때 단순히 축소만 하면 이미지가 찌그러지거나 중요한 부분이 잘릴 수 있죠. --smartcrop 옵션을 사용하면 이미지에서 중요한 영역을 자동으로 감지해서 크롭합니다.

# 관심 영역 기반 스마트 크롭
vipsthumbnail photo.jpg -s 400x400 --smartcrop attention

# 엔트로피(정보량) 기반 스마트 크롭
vipsthumbnail photo.jpg -s 400x400 --smartcrop entropy

attention은 사람의 시선이 자연스럽게 향하는 영역(얼굴, 밝은 색상 등)을 기준으로, entropy는 정보가 가장 많은 영역을 기준으로 크롭합니다. 인물 사진에는 attention이, 풍경이나 그래프 같은 이미지에는 entropy가 더 잘 맞는 편이에요.

EXIF 회전 반영

스마트폰으로 찍은 사진은 EXIF 메타데이터에 회전 정보가 들어 있어서 원본 픽셀은 실제로는 눕혀져 있는 경우가 있습니다. -t 옵션(또는 --rotate)을 사용하면 EXIF 회전 정보를 반영해서 올바른 방향으로 저장합니다.

vipsthumbnail photo.jpg -s 300 -t -o thumb_%s.jpg

여러 파일 한꺼번에 처리

vipsthumbnail의 가장 편리한 점 중 하나는 여러 파일을 한 번에 처리할 수 있다는 것입니다.

# 현재 디렉토리의 모든 JPEG 파일을 썸네일로 변환
vipsthumbnail *.jpg -s 300 -o thumb_%s.webp[Q=80]

더 많은 파일을 병렬로 처리하고 싶다면 GNU parallel과 함께 쓸 수 있어요.

parallel vipsthumbnail -s 300 -o thumb_{/.}.webp[Q=80] ::: *.jpg

vips로 이미지 변환하기

vips 명령어는 libvips가 제공하는 300개 이상의 연산을 직접 실행할 수 있는 범용 도구입니다. 리사이징, 크롭, 회전, 색상 조정, 포맷 변환 등 거의 모든 이미지 처리 작업을 할 수 있어요.

포맷 변환

가장 자주 쓰이는 작업이 포맷 변환인데요. vips copy로 입력 파일을 다른 포맷의 출력 파일로 복사하면 자동으로 변환됩니다.

# PNG를 JPEG으로 변환
vips copy photo.png photo.jpg

# JPEG을 WebP로 변환
vips copy photo.jpg photo.webp

# JPEG을 AVIF로 변환
vips copy photo.jpg photo.avif

출력 파일 이름 뒤에 대괄호로 포맷별 옵션을 지정할 수 있습니다.

# JPEG 품질 85로 변환
vips copy photo.png photo.jpg[Q=85]

# WebP 품질 80으로 변환
vips copy photo.jpg photo.webp[Q=80]

# 무손실 WebP로 변환
vips copy photo.png photo.webp[lossless]

# AVIF 품질 50으로 변환 (AVIF Q50은 JPEG Q75와 비슷한 품질)
vips copy photo.jpg photo.avif[Q=50]

메타데이터를 제거하고 싶으면 strip 옵션을 추가하면 됩니다.

vips copy photo.jpg output.jpg[Q=85,strip]

포맷별 주요 옵션

각 포맷마다 사용할 수 있는 옵션이 다른데, 자주 쓰이는 것들을 정리하면 이렇습니다.

JPEG의 경우 Q로 품질(0~100, 기본 75)을 지정하고, interlace를 추가하면 프로그레시브 JPEG이 됩니다. optimize_coding은 허프만 테이블을 최적화하고, strip은 메타데이터를 제거합니다. 최대한 압축하고 싶다면 mozjpeg 스타일 설정을 사용할 수 있어요.

vips copy input.jpg output.jpg[strip,optimize_coding,interlace,optimize_scans,trellis_quant,quant_table=3]

WebP에서는 Q로 품질(0~100, 기본 75)을 지정하고, lossless로 무손실 모드를 켤 수 있습니다. effort(0~6, 기본 4)는 높일수록 파일이 작아지지만 인코딩이 느려집니다.

vips copy input.jpg output.webp[Q=80,effort=6]

AVIF에서는 Q로 품질을 지정하는데, AVIF의 Q=30 정도면 JPEG Q=75와 비슷한 화질이 나옵니다. effort(0~9, 기본 4)와 lossless 옵션도 사용할 수 있어요.

vips copy input.jpg output.avif[Q=30,effort=4]

PNG에서는 compression(0~9, 기본 6)으로 압축 수준을 지정하고, palette를 추가하면 8비트 팔레트 PNG로 변환됩니다.

vips copy input.png output.png[compression=9,palette]

리사이징

vips resize는 스케일 팩터(배율)를 사용해서 이미지 크기를 조정합니다.

# 50%로 축소
vips resize photo.jpg resized.jpg 0.5

# 200%로 확대
vips resize photo.jpg resized.jpg 2.0

# 가로 세로 다른 비율로 조정
vips resize photo.jpg resized.jpg 0.5 --vscale 0.75

픽셀 단위로 크기를 지정하고 싶으면 vips thumbnail을 사용하는 게 더 편합니다.

# 가로 800px로 축소 (세로는 비율 유지)
vips thumbnail photo.jpg resized.jpg 800

# 포맷도 함께 변환
vips thumbnail photo.jpg resized.webp[Q=80] 800

크롭

vips crop은 이미지에서 원하는 영역을 잘라냅니다. 왼쪽 위 좌표와 크기를 지정하는 방식입니다.

# (100, 100) 위치에서 500x400 영역을 잘라내기
vips crop photo.jpg cropped.jpg 100 100 500 400

vips smartcrop은 중요한 영역을 자동으로 감지해서 지정한 크기로 잘라줍니다.

# 500x500 크기로 스마트 크롭
vips smartcrop photo.jpg cropped.jpg 500 500

회전

vips rot은 90도 단위로 회전합니다.

vips rot photo.jpg rotated.jpg d90
vips rot photo.jpg rotated.jpg d180
vips rot photo.jpg rotated.jpg d270

임의의 각도로 회전하려면 vips rotate를 사용합니다.

vips rotate photo.jpg rotated.jpg 45

연산 목록 확인

어떤 연산을 사용할 수 있는지 궁금하면 vips -l 명령어로 전체 목록을 확인할 수 있습니다.

# 모든 연산 목록
vips -l

# 포맷 관련 연산만 보기
vips -l foreign

# 특정 연산의 사용법 확인
vips resize

연산 이름만 인자 없이 실행하면 해당 연산의 사용법과 옵션이 출력됩니다.

vips thumbnail
결과
resize an image to a target size by area
usage:
   thumbnail filename out width
where:
   filename     - Filename to read from
   out          - Output image
   width        - Size to this width
optional arguments:
   height       - Size to this height, default: 0
   size         - Only upsize, only downsize, or both, default: both
   crop         - Reduce to fill target rectangle, then crop, default: none
   ...

파이프로 연결하기

여러 연산을 연속으로 적용해야 할 때는 libvips의 .v 포맷을 중간 파일로 사용하면 됩니다. .v는 libvips의 내부 포맷으로, 재압축 없이 빠르게 읽고 쓸 수 있어요.

# 리사이징 후 크롭하기
vips resize photo.jpg temp.v 0.5
vips crop temp.v result.jpg 0 0 400 300
rm temp.v

표준 입출력을 통한 파이프도 지원합니다.

cat photo.jpg | vips thumbnail_source [descriptor=0] .jpg[Q=85] 300 > thumb.jpg

성능 비교

libvips가 정말 빠를까요? 10000x10000 RGB TIFF 이미지를 리사이징하는 벤치마크 결과를 보면 차이가 확연합니다.

도구처리 시간메모리 사용량
libvips0.57초94 MB
Pillow-SIMD1.51초1,040 MB
GraphicsMagick2.05초1,976 MB
OpenCV3.15초798 MB
ImageMagick4.44초1,499 MB

libvips는 ImageMagick보다 약 8배 빠르면서 메모리는 16분의 1만 사용합니다. 이 차이가 나는 이유는 앞서 설명한 파이프라인 아키텍처 덕분인데요. ImageMagick이 이미지를 통째로 메모리에 올려서 처리하는 반면, libvips는 작은 타일 단위로 처리하면서 L2 캐시를 효율적으로 활용합니다.

이런 성능 차이는 이미지가 클수록, 처리할 파일이 많을수록 더 크게 체감됩니다. 웹 서비스에서 사용자가 업로드한 이미지를 실시간으로 리사이징해야 하는 경우에 특히 유리하죠.

실전 활용 예제

실제 업무에서 자주 마주치는 시나리오별로 명령어를 정리해보겠습니다.

웹용 이미지 최적화가 필요한 경우, 원본 JPEG을 가로 1920px 이하로 축소하면서 WebP와 AVIF 포맷으로 변환할 수 있습니다.

# 원본을 1920px로 축소하면서 WebP 변환
vips thumbnail photo.jpg photo.webp[Q=80] 1920

# AVIF로도 변환
vips thumbnail photo.jpg photo.avif[Q=30] 1920

소셜 미디어용 OG 이미지를 만들어야 한다면 1200x630 크기로 스마트 크롭합니다.

vipsthumbnail photo.jpg -s 1200x630 --smartcrop attention -o og_%s.jpg[Q=85]

디렉토리 안의 모든 이미지를 WebP로 일괄 변환하려면 이렇게 합니다.

for f in *.jpg *.png; do
  vips copy "$f" "${f%.*}.webp[Q=80]"
done

반응형 이미지를 위해 여러 크기의 썸네일을 한꺼번에 만들 수도 있습니다.

for size in 320 640 960 1280 1920; do
  vips thumbnail photo.jpg "photo-${size}w.webp[Q=80]" $size
done

마치며

libvips CLI는 이미지 처리가 필요한 거의 모든 상황에서 유용합니다. vipsheader로 이미지 정보를 빠르게 확인하고, vipsthumbnail로 썸네일을 일괄 생성하고, vips로 포맷 변환이나 리사이징 같은 세밀한 작업을 처리할 수 있죠.

무엇보다 ImageMagick 대비 압도적인 성능이 매력적입니다. 처리 속도가 8배 빠르고 메모리는 16분의 1만 사용하니까, 대량의 이미지를 다뤄야 하는 상황에서는 특히 차이가 큽니다.

이미 Astro의 이미지 최적화 파이프라인에서 내부적으로 Sharp(libvips)를 사용하고 있듯이, 대부분의 웹 프레임워크와 이미지 프록시 서버에서도 libvips를 선택하는 추세입니다. CLI 사용법을 알아두면 빌드 스크립트, CI/CD 파이프라인, 이미지 일괄 처리 등에서 바로 활용할 수 있을 거예요. 영상이나 오디오 파일도 터미널에서 다루고 싶다면 FFmpeg 사용법도 함께 알아두면 좋습니다.

더 자세한 내용은 libvips 공식 문서를 참고하시면 좋겠습니다.

This work is licensed under CC BY 4.0 CC BY

개발자를 위한 뉴스레터

달레가 정리한 AI 개발 트렌드와 직접 만든 콘텐츠를 전해드립니다.

Discord