I now have the ability to export images from a Game Boy Camera SRAM file to printable 160x144 tile files
This commit is contained in:
parent
26196ab925
commit
6a5fc83ede
4 changed files with 201 additions and 22 deletions
84
bin/main.c
84
bin/main.c
|
@ -40,7 +40,7 @@ static void usage(int argc, char **argv, const char *message, ...) {
|
|||
" %1$s split file.sav rn gn bn input.png\n"
|
||||
" %1$s merge file.sav rn gn bn output.png\n"
|
||||
" %1$s import-tile file.sav 1..30 printer.tile\n"
|
||||
" %1$s export-tile file.sav 1..30 output.png\n"
|
||||
" %1$s export-tile file.sav 1..30 output.tile\n"
|
||||
" %1$s convert-tile printer.tile output.png\n",
|
||||
argv[0]);
|
||||
|
||||
|
@ -587,6 +587,87 @@ error_sram_open:
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int export_tile(int argc, char **argv) {
|
||||
cammy_sram *sram;
|
||||
cammy_image *dest, *src;
|
||||
int photo;
|
||||
|
||||
if (argc < 2) {
|
||||
usage(argc, argv, "No camera SRAM file provided");
|
||||
} else if (argc < 3) {
|
||||
usage(argc, argv, "No picture number provided");
|
||||
} else if (argc < 4) {
|
||||
usage(argc, argv, "No Game Boy screen tile data file provided");
|
||||
}
|
||||
|
||||
photo = atoi(argv[3]);
|
||||
|
||||
if (photo < 1 || photo > CAMMY_SRAM_PHOTO_COUNT) {
|
||||
usage(argc, argv, "Invalid photo number");
|
||||
}
|
||||
|
||||
if ((sram = cammy_sram_open(argv[2])) == NULL) {
|
||||
fprintf(stderr, "%s: %s: %s: %s\n",
|
||||
argv[0], "cammy_sram_open()", argv[2], strerror(errno));
|
||||
|
||||
goto error_sram_open;
|
||||
}
|
||||
|
||||
if ((src = malloc(sizeof(*src))) == NULL) {
|
||||
fprintf(stderr, "%s: %s: %s\n",
|
||||
argv[0], "malloc()", strerror(errno));
|
||||
|
||||
goto error_malloc_src;
|
||||
}
|
||||
|
||||
src->format = CAMMY_IMAGE_TILE;
|
||||
src->size = CAMMY_PHOTO_SIZE;
|
||||
src->width = CAMMY_PHOTO_WIDTH;
|
||||
src->height = CAMMY_PHOTO_HEIGHT;
|
||||
src->tiles = (cammy_tile *)&sram->data->photos[photo-1].tiles;
|
||||
|
||||
if ((dest = cammy_image_new(CAMMY_IMAGE_TILE,
|
||||
CAMMY_SCREEN_WIDTH,
|
||||
CAMMY_SCREEN_HEIGHT)) == NULL) {
|
||||
fprintf(stderr, "%s: %s: %s\n",
|
||||
argv[0], "cammy_image_new()", strerror(errno));
|
||||
|
||||
goto error_image_new_dest;
|
||||
}
|
||||
|
||||
memset(dest->buf, '\0', dest->size);
|
||||
|
||||
cammy_image_copy(dest, src,
|
||||
16, 16, 0, 0, CAMMY_PHOTO_WIDTH, CAMMY_PHOTO_HEIGHT);
|
||||
|
||||
if (cammy_image_save_tile(dest, argv[4]) < 0) {
|
||||
fprintf(stderr, "%s: %s: %s: %s\n",
|
||||
argv[0], "cammy_image_save_tile()", argv[4], strerror(errno));
|
||||
|
||||
goto error_image_save_tile_dest;
|
||||
}
|
||||
|
||||
free(dest);
|
||||
|
||||
cammy_image_close(src);
|
||||
|
||||
cammy_sram_close(sram);
|
||||
|
||||
return 0;
|
||||
|
||||
error_image_save_tile_dest:
|
||||
cammy_image_destroy(dest);
|
||||
|
||||
error_image_new_dest:
|
||||
free(src);
|
||||
|
||||
error_malloc_src:
|
||||
cammy_sram_close(sram);
|
||||
|
||||
error_sram_open:
|
||||
return errno || 1;
|
||||
}
|
||||
|
||||
static int convert_tile(int argc, char **argv) {
|
||||
int fd;
|
||||
void *in, *out;
|
||||
|
@ -664,6 +745,7 @@ static struct {
|
|||
{ "split", split },
|
||||
{ "merge", merge },
|
||||
{ "import-tile", import_tile },
|
||||
{ "export-tile", export_tile },
|
||||
{ "convert-tile", convert_tile },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -21,7 +21,8 @@ typedef enum {
|
|||
typedef struct _cammy_image {
|
||||
cammy_image_format format;
|
||||
|
||||
size_t width,
|
||||
size_t size,
|
||||
width,
|
||||
height;
|
||||
|
||||
union {
|
||||
|
@ -30,12 +31,20 @@ typedef struct _cammy_image {
|
|||
};
|
||||
} cammy_image;
|
||||
|
||||
cammy_image *cammy_image_new(cammy_image_format format,
|
||||
size_t width,
|
||||
size_t height);
|
||||
|
||||
cammy_image *cammy_image_open_tile(const char *filename,
|
||||
size_t width,
|
||||
size_t height);
|
||||
|
||||
int cammy_image_save_tile(cammy_image *image, const char *filename);
|
||||
|
||||
void cammy_image_close(cammy_image *image);
|
||||
|
||||
void cammy_image_destroy(cammy_image *image);
|
||||
|
||||
int cammy_image_save(cammy_image *image, const char *filename);
|
||||
|
||||
void cammy_image_dither(uint8_t *dest,
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#define CAMMY_PHOTO_TILES_WIDTH 16
|
||||
#define CAMMY_PHOTO_TILES_HEIGHT 14
|
||||
|
||||
#define CAMMY_PHOTO_SIZE \
|
||||
(CAMMY_TILE_SIZE * CAMMY_PHOTO_TILES_WIDTH * CAMMY_PHOTO_TILES_HEIGHT)
|
||||
|
||||
#define CAMMY_PHOTO_WIDTH \
|
||||
(CAMMY_TILE_WIDTH * CAMMY_PHOTO_TILES_WIDTH)
|
||||
|
||||
|
|
121
src/image.c
121
src/image.c
|
@ -2,6 +2,7 @@
|
|||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <cammy/image.h>
|
||||
|
@ -140,28 +141,81 @@ static inline void buf_write(uint8_t *buf,
|
|||
buf[depth*stride*y + depth*x + 2] = b;
|
||||
}
|
||||
|
||||
cammy_image *cammy_image_open_tile(const char *filename,
|
||||
cammy_image *cammy_image_new(cammy_image_format format,
|
||||
size_t width,
|
||||
size_t height) {
|
||||
cammy_image *image;
|
||||
int fd;
|
||||
size_t size;
|
||||
|
||||
size_t size = (width * height) >> 2,
|
||||
off;
|
||||
switch (format) {
|
||||
case CAMMY_IMAGE_TILE: {
|
||||
size_t tiles_width = width >> 3,
|
||||
tiles_height = height >> 3;
|
||||
|
||||
if ((fd = open(filename, O_RDONLY)) < 0) {
|
||||
goto error_open;
|
||||
if (width & 7) tiles_width++;
|
||||
if (height & 7) tiles_height++;
|
||||
|
||||
size = CAMMY_TILE_SIZE * tiles_width * tiles_height;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CAMMY_IMAGE_RGB: {
|
||||
size = 3 * width * height;
|
||||
break;
|
||||
}
|
||||
|
||||
case CAMMY_IMAGE_RGBA: {
|
||||
size = 4 * width * height;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
errno = EINVAL;
|
||||
goto error_invalid_format;
|
||||
}
|
||||
}
|
||||
|
||||
if ((image = malloc(sizeof(*image))) == NULL) {
|
||||
goto error_malloc_image;
|
||||
}
|
||||
|
||||
if ((image->tiles = malloc(size)) == NULL) {
|
||||
goto error_malloc_tiles;
|
||||
if ((image->buf = malloc(size)) == NULL) {
|
||||
goto error_malloc_buf;
|
||||
}
|
||||
|
||||
for (off=0; off<size;) {
|
||||
image->format = format;
|
||||
image->size = size;
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
|
||||
return image;
|
||||
|
||||
error_malloc_buf:
|
||||
free(image);
|
||||
|
||||
error_malloc_image:
|
||||
error_invalid_format:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cammy_image *cammy_image_open_tile(const char *filename,
|
||||
size_t width,
|
||||
size_t height) {
|
||||
cammy_image *image;
|
||||
int fd;
|
||||
|
||||
size_t off;
|
||||
|
||||
if ((fd = open(filename, O_RDONLY)) < 0) {
|
||||
goto error_open;
|
||||
}
|
||||
|
||||
if ((image = cammy_image_new(CAMMY_IMAGE_TILE, width, height)) == NULL) {
|
||||
goto error_image_new;
|
||||
}
|
||||
|
||||
for (off=0; off<image->size;) {
|
||||
ssize_t len;
|
||||
|
||||
if ((len = read(fd, &image->buf[off], CAMMY_IMAGE_CHUNK_SIZE)) < 0) {
|
||||
|
@ -173,19 +227,12 @@ cammy_image *cammy_image_open_tile(const char *filename,
|
|||
|
||||
close(fd);
|
||||
|
||||
image->format = CAMMY_IMAGE_TILE;
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
|
||||
return image;
|
||||
|
||||
error_read:
|
||||
free(image->tiles);
|
||||
cammy_image_destroy(image);
|
||||
|
||||
error_malloc_tiles:
|
||||
free(image);
|
||||
|
||||
error_malloc_image:
|
||||
error_image_new:
|
||||
close(fd);
|
||||
|
||||
error_open:
|
||||
|
@ -193,10 +240,48 @@ error_open:
|
|||
}
|
||||
|
||||
void cammy_image_close(cammy_image *image) {
|
||||
free(image);
|
||||
}
|
||||
|
||||
void cammy_image_destroy(cammy_image *image) {
|
||||
free(image->buf);
|
||||
free(image);
|
||||
}
|
||||
|
||||
int cammy_image_save_tile(cammy_image *image, const char *filename) {
|
||||
size_t off,
|
||||
rest = image->size;
|
||||
|
||||
int fd;
|
||||
|
||||
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) {
|
||||
goto error_open;
|
||||
}
|
||||
|
||||
for (off=0; off<image->size; off+=CAMMY_IMAGE_CHUNK_SIZE) {
|
||||
size_t chunk = rest > CAMMY_IMAGE_CHUNK_SIZE?
|
||||
CAMMY_IMAGE_CHUNK_SIZE: rest;
|
||||
|
||||
ssize_t len;
|
||||
|
||||
if ((len = write(fd, image->buf + off, chunk)) < 0) {
|
||||
goto error_write;
|
||||
}
|
||||
|
||||
rest -= len;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
|
||||
error_write:
|
||||
close(fd);
|
||||
|
||||
error_open:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void cammy_image_dither(uint8_t *dest,
|
||||
uint8_t *src,
|
||||
size_t width,
|
||||
|
|
Loading…
Add table
Reference in a new issue