image: remove alpha field of images

This commit is contained in:
Lephe 2022-05-14 12:54:59 +01:00
parent 5a69e44078
commit fc6f7d3051
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
19 changed files with 79 additions and 58 deletions

View File

@ -159,6 +159,7 @@ set(SOURCES_CG
src/r61524/r61524.c
# Image library
src/image/image_alloc.c
src/image/image_alpha.c
src/image/image_clear.c
src/image/image_copy.c
src/image/image_copy_palette.c

View File

@ -12,7 +12,7 @@
//
// This module supports 3 bit depths: full-color 16-bit (RGB565), indexed 8-bit
// (P8) and indexed 4-bit (P4). All three have an "alpha" variation where one
// color is treated as transparent, leading to 6 total formats.
// color is treated as transparent, leading to 6 total formats.
//
// The image renderers support so-called *dynamic effects*, which are image
// transformations performed on-the-fly while rendering, without generating an
@ -92,8 +92,10 @@ typedef struct
uint8_t format;
/* Additional flags, a combination of IMAGE_FLAGS_* values */
uint8_t flags;
/* For formats with alpha, value or index used for transparency */
uint16_t alpha;
/* For P8 and P4, number of colors in the palette; this includes alpha for
transparent images, since alpha is always the first entry. For valid P4
images this is always 16, while for P8 it ranges between 1 and 256. */
int16_t color_count;
/* Full width and height, in pixels */
uint16_t width;
uint16_t height;
@ -107,17 +109,15 @@ typedef struct
- Each 2-byte value is an RGB565 color
P8:
- 1 byte per entry
- Each byte is a shifted palette index (to access the palette, use:
palette.colors[<value>+128])
- Each byte is a palette index shifted by 128 (to access the color, use
palette[<value>+128])
P4:
- 4 bits per entry, each row padded to a full byte
- Each entry is a palette index (0...15) */
void *data;
/* For P8 and P4, palette. The color count does not account for alpha
(which is usually the last entry, but not materialized) and instead
indicates how much memory is allocated. */
int color_count;
/* For P8 and P4, color palette. The number of entries allocated in the
array is equal to the color_count attribute. */
uint16_t *palette;
} GPACKED(4) image_t;
@ -183,26 +183,23 @@ enum {
By default, a new palette is allocated for formats with palettes; the new
image owns the palette and frees it when freed. This can be overriden by
setting the [palette] pointer to the desired palette; in this case, the new
image does not own the palette and does not free it when freed.
setting the [palette] argument to the desired palette; in this case, the new
image does not own the palette and does not free it when freed. For formats
with alpha the first entry of the palette is the alpha color.
Regardless of whether the palette is allocated or specified by hand, for P8
the palette size must be indicated. A value of -1 can be specified to use
the default (256 colors). For all other formats, set a value of -1.
For images with alpha, the last parameter [alpha] indicates the palette
index or color value that denotes transparent pixels.
The returned image structure must be freed with image_free() after use.
@width Width of the new image
@height Height of the new image
@format Pixel format; one of the IMAGE_* formats defined above
@palette If not NULL, specifies the palette instead of allocating it
@palette_size For P8, indicates the palette size to use
@alpha For formats with alpha, color or index denoting alpha */
@palette_size For P8, indicates the palette size to use */
image_t *image_alloc(int width, int height, int format,
void *palette, int palette_size, int alpha);
void *palette, int palette_size);
/* image_create(): Create a bare image with no data/palette
@ -217,11 +214,8 @@ image_t *image_alloc(int width, int height, int format,
the image if the user wishes for the image to free its data and palette when
freed.
For images with alpha, the last parameter [alpha] indicates the palette
index or color value that denotes transparent pixels.
The returned image structure must be freed with image_free() after use. */
image_t *image_create(int width, int height, int format, int alpha);
image_t *image_create(int width, int height, int format);
/* image_create_vram(): Create a reference to gint_vram
@ -234,7 +228,7 @@ image_t *image_create(int width, int height, int format, int alpha);
account for this option. (Using this function twice then replacing one of
the [data] pointers is allowed.)
The VRAM image ows no data but it does own its own structure so it must
The VRAM image owns no data but it does own its own structure so it must
still be freed with image_free() after use. */
image_t *image_create_vram(void);
@ -269,6 +263,17 @@ uint16_t *image_copy_palette(image_t const *img);
pointer, and for palette formats a valid palette pointer. */
bool image_valid(image_t const *img);
/* image_alpha(): Get the alpha value for an image format
This function returns the alpha value for any specific image format:
* RGB16: 0x0001
* P8: -128 (0x80)
* P4: 0
For non-transparent formats, it returns a value that is different from all
valid pixel values of the format, which means it is always safe to compare a
pixel value to the image_alpha() of the format. */
int image_alpha(int format);
/* image_get_pixel(): Read a pixel from the data array
This function reads a pixel from the image's data array at position (x,y).
@ -318,11 +323,10 @@ int image_palette_size(image_t const *img);
Formats: RGB16, P8, P4 */
void image_set_pixel(image_t const *img, int x, int y, int value);
/* image_copy(): Copy an image into another one
/* image_copy(): Convert and copy an image
This function copies an image into another image. The target must be a valid
image with the same format as the source, otherwise this function is a
no-op. Unlike transforms, this function does clip, so there are no
This function copies an image into another image while converting certain
formats. Unlike transforms, this function does clip, so there are no
conditions on the size of the target.
If [copy_alpha] is true, transparent pixels are copied verbatim, which
@ -330,14 +334,23 @@ void image_set_pixel(image_t const *img, int x, int y, int value);
transparent pixels of [src] are skipped, effectively rendering [src] over
the top-left corner of [src].
The color scheme of src and dst should normally match. In RGB16, if
src->alpha and dst->alpha differ, this function adopts a resonable behavior;
inputs of value src->alpha are turned into dst->alpha if copy_alpha is true,
ignored otherwise; and opaque inputs of value dst->alpha are turned into
[dst->alpha ^ 1] to keep the visuals consistent. In P8, no attempt is made
to merge the palettes.
This function converts between all formats except from RGB16 to P8/P4, since
this requires generating a palette (which is a complex endeavour).
Conversions from P8/P4 to RGB16 simply decode the palette. Conversions
between P8/P4 preserve the contents but renumber the palette entries. From
P4 to P8, the image is always preserved. From P8 to P4, the image is only
preserved if it has less than 16 colors (this is intended to allow P4 images
to be converted to P8 for edition by this library, and then back to P4). The
following table summarizes the conversions:
Formats: RGB16, P8 */
Source format RGB16 P8 P4
Target format +-----------+----------------+------------------+
RGB16 | Copy Decode palette Decode palette |
P8 | - Copy Enlarge palette |
P4 | - Narrow palette Copy |
+-----------+----------------+------------------+
Formats: RGB16 RGB16, P8 Anything, P4 Anything */
void image_copy(image_t const *src, image_t *dst, bool copy_alpha);
/* image_fill(): Fill an image with a single pixel value */

