Improve handling of color palettes.

This commit adds new functions to streamline palette access:

  FT_Palette_Set: Set a user-defined palette.
  FT_Palette_Get: Get palette and palette index.
  FT_Palette_Get_Foreground_Color: Get foreground color.

Fixes issue #1134.

* include/freetype/internal/tttypes.h (TT_FaceRec): Change type of
`palette_index` to `FT_Int`.  Negative values now represent user-defined
palettes.

* src/base/ftcolor.c (FT_Palette_Set, FT_Palette_Get,
FT_Palette_Get_Foreground_Color): New functions.

* include/freetype/ftcolor.h: Updated.
This commit is contained in:
Werner Lemberg 2022-03-07 14:57:53 +01:00
parent 1e2eb65048
commit 9d86c63f4a
3 changed files with 283 additions and 22 deletions

View File

@ -45,6 +45,12 @@ FT_BEGIN_HEADER
* @description:
* The functions described here allow access and manipulation of color
* palette entries in OpenType's 'CPAL' tables.
*
* FreeType maintains a 'working palette' (together with a corresponding
* 'working palette index'), which can be set either to a palette stored
* in the font (function @FT_Palette_Select) or to a user-defined palette
* (function @FT_Palette_Set). For user-defined palettes, the working
* palette index is negative, and positive otherwise.
*/
@ -218,18 +224,13 @@ FT_BEGIN_HEADER
* FT_Palette_Select
*
* @description:
* This function has two purposes.
* This function copies a palette entry in the font's 'CPAL' table into a
* 'working palette', which is a read-write array managed by FreeType.
* It also sets the 'working palette index' to the index value given as
* an argument.
*
* (1) It activates a palette for rendering color glyphs, and
*
* (2) it retrieves all (unmodified) color entries of this palette. This
* function returns a read-write array, which means that a calling
* application can modify the palette entries on demand.
*
* A corollary of (2) is that calling the function, then modifying some
* values, then calling the function again with the same arguments resets
* all color entries to the original 'CPAL' values; all user modifications
* are lost.
* The current working palette and palette index can be retrieved with
* @FT_Palette_Get.
*
* @input:
* face ::
@ -240,10 +241,10 @@ FT_BEGIN_HEADER
*
* @output:
* apalette ::
* An array of color entries for a palette with index `palette_index`,
* having `num_palette_entries` elements (as found in the
* `FT_Palette_Data` structure). If `apalette` is set to `NULL`, no
* array gets returned (and no color entries can be modified).
* A pointer to the 'working palette', which is an array of color
* entries for a palette with index `palette_index`, having
* `num_palette_entries` elements (as found in the `FT_Palette_Data`
* structure). If `apalette` is set to `NULL`, no array gets returned.
*
* In case the font doesn't support color palettes, `NULL` is returned.
*
@ -266,6 +267,92 @@ FT_BEGIN_HEADER
FT_Color* *apalette );
/**************************************************************************
*
* @function:
* FT_Palette_Set
*
* @description:
* Set FreeType's 'working palette' and 'working palette index' to the
* given arguments. Use this function if you want to provide a
* user-defined palette, not being part of the font's 'CPAL' table.
*
* The current working palette and palette index can be retrieved with
* @FT_Palette_Get.
*
* @input:
* face ::
* The source face handle.
*
* palette_index ::
* A palette index, which must be an arbitrary, negative integer (since
* positive values are reserved for indices from the 'CPAL' table).
* FreeType sets the 'working palette index' to this value.
*
* palette ::
* A pointer to an array of color entries, having `num_palette_entries`
* elements (as found in the `FT_Palette_Data` structure). FreeType
* copies this array into its 'working palette'.
*
* @return:
* FreeType error code. 0~means success.
*
* @note:
* This function always returns an error if the config macro
* `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`.
*
* @since:
* 2.12
*/
FT_EXPORT( FT_Error )
FT_Palette_Set( FT_Face face,
FT_Int index,
FT_Color* palette );
/**************************************************************************
*
* @function:
* FT_Palette_Get
*
* @description:
* Get FreeType's 'working palette' and 'working palette index'.
*
* The working palette and palette index can be set with @FT_Palette_Set.
*
* @input:
* face ::
* The source face handle.
*
* @output:
* anindex ::
* The 'working palette index'. If the value is zero or positive, the
* working palette represents an entry from the font's 'CPAL' table
* (with the given index). Otherwise it is a user-defined palette. If
* `anindex` is set to `NULL`, no value gets returned.
*
* apalette ::
* A pointer to the 'working palette', which is an array of color
* entries for a palette having `num_palette_entries` elements (as
* found in the `FT_Palette_Data` structure). If `apalette` is set to
* `NULL`, no array gets returned.
*
* @return:
* FreeType error code. 0~means success.
*
* @note:
* This function always returns an error if the config macro
* `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`.
*
* @since:
* 2.12
*/
FT_EXPORT( FT_Error )
FT_Palette_Get( FT_Face face,
FT_Int *anindex,
FT_Color* *apalette );
/**************************************************************************
*
* @function:
@ -286,11 +373,9 @@ FT_BEGIN_HEADER
* FreeType error code. 0~means success.
*
* @note:
* If this function isn't called, the text foreground color is set to
* white opaque (BGRA value 0xFFFFFFFF) if
* @FT_PALETTE_FOR_DARK_BACKGROUND is present for the current palette,
* and black opaque (BGRA value 0x000000FF) otherwise, including the case
* that no palette types are available in the 'CPAL' table.
* See function @FT_Palette_Get_Foreground_Color for details on what
* foreground color is used if `FT_Palette_Set_Foreground_Color` is not
* called.
*
* This function always returns an error if the config macro
* `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`.
@ -303,6 +388,53 @@ FT_BEGIN_HEADER
FT_Color foreground_color );
/**************************************************************************
*
* @function:
* FT_Palette_Get_Foreground_Color
*
* @description:
* Get the 'text foreground color' as set by a previous call to
* @FT_Palette_Set_Foreground_Color.
*
* @input:
* face ::
* The source face handle.
*
* @output:
* aforeground_color ::
* The text foreground color.
*
* @return:
* FreeType error code. 0~means success.
*
* @note:
* The returned color is as follows.
*
* * If a foreground color was set with @FT_Palette_Get_Foreground_Color,
* return this value.
*
* * Otherwise, return black opaque (BGRA value 0x000000FF) if the
* 'working palette' is a user-defined palette.
*
* * Otherwise, return white opaque (BGRA value 0xFFFFFFFF) if
* @FT_PALETTE_FOR_DARK_BACKGROUND is present for the current palette.
*
* * Otherwise, return black opaque (BGRA value 0x000000FF). This
* includes the case that no palette types are available in the 'CPAL'
* table.
*
* This function always returns an error if the config macro
* `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`.
*
* @since:
* 2.12
*/
FT_EXPORT( FT_Error )
FT_Palette_Get_Foreground_Color( FT_Face face,
FT_Color* aforeground_color );
/**************************************************************************
*
* @section:

View File

@ -1537,7 +1537,7 @@ FT_BEGIN_HEADER
/* glyph colors */
FT_Palette_Data palette_data; /* since 2.10 */
FT_UShort palette_index;
FT_Int palette_index;
FT_Color* palette;
FT_Bool have_foreground_color;
FT_Color foreground_color;

