KorIM Colors

KorIM support several color formats, packed inline classes and conversion between them as well as mixing, de/premultiplication and other optimized operations.

Table of contents:

ColorFormat

All color formats implements the ColorFormat interface.

interface ColorFormat {
    val bpp: Int
	fun getR(v: Int): Int
	fun getG(v: Int): Int
	fun getB(v: Int): Int
	fun getA(v: Int): Int
	fun pack(r: Int, g: Int, b: Int, a: Int): Int
}

PaletteColorFormat

class PaletteColorFormat(val palette: RgbaArray) : ColorFormat {
    override val bpp = 8
}

RGBA-based ColorFormat

  • ARGB, BGRA
  • RGB, BGR

16-bit RGBA-based ColorFormat

  • RGBA_4444
  • RGBA_5551
  • RGB_555
  • RGB_565
  • BGRA_4444
  • BGR_555
  • BGR_565
  • BGRA_5551

Floating-Point RGBA

Not a direct ColorFormat, but a way to store mutable colors allowing overflowing and special operations.

These clases store each component separately taking a Float or Double per component.

  • RGBAd
  • RGBAf

CMYK ColorFormat

CMYK is a color format used for printing. Its components are Cyan, Magenta, Yellow and Black. There is an inline class for packing CMYK colors and a color format to convert from/between RGBA colors.

  • CMYK, RGBA.toCMYK(), CMYK.toRGBA()

YCbCr and YUVA ColorFormat

KorIM supports a color format based on Luma and Two chromiance components. In addition to the companion object ColorFormat, these color formats provide inline classes wrapping an integer.

  • YCbCr, RGBA.toYCbCr(), YCbCr.toRGBA()
  • YUVA, RGBA.toYUVA(), YUVA.toRGBA()

Extended API

Determine the storage size

To determine the number of bytes a number of pixels would take to store in a specific format, we can use numberOfBytes or bytesPerPixel with a multiplication:

fun ColorFormat.numberOfBytes(pixels: Int): Int
val ColorFormat.bytesPerPixel: Double

Convert into/from RGBA

If we want to convert an Int-packed value into/from RGBA, we can use these functions:

fun ColorFormat.toRGBA(v: Int): RGBA
fun ColorFormat.packRGBA(c: RGBA): Int

Getting floating-point RGBA components

If we want to get values between 0-1 we can use the exntesion methods that convert the component values between 0-255 to Float or Double.

fun ColorFormat.getRf(v: Int): Float
fun ColorFormat.getGf(v: Int): Float
fun ColorFormat.getBf(v: Int): Float
fun ColorFormat.getAf(v: Int): Float

fun ColorFormat.getRd(v: Int): Double
fun ColorFormat.getGd(v: Int): Double
fun ColorFormat.getBd(v: Int): Double
fun ColorFormat.getAd(v: Int): Double

Packing and unpacking colors into ByteArray and Bitmap32

fun ColorFormat.unpackToRGBA(packed: Int): RGBA
fun ColorFormat.convertTo(color: Int, target: ColorFormat): Int
fun ColorFormat.decode(data: ByteArray, dataOffset: Int, out: RgbaArray, outOffset: Int, size: Int, littleEndian: Boolean = true)
fun ColorFormat.decode(data: ByteArray, dataOffset: Int = 0, size: Int = (data.size / bytesPerPixel).toInt(), littleEndian: Boolean = true): RgbaArray
fun ColorFormat.decodeToBitmap32(width: Int, height: Int, data: ByteArray, dataOffset: Int = 0, littleEndian: Boolean = true): Bitmap32 
fun ColorFormat.decodeToBitmap32(bmp: Bitmap32, data: ByteArray, dataOffset: Int = 0, littleEndian: Boolean = true): Bitmap32 
fun ColorFormat.encode(colors: RgbaArray, colorsOffset: Int, out: ByteArray, outOffset: Int, size: Int, littleEndian: Boolean = true)
fun ColorFormat.encode(colors: RgbaArray,colorsOffset: Int = 0,size: Int = colors.size,littleEndian: Boolean = true)
fun ColorFormat16.encode(colors: IntArray, colorsOffset: Int, out: ShortArray, outOffset: Int, size: Int): Unit
fun ColorFormat32.encode(colors: IntArray, colorsOffset: Int, out: IntArray, outOffset: Int, size: Int): Unit

RGBA and RGBAPremultiplied

These Color Formats and color packings (inline classes wrapping Int) represent 32-bit (8-bit per component) Red Green Blue and Alpha colors. The premultiplied version means that RGB components have been multiplied by its alpha component. Premultiplied alpha is useful when performing blending since less operations are required.

Converting color into string

val hexString: String get() ="#%02x%02x%02x%02x".format(r, g, b, a)
val htmlColor: String get() = "rgba($r, $g, $b, $af)"
val htmlStringSimple: String get() = "#%02x%02x%02x".format(r, g, b)

Mixing two colors

To mix two colors together:

  • RGBA.mix(RGBA)
  • RGBA.Companion.mix(dst: RGBA, src: RGBA)

To combine two colors weighting one over another:

  • RGBA.Companion.mix(RGBA, RGBA, factor)

Converting between premultiplied and premultiplied

RgbaArray and RgbaPremultipliedArray

RgbaArray and RgbaPremultipliedArray inline-wraps an IntArray and provides ways to set, get and fill values using RGBA and RGBAPremultiplied

ColorTransform

A ColorTransform represents multiplications and additions per component. You can achieve simple color transformations with this class.

val identity = ColorTransform(
    1, 1, 1, 1, // Multiplicative
    0, 0, 0, 0  // Additive
)

ColorMatrix

A colorMatrix represents a 5x4 matrix multiplying each component by each other and providing additions to each component.

val identity = ColorMatrix(
    1, 0, 0, 0,  0,
    0, 1, 0, 0,  0,
    0, 0, 1, 0,  0,
    0, 0, 0, 1,  0,
)
  • RGBA.transform(colorMatrix)