Implement parsing of colors for styles
- Change error reporting format - Add color type and helper macros - Add parser for all styles that are solid colors
This commit is contained in:
parent
795ab27bc4
commit
6486b516db
186
src/hvif-light.c
186
src/hvif-light.c
|
@ -3,7 +3,58 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
char const* const eof_error = "File ended prematurely.";
|
||||
enum
|
||||
{
|
||||
STYLE_TYPE_SOLID_COLOR = 1,
|
||||
STYLE_TYPE_GRADIENT = 2,
|
||||
STYLE_TYPE_SOLID_COLOR_NO_ALPHA = 3,
|
||||
STYLE_TYPE_SOLID_GRAY = 4,
|
||||
STYLE_TYPE_SOLID_GRAY_NO_ALPHA = 5,
|
||||
|
||||
SHAPE_TYPE_PATH_SOURCE = 10,
|
||||
|
||||
TRANSFORMER_TYPE_AFFINE = 20,
|
||||
TRANSFORMER_TYPE_CONTOUR = 21,
|
||||
TRANSFORMER_TYPE_PERSPECTIVE = 22,
|
||||
TRANSFORMER_TYPE_STROKE = 23,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GRADIENT_FLAG_TRANSFORM = 1 << 1,
|
||||
GRADIENT_FLAG_NO_ALPHA = 1 << 2,
|
||||
GRADIENT_FLAG_16_BIT_COLORS = 1 << 3, /* not yet used */
|
||||
GRADIENT_FLAG_GRAYS = 1 << 4,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PATH_FLAG_CLOSED = 1 << 1,
|
||||
PATH_FLAG_USES_COMMANDS = 1 << 2,
|
||||
PATH_FLAG_NO_CURVES = 1 << 3,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PATH_COMMAND_H_LINE = 0,
|
||||
PATH_COMMAND_V_LINE = 1,
|
||||
PATH_COMMAND_LINE = 2,
|
||||
PATH_COMMAND_CURVE = 3,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SHAPE_FLAG_TRANSFORM = 1 << 1,
|
||||
SHAPE_FLAG_HINTING = 1 << 2,
|
||||
SHAPE_FLAG_LOD_SCALE = 1 << 3,
|
||||
SHAPE_FLAG_HAS_TRANSFORMERS = 1 << 4,
|
||||
SHAPE_FLAG_TRANSLATION = 1 << 5,
|
||||
};
|
||||
|
||||
#define ERROR_RESULT(E) \
|
||||
(hvif_result) { .status = E }
|
||||
#define SUCCESS_RESULT(I) \
|
||||
(hvif_result) { .status = SUCCESS, .image = I }
|
||||
|
||||
#define le_read(V, BUFFER) V = _Generic((V), uint32_t : le_read_uint32)(BUFFER)
|
||||
static inline uint32_t
|
||||
|
@ -13,11 +64,104 @@ le_read_uint32(char buffer[static 1])
|
|||
(buffer[3] << 24);
|
||||
}
|
||||
|
||||
#define ERROR_RESULT(M) \
|
||||
(hvif_result) { .success = false, .error = M }
|
||||
typedef uint32_t hvif_color; /* 8bit each: alpha, blue, green, red */
|
||||
#define COLOR_GET_RED(C) (C & 0xff)
|
||||
#define COLOR_GET_GREEN(C) ((C >> 8) & 0xff)
|
||||
#define COLOR_GET_BLUE(C) ((C >> 16) & 0xff)
|
||||
#define COLOR_GET_ALPHA(C) ((C >> 24) & 0xff)
|
||||
#define _BM8(N) (0xff << N)
|
||||
#define COLOR_SET_RED(C, V) (C = ((C & (~_BM8(0))) | (V & 0xff)))
|
||||
#define COLOR_SET_GREEN(C, V) (C = ((C & (~_BM8(8))) | ((V & 0xff) << 8)))
|
||||
#define COLOR_SET_BLUE(C, V) (C = ((C & (~_BM8(16))) | ((V & 0xff) << 16)))
|
||||
#define COLOR_SET_ALPHA(C, V) (C = ((C & (~_BM8(24))) | ((V & 0xff) << 24)))
|
||||
#define COLOR_SET_RGB(C, R, G, B) \
|
||||
(C = (C & (~0xffffff)) | (R & 0xff) | ((G & 0xff) << 8) | ((B & 0xff) << 16))
|
||||
|
||||
typedef struct hvif_style hvif_style;
|
||||
struct hvif_style
|
||||
{
|
||||
signed gradient_type;
|
||||
uint8_t stops;
|
||||
hvif_color* colors;
|
||||
float* offsets;
|
||||
};
|
||||
|
||||
struct hvif_image
|
||||
{};
|
||||
{
|
||||
uint8_t num_styles;
|
||||
hvif_style* styles;
|
||||
};
|
||||
|
||||
hvif_color
|
||||
read_color(char* buffer, bool gray, bool alpha)
|
||||
{
|
||||
/* On disk a color is:
|
||||
red, green, blue, alpha
|
||||
Hence reading this as a (little-endian) uint32 result in the desired
|
||||
format. If `alpha` is `false` then only three bytes are used and alpha
|
||||
is `0xff`. If gray is `true` only one one byte is used for the three
|
||||
colors.
|
||||
*/
|
||||
hvif_color c = 0;
|
||||
if (alpha) {
|
||||
if (gray) {
|
||||
COLOR_SET_RGB(c, buffer[0], buffer[0], buffer[0]);
|
||||
COLOR_SET_ALPHA(c, buffer[1]);
|
||||
} else {
|
||||
le_read(c, buffer);
|
||||
}
|
||||
} else {
|
||||
COLOR_SET_ALPHA(c, 0xff);
|
||||
if (gray) {
|
||||
COLOR_SET_RGB(c, buffer[0], buffer[0], buffer[0]);
|
||||
} else {
|
||||
COLOR_SET_RGB(c, buffer[0], buffer[1], buffer[2]);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
hvif_status
|
||||
read_color_style(hvif_style* style, char* buffer, bool gray, bool alpha)
|
||||
{
|
||||
hvif_color color = read_color(buffer, gray, alpha);
|
||||
style->colors = calloc(1, sizeof(hvif_color));
|
||||
style->offsets = calloc(1, sizeof(float));
|
||||
if (!style->colors || !style->colors) return ERROR_NOMEM;
|
||||
|
||||
style->colors[0] = color;
|
||||
style->offsets[0] = 1.0; /* TODO: Is this ok for solid colors */
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
hvif_status
|
||||
read_style(FILE* file, hvif_style* style)
|
||||
{
|
||||
uint8_t type;
|
||||
if (fread(&type, 1, 1, file) != 1) { return ERROR_STYLE; }
|
||||
char buffer[4];
|
||||
switch (type) {
|
||||
case STYLE_TYPE_SOLID_COLOR:
|
||||
if (fread(buffer, 1, 4, file) != 4) { return ERROR_EOF; }
|
||||
read_color_style(style, buffer, false, true);
|
||||
break;
|
||||
case STYLE_TYPE_GRADIENT: break;
|
||||
case STYLE_TYPE_SOLID_COLOR_NO_ALPHA:
|
||||
if (fread(buffer, 1, 3, file) != 3) { return ERROR_EOF; }
|
||||
read_color_style(style, buffer, false, false);
|
||||
break;
|
||||
case STYLE_TYPE_SOLID_GRAY:
|
||||
if (fread(buffer, 1, 2, file) != 2) { return ERROR_EOF; }
|
||||
read_color_style(style, buffer, true, true);
|
||||
break;
|
||||
case STYLE_TYPE_SOLID_GRAY_NO_ALPHA:
|
||||
if (fread(buffer, 1, 1, file) != 1) { return ERROR_EOF; }
|
||||
read_color_style(style, buffer, true, false);
|
||||
break;
|
||||
default: return ERROR_STYLE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
hvif_result
|
||||
hvif_from_file(FILE* file)
|
||||
|
@ -25,20 +169,42 @@ hvif_from_file(FILE* file)
|
|||
uint32_t const magic = 0x6669636e; /* 'finc' (on disk little endian 'cnif') */
|
||||
|
||||
char magic_buffer[4];
|
||||
if (fread(magic_buffer, 1, 4, file) != 4) { return ERROR_RESULT(eof_error); }
|
||||
if (fread(magic_buffer, 1, 4, file) != 4) { return ERROR_RESULT(ERROR_EOF); }
|
||||
uint32_t read_magic;
|
||||
le_read(read_magic, magic_buffer);
|
||||
if (read_magic != magic) {
|
||||
printf("%04x %04x\n", magic, read_magic);
|
||||
return ERROR_RESULT("Wrong magic number.");
|
||||
if (read_magic != magic) { return ERROR_RESULT(ERROR_MAGIC); }
|
||||
|
||||
hvif_image* image = calloc(1, sizeof(hvif_image));
|
||||
if (!image) return ERROR_RESULT(ERROR_NOMEM);
|
||||
|
||||
uint8_t num_styles;
|
||||
if (fread(&num_styles, 1, 1, file) != 1) {
|
||||
hvif_free(image);
|
||||
return ERROR_RESULT(ERROR_EOF);
|
||||
}
|
||||
image->styles = calloc(num_styles, sizeof(hvif_style));
|
||||
if (!image->styles) {
|
||||
hvif_free(image);
|
||||
return ERROR_RESULT(ERROR_NOMEM);
|
||||
}
|
||||
for (unsigned i = 0; i < image->num_styles; ++i) {
|
||||
hvif_status s = read_style(file, &image->styles[i]);
|
||||
if (s != SUCCESS) {
|
||||
hvif_free(image);
|
||||
return ERROR_RESULT(s);
|
||||
}
|
||||
}
|
||||
|
||||
hvif_image* image = malloc(sizeof(hvif_image));
|
||||
return (hvif_result){ .success = true, .image = image };
|
||||
return SUCCESS_RESULT(image);
|
||||
}
|
||||
|
||||
void
|
||||
hvif_free(hvif_image* image)
|
||||
{
|
||||
for (unsigned i = 0; i < image->num_styles; ++i) {
|
||||
free(image->styles[i].colors);
|
||||
free(image->styles[i].offsets);
|
||||
}
|
||||
free(image->styles);
|
||||
free(image);
|
||||
}
|
||||
|
|
|
@ -4,17 +4,22 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum hvif_status
|
||||
{
|
||||
SUCCESS = 0,
|
||||
ERROR_EOF,
|
||||
ERROR_NOMEM,
|
||||
ERROR_MAGIC,
|
||||
ERROR_STYLE
|
||||
} hvif_status;
|
||||
|
||||
typedef struct hvif_image hvif_image;
|
||||
|
||||
typedef struct hvif_result hvif_result;
|
||||
struct hvif_result
|
||||
{
|
||||
bool success;
|
||||
union
|
||||
{
|
||||
char const* const error;
|
||||
hvif_image* image;
|
||||
};
|
||||
hvif_status status;
|
||||
hvif_image* image;
|
||||
};
|
||||
|
||||
hvif_result hvif_from_file(FILE* file);
|
||||
|
|
|
@ -9,17 +9,15 @@ main(void)
|
|||
{
|
||||
puts("This is " PACKAGE_STRING ".");
|
||||
|
||||
FILE* imagefile = fopen("test.hvif", "r");
|
||||
FILE* imagefile = fopen("test.hvif", "rb");
|
||||
if (!imagefile) {
|
||||
fputs("fopen failed.\n", stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hvif_result result = hvif_from_file(imagefile);
|
||||
if (!result.success) {
|
||||
if (result.status != SUCCESS) {
|
||||
fputs("Reading image failed.\n", stderr);
|
||||
fputs(result.error, stderr);
|
||||
fputc('\n', stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
puts("Reading image succeeded.");
|
||||
|
|
Loading…
Reference in New Issue