mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-29 13:03:36 +01:00
image: clean up palette semantics, and conversion
This commit is contained in:
parent
fc6f7d3051
commit
9468a8d725
12 changed files with 283 additions and 99 deletions
|
@ -162,6 +162,7 @@ set(SOURCES_CG
|
||||||
src/image/image_alpha.c
|
src/image/image_alpha.c
|
||||||
src/image/image_clear.c
|
src/image/image_clear.c
|
||||||
src/image/image_copy.c
|
src/image/image_copy.c
|
||||||
|
src/image/image_copy_alloc.c
|
||||||
src/image/image_copy_palette.c
|
src/image/image_copy_palette.c
|
||||||
src/image/image_create.c
|
src/image/image_create.c
|
||||||
src/image/image_create_vram.c
|
src/image/image_create_vram.c
|
||||||
|
|
|
@ -92,9 +92,11 @@ typedef struct
|
||||||
uint8_t format;
|
uint8_t format;
|
||||||
/* Additional flags, a combination of IMAGE_FLAGS_* values */
|
/* Additional flags, a combination of IMAGE_FLAGS_* values */
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
/* For P8 and P4, number of colors in the palette; this includes alpha for
|
/* Number of colors in the palette; this includes alpha for transparent
|
||||||
transparent images, since alpha is always the first entry. For valid P4
|
images, as alpha is always the first entry.
|
||||||
images this is always 16, while for P8 it ranges between 1 and 256. */
|
RGB16: 0
|
||||||
|
P8: Ranges between 1 and 256
|
||||||
|
P4: 16 */
|
||||||
int16_t color_count;
|
int16_t color_count;
|
||||||
/* Full width and height, in pixels */
|
/* Full width and height, in pixels */
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
|
@ -103,17 +105,12 @@ typedef struct
|
||||||
int stride;
|
int stride;
|
||||||
|
|
||||||
/* Pixel data in row-major order, left to right.
|
/* Pixel data in row-major order, left to right.
|
||||||
|
- RGB16: 2 bytes per entry, each row padded to 4 bytes for alignment.
|
||||||
RGB16:
|
Each 2-byte value is an RGB565 color.
|
||||||
- 2 bytes per entry, each row padded to 4 bytes for alignment
|
- P8: 1 signed byte per entry. Each byte is a palette index shifted by
|
||||||
- Each 2-byte value is an RGB565 color
|
128 (to access the color, use palette[<value>+128]).
|
||||||
P8:
|
- P4: 4 bits per entry, each row padded to a full byte. Each entry is a
|
||||||
- 1 byte per entry
|
direct palette index between 0 and 15. */
|
||||||
- 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;
|
void *data;
|
||||||
|
|
||||||
/* For P8 and P4, color palette. The number of entries allocated in the
|
/* For P8 and P4, color palette. The number of entries allocated in the
|
||||||
|
@ -173,46 +170,67 @@ enum {
|
||||||
/* image_alloc(): Create a new (uninitialized) image
|
/* image_alloc(): Create a new (uninitialized) image
|
||||||
|
|
||||||
This function allocates a new image of the specified dimensions and format.
|
This function allocates a new image of the specified dimensions and format.
|
||||||
It always allocates a new data array, though a palette from another image
|
It always allocates a new data array; if you need to reuse a data array, use
|
||||||
can be reused. (If you need to reuse a data array, see image_create() below
|
the lower-level image_create() or image_create_sub().
|
||||||
or use img_create_sub().)
|
|
||||||
|
|
||||||
The first parameters [width] and [height] specify the dimensions of the new
|
The first parameters [width] and [height] specify the dimensions of the new
|
||||||
image in pixels. The [format] should be one of the IMAGE_* formats, for
|
image in pixels. The [format] should be one of the IMAGE_* formats, for
|
||||||
example IMAGE_RGB565A or IMAGE_P4_RGB565.
|
example IMAGE_RGB565A or IMAGE_P4_RGB565.
|
||||||
|
|
||||||
By default, a new palette is allocated for formats with palettes; the new
|
This function does not specify or initialize the palette of the new image;
|
||||||
image owns the palette and frees it when freed. This can be overriden by
|
use image_set_palette(), image_alloc_palette() or image_copy_palette()
|
||||||
setting the [palette] argument to the desired palette; in this case, the new
|
after calling this function.
|
||||||
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.
|
|
||||||
|
|
||||||
The returned image structure must be freed with image_free() after use.
|
The returned image structure must be freed with image_free() after use.
|
||||||
|
|
||||||
@width Width of the new image
|
@width Width of the new image
|
||||||
@height Height of the new image
|
@height Height of the new image
|
||||||
@format Pixel format; one of the IMAGE_* formats defined above
|
@format Pixel format; one of the IMAGE_* formats defined above */
|
||||||
@palette If not NULL, specifies the palette instead of allocating it
|
image_t *image_alloc(int width, int height, int format);
|
||||||
@palette_size For P8, indicates the palette size to use */
|
|
||||||
image_t *image_alloc(int width, int height, int format,
|
/* image_set_palette(): Specify an external palette for an image
|
||||||
void *palette, int palette_size);
|
|
||||||
|
This function sets the image's palette to the provided address. The number
|
||||||
|
of entries allocated must be specified in size. It is also the caller's
|
||||||
|
responsibility to ensure that the palette covers all the indices used in the
|
||||||
|
image data.
|
||||||
|
|
||||||
|
The old palette, if owned by the image, is freed. If [owns=true] the
|
||||||
|
palette's ownership is given to the image, otherwise it is kept external. */
|
||||||
|
void image_set_palette(image_t *img, uint16_t *palette, int size, bool owns);
|
||||||
|
|
||||||
|
/* image_alloc_palette(): Allocate a new palette for an image
|
||||||
|
|
||||||
|
This function allocates a new palette for an image. The number of entries is
|
||||||
|
specified in size; for P8 it can vary between 1 and 256, for P4 it is
|
||||||
|
ignored (P4 images always have 16 colors).
|
||||||
|
|
||||||
|
The old palette, if owned by the image, is freed. The entries of the new
|
||||||
|
palette are all initialized to 0. If size is -1, the format's default
|
||||||
|
palette size is used. Returns true on success. */
|
||||||
|
bool image_alloc_palette(image_t *img, int size);
|
||||||
|
|
||||||
|
/* image_copy_palette(): Copy another image's palette
|
||||||
|
|
||||||
|
This function allocates a new palette for an image, and initializes it with
|
||||||
|
a copy of another image's palette. For P8 the palette can be resized by
|
||||||
|
specifying a value other than -1 as the size; by default, the source image's
|
||||||
|
palette size is used (within the limits of the new format). Retuns true on
|
||||||
|
success. */
|
||||||
|
bool image_copy_palette(image_t const *src, image_t *dst, int size);
|
||||||
|
|
||||||
/* image_create(): Create a bare image with no data/palette
|
/* image_create(): Create a bare image with no data/palette
|
||||||
|
|
||||||
This function allocates a new image structure but without data or palette.
|
This function allocates a new image structure but without data or palette.
|
||||||
The [data] and [palette] members are NULL, and [color_count] is either 0 or
|
The [data] and [palette] members are NULL, [color_count] and [stride] are 0.
|
||||||
-1 depending on whether the format normally has a palette.
|
|
||||||
|
|
||||||
This function is useful to create images that reuse externally-provided
|
This function is useful to create images that reuse externally-provided
|
||||||
information. It is intended that the user of this function sets the [data],
|
information. It is intended that the user of this function sets the [data]
|
||||||
[stride] and [palette] and [color_count] members themselves. The
|
and [stride] fields themselves, along with the IMAGE_FLAGS_DATA_ALLOC flag
|
||||||
IMAGE_FLAGS_DATA_ALLOC and the IMAGE_FLAGS_PALETTE_ALLOC flags can be set on
|
if the image should own its data.
|
||||||
the image if the user wishes for the image to free its data and palette when
|
|
||||||
freed.
|
The [palette] and [color_count] members can be set with image_set_palette(),
|
||||||
|
image_alloc_palette(), image_copy_palette(), or manually.
|
||||||
|
|
||||||
The returned image structure must be freed with image_free() after use. */
|
The returned image structure must be freed with image_free() after use. */
|
||||||
image_t *image_create(int width, int height, int format);
|
image_t *image_create(int width, int height, int format);
|
||||||
|
@ -245,15 +263,6 @@ image_t *image_create_vram(void);
|
||||||
exist, as this could cause the reference's pointers to become dangling. */
|
exist, as this could cause the reference's pointers to become dangling. */
|
||||||
void image_free(image_t *img);
|
void image_free(image_t *img);
|
||||||
|
|
||||||
/* image_copy_palette(): Duplicate an image's palette
|
|
||||||
|
|
||||||
This function duplicates the palette and returns a new one allocated with
|
|
||||||
malloc(). If the input image is not in a palette format or has no palette
|
|
||||||
assigned, returns NULL. If the returned pointer is not NULL, free() after
|
|
||||||
use or set the IMAGE_FLAGS_PALETTE_ALLOC flag on the image holding it so
|
|
||||||
that free() is automatically called when the image is freed. */
|
|
||||||
uint16_t *image_copy_palette(image_t const *img);
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Basic image access and information
|
// Basic image access and information
|
||||||
//---
|
//---
|
||||||
|
@ -350,9 +359,19 @@ void image_set_pixel(image_t const *img, int x, int y, int value);
|
||||||
P4 | - Narrow palette Copy |
|
P4 | - Narrow palette Copy |
|
||||||
+-----------+----------------+------------------+
|
+-----------+----------------+------------------+
|
||||||
|
|
||||||
|
Note that conversions to RGB16 are not lossless because RGB565, P8 and P4
|
||||||
|
can represent any color; if a color equal to image_alpha(IMAGE_RGB565A) is
|
||||||
|
found during conversion, this function transforms it slightly to look
|
||||||
|
similar instead of being transparent.
|
||||||
|
|
||||||
Formats: RGB16 → RGB16, P8 → Anything, P4 → Anything */
|
Formats: RGB16 → RGB16, P8 → Anything, P4 → Anything */
|
||||||
void image_copy(image_t const *src, image_t *dst, bool copy_alpha);
|
void image_copy(image_t const *src, image_t *dst, bool copy_alpha);
|
||||||
|
|
||||||
|
/* image_copy_alloc(): Convert and copy into a new image
|
||||||
|
This function is similar to image_copy(), but it allocates a target image of
|
||||||
|
the desired format before copying. */
|
||||||
|
image_t *image_copy_alloc(image_t const *src, int new_format);
|
||||||
|
|
||||||
/* image_fill(): Fill an image with a single pixel value */
|
/* image_fill(): Fill an image with a single pixel value */
|
||||||
void image_fill(image_t *img, int value);
|
void image_fill(image_t *img, int value);
|
||||||
|
|
||||||
|
@ -403,8 +422,41 @@ image_t *image_sub(image_t const *src, int x, int y, int w, int h,
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Geometric image transforms
|
// Geometric image transforms
|
||||||
|
//
|
||||||
|
// All geometric transforms render to position (0,0) of the target image and
|
||||||
|
// fail if the target image is not large enough to hold the transformed result
|
||||||
|
// (unlike the rendering functions which render only the visible portion).
|
||||||
|
//
|
||||||
|
// To render at position (x,y) of the target image, use img_at(). For instance:
|
||||||
|
// image_hflip(src, image_at(dst, x, y));
|
||||||
|
//
|
||||||
|
// Each transform function has an [_alloc] variant which does the same
|
||||||
|
// transform but allocates the target image on the fly and returns it. Remember
|
||||||
|
// that allocation can fail, so you need to check whether the returned image is
|
||||||
|
// valid.
|
||||||
|
//
|
||||||
|
// (You can still pass an invalid image to libimg functions when chaining
|
||||||
|
// transforms. The invalid image will be ignored or returned unchanged, so you
|
||||||
|
// can check for it at the end of any large chain.)
|
||||||
|
//
|
||||||
|
// Some functions support in-place transforms. This means they can be called
|
||||||
|
// with the source as destination, and will transform the image without needing
|
||||||
|
// new memory. For instance, image_hflip(src, src) flips in-place and replaces
|
||||||
|
// src with a flipped version of itself.
|
||||||
|
//
|
||||||
|
// (However, it is not possible to transform in-place if the source and
|
||||||
|
// destination intersect in non-trivial ways. The result will be incorrect.)
|
||||||
|
//
|
||||||
|
// When transforming to a new image, transparent pixels are ignored, so if the
|
||||||
|
// destination already has some data, it will not be erased automatically. Use
|
||||||
|
// image_clear() beforehand to achieve that effect. This allows alpha blending
|
||||||
|
// while transforming, which is especially useful on the VRAM.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
/* image_hflip(): Flip horizontally (supports in-place) */
|
||||||
|
void image_hflip(image_t const *src, image_t *dst);
|
||||||
|
image_t *image_hflip_alloc(image_t const *src);
|
||||||
|
|
||||||
/* TODO: Geometric transforms */
|
/* TODO: Geometric transforms */
|
||||||
|
|
||||||
//---
|
//---
|
||||||
|
|
|
@ -2,25 +2,18 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <gint/defs/util.h>
|
#include <gint/defs/util.h>
|
||||||
|
|
||||||
image_t *image_alloc(int width, int height, int format,
|
image_t *image_alloc(int width, int height, int format)
|
||||||
void *palette, int palette_size)
|
|
||||||
{
|
{
|
||||||
image_t *img = image_create(width, height, format);
|
image_t *img = image_create(width, height, format);
|
||||||
if(!img)
|
if(!img)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if(IMAGE_IS_RGB16(format)) {
|
if(IMAGE_IS_RGB16(format))
|
||||||
img->stride = ((width + 1) >> 1) * 4;
|
img->stride = ((width + 1) >> 1) * 4;
|
||||||
palette_size = -1;
|
else if(IMAGE_IS_P8(format))
|
||||||
}
|
|
||||||
else if(IMAGE_IS_P8(format)) {
|
|
||||||
img->stride = width;
|
img->stride = width;
|
||||||
palette_size = max(0, min(256, palette_size));
|
else if(IMAGE_IS_P4(format))
|
||||||
}
|
|
||||||
else if(IMAGE_IS_P4(format)) {
|
|
||||||
img->stride = ((width + 1) >> 1);
|
img->stride = ((width + 1) >> 1);
|
||||||
palette_size = 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *data = malloc(height * img->stride);
|
void *data = malloc(height * img->stride);
|
||||||
if(!data) {
|
if(!data) {
|
||||||
|
@ -30,16 +23,5 @@ image_t *image_alloc(int width, int height, int format,
|
||||||
|
|
||||||
img->data = data;
|
img->data = data;
|
||||||
img->flags |= IMAGE_FLAGS_DATA_ALLOC;
|
img->flags |= IMAGE_FLAGS_DATA_ALLOC;
|
||||||
|
|
||||||
if(!palette && palette_size > 0) {
|
|
||||||
palette = malloc(palette_size * 2);
|
|
||||||
if(!palette) {
|
|
||||||
image_free(img);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img->palette = palette;
|
|
||||||
img->color_count = palette_size;
|
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
30
src/image/image_alloc_palette.c
Normal file
30
src/image/image_alloc_palette.c
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include <gint/image.h>
|
||||||
|
#include <gint/defs/util.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
bool image_alloc_palette(image_t *img, int size)
|
||||||
|
{
|
||||||
|
if(!img || !IMAGE_IS_INDEXED(img))
|
||||||
|
return;
|
||||||
|
if(img->flags & IMAGE_FLAGS_PALETTE_OWN)
|
||||||
|
free(img->palette);
|
||||||
|
|
||||||
|
if(IMAGE_IS_P8(img)) {
|
||||||
|
size = (size <= 0) ? 256 : min(size, 256);
|
||||||
|
}
|
||||||
|
if(IMAGE_IS_P4(img)) {
|
||||||
|
size = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
img->palette = calloc(size, 2);
|
||||||
|
img->color_count = 0;
|
||||||
|
img->flags &= ~IMAGE_FLAGS_PALETTE_OWN;
|
||||||
|
|
||||||
|
if(!img->palette)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memset(img->palette, 0, 2*size);
|
||||||
|
img->color_count = size;
|
||||||
|
img->flags |= IMAGE_FLAGS_PALETTE_OWN;
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ int image_alpha(int format)
|
||||||
case IMAGE_P4_RGB565A:
|
case IMAGE_P4_RGB565A:
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
|
/* A value that cannot be found in any pixel of any format */
|
||||||
return 0x10000;
|
return 0x10000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
void image_copy(image_t const *src, image_t *dst, bool copy_alpha)
|
void image_copy(image_t const *src, image_t *dst, bool copy_alpha)
|
||||||
{
|
{
|
||||||
if(!image_target(src, dst, NOT_P4, DATA_RW, SAME_DEPTH))
|
if(!image_target(src, dst, DATA_RW))
|
||||||
return;
|
return;
|
||||||
if(!IMAGE_IS_ALPHA(src->format))
|
if(!IMAGE_IS_ALPHA(src->format))
|
||||||
copy_alpha = true;
|
copy_alpha = true;
|
||||||
|
@ -17,19 +17,39 @@ void image_copy(image_t const *src, image_t *dst, bool copy_alpha)
|
||||||
void *src_px = src->data;
|
void *src_px = src->data;
|
||||||
void *dst_px = dst->data;
|
void *dst_px = dst->data;
|
||||||
int src_alpha = copy_alpha ? 0x10000 : image_alpha(src->format);
|
int src_alpha = copy_alpha ? 0x10000 : image_alpha(src->format);
|
||||||
|
int dst_alpha = copy_alpha ? 0x10000 : image_alpha(dst->format);
|
||||||
|
|
||||||
if(IMAGE_IS_RGB16(src->format)) {
|
if(IMAGE_IS_RGB16(src->format) && IMAGE_IS_RGB16(dst->format)) {
|
||||||
do {
|
do {
|
||||||
for(int x = 0; x < w; x++) {
|
for(int x = 0; x < w; x++) {
|
||||||
int px = ((uint16_t *)src_px)[x];
|
int px = ((uint16_t *)src_px)[x];
|
||||||
if(px != src_alpha)
|
if(px != src_alpha) {
|
||||||
((uint16_t *)dst_px)[x] = px;
|
/* Don't copy opaque pixels of value 0x0001 into an RGB565A
|
||||||
|
array. We can use -= which is faster (subc) without
|
||||||
|
changing the visuals because dst_alpha != 0. */
|
||||||
|
((uint16_t *)dst_px)[x] = px - (px == dst_alpha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
src_px += src->stride;
|
src_px += src->stride;
|
||||||
dst_px += dst->stride;
|
dst_px += dst->stride;
|
||||||
} while(--h > 0);
|
} while(--h > 0);
|
||||||
}
|
}
|
||||||
else if(IMAGE_IS_P8(src->format)) {
|
else if(IMAGE_IS_P8(src->format) && IMAGE_IS_RGB16(dst->format)) {
|
||||||
|
uint16_t *palette = src->palette + 128;
|
||||||
|
|
||||||
|
do {
|
||||||
|
for(int x = 0; x < w; x++) {
|
||||||
|
int px = ((int8_t *)src_px)[x];
|
||||||
|
if(px != src_alpha) {
|
||||||
|
px = palette[px];
|
||||||
|
((uint16_t *)dst_px)[x] = px - (px == dst_alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src_px += src->stride;
|
||||||
|
dst_px += dst->stride;
|
||||||
|
} while(--h > 0);
|
||||||
|
}
|
||||||
|
else if(IMAGE_IS_P8(src->format) && IMAGE_IS_P8(dst->format)) {
|
||||||
do {
|
do {
|
||||||
for(int x = 0; x < w; x++) {
|
for(int x = 0; x < w; x++) {
|
||||||
int px = ((int8_t *)src_px)[x];
|
int px = ((int8_t *)src_px)[x];
|
||||||
|
@ -40,4 +60,63 @@ void image_copy(image_t const *src, image_t *dst, bool copy_alpha)
|
||||||
dst_px += dst->stride;
|
dst_px += dst->stride;
|
||||||
} while(--h > 0);
|
} while(--h > 0);
|
||||||
}
|
}
|
||||||
|
else if(IMAGE_IS_P8(src->format) && IMAGE_IS_P4(dst->format)) {
|
||||||
|
do {
|
||||||
|
for(int x = 0; x < w; x++) {
|
||||||
|
int px = ((int8_t *)src_px)[x];
|
||||||
|
if(px != src_alpha) {
|
||||||
|
uint8_t *cell = dst_px + (x >> 1);
|
||||||
|
if(x & 1)
|
||||||
|
*cell = (*cell & 0xf0) | (px & 0x0f);
|
||||||
|
else
|
||||||
|
*cell = (*cell & 0x0f) | (px << 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src_px += src->stride;
|
||||||
|
dst_px += dst->stride;
|
||||||
|
} while(--h > 0);
|
||||||
|
}
|
||||||
|
else if(IMAGE_IS_P4(src->format) && IMAGE_IS_P4(dst->format)) {
|
||||||
|
do {
|
||||||
|
for(int x = 0; x < w; x++) {
|
||||||
|
int px = ((uint8_t *)src_px)[x >> 1];
|
||||||
|
px = (x & 1) ? (px & 0x0f) : (px >> 4);
|
||||||
|
if(px != src_alpha) {
|
||||||
|
uint8_t *cell = dst_px + (x >> 1);
|
||||||
|
if(x & 1)
|
||||||
|
*cell = (*cell & 0xf0) | (px & 0x0f);
|
||||||
|
else
|
||||||
|
*cell = (*cell & 0x0f) | (px << 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src_px += src->stride;
|
||||||
|
dst_px += dst->stride;
|
||||||
|
} while(--h > 0);
|
||||||
|
}
|
||||||
|
else if(IMAGE_IS_P4(src->format) && IMAGE_IS_P8(dst->format)) {
|
||||||
|
do {
|
||||||
|
for(int x = 0; x < w; x++) {
|
||||||
|
int px = ((uint8_t *)src_px)[x >> 1];
|
||||||
|
px = (x & 1) ? (px & 0x0f) : (px >> 4);
|
||||||
|
if(px != src_alpha)
|
||||||
|
((int8_t *)dst_px)[x] = px;
|
||||||
|
}
|
||||||
|
src_px += src->stride;
|
||||||
|
dst_px += dst->stride;
|
||||||
|
} while(--h > 0);
|
||||||
|
}
|
||||||
|
else if(IMAGE_IS_P4(src->format) && IMAGE_IS_RGB16(dst->format)) {
|
||||||
|
do {
|
||||||
|
for(int x = 0; x < w; x++) {
|
||||||
|
int px = ((uint8_t *)src_px)[x >> 1];
|
||||||
|
px = (x & 1) ? (px & 0x0f) : (px >> 4);
|
||||||
|
if(px != src_alpha) {
|
||||||
|
px = src->palette[px];
|
||||||
|
((uint16_t *)dst_px)[x] = px - (px == dst_alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src_px += src->stride;
|
||||||
|
dst_px += dst->stride;
|
||||||
|
} while(--h > 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
20
src/image/image_copy_alloc.c
Normal file
20
src/image/image_copy_alloc.c
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include <gint/image.h>
|
||||||
|
#include <gint/defs/util.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
image_t *image_copy_alloc(image_t const *src, int new_format)
|
||||||
|
{
|
||||||
|
if(!image_valid(src))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
image_t *dst = image_alloc(src->width, src->height, new_format);
|
||||||
|
if(!dst)
|
||||||
|
return NULL;
|
||||||
|
if(!image_copy_palette(src, dst, -1)) {
|
||||||
|
image_free(dst);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_copy(src, dst, true);
|
||||||
|
return dst;
|
||||||
|
}
|
|
@ -1,16 +1,18 @@
|
||||||
#include <gint/image.h>
|
#include <gint/image.h>
|
||||||
#include <stdlib.h>
|
#include <gint/defs/util.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
uint16_t *image_copy_palette(image_t const *img)
|
bool image_copy_palette(image_t const *src, image_t *dst, int size)
|
||||||
{
|
{
|
||||||
int size = image_palette_size(img);
|
if(!image_valid(src) || !dst)
|
||||||
if(size < 0 || !img->palette)
|
return false;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
void *palette = malloc(size);
|
if(size < 0)
|
||||||
if(!palette)
|
size = src->color_count;
|
||||||
return NULL;
|
if(!image_alloc_palette(dst, size))
|
||||||
|
return false;
|
||||||
|
|
||||||
return memcpy(palette, img->palette, size);
|
int N = min(src->color_count, dst->color_count);
|
||||||
|
memcpy(dst->palette, src->palette, 2*N);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,11 @@ image_t *image_create(int width, int height, int format)
|
||||||
|
|
||||||
img->format = format;
|
img->format = format;
|
||||||
img->flags = 0;
|
img->flags = 0;
|
||||||
|
img->color_count = 0;
|
||||||
img->width = width;
|
img->width = width;
|
||||||
img->height = height;
|
img->height = height;
|
||||||
|
|
||||||
img->stride = 0;
|
img->stride = 0;
|
||||||
img->data = NULL;
|
img->data = NULL;
|
||||||
img->color_count = IMAGE_IS_INDEXED(format) ? 0 : -1;
|
|
||||||
img->palette = NULL;
|
img->palette = NULL;
|
||||||
|
|
||||||
return img;
|
return img;
|
||||||
|
|
18
src/image/image_set_palette.c
Normal file
18
src/image/image_set_palette.c
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include <gint/image.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void image_set_palette(image_t *img, uint16_t *palette, int size, bool owns)
|
||||||
|
{
|
||||||
|
if(!img || !IMAGE_IS_INDEXED(img))
|
||||||
|
return;
|
||||||
|
if(img->flags & IMAGE_FLAGS_PALETTE_OWN)
|
||||||
|
free(img->palette);
|
||||||
|
|
||||||
|
img->palette = palette;
|
||||||
|
img->color_count = size;
|
||||||
|
|
||||||
|
if(owns)
|
||||||
|
img->flags |= IMAGE_FLAGS_PALETTE_OWN;
|
||||||
|
else
|
||||||
|
img->flags &= ~IMAGE_FLAGS_PALETTE_OWN;
|
||||||
|
}
|
|
@ -24,16 +24,16 @@ 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;
|
int const ro_flags = IMAGE_FLAGS_DATA_RO | IMAGE_FLAGS_PALETTE_RO;
|
||||||
dst->format = src->format;
|
dst->format = src->format;
|
||||||
dst->flags = src->flags & ro_flags;
|
dst->flags = src->flags & ro_flags;
|
||||||
dst->stride = src->stride;
|
dst->color_count = src->color_count;
|
||||||
dst->width = box.w;
|
dst->width = box.w;
|
||||||
dst->height = box.h;
|
dst->height = box.h;
|
||||||
|
dst->stride = src->stride;
|
||||||
|
|
||||||
if(IMAGE_IS_RGB16(src->format))
|
if(IMAGE_IS_RGB16(src->format))
|
||||||
dst->data = src->data + box.top * src->stride + 2 * box.left;
|
dst->data = src->data + box.top * src->stride + 2 * box.left;
|
||||||
else if(IMAGE_IS_P8(src->format))
|
else if(IMAGE_IS_P8(src->format))
|
||||||
dst->data = src->data + box.top * src->stride + box.left;
|
dst->data = src->data + box.top * src->stride + box.left;
|
||||||
|
|
||||||
dst->color_count = src->color_count;
|
|
||||||
dst->palette = src->palette;
|
dst->palette = src->palette;
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ bool image_valid(image_t const *img)
|
||||||
return (img->data != NULL);
|
return (img->data != NULL);
|
||||||
}
|
}
|
||||||
if(IMAGE_IS_P8(img->format) || IMAGE_IS_P4(img->format)) {
|
if(IMAGE_IS_P8(img->format) || IMAGE_IS_P4(img->format)) {
|
||||||
return (img->data != NULL) && (img->palette != NULL);
|
return (img->data != NULL) && (img->palette != NULL) &&
|
||||||
|
(img->color_count != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invalid format */
|
/* Invalid format */
|
||||||
|
|
Loading…
Reference in a new issue