/* * This file was part of gggl, it implements a variety of pixel conversion * functions that are usable with babl, the file needs more cleanup, and * doesn't return the number of samples processed as a long, like it's * supposed to. * * 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 Øyvind Kolås */ //#define _POSIX_C_SOURCE 200112L #include "config.h" #include #include #include "babl.h" #include "base/util.h" #include "extensions/util.h" /* * 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, * gamma correction (not really,. gamma correction belongs in seperate ops,. */ /* lookup tables used in conversion */ static float table_8_F[1 << 8]; static float table_16_F[1 << 16]; static unsigned char table_F_8[1 << 16]; static unsigned short table_F_16[1 << 16]; static int table_inited = 0; static void table_init (void) { int i; if (table_inited) return; table_inited = 1; /* fill tables for conversion from integer to float */ for (i = 0; i < 1 << 8; i++) { table_8_F[i] = (i * 1.0) / 255.0; } for (i = 0; i < 1 << 16; i++) { table_16_F[i] = (i * 1.0) / 65535.0; } /* fill tables for conversion from float to integer */ { union { float f; unsigned short s[2]; } u; u.f = 0.0; u.s[0] = 0x8000; for (i = 0; i < 1 << 16; i++) { unsigned char c; unsigned short s; u.s[1] = i; if (u.f <= 0.0) { c = 0; s = 0; } else if (u.f >= 1.0) { c = 255; s = 65535; } else { c = u.f * 255 + 0.5f; s = u.f * 65535 + 0.5f; } /*fprintf (stderr, "%2.3f=%03i %05i ", f, c, (*hi)); / if (! ((*hi)%9)) / fprintf (stderr, "\n"); */ table_F_8[u.s[1]] = c; table_F_16[u.s[1]] = s; } } /* fix tables to ensure 1:1 conversions back and forth */ if (0) { /*FIXME: probably not the right way to do it,.. must sit down and scribble on paper */ int i; for (i = 0; i < 256; i++) { float f = table_8_F[i]; unsigned short *hi = ((unsigned short *) (void *) &f); unsigned short *lo = ((unsigned short *) (void *) &f); *lo = 0; table_F_8[(*hi)] = i; } } } /* function to find the index in table for a float */ static unsigned int gggl_float_to_index16 (float f) { union { float f; unsigned short s[2]; } u; u.f = f; return u.s[1]; } static 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 void conv_F_16 (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 short *) dst = table_F_16[gggl_float_to_index16 (f)]; dst += 2; src += 4; } } static void 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_16_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_16_F[*(unsigned short *) src]; dst += 4; src += 2; } } /*********/ static void conv_rgbaF_rgba8 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_F_8 (conversion, src, dst, samples * 4); } #define conv_rgbaF_rgbP8 conv_rgbaF_rgba8 static void conv_rgbF_rgb8 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_F_8 (conversion, src, dst, samples * 3); } static void 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_rgbaF_rgba16 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_F_16 (conversion, src, dst, samples * 4); } static void conv_rgbF_rgb16 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_F_16 (conversion, src, dst, samples * 3); } static void conv_gaF_ga16 (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_F_16 (conversion, src, dst, samples * 2); } #define conv_rgbAF_rgbA16 conv_rgbaF_rgba16 #define conv_gF_g16 conv_F_16 #define conv_gAF_gA16 conv_gaF_ga16 static void conv_rgba8_rgbaF (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_8_F (conversion, src, dst, samples * 4); } static void conv_rgb8_rgbF (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_8_F (conversion, src, dst, samples * 3); } static void conv_ga8_gaF (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_8_F (conversion, src, dst, samples * 2); } #define conv_rgbA8_rgbAF conv_rgba8_rgbaF #define conv_gA8_gAF conv_ga8_gaF #define conv_g8_gF conv_8_F static void conv_rgba16_rgbaF (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_16_F (conversion, src, dst, samples * 4); } static void conv_rgb16_rgbF (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_16_F (conversion, src, dst, samples * 3); } static void conv_ga16_gaF (const Babl *conversion, unsigned char *src, unsigned char *dst, long samples) { conv_16_F (conversion, src, dst, samples * 2); } #define conv_rgbA16_rgbAF conv_rgba16_rgbaF #define conv_gA16_gAF conv_ga16_gaF #define conv_g16_gF conv_16_F static void conv_rgbafloat_linear_cairo32_le (const Babl *conversion, unsigned char *src_char, unsigned char *dst, long samples) { long n = samples; float *src = (float*)src_char; while (n--) { float alpha = src[3] * 255; if (alpha <= BABL_ALPHA_FLOOR) { *(int *)dst = 0; } else { if (alpha > 255) alpha = 255; #define div_255(a) ((((a)+128)+(((a)+128)>>8))>>8) dst[0] = src[2] * alpha + 0.5f; dst[1] = src[1] * alpha + 0.5f; dst[2] = src[0] * alpha + 0.5f; dst[3] = alpha + 0.5f; } src += 4; dst += 4; } } int init (void); int init (void) { 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 *rgba16 = babl_format_new ( babl_model ("RGBA"), babl_type ("u16"), babl_component ("R"), babl_component ("G"), babl_component ("B"), babl_component ("A"), NULL); const Babl *rgba8 = babl_format_new ( babl_model ("RGBA"), babl_type ("u8"), 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 *rgbA16 = babl_format_new ( babl_model ("RaGaBaA"), babl_type ("u16"), babl_component ("Ra"), babl_component ("Ga"), babl_component ("Ba"), babl_component ("A"), NULL); const Babl *rgbA8 = babl_format_new ( babl_model ("RaGaBaA"), babl_type ("u8"), babl_component ("Ra"), babl_component ("Ga"), babl_component ("Ba"), babl_component ("A"), NULL); const Babl *rgbF = babl_format_new ( babl_model ("RGB"), babl_type ("float"), babl_component ("R"), babl_component ("G"), babl_component ("B"), NULL); const Babl *rgb16 = babl_format_new ( babl_model ("RGB"), babl_type ("u16"), babl_component ("R"), babl_component ("G"), babl_component ("B"), NULL); const Babl *rgb8 = babl_format_new ( babl_model ("RGB"), babl_type ("u8"), babl_component ("R"), babl_component ("G"), babl_component ("B"), NULL); const Babl *gaF = babl_format_new ( babl_model ("YA"), babl_type ("float"), babl_component ("Y"), babl_component ("A"), NULL); const Babl *gAF = babl_format_new ( babl_model ("YaA"), babl_type ("float"), babl_component ("Ya"), babl_component ("A"), NULL); const Babl *gF = babl_format_new ( babl_model ("Y"), babl_type ("float"), babl_component ("Y"), NULL); const Babl *ga16 = babl_format_new ( babl_model ("YA"), babl_type ("u16"), babl_component ("Y"), babl_component ("A"), NULL); const Babl *gA16 = babl_format_new ( babl_model ("YaA"), babl_type ("u16"), babl_component ("Ya"), babl_component ("A"), NULL); const Babl *g16 = babl_format_new ( babl_model ("Y"), babl_type ("u16"), babl_component ("Y"), NULL); const Babl *ga8 = babl_format_new ( babl_model ("YA"), babl_type ("u8"), babl_component ("Y"), babl_component ("A"), NULL); const Babl *gA8 = babl_format_new ( babl_model ("YaA"), babl_type ("u8"), babl_component ("Ya"), babl_component ("A"), NULL); const Babl *g8 = babl_format_new ( babl_model ("Y"), babl_type ("u8"), babl_component ("Y"), NULL); int testint = 23; char *testchar = (char*) &testint; int littleendian = (testchar[0] == 23); if (littleendian) { const Babl *f32 = babl_format_new ( "name", "cairo-ARGB32", 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 ); babl_conversion_new (babl_format ("RGBA float"), f32, "linear", conv_rgbafloat_linear_cairo32_le, NULL); } #define o(src, dst) \ babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) o (rgbaF, rgba8); o (rgba8, rgbaF); o (rgbaF, rgba16); o (rgba16, rgbaF); o (rgbAF, rgbA8); o (rgbA8, rgbAF); o (rgbAF, rgbA16); o (rgbA16, rgbAF); o (rgbF, rgb8); o (rgb8, rgbF); o (rgbF, rgb16); o (rgb16, rgbF); o (gaF, ga8); o (gAF, gA8); o (gF, g8); o (ga8, gaF); o (gA8, gAF); o (g8, gF); o (gaF, ga16); o (gAF, gA16); o (gF, g16); o (ga16, gaF); o (gA16, gAF); o (g16, gF); if (!table_inited) table_init (); return 0; }