View File

@ -3,9 +3,9 @@
#include <gint/defs/util.h>
image_t *image_alloc(int width, int height, int format,
void *palette, int palette_size, int alpha)
void *palette, int palette_size)
{
image_t *img = image_create(width, height, format, alpha);
image_t *img = image_create(width, height, format);
if(!img)
return NULL;

15
src/image/image_alpha.c Normal file
View File

@ -0,0 +1,15 @@
#include <gint/image.h>
int image_alpha(int format)
{
switch(format) {
case IMAGE_RGB565A:
return 0x0001;
case IMAGE_P8_RGB565A:
return -128;
case IMAGE_P4_RGB565A:
return 0;
default:
return 0x10000;
}
}

View File

@ -5,5 +5,5 @@ void image_clear(image_t *img)
if(!IMAGE_IS_ALPHA(img->format))
return;
image_fill(img, img->alpha);
image_fill(img, image_alpha(img->format));
}

View File

@ -16,26 +16,20 @@ void image_copy(image_t const *src, image_t *dst, bool copy_alpha)
void *src_px = src->data;
void *dst_px = dst->data;
int src_alpha = copy_alpha ? 0x10000 : image_alpha(src->format);
if(IMAGE_IS_RGB16(src->format)) {
int src_alpha = copy_alpha ? -1 : src->alpha;
int dst_alpha = IMAGE_IS_ALPHA(dst->format) ? -1 : dst->alpha;
do {
for(int x = 0; x < w; x++) {
int px = ((uint16_t *)src_px)[x];
if(px != src_alpha) {
px ^= (px == dst_alpha);
if(px != src_alpha)
((uint16_t *)dst_px)[x] = px;
}
}
src_px += src->stride;
dst_px += dst->stride;
} while(--h > 0);
}
else if(IMAGE_IS_P8(src->format)) {
int src_alpha = copy_alpha ? 256 : src->alpha;
do {
for(int x = 0; x < w; x++) {
int px = ((int8_t *)src_px)[x];

View File

@ -1,7 +1,7 @@
#include <gint/image.h>
#include <stdlib.h>
image_t *image_create(int width, int height, int format, int alpha)
image_t *image_create(int width, int height, int format)
{
if(!IMAGE_IS_RGB16(format) && !IMAGE_IS_P8(format) && !IMAGE_IS_P4(format))
return NULL;
@ -14,7 +14,6 @@ image_t *image_create(int width, int height, int format, int alpha)
img->format = format;
img->flags = 0;
img->alpha = alpha;
img->width = width;
img->height = height;

View File

@ -3,7 +3,7 @@
image_t *image_create_vram(void)
{
image_t *img = image_create(DWIDTH, DHEIGHT, IMAGE_RGB565, 0);
image_t *img = image_create(DWIDTH, DHEIGHT, IMAGE_RGB565);
if(!img)
return NULL;

View File

@ -13,7 +13,7 @@ int image_get_pixel(image_t const *img, int x, int y)
return data_u16[x];
}
else if(IMAGE_IS_P8(img->format)) {
return data_u8[x];
return (int8_t)data_u8[x];
}
else if(IMAGE_IS_P4(img->format)) {
if(x & 1)

View File

@ -24,7 +24,6 @@ image_t *image_sub(image_t const *src, int left, int top, int w, int h,
int const ro_flags = IMAGE_FLAGS_DATA_RO | IMAGE_FLAGS_PALETTE_RO;
dst->format = src->format;
dst->flags = src->flags & ro_flags;
dst->alpha = src->alpha;
dst->stride = src->stride;
dst->width = box.w;
dst->height = box.h;

View File

@ -11,7 +11,7 @@ void dsubimage_p4(int x, int y, image_t const *img,
{
if(img->format == IMAGE_P4_RGB565A)
return dsubimage_p4_clearbg(x, y, img, left, top, w, h, eff,
img->alpha);
image_alpha(img->format));
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;

View File

@ -15,7 +15,7 @@ void dsubimage_p4_dye(int x, int y, image_t const *img,
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, DWIDTH,
DHEIGHT)) return;
cmd.color_1 = img->alpha;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = dye_color;
cmd.loop = gint_image_p4_dye;
gint_image_p4_loop(DWIDTH, &cmd);

View File

@ -37,7 +37,7 @@ void dsubimage_p4_addbg(int x, int y, image_t const *img,
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, DWIDTH,
DHEIGHT)) return;
cmd.color_1 = img->alpha;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = bg_color;
cmd.loop = gint_image_p4_swapcolor;
gint_image_p4_loop(DWIDTH, &cmd);

View File

@ -11,7 +11,7 @@ void dsubimage_p8(int x, int y, image_t const *img,
{
if(img->format == IMAGE_P8_RGB565A)
return dsubimage_p8_clearbg(x, y, img, left, top, w, h, eff,
img->alpha);
image_alpha(img->format));
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;

View File

@ -15,7 +15,7 @@ void dsubimage_p8_dye(int x, int y, image_t const *img,
if(!gint_image_mkcmd(&box, img, eff, false, true, &cmd, DWIDTH,
DHEIGHT)) return;
cmd.color_1 = img->alpha;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = dye_color;
cmd.loop = gint_image_p8_dye;
gint_image_p8_loop(DWIDTH, &cmd);

View File

@ -37,7 +37,7 @@ void dsubimage_p8_addbg(int x, int y, image_t const *img,
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
cmd.color_1 = img->alpha;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = bg_color;
cmd.loop = gint_image_p8_swapcolor;
gint_image_p8_loop(DWIDTH, &cmd);

View File

@ -11,7 +11,7 @@ void dsubimage_rgb16(int x, int y, image_t const *img,
{
if(img->format == IMAGE_RGB565A)
return dsubimage_rgb16_clearbg(x, y, img, left, top, w, h, eff,
img->alpha);
image_alpha(img->format));
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;

View File

@ -15,7 +15,7 @@ void dsubimage_rgb16_dye(int x, int y, image_t const *img,
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
cmd.color_1 = img->alpha;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = dye_color;
cmd.loop = gint_image_rgb16_dye;
gint_image_rgb16_loop(DWIDTH, &cmd);

View File

@ -37,7 +37,7 @@ void dsubimage_rgb16_addbg(int x, int y, image_t const *img,
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
cmd.color_1 = img->alpha;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = bg_color;
cmd.loop = gint_image_rgb16_swapcolor;
gint_image_rgb16_loop(DWIDTH, &cmd);