Monthly Archives: May 2018

Dreaming of an image loading/saving/manipulation library

For decades I was using FreeImage as a “backend” images loading/saving library which I wrapped into my own Bitmap class providing additional image manipulation functionality on top: convert colors, blit, resize, convolve, move channels around, cut & paste, and so on and so forth. The Bitmap class has been evolving for almost 15 years to become what it is now, a true abomination combining different coding styles and looking like a patched stovepipe with numerous ugly fixes and hacks. While it is still doing its job, it is becoming more and more difficult to support and maintain it. A full-featured clean image manipulation library would be really nice to have. Here is my features wish list for it.

  • Support 1D, 2D, 3D and Cube images. I’m doing graphics and using this class as a staging ground to upload textures to GPU. 1D image can be a particular case of 2D image with the height of 1, 2D image can be a case of 3D image with the depth of 1, and Cube image can be a 3D image with the depth equal to 6. Should be able to convert equirectangular projection to a cube image and back. Should be able to convert vertical/horizontal cross image to a cube image and back. Should be able to extract a 2D slice from a 3D image (and write it back as well).
  • Support different pixel formats. 8/16/32-bit unsigned/signed integer. 16/32-bit floating point. Arbitrary number of channels, R/RG/RGB/RGBA. Basic image operations like GetPixel, SetPixel, Resize, Flip, etc should work with all these basic formats. GetPixel should support bilinear and trilinear (for 3D textures) filtering. Cube image lookup should support seamless mode.
  • Some notion of channels semantics. All flavours of RGB-BGR, RGBA-BGRA, ARGB-RGBA, etc conversions. Different color spaces (CMYK, Lab) desirable but are not a show stopper.
  • Conversion from sRGB to linear color and back.
  • Support of some esoteric formats to store compressed image data and upload it later to GPU. ETC2/ETC2_EAC is a minimum here. Basic image operations can skip all work with these formats. That’s it, just storage.
  • Blending operations. Normal, Lighten, Darken, Multiply, Average, Add, Subtract, Difference, Negation, Screen, Exclusion, SoftLight, HardLight, VividLight, PinLight, LinearLight, HardMix, ColodDodge, ColorBurn, LinearDodge, LinearBurn, etc.
  • The library should not be too pessimized on performance if compiled with -O0 optimization (many C++14/17/20 libraries have this). Should be able to run the code in debug builds reasonably well.
  • Add/remove scanline stride.
  • Load and save different image formats. JPEG, PNG, HDR, KTX, RAW (uncompressed pixels, mostly for 3D textures) loading and saving are vital necessary. EXR loading is necessary as well, however, saving is optional.
  • Load and save from/to files and memory.
  • Move channels around. “Take the 2nd channel from this image and put it into the 1st channel of this one”.
  • Some rudimentary drawing operations: ClearColor, FillBox, MakeXorPattern, line drawing, etc.
  • Store mipmap levels (just having a NextImage pointer will do). Treat mipmaps well while loading and saving image formats which support them (KTX).
  • Calculate normal maps from heigh maps and height maps from normal maps.
  • Should have configurable dependencies. All supported image formats should be optional and configurable at will.
  • Support multiple image loading/saving backends switchable at compile time. For example, libpng/libjpeg vs stb_image.
  • Simple to compile. Two files would be ideal: .cpp and .hpp
  • Anyone?