From a4b5b706053b4796a3418345a49f0e6ff0623572 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Mon, 30 Jan 2023 22:58:00 +0100 Subject: Add libglitter_redistribute_energy_double stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 2 + README | 43 ++++++++-------- libglitter.7 | 43 +++++++++++----- libglitter.h | 88 +++++++++++++++++++++++++++++++++ libglitter_compose_double.3 | 1 + libglitter_redistribute_energy_double.c | 80 ++++++++++++++++++++++++++++++ libglitter_redistribute_energy_float.3 | 1 + libglitter_redistribute_energy_float.c | 6 +++ 8 files changed, 231 insertions(+), 33 deletions(-) create mode 100644 libglitter_redistribute_energy_double.c create mode 120000 libglitter_redistribute_energy_float.3 create mode 100644 libglitter_redistribute_energy_float.c diff --git a/Makefile b/Makefile index 98fe38a..cb23ead 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,8 @@ OBJ =\ libglitter_get_colour_model_conversion_matrix_float.o\ libglitter_per_channel_desaturate_double.o\ libglitter_per_channel_desaturate_float.o\ + libglitter_redistribute_energy_double.o\ + libglitter_redistribute_energy_float.o\ libglitter_reorder_rasters.o\ libglitter_split_uint32_raster.o\ libglitter_split_uint64_raster.o\ diff --git a/README b/README index f4996a7..e3ac777 100644 --- a/README +++ b/README @@ -8,29 +8,32 @@ DESCRIPTION rasterise glyphs nor does it know about the montor's subpixel layout or rendering configurations. - To use libglitter you first apply hinting to the text so that - the glyph outlines aligns with the output's pixel-grid as - closely as possible. The next step is to get the output's - subpixel arrangement and scaling factor, then assuming that - the output's subpixel arrangement is subpixel-rendering - compatible and that its native resolution is used, you - rasterise the text using greyscale-antialiasing into a raster - sized according to the output's horizontal and vertical + To use libglitter you first (optionally) apply hinting to the + text so that the glyph outlines aligns with the output's + pixel-grid as closely as possible. The next step is to get + the output's subpixel arrangement and scaling factor, then + assuming that the output's subpixel arrangement is subpixel- + rendering compatible and that its native resolution is used, + you rasterise the text using greyscale-antialiasing into a + raster sized according to the output's horizontal and vertical subpixel densities (rather than pixel densities as normally done with greyscale-antialiasing; some subpixels may have be counted multiple times depending on the subpixel arrangement). - After this you create an uninitialised colour raster for text - and the output's pixel density, and split it into one raster - per colour channel using libglitter_split_uint64_raster(3) or - libglitter_split_uint32_raster(3), this is when libglitter is - first used in this process; alternatively you create one - raster for each colour channel directly. Then you use - libglitter_compose_double(3), libglitter_compose_float(3), - libglitter_compose_uint64(3), libglitter_compose_uint32(3), - libglitter_compose_uint16(3), or libglitter_compose_uint8(3) - to create the subpixel-antialiased image of the text; you may - have to first call libglitter_reorder_rasters(3) to put the - rasters in the expected order. + At this point, depending on final result, you may (will + probably) want to use libglitter_redistribute_energy_double(3) + or libglitter_redistribute_energy_float(3) to make the text a + bit blurrier but reduce colour fringing. After this you create + an uninitialised colour raster for text and the output's pixel + density, and split it into one raster per colour channel using + libglitter_split_uint64_raster(3) or libglitter_split_uint32_- + raster(3), this is when libglitter is first used in this + process; alternatively you create one raster for each colour + channel directly. Then you use libglitter_compose_double(3), + libglitter_compose_float(3), libglitter_compose_uint64(3), + libglitter_compose_uint32(3), libglitter_compose_uint16(3), or + libglitter_compose_uint8(3) to create the subpixel-antialiased + image of the text; you may have to first call libglitter_- + reorder_rasters(3) to put the rasters in the expected order. An optional next step is to use lessen the intensity of the subpixel-antialiasing with libglitter_desaturate_double(3), diff --git a/libglitter.7 b/libglitter.7 index 1e32967..bed8b56 100644 --- a/libglitter.7 +++ b/libglitter.7 @@ -13,7 +13,7 @@ layout or rendering configurations. .PP To use .B libglitter -you first apply hinting to the text so that +you first (optionally) apply hinting to the text so that the glyph outlines aligns with the output's pixel-grid as closely as possible. The next step is to get the output's subpixel arrangement and scaling factor, then assuming that @@ -24,6 +24,12 @@ sized according to the output's horizontal and vertical subpixel densities (rather than pixel densities as normally done with greyscale-antialiasing; some subpixels may have be counted multiple times depending on the subpixel arrangement). +At this point, depending on final result, you may (will +probably) want to use +.BR libglitter_redistribute_energy_double (3) +or +.BR libglitter_redistribute_energy_float (3) +to make the text a bit blurrier but reduce colour fringing. After this you create an uninitialised colour raster for text and the output's pixel density, and split it into one raster per colour channel using @@ -100,22 +106,24 @@ not for subpixel-antialiasing, and should even only used it if the user explicitly requests it. .PP Hinting is another important issue. For aliased text, hinting -is critical to ensure that strokes do not disable because they +is critical to ensure that strokes do not disappear because they are not wide enough, but also it is important so that a stroke's width is not doubled because it is a bit wider than a pixel or not aligned well with the pixel grid. Hinting attempts to align the font outline with the pixel grid. For greyscale-antialiased text, hinting as not as important, but it removes blurring and -dim strokes. For subpixel-antialiased text, hinting is not as -important as for aliased text, but it is more much important -that one greyscale-antialiased text. For subpixel-antialiased -text, hinting removes fringing (colours along the edge of a -stroke) and miscoloured strokes, strokes can even disappear: -for example, if the stroke only hits blue subpixels, but -should be rendered as pure red (the primary colour) on black, -there will only be black, as that is what primary red muliplied -by primary blue results in. Applications are discourage for -using subpixel-rendering on non-hinted text unless that user +dim strokes. However some people are more bothered by hinting +artefacts, so hinting should not always be applied. For +subpixel-antialiased text, hinting is not as important as for +aliased text, but it is more much important than on +greyscale-antialiased text. For subpixel-antialiased text, +hinting removes fringing (colours along the edge of a stroke) +and miscoloured strokes, strokes can even disappear: for +example, if the stroke only hits blue subpixels, but should be +rendered as pure red (the primary colour) on black, there will +only be black, as that is what primary red muliplied by primary +blue results in. Applications are discourage for using +subpixel-rendering on non-hinted text unless that user explicitly says it he wants subpixel-rendered text even it will look bad (presumably to see how it looks). Subpixel-rendering may also be a bad idea on coloured text. @@ -141,7 +149,16 @@ native colour model: as the primary colours' chromacity may differ from sRGB, it is possible that when outputing colour it is intepreted as sRGB, and converting to the output's colour model, which may change the activation level on the subpixels -as compared to how it was rendered. +as compared to how it was rendered. Applications should also +if possible attempt align strokes to the pixel-grid rather than +the subpixel grid: if you have a monitor with vertical stripes +of subpixels, and draw a white, one pixel wide vertical line +on black, it will look like a white-on-black line, but not so +if you shift the line over one pixel, suddenly it becomes two +inversely coloured lines (this does however depend on the +monitor: there are less common monitors that are actually +designed so that this doesn't happen: they use a different +pixel model). .PP Applications should be aware that the user's may use different monitors and may therefore need to render text differently diff --git a/libglitter.h b/libglitter.h index d285104..277b7e4 100644 --- a/libglitter.h +++ b/libglitter.h @@ -87,6 +87,13 @@ */ #define LIBGLITTER_FEATURE_COLOUR_MODEL UINT64_C(0x0000000000000200) +/** + * The allocation will use at least one of the functions + * `libglitter_redistribute_energy_double`, and + * `libglitter_redistribute_energy_float` + */ +#define LIBGLITTER_FEATURE_REDISTRIBUTE UINT64_C(0x0000000000000400) + /** * The CIE xyY values of the D65 illuminant @@ -141,6 +148,7 @@ enum libglitter_colour { * - LIBGLITTER_FEATURE_UINT32_TYPE, * - LIBGLITTER_FEATURE_UINT16_TYPE, * - LIBGLITTER_FEATURE_UINT8_TYPE, + ' - LIBGLITTER_FEATURE_REDISTRIBUTE, * - LIBGLITTER_FEATURE_COMPOSE, * - LIBGLITTER_FEATURE_CU_DESATURATION, * - LIBGLITTER_FEATURE_PC_DESATURATION, and @@ -217,6 +225,86 @@ LIBGLITTER_RENDER_CONTEXT *libglitter_create_render_context(size_t, size_t, size void libglitter_update_render_context(LIBGLITTER_RENDER_CONTEXT *, size_t); +/** + * Apply a horizontal, 1-dimensional convolution kernel + * and a vertical, 1-dimensional convolution kernel + * (both are optional) to kernel to blur the text in + * order to reduce colour fringing + * + * Each raster shall be row-major ordered an shall + * have horizontally adjacent cells adjacent in memory: + * the is no space between the cells' memory areas if + * there is no horizontal space between them in the + * raster + * + * @param output Output subpixel raster, need not be initialised; + * this raster is latter used as the input raster + * for the `libglitter_compose_double` function. + * This raster is assumed to have the height + * `height + (vkernelsize - 1)` and the width + * `width + (hkernelsize - 1)`; the text will be + * offset from the top by `(vkernelsize - 1) / 2` + * cells downward and and from the left by + * `(hkernelsize - 1) / 2` cells rightward + * @param input Input subpixel raster; this raster must have + * a left padding and a right padding of + * `hkernel - 1` zero-initialised cells, as well + * as a top padding and a bottom padding of + * `vkernel - 1` zero-initialised cells. The + * the pointer itself shall point to the first + * pixel, the topmost and leftmost pixel that + * is not part of the padding. + * @param output_rowsize The number of cells a pointer to cell in + * `output` must be offset with to get to the + * cell on the next row but in the same column + * @param input_rowsize The number of cells a pointer to cell in + * `input` must be offset with to get to the + * cell on the next row but in the same column + * @param width The width of the input raster, excluding + * padding, in cells + * @param height The height of the input raster, excluding + * padding, in cells + * @param hkernelsize The size (number of elements) of `hkernel`; + * must be odd; if 1, `hkernel` is not applied + * @param vkernelsize The size (number of elements) of `vkernel`; + * must be odd; if 1, `vkernel` is not applied + * @param hkernel The horizontal convolution kernel; the sum + * of its elements shall be 1. It can be `NULL` + * if `hkernelsize` is 1, as it will not be + * applied + * @param vkernel The vertical convolution kernel; the sum + * of its elements shall be 1. It can be `NULL` + * if `vkernelsize` is 1, as it will not be + * applied + * + * If the input value of the `widthmul` parameter to the + * `libglitter_create_render_context` function is `1`, it + * the suggested `hkernel` is `{1.}`, otherwise the suggested + * `hkernel` is `{1/3., 1/3., 1/3.}`. Likewise, if the + * input value of the `heightmul` parameter to the + * `libglitter_create_render_context` function is `1`, it + * the suggested `vkernel` is `{1.}`, otherwise the suggested + * `vkernel` is `{1/3., 1/3., 1/3.}`. Of course user + * experimentation is required to find the best kernel. + */ +LIBGLITTER_GCC_ATTRS__(nonnull(1, 2)) +void libglitter_redistribute_energy_double(double *restrict output, const double *restrict input, + size_t output_rowsize, size_t input_rowsize, size_t width, + size_t height, size_t hkernelsize, size_t vkernelsize, + const double *hkernel, const double *vkernel); + +/** + * This value is identical to `libglitter_redistribute_energy_double`, + * apart from it parameter types, see `libglitter_redistribute_energy_double` + * for details about this function + */ +LIBGLITTER_GCC_ATTRS__(nonnull(1, 2)) +void libglitter_redistribute_energy_float(float *restrict output, const float *restrict input, + size_t output_rowsize, size_t input_rowsize, size_t width, + size_t height, size_t hkernelsize, size_t vkernelsize, + const float *hkernel, const float *vkernel); + + /** * Create one raster per monitor colour from a raster of * subpixels (which may be further divided in the raster) diff --git a/libglitter_compose_double.3 b/libglitter_compose_double.3 index 36bbf02..40f08a6 100644 --- a/libglitter_compose_double.3 +++ b/libglitter_compose_double.3 @@ -146,5 +146,6 @@ None. .BR libglitter (7), .BR libglitter_colour_model_convert_rasters_double (3), .BR libglitter_desaturate_double (3), +.BR libglitter_redistribute_energy_double (3), .BR libglitter_reorder_rasters (3), .BR libglitter_split_uint64_raster (3) diff --git a/libglitter_redistribute_energy_double.c b/libglitter_redistribute_energy_double.c new file mode 100644 index 0000000..3eb39e0 --- /dev/null +++ b/libglitter_redistribute_energy_double.c @@ -0,0 +1,80 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +static void +hselfconvolute(double *restrict raster, size_t rowsize, size_t width, size_t height, size_t kernelsize, const double *hkernel) +{ + /* TODO */ +} + + +static void +hconvolute(double *restrict output, const double *restrict input, size_t output_rowsize, size_t input_rowsize, + size_t width, size_t height, size_t kernelsize, const double *kernel) +{ + /* TODO */ +} + + +static void +vconvolute(double *restrict output, const double *restrict input, size_t output_rowsize, size_t input_rowsize, + size_t width, size_t height, size_t kernelsize, const double *kernel) +{ + /* TODO */ +} + + +static void +copyraster(double *restrict output, const double *restrict input, size_t output_rowsize, + size_t input_rowsize, size_t width, size_t height) +{ + size_t y; + for (y = 0; y < height; y++) { + memcpy(output, input, width * sizeof(double)); + output = &output[output_rowsize]; + input = &input[input_rowsize]; + } +} + + +void +libglitter_redistribute_energy_double(double *restrict output, const double *restrict input, /* TODO add man page */ + size_t output_rowsize, size_t input_rowsize, size_t width, + size_t height, size_t hkernelsize, size_t vkernelsize, + const double *hkernel, const double *vkernel) +{ + /* TODO Can we allow output==input ? */ + if (vkernelsize > 1) { + vconvolute(output, input, output_rowsize, input_rowsize, width, height, vkernelsize, vkernel); + if (hkernelsize > 1) + hselfconvolute(output, output_rowsize, width, height, hkernelsize, hkernel); + } else if (hkernelsize > 1) { + vconvolute(output, input, output_rowsize, input_rowsize, width, height, hkernelsize, hkernel); + } else { + copyraster(output, input, output_rowsize, input_rowsize, width, height); + } +} + + +#else + + +#define TOLERANCE 0.0001 + +static int +eq(double a, double b) +{ + double r = a - b; + return (r < 0 ? -r : r) < TOLERANCE; +} + +int +main(void) +{ + return 0; /* TODO add test */ +} + + +#endif diff --git a/libglitter_redistribute_energy_float.3 b/libglitter_redistribute_energy_float.3 new file mode 120000 index 0000000..4bcb222 --- /dev/null +++ b/libglitter_redistribute_energy_float.3 @@ -0,0 +1 @@ +libglitter_redistribute_energy_double.3 \ No newline at end of file diff --git a/libglitter_redistribute_energy_float.c b/libglitter_redistribute_energy_float.c new file mode 100644 index 0000000..4a3f553 --- /dev/null +++ b/libglitter_redistribute_energy_float.c @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#define libglitter_redistribute_energy_double libglitter_redistribute_energy_float +#define double float +#define fma fmaf +#include "libglitter_redistribute_energy_double.c" -- cgit v1.2.3-70-g09d2