babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples);
}
+static inline void
+universal_linear_rgb_nonlinear_converter (const Babl *conversion,
+ unsigned char *src_char,
+ unsigned char *dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *destination_space = conversion->conversion.destination->format.space;
+ float * matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ babl_matrix_mul_vectorff_buf4 (matrixf, rgba_in, rgba_out, samples);
+
+ TRC_OUT(rgba_out, rgba_out);
+}
+
static inline void
universal_nonlinear_rgba_u8_converter (const Babl *conversion,
unsigned char *src_char,
babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples);
}
+
+
+static inline void
+universal_linear_rgb_nonlinear_converter_sse2 (const Babl *conversion,
+ unsigned char *src_char,
+ unsigned char *dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *destination_space = conversion->conversion.destination->format.space;
+ float * matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_in, rgba_out, samples);
+
+ TRC_OUT(rgba_out, rgba_out);
+}
#endif
if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE) &&
(babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE2))
{
+
+
prep_conversion(babl_conversion_new(
babl_format_with_space("RGBA float", space),
babl_format_with_space("RGBA float", babl),
babl_format_with_space("R'G'B'A float", space),
"linear", universal_nonlinear_rgba_converter_sse2,
NULL));
+
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", space),
+ babl_format_with_space("RGBA float", babl),
+ "linear", universal_nonlinear_rgb_linear_converter_sse2,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", babl),
+ babl_format_with_space("RGBA float", space),
+ "linear", universal_nonlinear_rgb_linear_converter_sse2,
+ NULL));
+
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", babl),
+ babl_format_with_space("R'G'B'A float", space),
+ "linear", universal_linear_rgb_nonlinear_converter_sse2,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", space),
+ babl_format_with_space("R'G'B'A float", babl),
+ "linear", universal_linear_rgb_nonlinear_converter_sse2,
+ NULL));
+
prep_conversion(babl_conversion_new(
babl_format_with_space("R'G'B'A u8", space),
babl_format_with_space("R'G'B'A u8", babl),
babl_format_with_space("RGBA float", space),
"linear", universal_rgba_converter,
NULL));
+
prep_conversion(babl_conversion_new(
babl_format_with_space("R'G'B'A float", space),
babl_format_with_space("R'G'B'A float", babl),
babl_format_with_space("R'G'B'A float", space),
"linear", universal_nonlinear_rgba_converter,
NULL));
+
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", space),
+ babl_format_with_space("RGBA float", babl),
+ "linear", universal_nonlinear_rgb_linear_converter_sse2,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", babl),
+ babl_format_with_space("RGBA float", space),
+ "linear", universal_nonlinear_rgb_linear_converter_sse2,
+ NULL));
+
prep_conversion(babl_conversion_new(
babl_format_with_space("R'G'B'A u8", space),
babl_format_with_space("R'G'B'A u8", babl),
babl_format_with_space("R'G'B' u8", space),
"linear", universal_nonlinear_rgb_u8_converter,
NULL));
+
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", babl),
+ babl_format_with_space("R'G'B'A float", space),
+ "linear", universal_linear_rgb_nonlinear_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", space),
+ babl_format_with_space("R'G'B'A float", babl),
+ "linear", universal_linear_rgb_nonlinear_converter,
+ NULL));
}
prep_conversion(babl_conversion_new(
#endif
} BablCMYK;
+typedef struct _BablSpectrumType BablSpectrumType;
+
+struct _BablSpectrumType {
+ double nm_start;
+ double nm_gap;
+ double nm_end; /* last band, computed */
+ int bands;
+};
+
+typedef struct
+{
+ BablSpectrumType spectrum_type;
+ int is_spectral;
+ float *observer_x;
+ float *observer_y;
+ float *observer_z;
+ float *illuminant;
+ float rev_y_scale;
+} BablSpectralSpace;
+
+typedef struct
+{
+ BablSpectralSpace *spectral_space;
+ int inks;
+ float *on_white;
+ float *on_black;
+ float *opaqueness;
+ float scale;
+ float trc_gamma;
+ float *illuminant;
+} BablCoat;
+
+#define BABL_MAX_COATS 16
+
+typedef struct
+{
+ BablSpectralSpace *spectral_space;
+ BablCoat coat_def[BABL_MAX_COATS];
+ int coats;
+ float *substrate;
+
+ int stochastic_iterations;
+ float stochastic_diffusion0;
+ float stochastic_diffusion1;
+} BablProcessSpace;
+
typedef struct
{
BablInstance instance;
*/
char *icc_profile;
int icc_length;
-
BablCMYK cmyk;
} BablSpace;
tools/xml_insert.sh \
tools/changelog2rss \
index-static.html.in \
+ ColorManagement.html \
+ CMYK.html \
+ SymmetricAlpha.html \
COPYING \
- COPYING.LESSER \
+ toc \
+ COPYING.LESSER \
meson.build
-BUILT_EXTRA_DIST = index.html
+BUILT_EXTRA_DIST = index.html ColorManagement.html CMYK.html SymmetricAlpha.html
CLEANFILES = README changelog.rss
DISTCLEANFILES = index-static.html $(BUILT_EXTRA_DIST)
$(top_srcdir)/AUTHORS \
$(top_srcdir)/TODO \
$(top_srcdir)/NEWS \
+ toc \
Makefile.am
echo -n "HTML: $@"
cp $< $@
$(SHELL) $(top_srcdir)/docs/tools/xml_insert.sh $@ BablBase $$TMPFILE;\
rm -f $$TMPFILE )
echo -n "."
-
+ $(SHELL) $(top_srcdir)/docs/build-docs.sh $(top_srcdir) $(top_builddir)/docs
$(SHELL) $(top_srcdir)/docs/tools/xml_insert.sh $@ AUTHORS $(top_srcdir)/AUTHORS
$(SHELL) $(top_srcdir)/docs/tools/xml_insert.sh $@ TODO $(top_srcdir)/TODO
$(SHELL) $(top_srcdir)/docs/tools/xml_insert.sh $@ NEWS $(top_srcdir)/NEWS
+ $(SHELL) $(top_srcdir)/docs/tools/xml_insert.sh $@ TOC $(top_srcdir)/docs/toc
echo " [OK]"
distclean-local:
<h1>Babl-@BABL_VERSION@</h1>
</div>
</div>
+<!--TOC-->
- <div class='toc'>
- <div class='print'>
- <h3>Contents</h3>
- </div>
- <ul>
- <li><a href='#Download'> Download</a></li>
- <li><a href='#Features'> Features</a></li>
- <li><a href='#ColorManagement'> Color Management</a></li>
- <li><a href='#Symmetric-Alpha'> Symmetric-Alpha</a></li>
- <li><a href='#CMYK'> CMYK</a></li>
- <!--<li><a href='#Background'>Background</a></li>-->
- <li><a href='#Usage'> Usage</a></li>
- <li><a href='#Vocabulary'> Vocabulary</a></li>
- <!--<li><a href='#Data-types'> Data types</a></li>
- <li><a href='#Color-models'> Color models</a></li>
- <li><a href='#Pixel-formats'> Pixel formats</a></li>-->
-
- <li><a href='#Environment'> Environment</a></li>
- <li><a href='#Extending'> Extending</a></li>
- <li><a href='#DirectoryOverview'> Directory Overview</a></li>
- <!--<li><a href='#ColorManagement'>Color Management</a></li>-->
- <li><a href='#TODO'> Todo</a></li>
-
- <li><a href='#Copyright'> Copyright</a></li>
- <li><a href='#Authors'> Authors</a></li>
- </ul>
- </div>
<div><a name='Babl'></a></div>
<div class='paper'>
<h2>Features</h2>
<ul>
- <li>ANSI C without external dependencies, works on win32, linux and mac,
- 32bit and 64bit systems.</li>
- <li>Stable, small API, with singleton objects returned.</li>
- <li>Extendable with new formats, color models, components and datatypes.</li>
- <li>Can load <a href='#ColorManagement'> Color
-Spaces</a></li> from ICC v2 and v4 profiles containing RGB matrix + TRC, or <a
-href='#CMYK'>CMYK</a> profiles.</li>
- <li><a href='#Symmetric-Alpha'>Symmetric-Alpha</a> no loss of color fidelity due to asymptotic behavior near alpha 0.0 in floating point.</li>
+ <li>Runtim-extendable with new formats, color models, components and datatypes, and SIMD code paths.</li>
<li>Reference 64bit floating point conversions for datatypes and color
models, with 32bit floating point reference speed-ups in some places.
</li>
<li>Runtime profiling/validating and code-path optimizing with persistence of profiling data across runs, with caching of results.</li>
+ <li>Can load <a href='ColorManagement.html'>Color Spaces</a> from ICC v2 and v4 profiles containing RGB matrix + TRC and with lcms2 dependency also <a
+href='CMYK.html'>CMYK</a> profiles.</li>
+ <li>Uses <a href='SymmetricAlpha.html'>Symmetric Alpha</a> conversions for conversions between separate and associate alpha, avoiding loss of color fidelity due to asymptotic behavior near alpha 0.0 in floating point.</li>
+ <li>Portable self contained C code working on win32, linux, bsds and mac
+on 32bit and 64bit systems.</li>
+ <li>Stable, small API, with singleton objects returned.</li>
</ul>
- <p><a href='http://www.gegl.org/'>GEGL</a> through <a
- href='http://www.gegl.org/api.html#GeglBuffer'>GeglBuffer</a> provides
- tiled buffers with on disk storage as well as linear buffers with accessor
- functions for efficient data access transparently using babl fishes for
- translation to the desired pixel formats.</p>
+ <p>The pixel data storage in <a href='https://www.gimp.org/'>GIMP</a> uses
+<a href='http://www.gegl.org/'>GEGL</a>'s GeglBuffer which internally stores
+tiles and provides an API for retrieving and storing pixel data with implicit
+conversions using babl formats.
+ </p>
<a name='Download'></a>
<h2>Download</h2>
to the GEGL release.</p>
<!--NEWS-->
- For more news see git log.
-
-
- <a name='ColorManagement'></a>
- <h2>Color Management</h2>
-
- <p>All pixel formats in babl have a specified color space, if NULL is passed
-as a space constants for (unbounded) linear sRGB data is assumed, data being
-sRGB defines the conversion to and from gray-scale as well as the gamma
- - or Transfer Response Curve, TRC, used for converting between linear and
- non-linear variants of the data.</p>
-
- <p>babl has API for creating a format for a specific space:
-<tt>babl_format_with_space("R'G'B' u16", babl_space ("Rec2020"))</tt> creates a
-16 bit integer format for the Rec2020 color space. Babl knows internally about
-"sRGB", "Rec2020", "Adobe", "Apple", "ProPhoto", "ACEScg" and "ACES2065-1"
-spaces, as they are defined with constants on their wikipedia pages or similar upstream references.</p>
-
- <p>Additional spaces can be loaded from monitor-class matrix+TRC ICC v2 and
- v4 profiles. Using babl_icc_make_space (see babl.h for details). The space of
- a babl format can also be queried with babl_format_get_space.
- </p>
-
- <a name='Symmetric-Alpha'></a>
- <h2>Symmetric transformations for floating point alpha</h2>
-
+ For more detailed changes see git log.
- <p> babl clamps the alpha used when going from separate alpha to associated
-alpha or from associated alpha to separate alpha to BABL_ALPHA_FLOOR. This
-replaces asymptotic behavior and direct precision loss of color precision when
-multiplying or dividing by alphas near 0.0 with a consistent symmetric
-transformation.</p>
-
-<p>Original intent of data as well as non-asymptotic precision loss is thus
-maintained when the processing chain might temporarily use the other alpha
-representation.</p>
-
-<pre>
- #define BABL_ALPHA_FLOOR (1.0/65536.0)
- #define BABL_ALPHA_FLOOR_F (1.0f/65536.0f)
-</pre>
-
-<p>The deviation from not clamping near 0.0 is within the quantization margin
-of 16bit integer alpha, thus no adaptations for any SIMD or and similar 8bit
-and 16bit extensions of pixel format conversions are needed.
- </p>
-
- <p>This is the clamping function in use:</p>
-<pre>
-static inline float
-babl_epsilon_for_zero_float (float value)
-{
- if (value <= BABL_ALPHA_FLOOR_F)
- {
- /* for performance one could directly retun BABL_ALPHA_FLOOR_F here
- and dropping handling negative values consistently. */
- if (value >= 0.0f)
- return BABL_ALPHA_FLOOR_F;
- else if (value >= -BABL_ALPHA_FLOOR_F)
- return -BABL_ALPHA_FLOOR_F;
- }
- return value; /* most common case, return input value */
-}
-</pre>
-<p>And an example use of this clamping function that is consistent with babls behavior:</p>
-<pre>
-static inline void
-associated_to_separate_rgba (const float *associated_rgba,
- float *separate_rgba)
-{
- float alpha = associated_rgba[3];
- float clamped_alpha = babl_epsilon_for_zero_float (alpha);
- float reciprocal_alpha = 1.0f / clamped_alpha;
-
- separate_rgba[0] = associated_rgba[0] * reciprocal_alpha;
- separate_rgba[1] = associated_rgba[1] * reciprocal_alpha;
- separate_rgba[2] = associated_rgba[2] * reciprocal_alpha;
- separate_rgba[3] = alpha;
-}
-</pre>
-
-
-<p>For more detils see <a href='https://gitlab.gnome.org/GNOME/babl/commit/a4d607843d3cab18745d547fc8a46dec51dcea5e'>the commit message of the most recent refinement</a> as well as <a href='https://www.patreon.com/posts/premultiplied-in-21014115'>blog post with further background</a>.</p>
-
-
- <a name='CMYK'></a>
- <h2>CMYK</h2>
-
- <p>CMYK handling is done using babl-spaces created with ICC profiles
-containing CMYK profiles. BablSpaces for these ICC profiles handle color conversions using lcms2 - or if compiled without lcms2 support a naive profile independent fallback.</p>
- <p>When a babl space derived from a CMYK ICC profile is used to instantiate
-RGB formats, the resulting formats are using the default/NULL space for
-primaries and TRCs.</p>
-
- <p>The CMYK formats that use lcms2 for color interchange with the rest of
-babl are the following, which are available for all data types, u8, u16, half
-and float:</p>
- <dl>
- <dt>CMYK</dt><dd>Cyan Magenta Yellow Key, with 0 being white and 1.0 full ink coverage.</dd>
- <dt>CMYKA</dt><dd>as previous, with separate alpha channel</dd>
- <dt>CaMaYaKaA</dt><dd>as previous but associated alpha</dd>
- <dt>cmyk</dt><dd>inverted CMYK, where 0.0 is full ink coverage and 1.0 is none</dd>
- <dt>cmykA</dt><dd>as previous, with separate alpha channel</dd>
- <dt>camayakaA</dt><dd>as previous but associated alpha</dd>
- </dl>
<a name='Usage'></a>
<h2>Usage</h2>
+ <p>Most users of babl do not know they are using babl and it is GIMP itself
+ which uses babl, this is documentation for such uses - and others that might
+ want to use babl for pixel format or color space conversion in other software.
+</p>
+
<p>When using BablFishes to do your conversions, you request a fish to
convert between two formats, and an optimal fish to babls capability is
provided that you can use to do your conversions. Babl also provides
join_paths(meson.source_root(), 'AUTHORS'),
join_paths(meson.source_root(), 'TODO'),
join_paths(meson.source_root(), 'NEWS'),
+ 'toc',
],
output: [ 'index.html', ],
command: [
'&&', xml_insert, '@OUTPUT@', 'AUTHORS', '@INPUT2@',
'&&', xml_insert, '@OUTPUT@', 'TODO', '@INPUT3@',
'&&', xml_insert, '@OUTPUT@', 'NEWS', '@INPUT4@',
+ '&&', xml_insert, '@OUTPUT@', 'toc', '@INPUT5@',
+ ],
+ build_by_default: true,
+)
+
+
+CMYK_html = custom_target('CMYK.html',
+ input : [
+ 'CMYK-static.html',
+ 'toc',
+ ],
+ output: [ 'CMYK.html', ],
+ command: [
+ env_bin,
+ 'cp', '@INPUT0@', '@OUTPUT@',
+ '&&', xml_insert, '@OUTPUT@', 'toc', '@INPUT1@',
+ ],
+ build_by_default: true,
+)
+
+ColorManagement_html = custom_target('ColorManagement.html',
+ input : [
+ 'ColorManagement-static.html',
+ 'toc',
+ ],
+ output: [ 'ColorManagement.html', ],
+ command: [
+ env_bin,
+ 'cp', '@INPUT0@', '@OUTPUT@',
+ '&&', xml_insert, '@OUTPUT@', 'toc', '@INPUT1@',
+ ],
+ build_by_default: true,
+)
+
+SymmetricAlpha_html = custom_target('SymmetricAlpha.html',
+ input : [
+ 'SymmetricAlpha-static.html',
+ 'toc',
+ ],
+ output: [ 'SymmetricAlpha.html', ],
+ command: [
+ env_bin,
+ 'cp', '@INPUT0@', '@OUTPUT@',
+ '&&', xml_insert, '@OUTPUT@', 'toc', '@INPUT1@',
],
build_by_default: true,
)
#include "../config.h"
#include "babl/babl-internal.h"
+//#define SPACE1 babl_space("ProPhoto")
+#define SPACE1 babl_space("Apple")
+//#define SPACE1 babl_space("sRGB")
+//#define SPACE2 babl_space("Apple")
+
+static int
+file_get_contents (const char *path,
+ char **contents,
+ long *length,
+ void *error)
+{
+ FILE *file;
+ long size;
+ char *buffer;
+
+ file = fopen (path,"rb");
+
+ if (!file)
+ return -1;
+
+ if (fseek (file, 0, SEEK_END) == -1 || (size = ftell (file)) == -1)
+ {
+ fclose (file);
+ return -1;
+ }
+ if (length) *length = size;
+ rewind (file);
+ if ((size_t) size > SIZE_MAX - 8)
+ {
+ fclose (file);
+ return -1;
+ }
+ buffer = calloc(size + 8, 1);
+
+ if (!buffer)
+ {
+ fclose(file);
+ return -1;
+ }
+
+ size -= fread (buffer, 1, size, file);
+ if (size)
+ {
+ fclose (file);
+ free (buffer);
+ return -1;
+ }
+ fclose (file);
+ *contents = buffer;
+ return 0;
+}
+
int
main (int argc,
char **argv)
{
int final = 0;
const Babl *fish;
+ const Babl *SPACE2 = NULL;
+
+
if (argc < 3)
{
fprintf (stderr, "need two args, from and to babl-formats\n");
babl_init ();
- fish = babl_fish (babl_format(argv[1]), babl_format (argv[2]));
+#define ICC_PATH "/tmp/my.icc"
+//#define ICC_PATH "/usr/share/color/icc/colord/AppleRGB.icc"
+//#define ICC_PATH "/tmp/ACEScg-elle-V2-labl.icc"
+//#define ICC_PATH "/tmp/ACEScg-elle-V2-g10.icc"
+//#define ICC_PATH "/tmp/ACEScg-elle-V4-g10.icc"
+//#define ICC_PATH "/tmp/ACEScg-elle-V4-g22.icc"
+
+
+ {
+ char *icc_data = NULL;
+ long length = 0;
+ file_get_contents (ICC_PATH, &icc_data, &length, NULL);
+ SPACE2 = babl_space_from_icc (icc_data, length, BABL_ICC_INTENT_RELATIVE_COLORIMETRIC, NULL);
+ //SPACE2 = babl_space ("sRGB");
+ }
+
+ fish = babl_fish (babl_format_with_space(argv[1], SPACE1), babl_format_with_space (argv[2], SPACE2));
if (!fish)
+ {
+ fprintf (stderr, "!!!! %s %s\n", argv[1], argv[2]);
return -1;
+ }
if (final)
switch (fish->class_type)
{
case BABL_FISH:
- fprintf (stderr, "%s\n", babl_get_name (fish));
+ fprintf (stderr, ">%s\n", babl_get_name (fish));
break;
case BABL_FISH_PATH:
- fprintf (stderr, "chosen %s to %s: steps: %i error: %f cost: %f\n", argv[1], argv[2], fish->fish_path.conversion_list->count, fish->fish.error, fish->fish_path.cost);
+ fprintf (stderr, "chosen %s to %s: steps: %i error: %.12f cost: %f\n", argv[1], argv[2], fish->fish_path.conversion_list->count, fish->fish.error, fish->fish_path.cost);
for (int i = 0; i < fish->fish_path.conversion_list->count; i++)
{
- fprintf (stderr, "\t%s\n",
- babl_get_name(fish->fish_path.conversion_list->items[i] ));
+ fprintf (stderr, "\t%s (cost: %li)\n",
+ babl_get_name(fish->fish_path.conversion_list->items[i] ),
+ fish->fish_path.conversion_list->items[i]->conversion.cost);
}
break;
}