View File

@ -36,7 +36,7 @@
{
if ( !face )
return FT_THROW( Invalid_Face_Handle );
if ( !apalette_data)
if ( !apalette_data )
return FT_THROW( Invalid_Argument );
if ( FT_IS_SFNT( face ) )
@ -88,6 +88,57 @@
}
/* documentation is in ftcolor.h */
FT_EXPORT_DEF( FT_Error )
FT_Palette_Set( FT_Face face,
FT_Int index,
FT_Color* palette )
{
TT_Face ttface;
FT_UShort i;
if ( !face || !FT_IS_SFNT( face ) )
return FT_THROW( Invalid_Face_Handle );
if ( !palette || index >= 0 )
return FT_THROW( Invalid_Argument );
ttface = (TT_Face)face;
for ( i = 0; i < ttface->palette_data.num_palette_entries; i++ )
ttface->palette[i] = palette[i];
ttface->palette_index = index;
return FT_Err_Ok;
}
/* documentation is in ftcolor.h */
FT_EXPORT_DEF( FT_Error )
FT_Palette_Get( FT_Face face,
FT_Int *anindex,
FT_Color* *apalette )
{
TT_Face ttface;
if ( !face || !FT_IS_SFNT( face ) )
return FT_THROW( Invalid_Face_Handle );
ttface = (TT_Face)face;
if ( anindex )
*anindex = ttface->palette_index;
if ( apalette )
*apalette = ttface->palette;
return FT_Err_Ok;
}
/* documentation is in ftcolor.h */
FT_EXPORT_DEF( FT_Error )
@ -111,6 +162,44 @@
return FT_Err_Ok;
}
/* documentation is in ftcolor.h */
FT_EXPORT_DEF( FT_Error )
FT_Palette_Get_Foreground_Color( FT_Face face,
FT_Color* aforeground_color )
{
TT_Face ttface;
FT_Color white = { 0xFF, 0xFF, 0xFF, 0xFF };
FT_Color black = { 0x00, 0x00, 0x00, 0xFF };
if ( !face || !FT_IS_SFNT( face ) )
return FT_THROW( Invalid_Face_Handle );
if ( !aforeground_color )
return FT_THROW( Invalid_Argument );
ttface = (TT_Face)face;
if ( ttface->have_foreground_color )
*aforeground_color = ttface->foreground_color;
else if ( ttface->palette_index < 0 )
*aforeground_color = black;
else
{
if ( ttface->palette_data.palette_flags &&
( ttface->palette_data.palette_flags[ttface->palette_index] &
FT_PALETTE_FOR_DARK_BACKGROUND ) )
*aforeground_color = white;
else
*aforeground_color = black;
}
return FT_Err_Ok;
}
#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
FT_EXPORT_DEF( FT_Error )
@ -139,6 +228,34 @@
}
FT_EXPORT_DEF( FT_Error )
FT_Palette_Set( FT_Face face,
FT_Int index,
FT_Color* palette )
{
FT_UNUSED( face );
FT_UNUSED( index );
FT_UNUSED( palette );
return FT_THROW( Unimplemented_Feature );
}
FT_EXPORT_DEF( FT_Error )
FT_Palette_Get( FT_Face face,
FT_Int *anindex,
FT_Color* *apalette )
{
FT_UNUSED( face );
FT_UNUSED( anindex );
FT_UNUSED( apalette );
return FT_THROW( Unimplemented_Feature );
}
FT_EXPORT_DEF( FT_Error )
FT_Palette_Set_Foreground_Color( FT_Face face,
FT_Color foreground_color )
@ -150,6 +267,18 @@
return FT_THROW( Unimplemented_Feature );
}
FT_EXPORT_DEF( FT_Error )
FT_Palette_Get_Foreground_Color( FT_Face face,
FT_Color* aforeground_color )
{
FT_UNUSED( face );
FT_UNUSED( aforeground_color );
return FT_THROW( Unimplemented_Feature );
}
#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */