/* babl - dynamically extendable universal pixel conversion library.
* Copyright (C) 2012 Øyvind Kolås.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see
* .
*/
#include
#include
#include
#include "config.h"
#include "babl-internal.h"
#include "base/util.h"
int init (void);
static void
conv_rgba8_cairo24_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
uint32_t *srci = (void *)src;
uint32_t *dsti = (void *)dst;
while (n--)
{
uint32_t orig = *srci++;
uint32_t green_alpha = (orig & 0x0000ff00);
uint32_t red_blue = (orig & 0x00ff00ff);
uint32_t red = red_blue << 16;
uint32_t blue = red_blue >> 16;
*dsti++ = green_alpha | red | blue | 0xff000000;
}
}
static void
conv_rgb8_cairo24_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
while (n--)
{
unsigned char red = *src++;
unsigned char green = *src++;
unsigned char blue = *src++;
*dst++ = blue;
*dst++ = green;
*dst++ = red;
*dst++ = 255;
}
}
#if 0
static void
conv_rgbA8_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
while (n--)
{
unsigned char red = *src++;
unsigned char green = *src++;
unsigned char blue = *src++;
unsigned char alpha = *src++;
*dst++ = blue;
*dst++ = green;
*dst++ = red;
*dst++ = alpha;
}
}
#else
static void
conv_rgbA8_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
uint32_t *srci = (void *)src;
uint32_t *dsti = (void *)dst;
while (n--)
{
uint32_t orig = *srci++;
uint32_t green_alpha = (orig & 0xff00ff00);
uint32_t red_blue = (orig & 0x00ff00ff);
uint32_t red = red_blue << 16;
uint32_t blue = red_blue >> 16;
*dsti++ = green_alpha | red | blue;
}
}
#endif
static void
conv_cairo32_rgba8_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
while (n--)
{
unsigned char blue = *src++;
unsigned char green = *src++;
unsigned char red = *src++;
unsigned char alpha = *src++;
if (alpha == 0)
{
*dst++ = 0;
*dst++ = 0;
*dst++ = 0;
*dst++ = 0;
}
else if (alpha == 255)
{
*dst++ = red;
*dst++ = green;
*dst++ = blue;
*dst++ = alpha;
}
else
{
float falpha = alpha / 255.0f;
*dst++ = red / falpha + 0.5f;
*dst++ = green / falpha + 0.5f;
*dst++ = blue / falpha + 0.5f;
*dst++ = alpha;
}
}
}
static void
conv_cairo32_rgbA8_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
while (n--)
{
unsigned char blue = *src++;
unsigned char green = *src++;
unsigned char red = *src++;
unsigned char alpha = *src++;
*dst++ = red;
*dst++ = green;
*dst++ = blue;
*dst++ = alpha;
}
}
static void
conv_cairo32_rgbAF_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst_char,
long samples)
{
long n = samples;
float *dst = (void*)dst_char;
while (n--)
{
unsigned char blue = *src++;
unsigned char green = *src++;
unsigned char red = *src++;
unsigned char alpha = *src++;
*dst++ = red / 255.0f;
*dst++ = green / 255.0f;
*dst++ = blue / 255.0f;
*dst++ = alpha / 255.0f;
}
}
static void
conv_cairo24_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
while (n--)
{
*dst++ = (*src++);
*dst++ = (*src++);
*dst++ = (*src++);
*dst++ = 255; src++;
}
}
static void
conv_cairo32_cairo24_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
#if 0
close .. but not quite acceptble this is perfect resolution for 1/300
/// 1/255 perfect resolution is around 0.0039
// maybe we are good enough! and babls fidelity once
//
// bad conversions are identified should be allowed to use
// the faster practically correct but not truely reversible variants?
//
$ rm ~/.cache/babl/babl-fishes; ninja && BABL_PATH=extensions BABL_TOLERANCE=0.1 ./tools/babl-verify cairo-ARGB32 cairo-RGB24
[7/7] Linking target extensions/x86-64-v3-cairo.so
extensions/x86-64-v3-cairo.so 0: cairo-ARGB32 to cairo-RGB24 error:0.002999 cost:219.000000
#endif
long n = samples;
while (n--)
{
int alpha = src[3];
if (alpha)
{
float falpha = (alpha/255.0f);
for (int c = 0; c < 3; c++)
*dst++ = (*src++)/falpha + .5f;
}
else
{
*dst++ = (*src++);
*dst++ = (*src++);
*dst++ = (*src++);
}
*dst++ = 0; src++;
}
}
static void
conv_rgba8_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
uint32_t *dsti = (void*) dst;
while (n--)
{
unsigned char alpha = src[3];
#if SIZE_MAX >= UINT64_MAX /* 64-bit */
uint64_t rbag = ((uint64_t) src[0] << 48) |
((uint64_t) src[2] << 32) |
((uint64_t) 255 << 16) |
((uint64_t) src[1] << 0);
rbag *= alpha;
rbag += 0x0080008000800080;
rbag += (rbag >> 8) & 0x00ff00ff00ff00ff;
rbag &= 0xff00ff00ff00ff00;
*dsti++ = (uint32_t) (rbag >> 0) |
(uint32_t) (rbag >> 40);
#else /* 32-bit */
uint32_t rb = ((uint32_t) src[0] << 16) |
((uint32_t) src[2] << 0);
uint64_t ag = ((uint32_t) 255 << 16) |
((uint32_t) src[1] << 0);
rb *= alpha;
ag *= alpha;
rb += 0x00800080;
ag += 0x00800080;
rb += (rb >> 8) & 0x00ff00ff;
ag += (ag >> 8) & 0x00ff00ff;
rb &= 0xff00ff00;
ag &= 0xff00ff00;
*dsti++ = (uint32_t) (ag >> 0) |
(uint32_t) (rb >> 8);
#endif
src+=4;
}
}
static void
conv_rgb8_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
while (n--)
{
unsigned char red = *src++;
unsigned char green = *src++;
unsigned char blue = *src++;
*dst++ = blue;
*dst++ = green;
*dst++ = red;
*dst++ = 0xff;
}
}
static void
conv_yA8_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
while (n--)
{
#define div_255(a) ((((a)+128)+(((a)+128)>>8))>>8)
unsigned char gray = *src++;
unsigned char alpha = *src++;
unsigned char val = div_255 (gray * alpha);
#undef div_255
*dst++ = val;
*dst++ = val;
*dst++ = val;
*dst++ = alpha;
}
}
static void
conv_yA16_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
uint16_t *ssrc = (void*) src;
while (n--)
{
float alpha = (ssrc[1]) / 65535.0f;
int val = (ssrc[0] * alpha) * (0xff / 65535.0f ) + 0.5f;
*dst++ = val;
*dst++ = val;
*dst++ = val;
*dst++ = (alpha * 0xff + 0.5f);
ssrc+=2;
}
}
static void
conv_y8_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
while (n--)
{
unsigned char val = *src++;
*dst++ = val;
*dst++ = val;
*dst++ = val;
*dst++ = 0xff;
}
}
static void
conv_y16_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
long n = samples;
uint16_t *s16 = (void*)src;
while (n--)
{
#define div_257(a) ((((a)+128)-(((a)+128)>>8))>>8)
uint16_t v16 = *s16++;
unsigned char val = div_257(v16);
#undef dib_257
*dst++ = val;
*dst++ = val;
*dst++ = val;
*dst++ = 0xff;
}
}
static void
conv_rgbA_gamma_float_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
float *fsrc = (float *) src;
unsigned char *cdst = (unsigned char *) dst;
int n = samples;
while (n--)
{
int val = fsrc[2] * 255.0f + 0.5f;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
val = fsrc[1] * 255.0f + 0.5f;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
val = fsrc[0] * 255.0f + 0.5f;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
val = fsrc[3] * 255.0f + 0.5f;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
fsrc+=4;
}
}
static void
conv_rgbafloat_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
const Babl *space = babl_conversion_get_destination_space (conversion);
const Babl **trc = (void*)space->space.trc;
float *fsrc = (float *) src;
unsigned char *cdst = (unsigned char *) dst;
int n = samples;
while (n--)
{
float red = *fsrc++;
float green = *fsrc++;
float blue = *fsrc++;
float alpha = *fsrc++;
if (alpha >= 1.0f)
{
int val = babl_trc_from_linear (trc[2], blue) * 0xff;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
val = babl_trc_from_linear (trc[1], green) * 0xff;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
val = babl_trc_from_linear (trc[0], red) * 0xff;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
*cdst++ = 0xff;
}
else if (alpha <= 0.0f)
{
(*(uint32_t*)cdst)=0;
cdst+=4;
}
else
{
float balpha = alpha * 0xff;
int val = babl_trc_from_linear (trc[2], blue) * balpha;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
val = babl_trc_from_linear (trc[1], green) * balpha;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
val = babl_trc_from_linear (trc[0], red) * balpha;
*cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
if (balpha > 255)balpha=255;
*cdst++ = balpha;
}
}
}
static void
conv_yafloat_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
const Babl *space = babl_conversion_get_destination_space (conversion);
const Babl **trc = (void*)space->space.trc;
float *fsrc = (float *) src;
unsigned char *cdst = (unsigned char *) dst;
int n = samples;
while (n--)
{
float gray = *fsrc++;
float alpha = *fsrc++;
if (alpha >= 1.0f)
{
int val = babl_trc_from_linear (trc[0], gray) * 0xff;
val = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
*cdst++ = val;
*cdst++ = val;
*cdst++ = val;
*cdst++ = 0xff;
}
else if (alpha <= 0.0f)
{
(*(uint32_t*)cdst)=0;
cdst+=4;
}
else
{
float balpha = alpha * 0xff;
int val = babl_trc_from_linear (trc[0], gray) * balpha + 0.5f;
val = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
*cdst++ = val;
*cdst++ = val;
*cdst++ = val;
*cdst++ = balpha + 0.5f;
}
}
}
static void
conv_yafloat_nl_cairo32_le (const Babl *conversion,
unsigned char *__restrict__ src,
unsigned char *__restrict__ dst,
long samples)
{
float *fsrc = (float *) src;
unsigned char *cdst = (unsigned char *) dst;
int n = samples;
while (n--)
{
float gray = *fsrc++;
float alpha = *fsrc++;
if (alpha >= 1.0f)
{
int val = gray * 0xff;
val = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
*cdst++ = val;
*cdst++ = val;
*cdst++ = val;
*cdst++ = 0xff;
}
else if (alpha <= 0.0f)
{
(*(uint32_t*)cdst)=0;
cdst+=4;
}
else
{
float balpha = alpha * 0xff;
int val = gray * balpha + 0.5f;
val = val >= 0xff ? 0xff : val <= 0 ? 0 : val;
*cdst++ = val;
*cdst++ = val;
*cdst++ = val;
*cdst++ = balpha + 0.5f;
}
}
}
#include "babl-verify-cpu.inc"
int
init (void)
{
int testint = 23;
char *testchar = (char*) &testint;
int littleendian = (testchar[0] == 23);
BABL_VERIFY_CPU();
if (littleendian)
{
const Babl *f32 = babl_format_new (
"name", "cairo-ARGB32",
"doc", "endianness adaptive native cairo format with alpha",
babl_model ("R'aG'aB'aA"),
babl_type ("u8"),
babl_component ("B'a"),
babl_component ("G'a"),
babl_component ("R'a"),
babl_component ("A"),
NULL
);
const Babl *f24 = babl_format_new (
"name", "cairo-RGB24",
"doc", "endianness adaptive native cairo format without alpha",
babl_model ("R'G'B'"),
babl_type ("u8"),
babl_component ("B'"),
babl_component ("G'"),
babl_component ("R'"),
babl_component ("PAD"),
NULL
);
babl_conversion_new (f32, babl_format ("R'aG'aB'aA float"), "linear",
conv_cairo32_rgbAF_le, NULL);
babl_conversion_new (f32, babl_format ("R'aG'aB'aA u8"), "linear",
conv_cairo32_rgbA8_le, NULL);
babl_conversion_new (f32, babl_format ("R'G'B'A u8"), "linear",
conv_cairo32_rgba8_le, NULL);
babl_conversion_new (f24, f32, "linear",
conv_cairo24_cairo32_le, NULL);
babl_conversion_new (f32, f24, "linear",
conv_cairo32_cairo24_le, NULL);
babl_conversion_new (babl_format ("R'aG'aB'aA u8"), f32, "linear",
conv_rgbA8_cairo32_le, NULL);
babl_conversion_new (babl_format ("R'G'B'A u8"), f32, "linear",
conv_rgba8_cairo32_le, NULL);
babl_conversion_new (babl_format ("R'G'B' u8"), f32, "linear",
conv_rgb8_cairo32_le, NULL);
babl_conversion_new (babl_format ("Y'A u8"), f32, "linear",
conv_yA8_cairo32_le, NULL);
babl_conversion_new (babl_format ("Y'A u16"), f32, "linear",
conv_yA16_cairo32_le, NULL);
babl_conversion_new (babl_format ("Y' u8"), f32, "linear",
conv_y8_cairo32_le, NULL);
babl_conversion_new (babl_format ("Y' u16"), f32, "linear",
conv_y16_cairo32_le, NULL);
babl_conversion_new (babl_format ("RGBA float"), f32, "linear",
conv_rgbafloat_cairo32_le, NULL);
babl_conversion_new (babl_format ("YA float"), f32, "linear",
conv_yafloat_cairo32_le, NULL);
babl_conversion_new (babl_format ("Y'A float"), f32, "linear",
conv_yafloat_nl_cairo32_le, NULL);
babl_conversion_new (babl_format ("R'aG'aB'aA float"), f32, "linear",
conv_rgbA_gamma_float_cairo32_le, NULL);
babl_conversion_new (babl_format ("R'G'B'A u8"), f24, "linear",
conv_rgba8_cairo24_le, NULL);
babl_conversion_new (babl_format ("R'G'B' u8"), f24, "linear",
conv_rgb8_cairo24_le, NULL);
}
else
{
babl_format_new (
"name", "cairo-ARGB32",
"doc", "endianness adaptive native cairo format with alpha",
babl_model ("R'aG'aB'aA"),
babl_type ("u8"),
babl_component ("A"),
babl_component ("R'a"),
babl_component ("G'a"),
babl_component ("B'a"),
NULL
);
babl_format_new (
"name", "cairo-RGB24",
"doc", "endianness adaptive native cairo format without alpha",
babl_model ("R'G'B'"),
babl_type ("u8"),
babl_component ("PAD"),
babl_component ("R'"),
babl_component ("G'"),
babl_component ("B'"),
NULL
);
/* formats are registered - but no fast paths, this will be slow */
}
babl_format_new (
"name", "cairo-A8",
babl_model ("YA"),
babl_type ("u8"),
babl_component ("A"),
NULL
);
/* formats that distribute different subset of the additive mixing variants
* of CMYK producing two syntetic RGB formats we run in parallel to derive
* a 4 instead of 3 component result, the same method could be used to
* extend processing/drawing with cairo to spectral data.
*/
if (littleendian)
{
babl_format_new ("name", "cairo-ACMK32",
"doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with cairo.",
babl_model ("camayakaA"),
babl_type ("u8"),
babl_component ("ka"),
babl_component ("ma"),
babl_component ("ca"),
babl_component ("A"),
NULL);
babl_format_new ("name", "cairo-ACYK32",
"doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with cairo.",
babl_model ("camayakaA"),
babl_type ("u8"),
babl_component ("ka"),
babl_component ("ya"),
babl_component ("ca"),
babl_component ("A"),
NULL);
}
else
{
babl_format_new ("name", "cairo-ACMK32",
"doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with cairo.",
babl_model ("camayakaA"),
babl_type ("u8"),
babl_component ("A"),
babl_component ("ca"),
babl_component ("ma"),
babl_component ("ka"),
NULL);
babl_format_new ("name", "cairo-ACYK32",
"doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with cairo.",
babl_model ("camayakaA"),
babl_type ("u8"),
babl_component ("A"),
babl_component ("ca"),
babl_component ("ya"),
babl_component ("ka"),
NULL);
}
/* companion subset formats for setting pango u16 RGB color values from cmykA
* */
babl_format_new ("name", "cykA u16",
"doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with pango.",
babl_model ("cmykA"),
babl_type ("u16"),
babl_component ("cyan"),
babl_component ("yellow"),
babl_component ("key"),
babl_component ("A"),
NULL);
babl_format_new ("name", "cmkA u16",
"doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with pango.",
babl_model ("cmykA"),
babl_type ("u16"),
babl_component ("cyan"),
babl_component ("magenta"),
babl_component ("key"),
babl_component ("A"),
NULL);
return 0;
}