don't make me start singing patriotic shit. come convert me now
This commit is contained in:
parent
8330736b1e
commit
22ce22fa4c
7 changed files with 326 additions and 415 deletions
86
bin/png.c
86
bin/png.c
|
@ -7,89 +7,3 @@
|
||||||
|
|
||||||
#include "pnglite.h"
|
#include "pnglite.h"
|
||||||
#include "png.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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#ifndef _CAMMY_IMAGE_H
|
#ifndef _CAMMY_IMAGE_H
|
||||||
#define _CAMMY_IMAGE_H
|
#define _CAMMY_IMAGE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <cammy/tile.h>
|
|
||||||
|
|
||||||
#define CAMMY_IMAGE_Y_COEFFICIENT_R 0.2126
|
#define CAMMY_IMAGE_Y_COEFFICIENT_R 0.2126
|
||||||
#define CAMMY_IMAGE_Y_COEFFICIENT_G 0.7152
|
#define CAMMY_IMAGE_Y_COEFFICIENT_G 0.7152
|
||||||
#define CAMMY_IMAGE_Y_COEFFICIENT_B 0.0722
|
#define CAMMY_IMAGE_Y_COEFFICIENT_B 0.0722
|
||||||
|
@ -21,27 +20,28 @@ typedef enum {
|
||||||
CAMMY_IMAGE_32BPP_RGBA
|
CAMMY_IMAGE_32BPP_RGBA
|
||||||
} cammy_image_format;
|
} cammy_image_format;
|
||||||
|
|
||||||
|
typedef struct _cammy_image_color {
|
||||||
|
uint8_t r, g, b, a;
|
||||||
|
} cammy_image_color;
|
||||||
|
|
||||||
typedef struct _cammy_image {
|
typedef struct _cammy_image {
|
||||||
cammy_image_format format;
|
cammy_image_format format;
|
||||||
|
cammy_image_color palette[4];
|
||||||
|
|
||||||
size_t size,
|
size_t size,
|
||||||
width,
|
width,
|
||||||
height;
|
height;
|
||||||
|
|
||||||
union {
|
uint8_t *buf;
|
||||||
uint8_t *buf;
|
|
||||||
cammy_tile *tiles;
|
|
||||||
};
|
|
||||||
|
|
||||||
char *file;
|
|
||||||
} cammy_image;
|
} cammy_image;
|
||||||
|
|
||||||
#define CAMMY_IMAGE_HEADER_VERSION 0x0001
|
#define CAMMY_IMAGE_HEADER_VERSION 0x0001
|
||||||
|
|
||||||
typedef struct _cammy_image_header {
|
typedef struct _cammy_image_header {
|
||||||
uint8_t magic[4];
|
uint8_t magic[4];
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
uint16_t width, height;
|
uint16_t width, height;
|
||||||
|
cammy_image_color palette[4];
|
||||||
} cammy_image_header;
|
} cammy_image_header;
|
||||||
|
|
||||||
typedef struct _cammy_image_point {
|
typedef struct _cammy_image_point {
|
||||||
|
@ -53,41 +53,19 @@ typedef struct _cammy_image_region {
|
||||||
} cammy_image_region;
|
} cammy_image_region;
|
||||||
|
|
||||||
cammy_image *cammy_image_new(cammy_image_format format,
|
cammy_image *cammy_image_new(cammy_image_format format,
|
||||||
|
cammy_image_color *palette,
|
||||||
size_t width,
|
size_t width,
|
||||||
size_t height);
|
size_t height);
|
||||||
|
|
||||||
cammy_image *cammy_image_open(const char *filename);
|
|
||||||
|
|
||||||
void cammy_image_destroy(cammy_image *image);
|
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);
|
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,
|
void cammy_image_copy(cammy_image *dest,
|
||||||
cammy_image *src,
|
cammy_image *src,
|
||||||
cammy_image_point *to,
|
cammy_image_point *to,
|
||||||
cammy_image_region *from);
|
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 */
|
#endif /* _CAMMY_IMAGE_H */
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <cammy/image.h>
|
||||||
#include <cammy/tile.h>
|
#include <cammy/tile.h>
|
||||||
|
|
||||||
#define CAMMY_PHOTO_TILES_WIDTH 16
|
#define CAMMY_PHOTO_TILES_WIDTH 16
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <cammy/image.h>
|
||||||
|
|
||||||
#define CAMMY_TILE_SIZE 16
|
#define CAMMY_TILE_SIZE 16
|
||||||
#define CAMMY_TILE_WIDTH 8
|
#define CAMMY_TILE_WIDTH 8
|
||||||
#define CAMMY_TILE_HEIGHT 8
|
#define CAMMY_TILE_HEIGHT 8
|
||||||
|
|
|
@ -11,7 +11,7 @@ HEADERS_LOCAL = pnglite.h
|
||||||
HEADERS_BUILD = $(HEADERS_LOCAL) \
|
HEADERS_BUILD = $(HEADERS_LOCAL) \
|
||||||
$(addprefix $(INCLUDE_PATH)/$(HEADER_SUBDIR)/,$(HEADERS))
|
$(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
|
OBJS = sram.o image.o photo.o pnglite.o
|
||||||
|
|
||||||
VERSION_MAJOR = 0
|
VERSION_MAJOR = 0
|
||||||
|
|
592
src/image.c
592
src/image.c
|
@ -77,8 +77,11 @@ static uint32_t bayer_matrix[256] = {
|
||||||
0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff,
|
0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff,
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint8_t level_2bpp_to_8bpp[4] = {
|
static cammy_image_color default_palette[4] = {
|
||||||
0, 87, 171, 255
|
{ 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) {
|
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;
|
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,
|
static inline void buf_read(uint8_t *buf,
|
||||||
size_t x, size_t y, size_t stride,
|
size_t x, size_t y, size_t stride,
|
||||||
uint8_t *r, uint8_t *g, uint8_t *b,
|
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 *cammy_image_new(cammy_image_format format,
|
||||||
|
cammy_image_color *palette,
|
||||||
size_t width,
|
size_t width,
|
||||||
size_t height) {
|
size_t height) {
|
||||||
cammy_image *image;
|
cammy_image *image;
|
||||||
|
@ -164,7 +137,12 @@ cammy_image *cammy_image_new(cammy_image_format format,
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case CAMMY_IMAGE_2BPP_TILE: {
|
case CAMMY_IMAGE_2BPP_TILE: {
|
||||||
|
if (palette == NULL) {
|
||||||
|
palette = default_palette;
|
||||||
|
}
|
||||||
|
|
||||||
size = size_2bpp_tile(width, height);
|
size = size_2bpp_tile(width, height);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,11 +170,16 @@ cammy_image *cammy_image_new(cammy_image_format format,
|
||||||
goto error_malloc_buf;
|
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->format = format;
|
||||||
image->size = size;
|
image->size = size;
|
||||||
image->width = width;
|
image->width = width;
|
||||||
image->height = height;
|
image->height = height;
|
||||||
image->file = NULL;
|
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
|
|
||||||
|
@ -213,55 +196,6 @@ void cammy_image_destroy(cammy_image *image) {
|
||||||
free(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) {
|
static cammy_image *load_tile(const char *filename) {
|
||||||
int fd;
|
int fd;
|
||||||
size_t off;
|
size_t off;
|
||||||
|
@ -284,6 +218,7 @@ static cammy_image *load_tile(const char *filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((image = cammy_image_new(CAMMY_IMAGE_2BPP_TILE,
|
if ((image = cammy_image_new(CAMMY_IMAGE_2BPP_TILE,
|
||||||
|
header.palette,
|
||||||
be16toh(header.width),
|
be16toh(header.width),
|
||||||
be16toh(header.height))) == NULL) {
|
be16toh(header.height))) == NULL) {
|
||||||
goto error_image_new;
|
goto error_image_new;
|
||||||
|
@ -315,6 +250,58 @@ error_open:
|
||||||
return NULL;
|
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 *cammy_image_open(const char *file) {
|
||||||
cammy_image *image;
|
cammy_image *image;
|
||||||
|
|
||||||
|
@ -361,7 +348,7 @@ error_open:
|
||||||
return NULL;
|
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,
|
size_t off,
|
||||||
rest = image->size;
|
rest = image->size;
|
||||||
|
|
||||||
|
@ -374,6 +361,8 @@ int cammy_image_save(cammy_image *image, const char *filename) {
|
||||||
.height = htobe16(image->height)
|
.height = htobe16(image->height)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
memcpy(&header.palette, image->palette, sizeof(header.palette));
|
||||||
|
|
||||||
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) {
|
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) {
|
||||||
goto error_open;
|
goto error_open;
|
||||||
}
|
}
|
||||||
|
@ -406,154 +395,252 @@ error_open:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cammy_image_dither(uint8_t *dest,
|
static inline void format_info_png(cammy_image_format format,
|
||||||
uint8_t *src,
|
int *depth,
|
||||||
size_t width,
|
int *color) {
|
||||||
size_t height,
|
switch (format) {
|
||||||
int depth,
|
case CAMMY_IMAGE_24BPP_RGB:
|
||||||
cammy_tile_palette *palette) {
|
if (depth) *depth = 3;
|
||||||
size_t x, y;
|
if (color) *color = PNG_TRUECOLOR;
|
||||||
|
|
||||||
for (y=0; y<height; y++) {
|
break;
|
||||||
for (x=0; x<width; x++) {
|
|
||||||
uint8_t r, g, b, value;
|
|
||||||
|
|
||||||
buf_read(src, x, y, width, &r, &g, &b, depth);
|
case CAMMY_IMAGE_32BPP_RGBA:
|
||||||
|
if (depth) *depth = 4;
|
||||||
|
if (color) *color = PNG_TRUECOLOR_ALPHA;
|
||||||
|
|
||||||
value = rgb_to_tile_2bpp(r, g, b, x, y);
|
break;
|
||||||
|
|
||||||
r = palette->colors[value][0];
|
default:
|
||||||
g = palette->colors[value][1];
|
if (depth) *depth = 0;
|
||||||
b = palette->colors[value][2];
|
if (color) *color = 0;
|
||||||
|
|
||||||
buf_write(dest, x, y, width, r, g, b, 3);
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cammy_image_split_to_tiles(cammy_tile *destr,
|
static int save_png(cammy_image *image, const char *file) {
|
||||||
cammy_tile *destg,
|
png_t png;
|
||||||
cammy_tile *destb,
|
|
||||||
uint8_t *src,
|
|
||||||
size_t width,
|
|
||||||
size_t height,
|
|
||||||
int depth) {
|
|
||||||
size_t x, y;
|
|
||||||
|
|
||||||
for (y=0; y<height; y++) {
|
int depth, color;
|
||||||
for (x=0; x<width; x++) {
|
|
||||||
uint8_t r, g, b;
|
|
||||||
|
|
||||||
buf_read(src, x, y, width, &r, &g, &b, depth);
|
format_info_png(image->format, &depth, &color);
|
||||||
|
|
||||||
tile_write(destr, x, y, width, rgb_to_tile_2bpp(r, r, r, x, y) ^ 3);
|
png_init(malloc, free);
|
||||||
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);
|
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,
|
int cammy_image_save(cammy_image *image, const char *filename) {
|
||||||
cammy_tile *src,
|
switch (image->format) {
|
||||||
size_t width,
|
case CAMMY_IMAGE_2BPP_TILE:
|
||||||
size_t height,
|
return save_tile(image, filename);
|
||||||
int depth,
|
|
||||||
cammy_tile_palette *palette) {
|
|
||||||
size_t x, y;
|
|
||||||
|
|
||||||
for (y=0; y<height; y++) {
|
case CAMMY_IMAGE_24BPP_RGB:
|
||||||
for (x=0; x<width; x++) {
|
case CAMMY_IMAGE_32BPP_RGBA:
|
||||||
uint8_t value = tile_read(src, x, y, width) ^ 3;
|
return save_png(image, filename);
|
||||||
|
|
||||||
buf_write(dest, x, y, width, palette->colors[value][0],
|
default:
|
||||||
palette->colors[value][1],
|
break;
|
||||||
palette->colors[value][2], depth);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errno = EINVAL;
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cammy_image_merge_tiles(uint8_t *dest,
|
static inline uint8_t tile_read(cammy_tile *tiles,
|
||||||
cammy_tile *srcr,
|
size_t x,
|
||||||
cammy_tile *srcg,
|
size_t y,
|
||||||
cammy_tile *srcb,
|
int stride) {
|
||||||
size_t width,
|
cammy_tile *tile = CAMMY_TILE_INDEXED(tiles, x, y, stride);
|
||||||
size_t height,
|
|
||||||
int depth) {
|
|
||||||
size_t x, y;
|
|
||||||
|
|
||||||
for (y=0; y<height; y++) {
|
int tile_x = x & 7,
|
||||||
for (x=0; x<width; x++) {
|
tile_y = y & 7;
|
||||||
uint8_t r = tile_read(srcr, x, y, width) ^ 3,
|
|
||||||
g = tile_read(srcg, x, y, width) ^ 3,
|
|
||||||
b = tile_read(srcb, x, y, width) ^ 3;
|
|
||||||
|
|
||||||
buf_write(dest, x, y, width, level_2bpp_to_8bpp[r],
|
return
|
||||||
level_2bpp_to_8bpp[g],
|
((tile->data[ tile_y<<1] & (0x80 >> tile_x)) >> (tile_x ^ 7)
|
||||||
level_2bpp_to_8bpp[b], depth);
|
| ((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,
|
static void copy_2bpp(cammy_image *dest,
|
||||||
cammy_image *src,
|
cammy_image *src,
|
||||||
cammy_image_point *to,
|
cammy_image_point *to,
|
||||||
cammy_image_region *from) {
|
cammy_image_region *from) {
|
||||||
size_t x_offset,
|
size_t x,
|
||||||
y_offset;
|
y;
|
||||||
|
|
||||||
for (y_offset=0; y_offset < from->height; y_offset++) {
|
for (y=0; y < from->height; y++) {
|
||||||
if (to->y + y_offset > dest->height) {
|
if (to->y + y > dest->height) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (x_offset=0; x_offset < from->width; x_offset++) {
|
for (x=0; x < from->width; x++) {
|
||||||
uint8_t value = tile_read(src->tiles, from->x + x_offset,
|
uint8_t value = tile_read((cammy_tile *)src->buf,
|
||||||
from->y + y_offset,
|
from->x + x,
|
||||||
src->width);
|
from->y + y,
|
||||||
|
src->width);
|
||||||
|
|
||||||
if (to->x + x_offset > dest->width) {
|
if (to->x + x > dest->width) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
tile_write(dest->tiles, to->x + x_offset,
|
tile_write((cammy_tile *)dest->buf,
|
||||||
to->y + y_offset,
|
to->x + x,
|
||||||
dest->width,
|
to->y + y,
|
||||||
value);
|
dest->width,
|
||||||
|
value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copy_to_2bpp_tile(cammy_image *dest,
|
static void copy_buf(cammy_image *dest,
|
||||||
cammy_image *src,
|
cammy_image *src,
|
||||||
cammy_image_point *to,
|
cammy_image_point *to,
|
||||||
cammy_image_region *from,
|
cammy_image_region *from) {
|
||||||
int depth) {
|
size_t x, y;
|
||||||
size_t x_offset, y_offset;
|
|
||||||
|
|
||||||
for (y_offset=0; y_offset < from->height; y_offset++) {
|
int depth, color;
|
||||||
if (to->y + y_offset > dest->height) {
|
|
||||||
|
format_info_png(dest->format, &depth, &color);
|
||||||
|
|
||||||
|
for (y=0; y < from->height; y++) {
|
||||||
|
if (to->y + y > dest->height) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (x_offset=0; x_offset < from->width; x_offset++) {
|
for (x=0; x < from->width; x++) {
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
|
|
||||||
if (to->x + x_offset > from->width) {
|
if (to->x + x > from->width) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_read(src->buf,
|
buf_read(src->buf,
|
||||||
from->x + x_offset,
|
from->x + x,
|
||||||
from->y + y_offset,
|
from->y + y,
|
||||||
from->width,
|
from->width,
|
||||||
&r, &g, &b, depth);
|
&r, &g, &b, depth);
|
||||||
|
|
||||||
tile_write(dest->tiles,
|
buf_write(dest->buf,
|
||||||
to->x + x_offset,
|
to->x + x,
|
||||||
to->y + y_offset,
|
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,
|
dest->width,
|
||||||
rgb_to_tile_2bpp(r, g, b, to->x + x_offset,
|
rgb_to_tile_2bpp(r, g, b, to->x + x,
|
||||||
to->y + y_offset) ^ 3);
|
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 *src,
|
||||||
cammy_image_point *to,
|
cammy_image_point *to,
|
||||||
cammy_image_region *from) {
|
cammy_image_region *from) {
|
||||||
if (src->format == dest->format) {
|
switch (src->format) {
|
||||||
switch (src->format) {
|
case CAMMY_IMAGE_2BPP_TILE:
|
||||||
case CAMMY_IMAGE_2BPP_TILE:
|
switch (dest->format) {
|
||||||
copy_2bpp(dest, src, to, from); break;
|
case CAMMY_IMAGE_2BPP_TILE:
|
||||||
|
copy_2bpp(dest, src, to, from);
|
||||||
|
|
||||||
default:
|
return;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
return;
|
||||||
switch (src->format) {
|
|
||||||
case CAMMY_IMAGE_24BPP_RGB:
|
|
||||||
copy_to_2bpp_tile(dest, src, to, from, 3);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAMMY_IMAGE_32BPP_RGBA:
|
default:
|
||||||
copy_to_2bpp_tile(dest, src, to, from, 4);
|
break;
|
||||||
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; x<width; x+=CAMMY_SCREEN_WIDTH + (2 * x_pad)) {
|
|
||||||
for (y=0; y<height; y+=CAMMY_SCREEN_HEIGHT + y_pad) {
|
|
||||||
cammy_image_point to = {
|
|
||||||
0, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
cammy_image_region from = {
|
|
||||||
x + x_pad, y, CAMMY_SCREEN_WIDTH, CAMMY_SCREEN_HEIGHT
|
|
||||||
};
|
|
||||||
|
|
||||||
cammy_image_copy(dest, &src, &to, &from);
|
|
||||||
|
|
||||||
if (save_tile_to_file(dest->tiles, CAMMY_SCREEN_WIDTH,
|
|
||||||
CAMMY_SCREEN_HEIGHT, file++) < 0) {
|
|
||||||
goto error_save_tile_to_file;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
12
src/photo.c
12
src/photo.c
|
@ -10,13 +10,23 @@ cammy_image *cammy_photo_export(cammy_photo *src,
|
||||||
cammy_tile_palette *palette) {
|
cammy_tile_palette *palette) {
|
||||||
cammy_image *image;
|
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_image_copy_from_tile(dest,
|
||||||
(cammy_tile *)&src->tiles,
|
(cammy_tile *)&src->tiles,
|
||||||
CAMMY_PHOTO_WIDTH,
|
CAMMY_PHOTO_WIDTH,
|
||||||
CAMMY_PHOTO_HEIGHT,
|
CAMMY_PHOTO_HEIGHT,
|
||||||
depth,
|
depth,
|
||||||
palette);
|
palette);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
|
||||||
|
error_image_new:
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cammy_photo_merge(cammy_photo *srcr,
|
void cammy_photo_merge(cammy_photo *srcr,
|
||||||
|
|
Loading…
Add table
Reference in a new issue