diff options
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | apply-glyph.h | 141 | ||||
-rw-r--r-- | common.h | 14 | ||||
-rw-r--r-- | config.mk | 7 | ||||
-rw-r--r-- | libskrift.h | 111 | ||||
-rw-r--r-- | libskrift_apply_glyph.c | 219 | ||||
-rw-r--r-- | libskrift_create_context.c | 8 | ||||
-rw-r--r-- | libskrift_format_settings.c | 36 | ||||
-rw-r--r-- | libskrift_get_grapheme_glyph.c | 42 | ||||
-rw-r--r-- | libskrift_merge_glyphs.c | 22 | ||||
-rw-r--r-- | libskrift_srgb_postprocess.c | 27 | ||||
-rw-r--r-- | libskrift_srgb_preprocess.c | 27 | ||||
-rw-r--r-- | srgb-gamma.h | 145 |
13 files changed, 740 insertions, 67 deletions
@@ -4,9 +4,11 @@ CONFIGFILE = config.mk include $(CONFIGFILE) OBJ =\ + libskrift_apply_glyph.o\ libskrift_calculate_dpi.o\ libskrift_close_font.o\ libskrift_create_context.o\ + libskrift_format_settings.o\ libskrift_free_context.o\ libskrift_get_grapheme_glyph.o\ libskrift_get_cluster_glyph.o\ @@ -18,13 +20,17 @@ OBJ =\ libskrift_open_font_fd.o\ libskrift_open_font_file.o\ libskrift_open_font_mem.o\ - libskrift_points_to_pixels.o + libskrift_points_to_pixels.o\ + libskrift_srgb_postprocess.o\ + libskrift_srgb_preprocess.o LIB_HDR =\ libskrift.h HDR =\ common.h\ + apply-glyph.h\ + srgb-gamma.h\ $(LIB_HDR) all: libskrift.a demo diff --git a/apply-glyph.h b/apply-glyph.h new file mode 100644 index 0000000..09cb9aa --- /dev/null +++ b/apply-glyph.h @@ -0,0 +1,141 @@ +/* See LICENSE file for copyright and license details. */ + +#ifndef NARROW_FLOAT_TYPE +# define NARROW_FLOAT_TYPE double +# define NARROW_FLOAT_TYPE_AUTO +#endif +#ifndef WIDE_FLOAT_TYPE +# define WIDE_FLOAT_TYPE NARROW_FLOAT_TYPE +# define WIDE_FLOAT_TYPE_AUTO +#endif +#ifndef TYPE +# define TYPE NARROW_FLOAT_TYPE +# define TYPE_AUTO +# define TYPEMAX 1 +#else +# define TYPEMAX ((TYPE)~(TYPE)0) +#endif +#ifndef RMAP +# define RMAP(Y) ((NARROW_FLOAT_TYPE)((WIDE_FLOAT_TYPE)(Y) / TYPEMAX)) +# define RMAP_AUTO +#endif +#define MAP(Y) (TYPE)((WIDE_FLOAT_TYPE)(Y) * TYPEMAX + (WIDE_FLOAT_TYPE)0.5f) +#define R (&((TYPE *)&img[i])[settings.rpos]) +#define G (&((TYPE *)&img[i])[settings.gpos]) +#define B (&((TYPE *)&img[i])[settings.bpos]) +#define A (&((TYPE *)&img[i])[settings.apos]) + +do { + NARROW_FLOAT_TYPE opacity = (NARROW_FLOAT_TYPE)colour->opacity / 255; + NARROW_FLOAT_TYPE al, alpha = (NARROW_FLOAT_TYPE)colour->alpha / 255; + NARROW_FLOAT_TYPE re, red = (NARROW_FLOAT_TYPE)colour->red / 255; + NARROW_FLOAT_TYPE gr, green = (NARROW_FLOAT_TYPE)colour->green / 255; + NARROW_FLOAT_TYPE bl, blue = (NARROW_FLOAT_TYPE)colour->blue / 255; + NARROW_FLOAT_TYPE transparency; + + if (settings.apos < 0) { + if (gly_psize > 1) { + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + *R = MAP(RMAP(*R) * (1 - opacity * gly[c + ri]) + gly[c + ri] * red); + *G = MAP(RMAP(*G) * (1 - opacity * gly[c + gi]) + gly[c + gi] * green); + *B = MAP(RMAP(*B) * (1 - opacity * gly[c + bi]) + gly[c + bi] * blue); + } + } + } else { + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + transparency = 1 - opacity * gly[c + ri]; + *R = MAP(RMAP(*R) * transparency + gly[c + ri] * red); + *G = MAP(RMAP(*G) * transparency + gly[c + gi] * green); + *B = MAP(RMAP(*B) * transparency + gly[c + bi] * blue); + } + } + } + } else if (image->premultiplied) { + if (gly_psize > 1) { + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + high = gly[c + ri] > gly[c + gi] ? gly[c + ri] : gly[c + gi]; + high = high > gly[c + bi] ? high : gly[c + bi]; + *R = MAP(RMAP(*R) * (1 - opacity * gly[c + ri]) + gly[c + ri] * red); + *G = MAP(RMAP(*G) * (1 - opacity * gly[c + gi]) + gly[c + gi] * green); + *B = MAP(RMAP(*B) * (1 - opacity * gly[c + bi]) + gly[c + bi] * blue); + *A = MAP(RMAP(*A) * (1 - opacity * high) + high * alpha); + } + } + } else { + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + transparency = 1 - opacity * gly[c + ri]; + *R = MAP(RMAP(*R) * transparency + gly[c + ri] * red); + *G = MAP(RMAP(*G) * transparency + gly[c + ri] * green); + *B = MAP(RMAP(*B) * transparency + gly[c + ri] * blue); + *A = MAP(RMAP(*A) * transparency + gly[c + ri] * alpha); + } + } + } + } else { + if (gly_psize > 1) { + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + high = gly[c + ri] > gly[c + gi] ? gly[c + ri] : gly[c + gi]; + high = high > gly[c + bi] ? high : gly[c + bi]; + re = RMAP(*R) * RMAP(*A) * (1 - opacity * gly[c + ri]) + gly[c + ri] * red; + gr = RMAP(*G) * RMAP(*A) * (1 - opacity * gly[c + gi]) + gly[c + gi] * green; + bl = RMAP(*B) * RMAP(*A) * (1 - opacity * gly[c + bi]) + gly[c + bi] * blue; + al = RMAP(*A) * (1 - opacity * high) + high * alpha; + if (fpclassify(al) != FP_ZERO) { + *R = MAP(re); + *G = MAP(gr); + *B = MAP(bl); + *A = MAP(al); + } else { + *R = *G = *B = *A = 0; + } + } + } + } else { + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + transparency = 1 - opacity * gly[c + ri]; + re = RMAP(*R) * RMAP(*A) * transparency + gly[c + ri] * red; + gr = RMAP(*G) * RMAP(*A) * transparency + gly[c + ri] * green; + bl = RMAP(*B) * RMAP(*A) * transparency + gly[c + ri] * blue; + al = RMAP(*A) * transparency + gly[c + ri] * alpha; + if (fpclassify(al) != FP_ZERO) { + *R = MAP(re); + *G = MAP(gr); + *B = MAP(bl); + *A = MAP(al); + } else { + *R = *G = *B = *A = 0; + } + } + } + } + } +} while (0); + +#ifdef NARROW_FLOAT_TYPE_AUTO +# undef NARROW_FLOAT_TYPE_AUTO +# undef NARROW_FLOAT_TYPE +#endif +#ifdef WIDE_FLOAT_TYPE_AUTO +# undef WIDE_FLOAT_TYPE_AUTO +# undef WIDE_FLOAT_TYPE +#endif +#ifdef TYPE_AUTO +# undef TYPE_AUTO +# undef TYPE +#endif +#undef TYPEMAX +#ifdef RMAP_AUTO +# undef RMAP_AUTO +# undef RMAP +#endif +#undef MAP +#undef R +#undef G +#undef B +#undef A @@ -2,6 +2,7 @@ #include <sys/mman.h> #include <sys/stat.h> +#include <endian.h> #include <errno.h> #include <math.h> #include <stdlib.h> @@ -14,6 +15,8 @@ #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define LEN(ARR) (sizeof(ARR) / sizeof(*(ARR))) + struct libskrift_font { SFT_Font *font; void *memory_free; @@ -31,3 +34,14 @@ struct libskrift_context { size_t nfonts; LIBSKRIFT_FONT *fonts[]; }; + +struct format_settings { + int float_type; + int8_t apos; + int8_t rpos; + int8_t gpos; + int8_t bpos; + size_t spsize; +}; + +extern const struct format_settings libskrift_format_settings[LIBSKRIFT_RGBA_LONG_DOUBLE + 1]; @@ -3,7 +3,12 @@ MANPREFIX = $(PREFIX)/share/man DEMO_FONT = /usr/share/fonts/liberation/LiberationSans-Regular.ttf -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE '-DDEMO_FONT="$(DEMO_FONT)"' +MERGE_STYLE = MAX +# MAX: The max value of the glyph (minimum legal result, insignificantly slower than SUM) +# OR: The bitwise OR of the glyph values (within legal range, fastest) +# SUM: The saturated sum of the glyph values (maximum legal result) + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE -D$(MERGE_STYLE)_MERGE '-DDEMO_FONT="$(DEMO_FONT)"' CFLAGS = -std=c99 -Wall -g LDFLAGS = -lschrift -lm -lgrapheme diff --git a/libskrift.h b/libskrift.h index 8745e09..93adb79 100644 --- a/libskrift.h +++ b/libskrift.h @@ -22,6 +22,49 @@ typedef struct libskrift_font LIBSKRIFT_FONT; typedef uint_least32_t libskrift_codepoint_t; +enum libskrift_format { + LIBSKRIFT_RAW, + LIBSKRIFT_R8G8B8, + LIBSKRIFT_X8R8G8B8, + LIBSKRIFT_A8R8G8B8, + LIBSKRIFT_R8G8B8A8, + LIBSKRIFT_R16G16B16, + LIBSKRIFT_X16R16G16B16, + LIBSKRIFT_A16R16G16B16, + LIBSKRIFT_R16G16B16A16, + LIBSKRIFT_R32G32B32, + LIBSKRIFT_X32R32G32B32, + LIBSKRIFT_A32R32G32B32, + LIBSKRIFT_R32G32B32A32, + LIBSKRIFT_R64G64B64, + LIBSKRIFT_X64R64G64B64, + LIBSKRIFT_A64R64G64B64, + LIBSKRIFT_R64G64B64A64, + LIBSKRIFT_RGB_FLOAT, + LIBSKRIFT_ARGB_FLOAT, + LIBSKRIFT_RGBA_FLOAT, + LIBSKRIFT_RGB_DOUBLE, + LIBSKRIFT_ARGB_DOUBLE, + LIBSKRIFT_RGBA_DOUBLE, + LIBSKRIFT_RGB_LONG_DOUBLE, + LIBSKRIFT_ARGB_LONG_DOUBLE, + LIBSKRIFT_RGBA_LONG_DOUBLE +}; + +enum libskrift_endian { + LIBSKRIFT_HOST_PIXEL, + LIBSKRIFT_NETWORK_PIXEL, + LIBSKRIFT_REVERSE_NETWORK_PIXEL, + LIBSKRIFT_HOST_SUBPIXEL, + LIBSKRIFT_NETWORK_SUBPIXEL, + LIBSKRIFT_REVERSE_NETWORK_SUBPIXEL + +#define LIBSKRIFT_BE_PIXEL LIBSKRIFT_NETWORK_PIXEL +#define LIBSKRIFT_BE_SUBPIXEL LIBSKRIFT_NETWORK_SUBPIXEL +#define LIBSKRIFT_LE_PIXEL LIBSKRIFT_REVERSE_NETWORK_PIXEL +#define LIBSKRIFT_LE_SUBPIXEL LIBSKRIFT_REVERSE_NETWORK_SUBPIXEL +}; + enum libskrift_subpixel_order { LIBSKRIFT_OTHER, /* LIBSKRIFT_NONE */ LIBSKRIFT_RGB, @@ -43,23 +86,24 @@ enum libskrift_hinting { LIBSKRIFT_FULL = 100 }; -#define LIBSKRIFT_CORRECT_GAMMA 0x00000001U -#define LIBSKRIFT_REMOVE_GAMMA 0x00000002U -#define LIBSKRIFT_Y_INCREASES_UPWARDS 0x00000004U /* SFT_DOWNWARD_Y otherwise */ -#define LIBSKRIFT_FLIP_TEXT 0x00000008U -#define LIBSKRIFT_MIRROR_TEXT 0x00000010U -#define LIBSKRIFT_MIRROR_CHARS 0x00000020U -#define LIBSKRIFT_TRANSPOSE_TEXT 0x00000040U -#define LIBSKRIFT_TRANSPOSE_CHARS 0x00000080U -#define LIBSKRIFT_NO_LIGATURES 0x00000100U -#define LIBSKRIFT_ADVANCE_TO_GRID 0x00000200U -#define LIBSKRIFT_REGRESS_TO_GRID 0x00000400U /* Combine with LIBSKRIFT_ADVANCE_TO_GRID for closest alternative */ -#define LIBSKRIFT_USE_SUBPIXEL_GRID 0x00000800U -#define LIBSKRIFT_VERTICAL_TEXT 0x00001000U -#define LIBSKRIFT_AUTOHINTING 0x00002000U /* Use autohinter even if hint information exists */ -#define LIBSKRIFT_NO_AUTOHINTING 0x00004000U /* Use autohinter if no hint information exist */ -#define LIBSKRIFT_AUTOKERNING 0x00008000U /* Use autokerner even if kerning information exists */ -#define LIBSKRIFT_NO_AUTOKERNING 0x00010000U /* Use autokerner if no kerning information exist */ +#define LIBSKRIFT_REMOVE_GAMMA 0x00000001L +#define LIBSKRIFT_Y_INCREASES_UPWARDS 0x00000002L /* SFT_DOWNWARD_Y otherwise */ +#define LIBSKRIFT_FLIP_TEXT 0x00000004L +#define LIBSKRIFT_MIRROR_TEXT 0x00000008L +#define LIBSKRIFT_MIRROR_CHARS 0x00000010L +#define LIBSKRIFT_TRANSPOSE_TEXT 0x00000020L +#define LIBSKRIFT_TRANSPOSE_CHARS 0x00000040L +#define LIBSKRIFT_NO_LIGATURES 0x00000080L +#define LIBSKRIFT_ADVANCE_CHAR_TO_GRID 0x00000100L +#define LIBSKRIFT_REGRESS_CHAR_TO_GRID 0x00000200L /* Combine with LIBSKRIFT_ADVANCE_CHAR_TO_GRID for closest alternative */ +#define LIBSKRIFT_ADVANCE_WORD_TO_GRID 0x00000400L +#define LIBSKRIFT_REGRESS_WORD_TO_GRID 0x00000800L /* Combine with LIBSKRIFT_ADVANCE_WORD_TO_GRID for closest alternative */ +#define LIBSKRIFT_USE_SUBPIXEL_GRID 0x00001000L +#define LIBSKRIFT_VERTICAL_TEXT 0x00002000L +#define LIBSKRIFT_AUTOHINTING 0x00004000L /* Use autohinter even if hint information exists */ +#define LIBSKRIFT_NO_AUTOHINTING 0x00008000L /* Use autohinter if no hint information exist */ +#define LIBSKRIFT_AUTOKERNING 0x00010000L /* Use autokerner even if kerning information exists */ +#define LIBSKRIFT_NO_AUTOKERNING 0x00020000L /* Use autokerner if no kerning information exist */ struct libskrift_rendering { int struct_version; @@ -97,6 +141,25 @@ struct libskrift_saved_grapheme { size_t len; }; +struct libskrift_image { + enum libskrift_format format; + enum libskrift_endian endian; + int premultiplied; + uint16_t width; + uint16_t height; + void (*preprocess)(struct libskrift_image *image, size_t x, size_t y, size_t width, size_t height); + void (*postprocess)(struct libskrift_image *image, size_t x, size_t y, size_t width, size_t height); + void *image; +}; + +struct libskrift_colour { + double opacity; /* [0, 1] */ + double alpha; /* [0, .opacity] */ + double red; /* [0, .alpha] */ + double green; /* [0, .alpha] */ + double blue; /* [0, .alpha] */ +}; + #define LIBSKRIFT_DEFAULT_RENDERING {\ .struct_version = LIBSKRIFT_RENDERING_STRUCT_VERSION,\ @@ -183,6 +246,18 @@ ssize_t libskrift_get_cluster_glyph(LIBSKRIFT_CONTEXT *, const char *, struct li double, double, struct libskrift_glyph **); _LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) -int libskrift_merge_glyphs(LIBSKRIFT_CONTEXT *, struct libskrift_glyph *, struct libskrift_glyph *, struct libskrift_glyph **); +int libskrift_merge_glyphs(LIBSKRIFT_CONTEXT *, const struct libskrift_glyph *, const struct libskrift_glyph *, + struct libskrift_glyph **); + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__(1, 2, 6)))) +int libskrift_apply_glyph(LIBSKRIFT_CONTEXT *, const struct libskrift_glyph *, const struct libskrift_colour *, + int16_t, int16_t, struct libskrift_image *); + + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) +void libskrift_srgb_preprocess(struct libskrift_image *, size_t, size_t, size_t, size_t); + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) +void libskrift_srgb_postprocess(struct libskrift_image *, size_t, size_t, size_t, size_t); #endif diff --git a/libskrift_apply_glyph.c b/libskrift_apply_glyph.c new file mode 100644 index 0000000..05770ce --- /dev/null +++ b/libskrift_apply_glyph.c @@ -0,0 +1,219 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +static const float uint8_rmap[] = { + 0/255.f, 1/255.f, 2/255.f, 3/255.f, 4/255.f, 5/255.f, 6/255.f, 7/255.f, + 8/255.f, 9/255.f, 10/255.f, 11/255.f, 12/255.f, 13/255.f, 14/255.f, 15/255.f, + 16/255.f, 17/255.f, 18/255.f, 19/255.f, 20/255.f, 21/255.f, 22/255.f, 23/255.f, + 24/255.f, 25/255.f, 26/255.f, 27/255.f, 28/255.f, 29/255.f, 30/255.f, 31/255.f, + 32/255.f, 33/255.f, 34/255.f, 35/255.f, 36/255.f, 37/255.f, 38/255.f, 39/255.f, + 40/255.f, 41/255.f, 42/255.f, 43/255.f, 44/255.f, 45/255.f, 46/255.f, 47/255.f, + 48/255.f, 49/255.f, 50/255.f, 51/255.f, 52/255.f, 53/255.f, 54/255.f, 55/255.f, + 56/255.f, 57/255.f, 58/255.f, 59/255.f, 60/255.f, 61/255.f, 62/255.f, 63/255.f, + 64/255.f, 65/255.f, 66/255.f, 67/255.f, 68/255.f, 69/255.f, 70/255.f, 71/255.f, + 72/255.f, 73/255.f, 74/255.f, 75/255.f, 76/255.f, 77/255.f, 78/255.f, 79/255.f, + 80/255.f, 81/255.f, 82/255.f, 83/255.f, 84/255.f, 85/255.f, 86/255.f, 87/255.f, + 88/255.f, 89/255.f, 90/255.f, 91/255.f, 92/255.f, 93/255.f, 94/255.f, 95/255.f, + 96/255.f, 97/255.f, 98/255.f, 99/255.f, 100/255.f, 101/255.f, 102/255.f, 103/255.f, + 104/255.f, 105/255.f, 106/255.f, 107/255.f, 108/255.f, 109/255.f, 110/255.f, 111/255.f, + 112/255.f, 113/255.f, 114/255.f, 115/255.f, 116/255.f, 117/255.f, 118/255.f, 119/255.f, + 120/255.f, 121/255.f, 122/255.f, 123/255.f, 124/255.f, 125/255.f, 126/255.f, 127/255.f, + 128/255.f, 129/255.f, 130/255.f, 131/255.f, 132/255.f, 133/255.f, 134/255.f, 135/255.f, + 136/255.f, 137/255.f, 138/255.f, 139/255.f, 140/255.f, 141/255.f, 142/255.f, 143/255.f, + 144/255.f, 145/255.f, 146/255.f, 147/255.f, 148/255.f, 149/255.f, 150/255.f, 151/255.f, + 152/255.f, 153/255.f, 154/255.f, 155/255.f, 156/255.f, 157/255.f, 158/255.f, 159/255.f, + 160/255.f, 161/255.f, 162/255.f, 163/255.f, 164/255.f, 165/255.f, 166/255.f, 167/255.f, + 168/255.f, 169/255.f, 170/255.f, 171/255.f, 172/255.f, 173/255.f, 174/255.f, 175/255.f, + 176/255.f, 177/255.f, 178/255.f, 179/255.f, 180/255.f, 181/255.f, 182/255.f, 183/255.f, + 184/255.f, 185/255.f, 186/255.f, 187/255.f, 188/255.f, 189/255.f, 190/255.f, 191/255.f, + 192/255.f, 193/255.f, 194/255.f, 195/255.f, 196/255.f, 197/255.f, 198/255.f, 199/255.f, + 200/255.f, 201/255.f, 202/255.f, 203/255.f, 204/255.f, 205/255.f, 206/255.f, 207/255.f, + 208/255.f, 209/255.f, 210/255.f, 211/255.f, 212/255.f, 213/255.f, 214/255.f, 215/255.f, + 216/255.f, 217/255.f, 218/255.f, 219/255.f, 220/255.f, 221/255.f, 222/255.f, 223/255.f, + 224/255.f, 225/255.f, 226/255.f, 227/255.f, 228/255.f, 229/255.f, 230/255.f, 231/255.f, + 232/255.f, 233/255.f, 234/255.f, 235/255.f, 236/255.f, 237/255.f, 238/255.f, 239/255.f, + 240/255.f, 241/255.f, 242/255.f, 243/255.f, 244/255.f, 245/255.f, 246/255.f, 247/255.f, + 248/255.f, 249/255.f, 250/255.f, 251/255.f, 252/255.f, 253/255.f, 254/255.f, 255/255.f +}; + +int +libskrift_apply_glyph(LIBSKRIFT_CONTEXT *ctx, const struct libskrift_glyph *glyph, const struct libskrift_colour *colour, + int16_t x, int16_t y, struct libskrift_image *image) +{ + struct format_settings settings; + size_t psize, startr, startc, endr, endc, r, c, n, j; + size_t img_linesize, gly_linesize, i, gly_psize, usize; + size_t ri, gi, bi, rj, gj, bj; + uint16_t x1, y1, x2, y2; + int16_t sx2, sy2; + uint8_t high; + uint8_t *img, *img_start = image->image; + const uint8_t *gly = glyph->image; + const uint16_t u16 = 0x0102; + const uint32_t u32 = 0x01020304L; + const uint64_t u64 = 0x0102030405060708LL; + + if (image->format == LIBSKRIFT_RAW || (unsigned int)image->format > (unsigned int)LEN(libskrift_format_settings)) { + errno = EINVAL; + return -1; + } + + settings = libskrift_format_settings[image->format]; + psize = settings.spsize * (size_t)(4 - (settings.apos <= -2)); + + if ((unsigned int)image->endian > LIBSKRIFT_REVERSE_NETWORK_SUBPIXEL || + (settings.float_type && (unsigned int)image->endian < LIBSKRIFT_HOST_SUBPIXEL) || + (!colour && settings.float_type) || + (image->endian % 3 && psize != 1 && psize != 2 && psize != 4 && psize != 8)) { + errno = EINVAL; + return -1; + } + + /* Drawing area on image */ + sx2 = (int16_t)(x + (int16_t)glyph->width); + sy2 = (int16_t)(y + (int16_t)glyph->height); + x1 = x < 0 ? 0 : (uint16_t)x; + y1 = y < 0 ? 0 : (uint16_t)y; + if (sx2 <= 0 || sy2 <= 0 || x1 >= image->width || y1 >= image->height) + return 0; + x2 = (uint16_t)sx2 < image->width ? (uint16_t)sx2 : image->width; + y2 = (uint16_t)sy2 < image->height ? (uint16_t)sy2 : image->height; + sx2 = (int16_t)x2; + sy2 = (int16_t)y2; + + /* Drawing area on glyph */ + startc = x <= 0 ? 0 : (size_t)-x; + startr = y <= 0 ? 0 : (size_t)-y; + endc = x2 < image->width ? glyph->width : (uint16_t)(sx2 - x); + endr = y2 < image->height ? glyph->height : (uint16_t)(sy2 - y); + + img_linesize = (size_t)image->width * psize; + img_start += (size_t)y1 * img_linesize; + img_start += (size_t)x1 * psize; + + gly_psize = ctx->rendering.smoothing ? 3 : 1; + gly_linesize = (size_t)image->width * gly_psize; + gly += startr * gly_linesize; + + usize = image->endian >= LIBSKRIFT_HOST_SUBPIXEL ? settings.spsize : psize; + +#define CHECK_ENDIAN(UPPER, LOWER, BITS)\ + ((image->endian == LIBSKRIFT_##UPPER##_PIXEL || image->endian == LIBSKRIFT_##UPPER##_SUBPIXEL) &&\ + usize == sizeof(uint##BITS##_t) &&\ + LOWER##BITS##toh(u##BITS) != u##BITS) + +#define EACH_UNIT\ + img = img_start, r = startr; r < endr; r++, img += img_linesize)\ + for (n = (endc - startc) * psize, i = 0; i < n; i += usize + + /* Convert endian in image to host endian */ + if (CHECK_ENDIAN(BE, be, 16)) for (EACH_UNIT) *(uint16_t *)&img[i] = be16toh(*(uint16_t *)&img[i]); + else if (CHECK_ENDIAN(BE, be, 32)) for (EACH_UNIT) *(uint32_t *)&img[i] = be32toh(*(uint32_t *)&img[i]); + else if (CHECK_ENDIAN(BE, be, 64)) for (EACH_UNIT) *(uint64_t *)&img[i] = be64toh(*(uint64_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 16)) for (EACH_UNIT) *(uint16_t *)&img[i] = le16toh(*(uint16_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 32)) for (EACH_UNIT) *(uint32_t *)&img[i] = le32toh(*(uint32_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 64)) for (EACH_UNIT) *(uint64_t *)&img[i] = le64toh(*(uint64_t *)&img[i]); + + /* Preprocess (e.g. remove gamma or colour model conversion) */ + if (image->preprocess) + image->preprocess(image, (size_t)x1, (size_t)y1, (size_t)(x2 - x1), (size_t)(y2 - y1)); + + /* Apply glyph */ + if (ctx->rendering.smoothing != LIBSKRIFT_SUBPIXEL) + ri = 0, gi = 0, bi = 0; + else if (ctx->subpixel_bgr) + bi = 0, gi = 1, ri = 2; + else + ri = 0, gi = 1, bi = 2; + startc *= gly_psize; + endc *= gly_psize; + if (colour) { + switch (settings.float_type) { + case 0: + switch (settings.spsize) { + case 1: +#define TYPE uint8_t +#define NARROW_FLOAT_TYPE float +#define RMAP(Y) uint8_rmap[Y] +#include "apply-glyph.h" +#undef NARROW_FLOAT_TYPE +#undef RMAP +#undef TYPE + break; + case 2: +#define TYPE uint16_t +#include "apply-glyph.h" +#undef TYPE + break; + case 4: +#define TYPE uint32_t +#include "apply-glyph.h" +#undef TYPE + break; + default: +#define TYPE uint64_t +#define WIDE_FLOAT_TYPE long double +#include "apply-glyph.h" +#undef TYPE +#undef WIDE_FLOAT_TYPE + break; + } + break; + case 1: +#define NARROW_FLOAT_TYPE float +#include "apply-glyph.h" +#undef NARROW_FLOAT_TYPE + break; + case 2: +#define NARROW_FLOAT_TYPE double +#include "apply-glyph.h" +#undef NARROW_FLOAT_TYPE + break; + default: +#define NARROW_FLOAT_TYPE long double +#include "apply-glyph.h" +#undef NARROW_FLOAT_TYPE + break; + } + } else { + /* Optimised version for opaque black-on-white/white-on-black, assumes no glyph overlap */ + rj = (size_t)settings.rpos * settings.spsize; + gj = (size_t)settings.gpos * settings.spsize; + bj = (size_t)settings.bpos * settings.spsize; + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + img[i + rj] ^= gly[c + ri]; + img[i + gj] ^= gly[c + gi]; + img[i + bj] ^= gly[c + bi]; + } + } + for (j = 1; j < settings.spsize; j++) { + ri = rj + j; + gi = gj + j; + bi = bj + j; + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + img[i + ri] = img[i + rj]; + img[i + gi] = img[i + gj]; + img[i + bi] = img[i + bj]; + } + } + } + } + startc /= gly_psize; + endc /= gly_psize; + + /* Postprocess (e.g. add gamma or colour model conversion) */ + if (image->postprocess) + image->postprocess(image, (size_t)x1, (size_t)y1, (size_t)(x2 - x1), (size_t)(y2 - y1)); + + /* Convert endian in image from host endian */ + if (CHECK_ENDIAN(BE, be, 16)) for (EACH_UNIT) *(uint16_t *)&img[i] = htobe16(*(uint16_t *)&img[i]); + else if (CHECK_ENDIAN(BE, be, 32)) for (EACH_UNIT) *(uint32_t *)&img[i] = htobe32(*(uint32_t *)&img[i]); + else if (CHECK_ENDIAN(BE, be, 64)) for (EACH_UNIT) *(uint64_t *)&img[i] = htobe64(*(uint64_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 16)) for (EACH_UNIT) *(uint16_t *)&img[i] = htole16(*(uint16_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 32)) for (EACH_UNIT) *(uint32_t *)&img[i] = htole32(*(uint32_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 64)) for (EACH_UNIT) *(uint64_t *)&img[i] = htole64(*(uint64_t *)&img[i]); + + return 0; +} diff --git a/libskrift_create_context.c b/libskrift_create_context.c index 2528221..fd8d086 100644 --- a/libskrift_create_context.c +++ b/libskrift_create_context.c @@ -5,12 +5,9 @@ LIBSKRIFT_NO_AUTOHINTING |\ LIBSKRIFT_NO_AUTOKERNING) -#define IMPLEMENTED_FLAGS (LIBSKRIFT_CORRECT_GAMMA |\ - LIBSKRIFT_REMOVE_GAMMA |\ +#define IMPLEMENTED_FLAGS (LIBSKRIFT_REMOVE_GAMMA |\ FORCED_FLAGS) /* libschrift does not add gamma, so not handling is required */ -#define HAVE_MULTIPLE_FLAGS(HAVE, CHECK) (((HAVE) & (CHECK)) & (((HAVE) & (CHECK)) - 1)) - #define COPY_ARRAY(DEST_STRUCT, SRC_STRUCT, FIELD)\ memcpy((DEST_STRUCT).FIELD, (SRC_STRUCT).FIELD, sizeof((SRC_STRUCT).FIELD)) @@ -30,8 +27,7 @@ libskrift_create_context(LIBSKRIFT_CONTEXT **ctxp, LIBSKRIFT_FONT **fonts, size_ } if (rendering) { - if (HAVE_MULTIPLE_FLAGS(rendering->flags, LIBSKRIFT_CORRECT_GAMMA | LIBSKRIFT_REMOVE_GAMMA) || - !rendering->grid_fineness) { + if (!rendering->grid_fineness) { errno = EINVAL; return -1; } diff --git a/libskrift_format_settings.c b/libskrift_format_settings.c new file mode 100644 index 0000000..aaa8255 --- /dev/null +++ b/libskrift_format_settings.c @@ -0,0 +1,36 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +#define RGBA 3, 0, 1, 2 +#define RGB -2, 0, 1, 2 +#define XRGB -1, 1, 2, 3 +#define ARGB 0, 1, 2, 3 + +const struct format_settings libskrift_format_settings[] = { + [LIBSKRIFT_R8G8B8] = {0, RGB, sizeof(uint8_t)}, + [LIBSKRIFT_X8R8G8B8] = {0, XRGB, sizeof(uint8_t)}, + [LIBSKRIFT_A8R8G8B8] = {0, ARGB, sizeof(uint8_t)}, + [LIBSKRIFT_R8G8B8A8] = {0, RGBA, sizeof(uint8_t)}, + [LIBSKRIFT_R16G16B16] = {0, RGB, sizeof(uint16_t)}, + [LIBSKRIFT_X16R16G16B16] = {0, XRGB, sizeof(uint16_t)}, + [LIBSKRIFT_A16R16G16B16] = {0, ARGB, sizeof(uint16_t)}, + [LIBSKRIFT_R16G16B16A16] = {0, RGBA, sizeof(uint16_t)}, + [LIBSKRIFT_R32G32B32] = {0, RGB, sizeof(uint32_t)}, + [LIBSKRIFT_X32R32G32B32] = {0, XRGB, sizeof(uint32_t)}, + [LIBSKRIFT_A32R32G32B32] = {0, ARGB, sizeof(uint32_t)}, + [LIBSKRIFT_R32G32B32A32] = {0, RGBA, sizeof(uint32_t)}, + [LIBSKRIFT_R64G64B64] = {0, RGB, sizeof(uint64_t)}, + [LIBSKRIFT_X64R64G64B64] = {0, XRGB, sizeof(uint64_t)}, + [LIBSKRIFT_A64R64G64B64] = {0, ARGB, sizeof(uint64_t)}, + [LIBSKRIFT_R64G64B64A64] = {0, RGBA, sizeof(uint64_t)}, + [LIBSKRIFT_RGB_FLOAT] = {1, RGB, sizeof(float)}, + [LIBSKRIFT_ARGB_FLOAT] = {1, ARGB, sizeof(float)}, + [LIBSKRIFT_RGBA_FLOAT] = {1, RGBA, sizeof(float)}, + [LIBSKRIFT_RGB_DOUBLE] = {2, RGB, sizeof(double)}, + [LIBSKRIFT_ARGB_DOUBLE] = {2, ARGB, sizeof(double)}, + [LIBSKRIFT_RGBA_DOUBLE] = {2, RGBA, sizeof(double)}, + [LIBSKRIFT_RGB_LONG_DOUBLE] = {3, RGB, sizeof(long double)}, + [LIBSKRIFT_ARGB_LONG_DOUBLE] = {3, ARGB, sizeof(long double)}, + [LIBSKRIFT_RGBA_LONG_DOUBLE] = {3, RGBA, sizeof(long double)} + /* REMEMBER that element count is specified in common.h */ +}; diff --git a/libskrift_get_grapheme_glyph.c b/libskrift_get_grapheme_glyph.c index cdaee2d..14f9a1b 100644 --- a/libskrift_get_grapheme_glyph.c +++ b/libskrift_get_grapheme_glyph.c @@ -1,34 +1,15 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -static const uint8_t gamma_map[] = { - 0, 13, 22, 28, 34, 38, 42, 46, 50, 53, 56, 59, 61, 64, 66, 69, - 71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90, 92, 93, 95, 96, 98, - 99, 101, 102, 104, 105, 106, 108, 109, 110, 112, 113, 114, 115, 117, 118, 119, - 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151, - 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164, - 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 175, 176, - 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184, 185, 185, 186, 187, 187, - 188, 189, 189, 190, 190, 191, 192, 192, 193, 194, 194, 195, 196, 196, 197, 197, - 198, 199, 199, 200, 200, 201, 202, 202, 203, 203, 204, 205, 205, 206, 206, 207, - 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, - 216, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, - 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, - 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, - 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, - 248, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255 -}; - int libskrift_get_grapheme_glyph(LIBSKRIFT_CONTEXT *ctx, libskrift_codepoint_t codepoint, double cursor_x, double cursor_y, struct libskrift_glyph **glyphp) { struct SFT_Char sft_chr; - size_t size = 1, width0, width1, width2, width3, osize, off, r, c, i; + size_t size = 1, width1, width2, width3, osize, off, r, c, i; int top = 0, left = 0, right = 0, bottom = 0; uint16_t width, height, vmul = 1, hmul = 1; - uint8_t *image, *in_image, t; + uint8_t *image, *in_image; memset(&sft_chr, 0, sizeof(sft_chr)); @@ -80,18 +61,9 @@ libskrift_get_grapheme_glyph(LIBSKRIFT_CONTEXT *ctx, libskrift_codepoint_t codep image += width3; in_image += sft_chr.width; } - if (ctx->subpixel_bgr) { - image = (*glyphp)->image; - for (i = 0; i < size; i += 3) { - t = image[i + 0]; - image[i + 0] = image[i + 2]; - image[i + 2] = t; - } - } } else if (ctx->subpixel_vertically && height) { - width0 = (size_t)width * (ctx->subpixel_bgr ? 2 : 0); width1 = (size_t)width * 1; - width2 = (size_t)width * (ctx->subpixel_bgr ? 0 : 2); + width2 = (size_t)width * 2; width3 = (size_t)width * 3; in_image = realloc(in_image, size); if (!in_image) { @@ -112,7 +84,7 @@ libskrift_get_grapheme_glyph(LIBSKRIFT_CONTEXT *ctx, libskrift_codepoint_t codep memset(&in_image[osize], 0, size - osize); for (i = r = 0; r < height; r++) { for (c = 0; c < width; c++, i += 3) { - image[i + 0] = in_image[c + width0]; + image[i + 0] = in_image[c]; image[i + 1] = in_image[c + width1]; image[i + 2] = in_image[c + width2]; } @@ -122,12 +94,6 @@ libskrift_get_grapheme_glyph(LIBSKRIFT_CONTEXT *ctx, libskrift_codepoint_t codep memcpy(image, in_image, size); } - if (ctx->rendering.flags & LIBSKRIFT_CORRECT_GAMMA) { - image = (*glyphp)->image; - for (i = 0; i < size; i++) - image[i] = gamma_map[image[i]]; - } - free(sft_chr.image); return 0; } diff --git a/libskrift_merge_glyphs.c b/libskrift_merge_glyphs.c index 48b1e5a..6c62fc8 100644 --- a/libskrift_merge_glyphs.c +++ b/libskrift_merge_glyphs.c @@ -4,14 +4,14 @@ /* TODO How common are grapheme clusters with more than two glyphs? Should we need a variadic version? */ int -libskrift_merge_glyphs(LIBSKRIFT_CONTEXT *ctx, struct libskrift_glyph *glyph1, - struct libskrift_glyph *glyph2, struct libskrift_glyph **glyphp) +libskrift_merge_glyphs(LIBSKRIFT_CONTEXT *ctx, const struct libskrift_glyph *glyph1, + const struct libskrift_glyph *glyph2, struct libskrift_glyph **glyphp) { int16_t x1a, x1b, x2a, x2b, y1a, y1b, y2a, y2b, x1, x2, y1, y2; size_t width, height, r, c, size, psize; size_t src_off, dest_off, src_linesize, dest_linesize; - psize = glyph1->size / ((size_t)glyph1->width * (size_t)glyph1->height); + psize = ctx->rendering.smoothing ? 3 : 1; x1a = glyph1->x; x1b = glyph2->x; @@ -54,15 +54,31 @@ libskrift_merge_glyphs(LIBSKRIFT_CONTEXT *ctx, struct libskrift_glyph *glyph1, src_linesize = glyph2->width * psize; dest_off = (size_t)(glyph2->y - y1) * dest_linesize; dest_off += (size_t)(glyph2->x - x1) * psize; + + /* TODO only use merging on actual overlap */ +#ifndef OR_MERGE if (ctx->rendering.smoothing) { +#ifdef SUM_MERGE + unsigned sum; + for (r = src_off = 0; r < glyph2->height; r++, dest_off += dest_linesize, src_off += src_linesize) { + for (c = 0; c < src_linesize; c++) { + sum = (unsigned)(*glyphp)->image[dest_off + c] + (unsigned)glyph2->image[src_off + c]; + (*glyphp)->image[dest_off + c] = (uint8_t)(sum | ((sum & 0x100) - 1)); + } + } +#else for (r = src_off = 0; r < glyph2->height; r++, dest_off += dest_linesize, src_off += src_linesize) for (c = 0; c < src_linesize; c++) (*glyphp)->image[dest_off + c] = MAX((*glyphp)->image[dest_off + c], glyph2->image[src_off + c]); +#endif } else { +#endif for (r = src_off = 0; r < glyph2->height; r++, dest_off += dest_linesize, src_off += src_linesize) for (c = 0; c < src_linesize; c++) (*glyphp)->image[dest_off + c] |= glyph2->image[src_off + c]; +#ifndef OR_MERGE } +#endif return 0; } diff --git a/libskrift_srgb_postprocess.c b/libskrift_srgb_postprocess.c new file mode 100644 index 0000000..3e994c1 --- /dev/null +++ b/libskrift_srgb_postprocess.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +#define GAMMA(TYPE, POW) (t <= (TYPE)0.0031308f ? (TYPE)12.92f * t : (TYPE)1.055f * POW(t, 1 / (TYPE)2.4f) - (TYPE)0.055f) + +static const uint8_t gamma_u8[] = { + 0, 13, 22, 28, 34, 38, 42, 46, 50, 53, 56, 59, 61, 64, 66, 69, + 71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90, 92, 93, 95, 96, 98, + 99, 101, 102, 104, 105, 106, 108, 109, 110, 112, 113, 114, 115, 117, 118, 119, + 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151, + 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164, + 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 175, 176, + 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184, 185, 185, 186, 187, 187, + 188, 189, 189, 190, 190, 191, 192, 192, 193, 194, 194, 195, 196, 196, 197, 197, + 198, 199, 199, 200, 200, 201, 202, 202, 203, 203, 204, 205, 205, 206, 206, 207, + 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, + 216, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, + 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, + 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, + 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, + 248, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255 +}; + +#define FUNCTION_NAME libskrift_srgb_preprocess + +#include "srgb-gamma.h" diff --git a/libskrift_srgb_preprocess.c b/libskrift_srgb_preprocess.c new file mode 100644 index 0000000..e290fc9 --- /dev/null +++ b/libskrift_srgb_preprocess.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +#define GAMMA(TYPE, POW) (t <= (TYPE)0.04045f ? t / (TYPE)12.92f : POW((t + (TYPE)0.055f) / (TYPE)1.055f, (TYPE)2.4f)) + +static const uint8_t gamma_u8[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, + 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, + 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 17, 18, 18, 19, 19, 20, + 20, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 27, 27, 28, 29, 29, + 30, 30, 31, 32, 32, 33, 34, 35, 35, 36, 37, 37, 38, 39, 40, 41, + 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, + 90, 91, 92, 93, 95, 96, 97, 99, 100, 101, 103, 104, 105, 107, 108, 109, + 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 125, 127, 128, 130, 131, 133, + 134, 136, 138, 139, 141, 142, 144, 146, 147, 149, 151, 152, 154, 156, 157, 159, + 161, 163, 164, 166, 168, 170, 171, 173, 175, 177, 179, 181, 183, 184, 186, 188, + 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, + 222, 224, 226, 229, 231, 233, 235, 237, 239, 242, 244, 246, 248, 250, 253, 255 +}; + +#define FUNCTION_NAME libskrift_srgb_preprocess + +#include "srgb-gamma.h" diff --git a/srgb-gamma.h b/srgb-gamma.h new file mode 100644 index 0000000..3388497 --- /dev/null +++ b/srgb-gamma.h @@ -0,0 +1,145 @@ +/* See LICENSE file for copyright and license details. */ + +static inline long double +gamma_ullf(long double t) +{ + return GAMMA(long double, powl); +} + +static inline double +gamma_ulf(double t) +{ + return GAMMA(double, pow); +} + +static inline float +gamma_uf(float t) +{ + return GAMMA(float, powf); +} + +static inline long double +gamma_llf(long double t) +{ + return t >= 0 ? gamma_ullf(t) : -gamma_ullf(-t); +} + +static inline double +gamma_lf(double t) +{ + return t >= 0 ? gamma_ulf(t) : -gamma_ulf(-t); +} + +static inline float +gamma_f(float t) +{ + return t >= 0 ? gamma_uf(t) : -gamma_uf(-t); +} + +static inline uint64_t +gamma_u64(uint64_t t) +{ + return (uint64_t)(gamma_ullf((long double)t / UINT64_MAX) * UINT64_MAX); +} + +static inline uint32_t +gamma_u32(uint32_t t) +{ + return (uint32_t)(gamma_ulf((double)t / UINT32_MAX) * UINT32_MAX); +} + +static inline uint16_t +gamma_u16(uint32_t t) +{ + return (uint16_t)(gamma_ulf((double)t / UINT16_MAX) * UINT16_MAX); +} + +void +FUNCTION_NAME(struct libskrift_image *image, size_t x, size_t y, size_t width, size_t height) +{ + struct format_settings settings; + uint8_t *img = image->image; + size_t linesize, psize; + + settings = libskrift_format_settings[image->format]; + psize = settings.spsize * (size_t)(4 - (settings.apos <= -2)); + linesize = (size_t)image->width * psize; + img += y * linesize + x * psize; + width *= psize; + + switch (settings.float_type) { + case 0: + switch (settings.spsize) { + case 1: + for (y = 0; y < height; y++, img += linesize) { + for (x = 0; x < width; x += psize) { + ((uint8_t *)&img[x])[settings.rpos] = gamma_u8[((uint8_t *)&img[x])[settings.rpos]]; + ((uint8_t *)&img[x])[settings.gpos] = gamma_u8[((uint8_t *)&img[x])[settings.gpos]]; + ((uint8_t *)&img[x])[settings.bpos] = gamma_u8[((uint8_t *)&img[x])[settings.bpos]]; + } + } + break; + + case 2: + for (y = 0; y < height; y++, img += linesize) { + for (x = 0; x < width; x += psize) { + ((uint16_t *)&img[x])[settings.rpos] = gamma_u16(((uint16_t *)&img[x])[settings.rpos]); + ((uint16_t *)&img[x])[settings.gpos] = gamma_u16(((uint16_t *)&img[x])[settings.gpos]); + ((uint16_t *)&img[x])[settings.bpos] = gamma_u16(((uint16_t *)&img[x])[settings.bpos]); + } + } + break; + + case 4: + for (y = 0; y < height; y++, img += linesize) { + for (x = 0; x < width; x += psize) { + ((uint32_t *)&img[x])[settings.rpos] = gamma_u32(((uint32_t *)&img[x])[settings.rpos]); + ((uint32_t *)&img[x])[settings.gpos] = gamma_u32(((uint32_t *)&img[x])[settings.gpos]); + ((uint32_t *)&img[x])[settings.bpos] = gamma_u32(((uint32_t *)&img[x])[settings.bpos]); + } + } + break; + + default: + for (y = 0; y < height; y++, img += linesize) { + for (x = 0; x < width; x += psize) { + ((uint64_t *)&img[x])[settings.rpos] = gamma_u64(((uint64_t *)&img[x])[settings.rpos]); + ((uint64_t *)&img[x])[settings.gpos] = gamma_u64(((uint64_t *)&img[x])[settings.gpos]); + ((uint64_t *)&img[x])[settings.bpos] = gamma_u64(((uint64_t *)&img[x])[settings.bpos]); + } + } + break; + } + break; + + case 1: + for (y = 0; y < height; y++, img += linesize) { + for (x = 0; x < width; x += psize) { + ((float *)&img[x])[settings.rpos] = gamma_f(((float *)&img[x])[settings.rpos]); + ((float *)&img[x])[settings.gpos] = gamma_f(((float *)&img[x])[settings.gpos]); + ((float *)&img[x])[settings.bpos] = gamma_f(((float *)&img[x])[settings.bpos]); + } + } + break; + + case 2: + for (y = 0; y < height; y++, img += linesize) { + for (x = 0; x < width; x += psize) { + ((double *)&img[x])[settings.rpos] = gamma_lf(((double *)&img[x])[settings.rpos]); + ((double *)&img[x])[settings.gpos] = gamma_lf(((double *)&img[x])[settings.gpos]); + ((double *)&img[x])[settings.bpos] = gamma_lf(((double *)&img[x])[settings.bpos]); + } + } + break; + + default: + for (y = 0; y < height; y++, img += linesize) { + for (x = 0; x < width; x += psize) { + ((long double *)&img[x])[settings.rpos] = gamma_llf(((long double *)&img[x])[settings.rpos]); + ((long double *)&img[x])[settings.gpos] = gamma_llf(((long double *)&img[x])[settings.gpos]); + ((long double *)&img[x])[settings.bpos] = gamma_llf(((long double *)&img[x])[settings.bpos]); + } + } + break; + } +} |