잡담

libWebP와 mozjpeg, Zopfli 삽질기

오랜만의 프로그래밍 일기. 요즘엔 이미지를 압축하는 프로그램을 만들어보고 있다. 프로그램 이름은 Degra. 열화 또는 저하를 뜻하는 degrade에서 따온 이름이다. 그러니까, 손실 압축 위주로 압축하는 프로그램.

UWP를 타겟으로 만들기 시작했는데, GUI 프레임워크 중에 쓸만하다고 생각하는건 XAML+C# 조합이고 x86, x64, ARM, ARM64 모두 동시 빌드해서 배포 가능한 플랫폼은 Win32 데스크톱보다는 UWP니까.

그런데 막상 UWP 앱으로 개발하려고 보니까 mozjpeg가 NASM이나 YASM을 써야 빌드가 되는 구조라 이걸 어쩌지 싶었다. 그래서 일단 libWebP부터 붙여서 webp 파일으로 압축하는 기능부터 구현.

멀티스레드 인코딩 기능이 분명 있는데 아무리 돌려도 WebP 인코딩에 싱글코어만  쓰는 문제가 있어서 아니 도대체 왜 이러는 걸까 했는데 릴리즈 모드로 빌드해보니 정상 작동. 아무래도 디버그 편의성을 위해서 디버그 모드에서는 싱글코어만 쓰는 걸로 추정된다. 어쨌든 WebP 인코딩 기능은 의외로 매우 편했다.

WebP 인코딩 기능 붙여놓고는 다시 mozjpeg를 붙이는 작업으로 돌아왔다. 일단 CMake로 Visual C++ 프로젝트 생성해놓고 빌드 결과물인 정적 라이브러리 파일을 UWP에 붙여보니 생각과 달리 잘 붙었다. x64로 테스트를 했었으니 나머지 x86, ARM, ARM64도 프로젝트 생성해서 붙이려고 하니 윈도우용 ARM과 ARM64를 mozjpeg에서 지원하지 않는 또다른 문제점이 있었다. 찾아보니 이슈는 만들어져 있는데 테스트 기기가 없어서 이슈가 닫혀있었다. 나도 뭐 딱히 테스트할 기기는 없고 해서 일단은 x64와 x86용만 붙여놨다. 인코딩 기능 인터페이스 자체는 libjpeg-turbo의 것을 사용하면 해결.

PNG 압축은 좀 고민을 더 했다. 8비트 인덱스 픽셀 포맷으로 만드는 기능은 추가가 이미 돼 있었고 인코딩은 Windows Imaging Codec(WIC)을 이용했는데 생각보다 압축률이 엄청 낮지는 않았음. 찾아보니 OptiPNG, pngquant, ZopfliPNG 등이 있어서 적용을 시도.

OptiPNG는 벤치마크 자료를 찾아보니 ZopfliPNG보다 성능이 딸리는데다 벤치마크 자료 찾아보기 전에 빌드 시도할 때 난황이 있었어서 포기. pngquant는 GPLv3 라이센스라 가져다 쓰기 좀 그랬는데 심지어 찾아보니 그냥 8비트 인덱스 픽셀 포맷으로 만들어주는 기능(+디더링, 미디언컷)만 있는 것 같길래 일단은 도입 포기. Zopfli만 적용하기로 했다.

드라마틱하게 압축률을 높여주진 않아서 실망했다. ZopfliPNG도 결국은 개선된 Deflate 알고리즘을 쓰는터라. Inflate에 들어가는 시간이 그냥 단순 WIC만 쓰는 것보다 많이 길어서 일단은 옵션으로만 남겨뒀다. 여러 인자를 좀 더 만져봐도 속도는 느려지는데 압축률은 고만고만 하더라. fast_zlib을 써서 libpng를 바로 적용해보는 것도 고민 중.

그래서 일단은 WebP, JPEG, PNG의 압축 기능은 구현이 됐다. 앱에서 GIF, TIFF 등의 그 외 포맷도 압축 기능을 지원할 지는 테스트 좀 더 해보고. UWP 파일 접근 권한 문제 때문에 안 그래도 골치아파.