From 9e7d87e78531157e6a6072650cf84e59d57133fa Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Wed, 29 Apr 2020 15:57:11 +0200 Subject: Add support for character mirroring and add functions for creating transformations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 10 +++ README | 6 +- demo.c | 11 +--- libskrift.h | 120 ++++++++++++++++++++++++++++++------ libskrift_add_180_degree_rotation.c | 4 ++ libskrift_add_270_degree_rotation.c | 4 ++ libskrift_add_90_degree_rotation.c | 4 ++ libskrift_add_rotation.c | 4 ++ libskrift_add_rotation_degrees.c | 4 ++ libskrift_add_scaling.c | 4 ++ libskrift_add_shear.c | 4 ++ libskrift_add_transformation.c | 4 ++ libskrift_add_translation.c | 4 ++ libskrift_add_transposition.c | 4 ++ libskrift_create_context.c | 47 +++++++++----- 15 files changed, 192 insertions(+), 42 deletions(-) create mode 100644 libskrift_add_180_degree_rotation.c create mode 100644 libskrift_add_270_degree_rotation.c create mode 100644 libskrift_add_90_degree_rotation.c create mode 100644 libskrift_add_rotation.c create mode 100644 libskrift_add_rotation_degrees.c create mode 100644 libskrift_add_scaling.c create mode 100644 libskrift_add_shear.c create mode 100644 libskrift_add_transformation.c create mode 100644 libskrift_add_translation.c create mode 100644 libskrift_add_transposition.c diff --git a/Makefile b/Makefile index 4c70752..85769d0 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,16 @@ CONFIGFILE = config.mk include $(CONFIGFILE) OBJ =\ + libskrift_add_180_degree_rotation.o\ + libskrift_add_270_degree_rotation.o\ + libskrift_add_90_degree_rotation.o\ + libskrift_add_rotation.o\ + libskrift_add_rotation_degrees.o\ + libskrift_add_scaling.o\ + libskrift_add_shear.o\ + libskrift_add_transformation.o\ + libskrift_add_translation.o\ + libskrift_add_transposition.o\ libskrift_apply_glyph.o\ libskrift_calculate_dpi.o\ libskrift_close_font.o\ diff --git a/README b/README index bfa17bf..f7327d9 100644 --- a/README +++ b/README @@ -36,6 +36,8 @@ Currently implemented: sRGB gamma function. + Affine transformations on glyphs. + Pending support in libschift: @@ -44,7 +46,7 @@ Pending support in libschift: Hinting. (Better subpixel rendering requires subpixel aware hinting.) - Affine transformations on glyphs, texts, part of outline. + Affine transformations on parts of outline. Kerning using font information. @@ -53,6 +55,8 @@ Pending support in libschift: Not implemented yet + Affine transformations on texts. + Glyph caching. Normalise text when glyphs are missing. diff --git a/demo.c b/demo.c index a4d998c..c6a27d2 100644 --- a/demo.c +++ b/demo.c @@ -11,24 +11,19 @@ main(void) LIBSKRIFT_CONTEXT *ctx; struct libskrift_image image = {LIBSKRIFT_R8G8B8A8, LIBSKRIFT_HOST_SUBPIXEL, 0, 800, 600, NULL, NULL, NULL}; struct libskrift_rendering rendering = LIBSKRIFT_DEFAULT_RENDERING; - struct libskrift_colour colour = LIBSKRIFT_PREMULTIPLY(0.8f, 0.25f, .80f, .50f, .20f); + struct libskrift_colour colour = LIBSKRIFT_PREMULTIPLY(.80f, .50f, .80f, .50f, .20f); double height; size_t size, i; rendering.smoothing = LIBSKRIFT_SUBPIXEL; rendering.subpixel_order = LIBSKRIFT_NONE; - rendering.flags = 0; + rendering.flags = LIBSKRIFT_MIRROR_CHARS; if (libskrift_open_font_file(&font, DEMO_FONT)) { perror("libskrift_open_font_file"); return -1; } - rendering.char_transformation[0] = 1; - rendering.char_transformation[1] = 0.25; - rendering.char_transformation[2] = 0; - rendering.char_transformation[3] = 0; - rendering.char_transformation[4] = 1; - rendering.char_transformation[5] = 0; + libskrift_add_rotation_degrees(rendering.char_transformation, 10); height = libskrift_points_to_pixels(72, &rendering); if (libskrift_create_context(&ctx, &font, 1, height, &rendering, NULL)) { perror("libskrift_create_context"); diff --git a/libskrift.h b/libskrift.h index 843de6e..57eb4d1 100644 --- a/libskrift.h +++ b/libskrift.h @@ -2,6 +2,7 @@ #ifndef LIBSKRIFT_H #define LIBSKRIFT_H 1 +#include #include #include #include @@ -86,25 +87,25 @@ enum libskrift_hinting { LIBSKRIFT_FULL = 100 }; -#define LIBSKRIFT_REMOVE_GAMMA 0x00000001L -#define LIBSKRIFT_Y_INCREASES_UPWARDS 0x00000002L /* SFT_DOWNWARD_Y otherwise */ -#define LIBSKRIFT_FLIP_TEXT 0x00000004L -#define LIBSKRIFT_FLIP_CHARS 0x00000008L -#define LIBSKRIFT_MIRROR_TEXT 0x00000010L -#define LIBSKRIFT_MIRROR_CHARS 0x00000020L -#define LIBSKRIFT_TRANSPOSE_TEXT 0x00000040L -#define LIBSKRIFT_TRANSPOSE_CHARS 0x00000080L -#define LIBSKRIFT_NO_LIGATURES 0x00000100L -#define LIBSKRIFT_ADVANCE_CHAR_TO_GRID 0x00000200L -#define LIBSKRIFT_REGRESS_CHAR_TO_GRID 0x00000400L /* Combine with LIBSKRIFT_ADVANCE_CHAR_TO_GRID for closest alternative */ -#define LIBSKRIFT_ADVANCE_WORD_TO_GRID 0x00000800L -#define LIBSKRIFT_REGRESS_WORD_TO_GRID 0x00001000L /* Combine with LIBSKRIFT_ADVANCE_WORD_TO_GRID for closest alternative */ -#define LIBSKRIFT_USE_SUBPIXEL_GRID 0x00002000L -#define LIBSKRIFT_VERTICAL_TEXT 0x00004000L -#define LIBSKRIFT_AUTOHINTING 0x00008000L /* Use autohinter even if hint information exists */ -#define LIBSKRIFT_NO_AUTOHINTING 0x00010000L /* Use autohinter if no hint information exist */ -#define LIBSKRIFT_AUTOKERNING 0x00020000L /* Use autokerner even if kerning information exists */ -#define LIBSKRIFT_NO_AUTOKERNING 0x00040000L /* Use autokerner if no kerning information exist */ +#define LIBSKRIFT_REMOVE_GAMMA UINT32_C(0x00000001) +#define LIBSKRIFT_Y_INCREASES_UPWARDS UINT32_C(0x00000002) /* SFT_DOWNWARD_Y otherwise */ +#define LIBSKRIFT_FLIP_TEXT UINT32_C(0x00000004) +#define LIBSKRIFT_FLIP_CHARS UINT32_C(0x00000008) +#define LIBSKRIFT_MIRROR_TEXT UINT32_C(0x00000010) +#define LIBSKRIFT_MIRROR_CHARS UINT32_C(0x00000020) +#define LIBSKRIFT_TRANSPOSE_TEXT UINT32_C(0x00000040) +#define LIBSKRIFT_TRANSPOSE_CHARS UINT32_C(0x00000080) +#define LIBSKRIFT_NO_LIGATURES UINT32_C(0x00000100) +#define LIBSKRIFT_ADVANCE_CHAR_TO_GRID UINT32_C(0x00000200) +#define LIBSKRIFT_REGRESS_CHAR_TO_GRID UINT32_C(0x00000400) /* Combine with LIBSKRIFT_ADVANCE_CHAR_TO_GRID for closest alternative */ +#define LIBSKRIFT_ADVANCE_WORD_TO_GRID UINT32_C(0x00000800) +#define LIBSKRIFT_REGRESS_WORD_TO_GRID UINT32_C(0x00001000) /* Combine with LIBSKRIFT_ADVANCE_WORD_TO_GRID for closest alternative */ +#define LIBSKRIFT_USE_SUBPIXEL_GRID UINT32_C(0x00002000) +#define LIBSKRIFT_VERTICAL_TEXT UINT32_C(0x00004000) +#define LIBSKRIFT_AUTOHINTING UINT32_C(0x00008000) /* Use autohinter even if hint information exists */ +#define LIBSKRIFT_NO_AUTOHINTING UINT32_C(0x00010000) /* Use autohinter if no hint information exist */ +#define LIBSKRIFT_AUTOKERNING UINT32_C(0x00020000) /* Use autokerner even if kerning information exists */ +#define LIBSKRIFT_NO_AUTOKERNING UINT32_C(0x00040000) /* Use autokerner if no kerning information exist */ struct libskrift_rendering { int struct_version; @@ -272,4 +273,85 @@ void libskrift_srgb_preprocess(struct libskrift_image *, 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); + +inline void +libskrift_add_transformation(double m[restrict 6], const double tm[restrict 6]) +{ + double a = m[0], b = m[1], c = m[2]; + double d = m[3], e = m[4], f = m[5]; + m[0] = tm[0] * a + tm[1] * d; + m[1] = tm[0] * b + tm[1] * e; + m[2] = tm[0] * c + tm[1] * f + tm[2]; + m[3] = tm[3] * a + tm[4] * d; + m[4] = tm[3] * b + tm[4] * e; + m[5] = tm[3] * c + tm[4] * f + tm[5]; +} + +inline void +libskrift_add_rotation(double m[6], double radians) +{ + double c = cos(-radians), s = sin(-radians); + libskrift_add_transformation(m, (double []){c, -s, 0, s, c, 0}); +} + +inline void +libskrift_add_rotation_degrees(double m[6], double degrees) +{ + libskrift_add_rotation(m, degrees * (double)0.017453292519943295f); +} + +inline void +libskrift_add_90_degree_rotation(double m[6]) +{ + double a = m[0], b = m[1], c = m[2]; + m[0] = m[3], m[1] = m[4], m[2] = m[5]; + m[3] = -a, m[4] = -b, m[5] = -c; +} + +inline void +libskrift_add_180_degree_rotation(double m[6]) +{ + m[0] = -m[0], m[1] = -m[1], m[2] = -m[2]; + m[3] = -m[3], m[4] = -m[4], m[5] = -m[5]; +} + +inline void +libskrift_add_270_degree_rotation(double m[6]) +{ + double a = m[0], b = m[1], c = m[2]; + m[0] = -m[3], m[1] = -m[4], m[2] = -m[5]; + m[3] = a, m[4] = b, m[5] = c; +} + +inline void +libskrift_add_scaling(double m[6], double x, double y) +{ + m[0] *= x, m[1] *= x, m[2] *= x; + m[3] *= y, m[4] *= y, m[5] *= y; +} + +inline void +libskrift_add_transposition(double m[6]) +{ + double a = m[0], b = m[1], c = m[2]; + m[0] = m[3], m[1] = m[4], m[2] = m[5]; + m[3] = a, m[4] = b, m[5] = c; +} + +inline void +libskrift_add_shear(double m[6], double x, double y) +{ + double a = m[0], b = m[1], c = m[2]; + double d = m[3], e = m[4], f = m[6]; + m[0] += x * d, m[1] += x * e, m[2] += x * f; + m[3] += y * a, m[4] += y * b, m[5] += y * c; +} + +inline void +libskrift_add_translation(double m[6], double x, double y) +{ + m[2] += x; + m[5] += y; +} + #endif diff --git a/libskrift_add_180_degree_rotation.c b/libskrift_add_180_degree_rotation.c new file mode 100644 index 0000000..776e7b4 --- /dev/null +++ b/libskrift_add_180_degree_rotation.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_180_degree_rotation(double m[6]); diff --git a/libskrift_add_270_degree_rotation.c b/libskrift_add_270_degree_rotation.c new file mode 100644 index 0000000..74a86ea --- /dev/null +++ b/libskrift_add_270_degree_rotation.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_270_degree_rotation(double m[6]); diff --git a/libskrift_add_90_degree_rotation.c b/libskrift_add_90_degree_rotation.c new file mode 100644 index 0000000..5c920e0 --- /dev/null +++ b/libskrift_add_90_degree_rotation.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_90_degree_rotation(double m[6]); diff --git a/libskrift_add_rotation.c b/libskrift_add_rotation.c new file mode 100644 index 0000000..8b03e81 --- /dev/null +++ b/libskrift_add_rotation.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_rotation(double m[6], double radians); diff --git a/libskrift_add_rotation_degrees.c b/libskrift_add_rotation_degrees.c new file mode 100644 index 0000000..239003b --- /dev/null +++ b/libskrift_add_rotation_degrees.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_rotation_degrees(double m[6], double degrees); diff --git a/libskrift_add_scaling.c b/libskrift_add_scaling.c new file mode 100644 index 0000000..f9d745a --- /dev/null +++ b/libskrift_add_scaling.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_scaling(double m[6], double x, double y); diff --git a/libskrift_add_shear.c b/libskrift_add_shear.c new file mode 100644 index 0000000..f48c507 --- /dev/null +++ b/libskrift_add_shear.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_shear(double m[6], double x, double y); diff --git a/libskrift_add_transformation.c b/libskrift_add_transformation.c new file mode 100644 index 0000000..fa14990 --- /dev/null +++ b/libskrift_add_transformation.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_transformation(double m[restrict 6], const double tm[restrict 6]); diff --git a/libskrift_add_translation.c b/libskrift_add_translation.c new file mode 100644 index 0000000..f5e2c14 --- /dev/null +++ b/libskrift_add_translation.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_translation(double m[6], double x, double y); diff --git a/libskrift_add_transposition.c b/libskrift_add_transposition.c new file mode 100644 index 0000000..2b2e91d --- /dev/null +++ b/libskrift_add_transposition.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline void libskrift_add_transposition(double m[6]); diff --git a/libskrift_create_context.c b/libskrift_create_context.c index cf67826..1500b20 100644 --- a/libskrift_create_context.c +++ b/libskrift_create_context.c @@ -6,30 +6,47 @@ LIBSKRIFT_NO_AUTOKERNING) #define IMPLEMENTED_FLAGS (LIBSKRIFT_REMOVE_GAMMA |\ + LIBSKRIFT_MIRROR_CHARS |\ FORCED_FLAGS) /* libschrift does not add gamma, so not handling is required */ +#define TRANSFORMING_FLAGS (LIBSKRIFT_MIRROR_TEXT |\ + LIBSKRIFT_MIRROR_CHARS |\ + LIBSKRIFT_TRANSPOSE_TEXT |\ + LIBSKRIFT_TRANSPOSE_CHARS) + #define COPY_ARRAY(DEST_STRUCT, SRC_STRUCT, FIELD)\ memcpy((DEST_STRUCT).FIELD, (SRC_STRUCT).FIELD, sizeof((SRC_STRUCT).FIELD)) static const struct libskrift_rendering default_rendering = LIBSKRIFT_DEFAULT_RENDERING; +static void +multiply_matrices(const double a[restrict 6], const double b[restrict 6], double r[restrict 6]) +{ + r[0] = a[0] * b[0] + a[1] * b[3]; + r[1] = a[0] * b[1] + a[1] * b[4]; + r[2] = a[0] * b[2] + a[1] * b[5] + a[2]; + r[3] = a[3] * b[0] + a[4] * b[3]; + r[4] = a[3] * b[1] + a[4] * b[4]; + r[5] = a[3] * b[2] + a[4] * b[5] + a[5]; +} + static int transformation_hook(void *hook_data, double advance, double transform[6]) { LIBSKRIFT_CONTEXT *ctx = hook_data; - double r1c1b = ctx->rendering.char_transformation[0], r1c1a = transform[0]; - double r1c2b = ctx->rendering.char_transformation[1], r1c2a = transform[2]; - double r1c3b = ctx->rendering.char_transformation[2], r1c3a = transform[4]; - double r2c1b = ctx->rendering.char_transformation[3], r2c1a = transform[1]; - double r2c2b = ctx->rendering.char_transformation[4], r2c2a = transform[3]; - double r2c3b = ctx->rendering.char_transformation[5], r2c3a = transform[5]; - transform[0] = r1c1a * r1c1b + r1c2a * r2c1b; - transform[2] = r1c1a * r1c2b + r1c2a * r2c2b; - transform[4] = r1c1a * r1c3b + r1c2a * r2c3b + r1c3a; - transform[1] = r2c1a * r1c1b + r2c2a * r2c1b; - transform[3] = r2c1a * r1c2b + r2c2a * r2c2b; - transform[5] = r2c1a * r1c3b + r2c2a * r2c3b + r2c3a; - (void) advance; + double schrift[6] = {transform[0], transform[2], transform[4], + transform[1], transform[3], transform[5]}; + double m1[6] = {1, 0, 0, 0, 1, 0}, m2[6] = {1, 0, 0, 0, 1, 0}; + if (((ctx->rendering.flags / LIBSKRIFT_MIRROR_CHARS) ^ (ctx->rendering.flags / LIBSKRIFT_MIRROR_TEXT)) & 1) + multiply_matrices((double []){-1, 0, advance / schrift[0], 0, 1, 0}, m2, m1); + multiply_matrices(ctx->rendering.char_transformation, m1, m2); + multiply_matrices(schrift, m2, m1); + transform[0] = m1[0]; + transform[2] = m1[1]; + transform[4] = m1[2]; + transform[1] = m1[3]; + transform[3] = m1[4]; + transform[5] = m1[5]; return 0; } @@ -82,6 +99,7 @@ libskrift_create_context(LIBSKRIFT_CONTEXT **ctxp, LIBSKRIFT_FONT **fonts, size_ (*ctxp)->rendering.hinting = LIBSKRIFT_NONE; (*ctxp)->rendering.flags &= IMPLEMENTED_FLAGS; (*ctxp)->rendering.flags |= FORCED_FLAGS; + (*ctxp)->rendering.flags |= LIBSKRIFT_REMOVE_GAMMA; /* libschrift does not add gamma */ (*ctxp)->rendering.grid_fineness = 1; (*ctxp)->rendering.kerning = 0; (*ctxp)->rendering.interletter_spacing = 0; @@ -92,7 +110,8 @@ libskrift_create_context(LIBSKRIFT_CONTEXT **ctxp, LIBSKRIFT_FONT **fonts, size_ (*ctxp)->schrift_ctx.xScale = (*ctxp)->schrift_ctx.yScale; (*ctxp)->schrift_ctx.xScale *= (*ctxp)->rendering.horizontal_dpi / (*ctxp)->rendering.vertical_dpi; (*ctxp)->schrift_ctx.hook_data = (*ctxp); - if (fpclassify((*ctxp)->rendering.char_transformation[0] - 1) != FP_ZERO || + if (((*ctxp)->rendering.flags & TRANSFORMING_FLAGS) || + fpclassify((*ctxp)->rendering.char_transformation[0] - 1) != FP_ZERO || fpclassify((*ctxp)->rendering.char_transformation[1]) != FP_ZERO || fpclassify((*ctxp)->rendering.char_transformation[2]) != FP_ZERO || fpclassify((*ctxp)->rendering.char_transformation[3]) != FP_ZERO || -- cgit v1.2.3-70-g09d2