diff --git a/bin/png.c b/bin/png.c index 74df74e..441d1c0 100644 --- a/bin/png.c +++ b/bin/png.c @@ -7,89 +7,3 @@ #include "pnglite.h" #include "png.h" - -int cammy_png_save(const char *file, - void *buf, - size_t width, - size_t height, - int depth, - int format) { - png_t *png; - - png_init(malloc, free); - - if ((png = malloc(sizeof(*png))) == NULL) { - goto error_malloc_png; - } - - if (png_open_file_write(png, file) < 0) { - goto error_png_open_file_write; - } - - if (png_set_data(png, width, height, depth, format, buf) < 0) { - goto error_png_set_data; - } - - png_close_file(png); - - free(png); - - return 0; - -error_png_set_data: - png_close_file(png); - -error_png_open_file_write: - free(png); - -error_malloc_png: - return -1; -} - -uint8_t *cammy_png_load(const char *file, - size_t *width, - size_t *height, - int *depth) { - png_t *png; - uint8_t *buf; - - png_init(malloc, free); - - if ((png = malloc(sizeof(*png))) == NULL) { - goto error_malloc_png; - } - - if (png_open_file_read(png, file) < 0) { - goto error_png_open_file_read; - } - - *width = png->width; - *height = png->height; - *depth = png->bpp; - - if ((buf = malloc(*width * *height * *depth)) == NULL) { - goto error_malloc_buf; - } - - if (png_get_data(png, buf) < 0) { - goto error_png_get_data; - } - - png_close_file(png); - - free(png); - - return buf; - -error_png_get_data: - free(buf); - -error_malloc_buf: - png_close_file(png); - -error_png_open_file_read: - free(png); - -error_malloc_png: - return NULL; -} diff --git a/include/cammy/image.h b/include/cammy/image.h index 618331a..1ae1958 100644 --- a/include/cammy/image.h +++ b/include/cammy/image.h @@ -1,10 +1,9 @@ #ifndef _CAMMY_IMAGE_H #define _CAMMY_IMAGE_H +#include #include -#include - #define CAMMY_IMAGE_Y_COEFFICIENT_R 0.2126 #define CAMMY_IMAGE_Y_COEFFICIENT_G 0.7152 #define CAMMY_IMAGE_Y_COEFFICIENT_B 0.0722 @@ -21,27 +20,28 @@ typedef enum { CAMMY_IMAGE_32BPP_RGBA } cammy_image_format; +typedef struct _cammy_image_color { + uint8_t r, g, b, a; +} cammy_image_color; + typedef struct _cammy_image { cammy_image_format format; + cammy_image_color palette[4]; size_t size, width, height; - union { - uint8_t *buf; - cammy_tile *tiles; - }; - - char *file; + uint8_t *buf; } cammy_image; #define CAMMY_IMAGE_HEADER_VERSION 0x0001 typedef struct _cammy_image_header { - uint8_t magic[4]; + uint8_t magic[4]; uint16_t version; uint16_t width, height; + cammy_image_color palette[4]; } cammy_image_header; typedef struct _cammy_image_point { @@ -53,41 +53,19 @@ typedef struct _cammy_image_region { } cammy_image_region; cammy_image *cammy_image_new(cammy_image_format format, + cammy_image_color *palette, size_t width, size_t height); -cammy_image *cammy_image_open(const char *filename); - void cammy_image_destroy(cammy_image *image); +cammy_image *cammy_image_open(const char *filename); + int cammy_image_save(cammy_image *image, const char *filename); -void cammy_image_split_to_tiles(cammy_tile *destr, - cammy_tile *destg, - cammy_tile *destb, - uint8_t *src, - size_t width, - size_t height, - int depth); - -void cammy_image_merge_tiles(uint8_t *dest, - cammy_tile *srcr, - cammy_tile *srcg, - cammy_tile *srcb, - size_t width, - size_t height, - int depth); - void cammy_image_copy(cammy_image *dest, cammy_image *src, cammy_image_point *to, cammy_image_region *from); -int cammy_image_slice(uint8_t *buf, - size_t width, - size_t height, - size_t x_pad, - size_t y_pad, - int depth); - #endif /* _CAMMY_IMAGE_H */ diff --git a/include/cammy/photo.h b/include/cammy/photo.h index 56866ff..a706dc6 100644 --- a/include/cammy/photo.h +++ b/include/cammy/photo.h @@ -3,6 +3,7 @@ #include +#include #include #define CAMMY_PHOTO_TILES_WIDTH 16 diff --git a/include/cammy/tile.h b/include/cammy/tile.h index 9ad16f2..d3967c9 100644 --- a/include/cammy/tile.h +++ b/include/cammy/tile.h @@ -3,6 +3,8 @@ #include +#include + #define CAMMY_TILE_SIZE 16 #define CAMMY_TILE_WIDTH 8 #define CAMMY_TILE_HEIGHT 8 diff --git a/src/Makefile b/src/Makefile index 3e7610f..b362bc5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,7 +11,7 @@ HEADERS_LOCAL = pnglite.h HEADERS_BUILD = $(HEADERS_LOCAL) \ $(addprefix $(INCLUDE_PATH)/$(HEADER_SUBDIR)/,$(HEADERS)) -HEADERS = sram.h image.h photo.h +HEADERS = sram.h image.h photo.h tile.h OBJS = sram.o image.o photo.o pnglite.o VERSION_MAJOR = 0 diff --git a/src/image.c b/src/image.c index 0e46949..db2f531 100644 --- a/src/image.c +++ b/src/image.c @@ -77,8 +77,11 @@ static uint32_t bayer_matrix[256] = { 0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff, }; -static uint8_t level_2bpp_to_8bpp[4] = { - 0, 87, 171, 255 +static cammy_image_color default_palette[4] = { + { 0, 0, 0, 0 }, + { 87, 87, 87, 0 }, + { 171, 171, 171, 0 }, + { 255, 255, 255, 0 } }; static uint8_t rgb_to_grayscale(uint8_t r, uint8_t g, uint8_t b) { @@ -97,37 +100,6 @@ static uint8_t rgb_to_tile_2bpp(uint8_t r, uint8_t g, uint8_t b, size_t x, size_ return (slot & (0x8000 >> ((y & 3) << 2) >> (x & 3)))? to: from; } -static inline uint8_t tile_read(cammy_tile *tiles, - size_t x, - size_t y, - int stride) { - cammy_tile *tile = CAMMY_TILE_INDEXED(tiles, x, y, stride); - - int tile_x = x & 7, - tile_y = y & 7; - - return - ((tile->data[ tile_y<<1] & (0x80 >> tile_x)) >> (tile_x ^ 7) - | ((tile->data[(tile_y<<1)|1] & (0x80 >> tile_x)) >> (tile_x ^ 7) << 1)); -} - -static inline void tile_write(cammy_tile *tiles, - size_t x, - size_t y, - int stride, - uint8_t value) { - cammy_tile *tile = CAMMY_TILE_INDEXED(tiles, x, y, stride); - - int tile_x = x & 7, - tile_y = y & 7; - - tile->data[ tile_y<<1] &= ~(1 << (tile_x ^ 7)); - tile->data[(tile_y<<1)|1] &= ~(1 << (tile_x ^ 7)); - - tile->data[ tile_y<<1] |= (value & 0x01) << (tile_x ^ 7); - tile->data[(tile_y<<1)|1] |= ((value & 0x02) >> 1) << (tile_x ^ 7); -} - static inline void buf_read(uint8_t *buf, size_t x, size_t y, size_t stride, uint8_t *r, uint8_t *g, uint8_t *b, @@ -157,6 +129,7 @@ static inline size_t size_2bpp_tile(size_t width, size_t height) { } cammy_image *cammy_image_new(cammy_image_format format, + cammy_image_color *palette, size_t width, size_t height) { cammy_image *image; @@ -164,7 +137,12 @@ cammy_image *cammy_image_new(cammy_image_format format, switch (format) { case CAMMY_IMAGE_2BPP_TILE: { + if (palette == NULL) { + palette = default_palette; + } + size = size_2bpp_tile(width, height); + break; } @@ -192,11 +170,16 @@ cammy_image *cammy_image_new(cammy_image_format format, goto error_malloc_buf; } + if (palette) { + memcpy(&image->palette, palette, sizeof(image->palette)); + } else { + memset(&image->palette, '\0', sizeof(image->palette)); + } + image->format = format; image->size = size; image->width = width; image->height = height; - image->file = NULL; return image; @@ -213,55 +196,6 @@ void cammy_image_destroy(cammy_image *image) { free(image); } -static cammy_image *load_png(const char *file) { - png_t png; - - cammy_image *image; - cammy_image_format format = CAMMY_IMAGE_NONE; - - png_init(malloc, free); - - if (png_open_file_read(&png, file) < 0) { - goto error_png_open_file_read; - } - - switch (png.bpp) { - case 3: - format = CAMMY_IMAGE_24BPP_RGB; - break; - - case 4: - format = CAMMY_IMAGE_32BPP_RGBA; - break; - - default: - errno = EINVAL; - goto error_invalid_format; - } - - if ((image = cammy_image_new(format, png.width, png.height)) == NULL) { - goto error_image_new; - } - - if (png_get_data(&png, image->buf) < 0) { - goto error_png_get_data; - } - - png_close_file(&png); - - return image; - -error_png_get_data: - cammy_image_destroy(image); - -error_image_new: -error_invalid_format: - png_close_file(&png); - -error_png_open_file_read: - return NULL; -} - static cammy_image *load_tile(const char *filename) { int fd; size_t off; @@ -284,6 +218,7 @@ static cammy_image *load_tile(const char *filename) { } if ((image = cammy_image_new(CAMMY_IMAGE_2BPP_TILE, + header.palette, be16toh(header.width), be16toh(header.height))) == NULL) { goto error_image_new; @@ -315,6 +250,58 @@ error_open: return NULL; } +static cammy_image *load_png(const char *file) { + png_t png; + + cammy_image *image; + cammy_image_format format = CAMMY_IMAGE_NONE; + + png_init(malloc, free); + + if (png_open_file_read(&png, file) < 0) { + goto error_png_open_file_read; + } + + switch (png.bpp) { + case 3: + format = CAMMY_IMAGE_24BPP_RGB; + break; + + case 4: + format = CAMMY_IMAGE_32BPP_RGBA; + break; + + default: + errno = EINVAL; + goto error_invalid_format; + } + + if ((image = cammy_image_new(format, + NULL, + png.width, + png.height)) == NULL) { + goto error_image_new; + } + + if (png_get_data(&png, image->buf) < 0) { + goto error_png_get_data; + } + + png_close_file(&png); + + return image; + +error_png_get_data: + cammy_image_destroy(image); + +error_image_new: +error_invalid_format: + png_close_file(&png); + +error_png_open_file_read: + return NULL; +} + cammy_image *cammy_image_open(const char *file) { cammy_image *image; @@ -361,7 +348,7 @@ error_open: return NULL; } -int cammy_image_save(cammy_image *image, const char *filename) { +static int save_tile(cammy_image *image, const char *filename) { size_t off, rest = image->size; @@ -374,6 +361,8 @@ int cammy_image_save(cammy_image *image, const char *filename) { .height = htobe16(image->height) }; + memcpy(&header.palette, image->palette, sizeof(header.palette)); + if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) { goto error_open; } @@ -406,154 +395,252 @@ error_open: return -1; } -void cammy_image_dither(uint8_t *dest, - uint8_t *src, - size_t width, - size_t height, - int depth, - cammy_tile_palette *palette) { - size_t x, y; +static inline void format_info_png(cammy_image_format format, + int *depth, + int *color) { + switch (format) { + case CAMMY_IMAGE_24BPP_RGB: + if (depth) *depth = 3; + if (color) *color = PNG_TRUECOLOR; - for (y=0; ycolors[value][0]; - g = palette->colors[value][1]; - b = palette->colors[value][2]; + default: + if (depth) *depth = 0; + if (color) *color = 0; - buf_write(dest, x, y, width, r, g, b, 3); - } + break; } } -void cammy_image_split_to_tiles(cammy_tile *destr, - cammy_tile *destg, - cammy_tile *destb, - uint8_t *src, - size_t width, - size_t height, - int depth) { - size_t x, y; +static int save_png(cammy_image *image, const char *file) { + png_t png; - for (y=0; yformat, &depth, &color); - tile_write(destr, x, y, width, rgb_to_tile_2bpp(r, r, r, x, y) ^ 3); - tile_write(destg, x, y, width, rgb_to_tile_2bpp(g, g, g, x, y) ^ 3); - tile_write(destb, x, y, width, rgb_to_tile_2bpp(b, b, b, x, y) ^ 3); - } + png_init(malloc, free); + + if (png_open_file_write(&png, file) < 0) { + goto error_png_open_file_write; } + + if (png_set_data(&png, + image->width, + image->height, + depth, + color, + image->buf) < 0) { + goto error_png_set_data; + } + + png_close_file(&png); + + return 0; + +error_png_set_data: + png_close_file(&png); + +error_png_open_file_write: + return -1; } -void cammy_image_copy_from_tile(uint8_t *dest, - cammy_tile *src, - size_t width, - size_t height, - int depth, - cammy_tile_palette *palette) { - size_t x, y; +int cammy_image_save(cammy_image *image, const char *filename) { + switch (image->format) { + case CAMMY_IMAGE_2BPP_TILE: + return save_tile(image, filename); - for (y=0; ycolors[value][0], - palette->colors[value][1], - palette->colors[value][2], depth); - } + default: + break; } + + errno = EINVAL; + + return -1; } -void cammy_image_merge_tiles(uint8_t *dest, - cammy_tile *srcr, - cammy_tile *srcg, - cammy_tile *srcb, - size_t width, - size_t height, - int depth) { - size_t x, y; +static inline uint8_t tile_read(cammy_tile *tiles, + size_t x, + size_t y, + int stride) { + cammy_tile *tile = CAMMY_TILE_INDEXED(tiles, x, y, stride); - for (y=0; ydata[ tile_y<<1] & (0x80 >> tile_x)) >> (tile_x ^ 7) + | ((tile->data[(tile_y<<1)|1] & (0x80 >> tile_x)) >> (tile_x ^ 7) << 1)); +} + +static inline void tile_write(cammy_tile *tiles, + size_t x, + size_t y, + int stride, + uint8_t value) { + cammy_tile *tile = CAMMY_TILE_INDEXED(tiles, x, y, stride); + + int tile_x = x & 7, + tile_y = y & 7; + + tile->data[ tile_y<<1] &= ~(1 << (tile_x ^ 7)); + tile->data[(tile_y<<1)|1] &= ~(1 << (tile_x ^ 7)); + + tile->data[ tile_y<<1] |= (value & 0x01) << (tile_x ^ 7); + tile->data[(tile_y<<1)|1] |= ((value & 0x02) >> 1) << (tile_x ^ 7); } static void copy_2bpp(cammy_image *dest, cammy_image *src, cammy_image_point *to, cammy_image_region *from) { - size_t x_offset, - y_offset; + size_t x, + y; - for (y_offset=0; y_offset < from->height; y_offset++) { - if (to->y + y_offset > dest->height) { + for (y=0; y < from->height; y++) { + if (to->y + y > dest->height) { break; } - for (x_offset=0; x_offset < from->width; x_offset++) { - uint8_t value = tile_read(src->tiles, from->x + x_offset, - from->y + y_offset, - src->width); + for (x=0; x < from->width; x++) { + uint8_t value = tile_read((cammy_tile *)src->buf, + from->x + x, + from->y + y, + src->width); - if (to->x + x_offset > dest->width) { + if (to->x + x > dest->width) { break; } - tile_write(dest->tiles, to->x + x_offset, - to->y + y_offset, - dest->width, - value); + tile_write((cammy_tile *)dest->buf, + to->x + x, + to->y + y, + dest->width, + value); } } } -static void copy_to_2bpp_tile(cammy_image *dest, - cammy_image *src, - cammy_image_point *to, - cammy_image_region *from, - int depth) { - size_t x_offset, y_offset; +static void copy_buf(cammy_image *dest, + cammy_image *src, + cammy_image_point *to, + cammy_image_region *from) { + size_t x, y; - for (y_offset=0; y_offset < from->height; y_offset++) { - if (to->y + y_offset > dest->height) { + int depth, color; + + format_info_png(dest->format, &depth, &color); + + for (y=0; y < from->height; y++) { + if (to->y + y > dest->height) { break; } - for (x_offset=0; x_offset < from->width; x_offset++) { + for (x=0; x < from->width; x++) { uint8_t r, g, b; - if (to->x + x_offset > from->width) { + if (to->x + x > from->width) { break; } buf_read(src->buf, - from->x + x_offset, - from->y + y_offset, + from->x + x, + from->y + y, from->width, &r, &g, &b, depth); - tile_write(dest->tiles, - to->x + x_offset, - to->y + y_offset, + buf_write(dest->buf, + to->x + x, + to->y + y, + dest->width, + r, g, b, depth); + } + } +} +static void copy_rgb_to_2bpp_tile(cammy_image *dest, + cammy_image *src, + cammy_image_point *to, + cammy_image_region *from) { + size_t x, y; + + int depth, color; + + format_info_png(dest->format, &depth, &color); + + for (y=0; y < from->height; y++) { + if (to->y + y > dest->height) { + break; + } + + for (x=0; x < from->width; x++) { + uint8_t r, g, b; + + if (to->x + x > from->width) { + break; + } + + buf_read(src->buf, + from->x + x, + from->y + y, + from->width, + &r, &g, &b, depth); + + tile_write((cammy_tile *)dest->buf, + to->x + x, + to->y + y, dest->width, - rgb_to_tile_2bpp(r, g, b, to->x + x_offset, - to->y + y_offset) ^ 3); + rgb_to_tile_2bpp(r, g, b, to->x + x, + to->y + y) ^ 3); + } + } +} + +static void copy_2bpp_tile_to_rgb(cammy_image *dest, + cammy_image *src, + cammy_image_point *to, + cammy_image_region *from) { + size_t x, y; + + int depth, color; + + format_info_png(dest->format, &depth, &color); + + for (y=0; y < from->height; y++) { + if (to->y + y > dest->height) { + break; + } + + for (x=0; x < from->width; x++) { + uint8_t c; + + if (to->x + x > from->width) { + break; + } + + c = tile_read((cammy_tile *)src->buf, + from->x + x, + from->y + y, + from->width); + + buf_write(src->buf, + from->x + x, + from->y + y, + from->width, + src->palette[c].r, + src->palette[c].g, + src->palette[c].b, + depth); } } } @@ -562,124 +649,43 @@ void cammy_image_copy(cammy_image *dest, cammy_image *src, cammy_image_point *to, cammy_image_region *from) { - if (src->format == dest->format) { - switch (src->format) { - case CAMMY_IMAGE_2BPP_TILE: - copy_2bpp(dest, src, to, from); break; + switch (src->format) { + case CAMMY_IMAGE_2BPP_TILE: + switch (dest->format) { + case CAMMY_IMAGE_2BPP_TILE: + copy_2bpp(dest, src, to, from); - default: - break; - } + return; - return; - } + case CAMMY_IMAGE_24BPP_RGB: + case CAMMY_IMAGE_32BPP_RGBA: + copy_2bpp_tile_to_rgb(dest, src, to, from); - if (dest->format == CAMMY_IMAGE_2BPP_TILE) { - switch (src->format) { - case CAMMY_IMAGE_24BPP_RGB: - copy_to_2bpp_tile(dest, src, to, from, 3); - break; + return; - case CAMMY_IMAGE_32BPP_RGBA: - copy_to_2bpp_tile(dest, src, to, from, 4); - break; - - default: - break; - } - } -} - -static int save_tile_to_file(cammy_tile *tiles, size_t width, - size_t height, - int file) { - static const char *format = "slice%04d.tile"; - char name[32]; - int fd; - struct stat st; - - if (snprintf(name, sizeof(name), format, file) < 0) { - goto error_snprintf_name; - } - - if (stat(name, &st) == 0) { - errno = EEXIST; - - goto error_exists; - } - - if ((fd = open(name, O_CREAT | O_WRONLY, 0644)) < 0) { - goto error_open; - } - - if (write(fd, tiles, (width * height) >> 2) < 0) { - goto error_write; - } - - close(fd); - - return 0; - -error_write: - close(fd); - -error_open: -error_exists: -error_snprintf_name: - return -1; -} - -int cammy_image_slice(uint8_t *buf, - size_t width, - size_t height, - size_t x_pad, - size_t y_pad, - int depth) { - cammy_image src = { - .format = CAMMY_IMAGE_2BPP_TILE, - .size = size_2bpp_tile(width, height), - .width = width, - .height = height, - .buf = buf - }, *dest; - - int file = 0; - - size_t x, y; - - if ((dest = cammy_image_new(CAMMY_IMAGE_2BPP_TILE, - width, - height - )) == NULL) { - goto error_image_new; - } - - for (x=0; xtiles, CAMMY_SCREEN_WIDTH, - CAMMY_SCREEN_HEIGHT, file++) < 0) { - goto error_save_tile_to_file; + default: + break; } - } + + case CAMMY_IMAGE_24BPP_RGB: + case CAMMY_IMAGE_32BPP_RGBA: + switch (dest->format) { + case CAMMY_IMAGE_2BPP_TILE: + copy_rgb_to_2bpp_tile(dest, src, to, from); + + return; + + case CAMMY_IMAGE_24BPP_RGB: + case CAMMY_IMAGE_32BPP_RGBA: + copy_buf(dest, src, to, from); + + return; + + default: + break; + } + + default: + break; } - - cammy_image_destroy(dest); - - return 0; - -error_save_tile_to_file: - cammy_image_destroy(dest); - -error_image_new: - return -1; } diff --git a/src/photo.c b/src/photo.c index ea051d7..9e844d2 100644 --- a/src/photo.c +++ b/src/photo.c @@ -10,13 +10,23 @@ cammy_image *cammy_photo_export(cammy_photo *src, cammy_tile_palette *palette) { cammy_image *image; - if ((image = cammy_image_)) + if ((image = cammy_image_new(format, + CAMMY_PHOTO_WIDTH, + CAMMY_PHOTO_HEIGHT)) == NULL) { + goto error_image_new; + } + cammy_image_copy_from_tile(dest, (cammy_tile *)&src->tiles, CAMMY_PHOTO_WIDTH, CAMMY_PHOTO_HEIGHT, depth, palette); + + return image; + +error_image_new: + return NULL; } void cammy_photo_merge(cammy_photo *srcr,