/* 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; }