/* * This file was part of gggl, it implements a variety of pixel conversion * functions that are usable with babl, the file needs more cleanup, but the * conversion functions that are usable gets used by babl. * * GGGL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GGGL 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GGGL; if not, see . * * Rights are granted to use this shared object in libraries covered by * LGPL. (exception added, during import into babl CVS.) * * Copyright 2003, 2004, 2005, 2007 Øyvind Kolås */ /* * Implemented according to information read from: * * http://www.cinenet.net/~spitzak/conversion/sketches_0265.pdf * * initially ignoring any diffusion, to keep the implementation * smaller, and interchangeable with the non optimized version. * * due to ability to be able to relicence gggl under a different * licence than GPL, I avoided the temptation to look at the * source files in the same location, in case I was going to * need this piece of code for projects where GPL compatibility * was a must. * * TODO: error diffusion, */ #include #include #include "config.h" #include "babl.h" #include "base/util.h" #include "extensions/util.h" /* lookup tables used in conversion */ static float table_8_F[1 << 8]; static float table_8g_F[1 << 8]; static unsigned char table_F_8[1 << 17]; static unsigned char table_F_8g[1 << 17]; static int table_inited = 0; static void table_init (void) { if (table_inited) return; table_inited = 1; /* fill tables for conversion from integer to float */ { int i; for (i = 0; i < 1 << 8; i++) { float direct = i / 255.0; table_8_F[i] = direct; table_8g_F[i] = gamma_2_2_to_linear (direct); } } /* fill tables for conversion from float to integer */ { union { float f; uint32_t s; } u; u.f = 0.0f; //u.s[0] = 0; for (u.s = 0; u.s < 4294900000U; u.s += 32768) { int c; int cg; if (u.f <= 0.0f) { c = 0; cg = 0; } else { c = (u.f * 255.1619f) + 0.5f; cg = (linear_to_gamma_2_2 (u.f) * 255.1619f) + 0.5f; if (cg > 255) cg = 255; if (c > 255) c = 255; } table_F_8[(u.s >> 15) & ((1 << 17)-1)] = c; table_F_8g[(u.s >> 15) & ((1 << 17)-1)] = cg; } } #if 0 /* fix tables to ensure 1:1 conversions back and forth */ if (0) { int i; for (i = 0; i < 256; i++) { float f; unsigned short *hi = ((unsigned short *) (void *) &f); unsigned short *lo = ((unsigned short *) (void *) &f); f = table_8_F[i]; *lo = 0; table_F_8[*hi] = i; f = table_8g_F[i]; *lo = 0; table_F_8g[*hi] = i; } } #endif } /* function to find the index in table for a float */ static inline unsigned int gggl_float_to_index16 (float f) { union { float f; uint32_t s; } u; u.f = f; return (u.s >> 15) & ((1 << 17)-1); } static inline void conv_F_8 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { long n = samples; if (!table_inited) table_init (); while (n--) { register float f = (*(float *) src); *(unsigned char *) dst = table_F_8[gggl_float_to_index16 (f)]; dst += 1; src += 4; } } static inline void conv_F_8g (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { long n = samples; if (!table_inited) table_init (); while (n--) { register float f = (*(float *) src); *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; dst += 1; src += 4; } } static inline void __attribute__((unused)) conv_8_F (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { long n = samples; if (!table_inited) table_init (); while (n--) { (*(float *) dst) = table_8_F[*(unsigned char *) src]; dst += 4; src += 1; } } static void conv_rgbaF_rgb8 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { long n = samples; while (n--) { register float f = (*(float *) src); *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; src += 4; dst += 1; f = (*(float *) src); *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; src += 4; dst += 1; f = (*(float *) src); *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; src += 4; dst += 1; src += 4; } } static void __attribute__((unused)) conv_rgbaF_rgba8 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { long n = samples; while (n--) { register float f = (*(float *) src); *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; src += 4; dst += 1; f = (*(float *) src); *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; src += 4; dst += 1; f = (*(float *) src); *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; src += 4; dst += 1; f = (*(float *) src); *(unsigned char *) dst = table_F_8[gggl_float_to_index16 (f)]; src += 4; dst += 1; } } #define conv_rgbaF_rgbP8 conv_rgbaF_rgba8 static void __attribute__((unused)) conv_rgbF_rgb8 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_F_8g (conversion, src, dst, samples * 3); } static void __attribute__((unused)) conv_gaF_ga8 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_F_8 (conversion, src, dst, samples * 2); } #define conv_rgbAF_rgbA8 conv_rgbaF_rgba8 #define conv_gF_g8 conv_F_8 #define conv_gAF_gA8 conv_gaF_ga8 static void conv_rgba8_rgbaF (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { long n = samples; while (n--) { (*(float *) dst) = table_8g_F[*(unsigned char *) src]; dst += 4; src += 1; (*(float *) dst) = table_8g_F[*(unsigned char *) src]; dst += 4; src += 1; (*(float *) dst) = table_8g_F[*(unsigned char *) src]; dst += 4; src += 1; (*(float *) dst) = table_8_F[*(unsigned char *) src]; dst += 4; src += 1; } } static void conv_ga8_rgbaF (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { long n = samples; while (n--) { float gray = table_8g_F[*(unsigned char *) src]; (*(float *) dst) = gray; dst += 4; src += 1; (*(float *) dst) = gray; dst += 4; (*(float *) dst) = gray; dst += 4; (*(float *) dst) = table_8_F[*(unsigned char *) src]; dst += 4; src += 1; } } static void conv_rgb8_rgbaF (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { long n = samples; while (n--) { (*(float *) dst) = table_8g_F[*(unsigned char *) src]; dst += 4; src += 1; (*(float *) dst) = table_8g_F[*(unsigned char *) src]; dst += 4; src += 1; (*(float *) dst) = table_8g_F[*(unsigned char *) src]; dst += 4; src += 1; (*(float *) dst) = 1.0; dst += 4; } } static void conv_rgbAF_rgb8 (const Babl *conversion, unsigned char *srcc, unsigned char *dstc, long samples) { float *src = (void *) srcc; unsigned char *dst = (void *) dstc; long n = samples; while (n--) { float alpha = src[3]; if (alpha == 0.0f) { dst[0] = 0.0f; dst[1] = 0.0f; dst[2] = 0.0f; } else { float alpha_recip = 1.0f / alpha; dst[0] = table_F_8g[gggl_float_to_index16 (src[0] * alpha_recip)]; dst[1] = table_F_8g[gggl_float_to_index16 (src[1] * alpha_recip)]; dst[2] = table_F_8g[gggl_float_to_index16 (src[2] * alpha_recip)]; } src += 4; dst += 3; } } static void conv_bgrA8_rgba8 (const Babl *conversion, unsigned char *srcc, unsigned char *dstc, long samples) { unsigned char *src = (void *) srcc; unsigned char *dst = (void *) dstc; long n = samples; while (n--) { unsigned char alpha = src[3]; dst[0] = alpha ? (src[2] * 255 / alpha) : 0; dst[1] = alpha ? (src[1] * 255 / alpha) : 0; dst[2] = alpha ? (src[0] * 255 / alpha) : 0; dst[3] = alpha; src += 4; dst += 4; } } static void conv_rgbaF_rgbAF (const Babl *conversion, unsigned char *srcc, unsigned char *dstc, long samples) { float *src = (void *) srcc; float *dst = (void *) dstc; long n = samples; while (n--) { float alpha = src[3]; float used_alpha = babl_epsilon_for_zero_float (alpha); dst[0] = src[0] * used_alpha; dst[1] = src[1] * used_alpha; dst[2] = src[2] * used_alpha; dst[3] = alpha; src += 4; dst += 4; } } static void conv_rgbAF_rgbaF (const Babl *conversion, unsigned char *srcc, unsigned char *dstc, long samples) { float *src = (void *) srcc; float *dst = (void *) dstc; long n = samples; while (n--) { float alpha = src[3]; float used_alpha = babl_epsilon_for_zero_float (alpha); float recip = 1.0f/used_alpha; dst[0] = src[0] * recip; dst[1] = src[1] * recip; dst[2] = src[2] * recip; dst[3] = alpha; src += 4; dst += 4; } } static void conv_rgbAF_lrgba8 (const Babl *conversion, unsigned char *srcc, unsigned char *dstc, long samples) { float *src = (void *) srcc; unsigned char *dst = (void *) dstc; long n = samples; while (n--) { float alpha = src[3]; float used_alpha = babl_epsilon_for_zero_float (alpha); float recip = (1.0f/used_alpha); dst[0] = table_F_8[gggl_float_to_index16 (src[0] * recip)]; dst[1] = table_F_8[gggl_float_to_index16 (src[1] * recip)]; dst[2] = table_F_8[gggl_float_to_index16 (src[2] * recip)]; dst[3] = table_F_8[gggl_float_to_index16 (alpha)]; src += 4; dst += 4; } } static void conv_rgba8_rgb8 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { long n = samples - 1; while (n--) { *(unsigned int *) dst = (*(unsigned int *) src); src += 4; dst += 3; } dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; } #define conv_rgb8_rgbAF conv_rgb8_rgbaF #define conv_gamma_rgbaF_gamma_rgbAF conv_rgbaF_rgbAF #define conv_gamma_rgbAF_gamma_rgbaF conv_rgbAF_rgbaF int init (void); #include "babl-verify-cpu.inc" int init (void) { BABL_VERIFY_CPU(); { const Babl *rgbaF = babl_format_new ( babl_model ("RGBA"), babl_type ("float"), babl_component ("R"), babl_component ("G"), babl_component ("B"), babl_component ("A"), NULL); const Babl *rgbAF = babl_format_new ( babl_model ("RaGaBaA"), babl_type ("float"), babl_component ("Ra"), babl_component ("Ga"), babl_component ("Ba"), babl_component ("A"), NULL); const Babl *gamma_rgbaF = babl_format_new ( babl_model ("R'G'B'A"), babl_type ("float"), babl_component ("R'"), babl_component ("G'"), babl_component ("B'"), babl_component ("A"), NULL); const Babl *gamma_rgbAF = babl_format_new ( babl_model ("R'aG'aB'aA"), babl_type ("float"), babl_component ("R'a"), babl_component ("G'a"), babl_component ("B'a"), babl_component ("A"), NULL); const Babl *lrgba8 = babl_format_new ( babl_model ("RGBA"), babl_type ("u8"), babl_component ("R"), babl_component ("G"), babl_component ("B"), babl_component ("A"), NULL); const Babl *rgba8 = babl_format_new ( babl_model ("R'G'B'A"), babl_type ("u8"), babl_component ("R'"), babl_component ("G'"), babl_component ("B'"), babl_component ("A"), NULL); const Babl *bgrA8 = babl_format_new ( "name", "B'aG'aR'aA u8", 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 *rgb8 = babl_format_new ( babl_model ("R'G'B'"), babl_type ("u8"), babl_component ("R'"), babl_component ("G'"), babl_component ("B'"), NULL); const Babl *ga8 = babl_format_new ( babl_model ("Y'A"), babl_type ("u8"), babl_component ("Y'"), babl_component ("A"), NULL); table_init (); #define o(src, dst) \ babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) o (rgbaF, rgbAF); o (rgbAF, rgbaF); o (gamma_rgbaF, gamma_rgbAF); o (gamma_rgbAF, gamma_rgbaF); o (rgbAF, lrgba8); o (rgb8, rgbaF); o (rgb8, rgbAF); o (rgba8, rgbaF); o (rgbaF, rgb8); o (rgbAF, rgb8); o (bgrA8, rgba8); o (rgba8, rgb8); o (ga8, rgbaF); } return 0; }