You know who just implemented RGB merging and splitting? XANTRONIX did. That's right.
This commit is contained in:
parent
924ba313a8
commit
94c8c95f2d
5 changed files with 312 additions and 1 deletions
205
bin/main.c
205
bin/main.c
|
@ -30,7 +30,9 @@ static void usage(int argc, char **argv, const char *message, ...) {
|
||||||
|
|
||||||
fprintf(stderr, "usage: %1$s import file.sav photo1..30 input.png\n"
|
fprintf(stderr, "usage: %1$s import file.sav photo1..30 input.png\n"
|
||||||
" %1$s export file.sav photo1..30 output.png\n"
|
" %1$s export file.sav photo1..30 output.png\n"
|
||||||
" %1$s dither input.png output.png\n",
|
" %1$s dither input.png output.png\n"
|
||||||
|
" %1$s split file.sav rn gn bn input.png\n"
|
||||||
|
" %1$s merge file.sav rn gn bn output.png\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -320,6 +322,205 @@ error_malloc_in:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void validate_photo_number(int argc, char **argv, int num) {
|
||||||
|
if (num < 1 || num > CAMMY_SRAM_PHOTO_COUNT) {
|
||||||
|
usage(argc, argv, "Invalid photo number");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int split(int argc, char **argv) {
|
||||||
|
cammy_sram *sram;
|
||||||
|
png_t *png;
|
||||||
|
|
||||||
|
int photo_r = 0,
|
||||||
|
photo_g = 0,
|
||||||
|
photo_b = 0;
|
||||||
|
|
||||||
|
uint8_t *buf;
|
||||||
|
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
usage(argc, argv, "No save file provided");
|
||||||
|
} else if (argc < 4) {
|
||||||
|
usage(argc, argv, "No red photo number provided");
|
||||||
|
} else if (argc < 5) {
|
||||||
|
usage(argc, argv, "No green photo number provided");
|
||||||
|
} else if (argc < 6) {
|
||||||
|
usage(argc, argv, "No blue photo number provided");
|
||||||
|
} else if (argc < 7) {
|
||||||
|
usage(argc, argv, "No photo provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_photo_number(argc, argv, photo_r = atoi(argv[3]));
|
||||||
|
validate_photo_number(argc, argv, photo_g = atoi(argv[4]));
|
||||||
|
validate_photo_number(argc, argv, photo_b = atoi(argv[5]));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_init(malloc, free);
|
||||||
|
|
||||||
|
if ((png = malloc(sizeof(*png))) == NULL) {
|
||||||
|
goto error_malloc_png;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((error = png_open_file_read(png, argv[6])) < 0) {
|
||||||
|
fprintf(stderr, "%s: %s: %s: %s\n",
|
||||||
|
argv[0], "png_open_file_read()", argv[6], png_error_string(error));
|
||||||
|
|
||||||
|
goto error_png_open_file_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (png->width != CAMMY_PHOTO_WIDTH
|
||||||
|
|| png->height != CAMMY_PHOTO_HEIGHT) {
|
||||||
|
fprintf(stderr, "%s: %s: %s\n",
|
||||||
|
argv[0], argv[6], "Invalid image dimensions");
|
||||||
|
|
||||||
|
goto error_invalid_dimensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf = buf_malloc(png->width, png->height, (int)png->bpp)) == NULL) {
|
||||||
|
fprintf(stderr, "%s: %s: %s\n",
|
||||||
|
argv[0], "malloc()", strerror(errno));
|
||||||
|
|
||||||
|
goto error_buf_malloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((error = png_get_data(png, buf)) < 0) {
|
||||||
|
fprintf(stderr, "%s: %s: %s: %s\n",
|
||||||
|
argv[0], "png_get_data()", argv[4], png_error_string(error));
|
||||||
|
|
||||||
|
goto error_png_get_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
cammy_photo_import_rgb(&sram->data->photos[photo_r-1],
|
||||||
|
&sram->data->photos[photo_g-1],
|
||||||
|
&sram->data->photos[photo_b-1], buf, (int)png->bpp);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
png_close_file(png);
|
||||||
|
|
||||||
|
free(png);
|
||||||
|
|
||||||
|
cammy_sram_close(sram);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_png_get_data:
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
error_buf_malloc:
|
||||||
|
error_invalid_dimensions:
|
||||||
|
png_close_file(png);
|
||||||
|
|
||||||
|
error_png_open_file_read:
|
||||||
|
free(png);
|
||||||
|
|
||||||
|
error_malloc_png:
|
||||||
|
cammy_sram_close(sram);
|
||||||
|
|
||||||
|
error_sram_open:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int merge(int argc, char **argv) {
|
||||||
|
cammy_sram *sram;
|
||||||
|
png_t *png;
|
||||||
|
|
||||||
|
int photo_r = 0,
|
||||||
|
photo_g = 0,
|
||||||
|
photo_b = 0;
|
||||||
|
|
||||||
|
uint8_t *buf;
|
||||||
|
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
usage(argc, argv, "No save file provided");
|
||||||
|
} else if (argc < 4) {
|
||||||
|
usage(argc, argv, "No red photo number provided");
|
||||||
|
} else if (argc < 5) {
|
||||||
|
usage(argc, argv, "No green photo number provided");
|
||||||
|
} else if (argc < 6) {
|
||||||
|
usage(argc, argv, "No blue photo number provided");
|
||||||
|
} else if (argc < 7) {
|
||||||
|
usage(argc, argv, "No photo provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_photo_number(argc, argv, photo_r = atoi(argv[3]));
|
||||||
|
validate_photo_number(argc, argv, photo_g = atoi(argv[4]));
|
||||||
|
validate_photo_number(argc, argv, photo_b = atoi(argv[5]));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_init(malloc, free);
|
||||||
|
|
||||||
|
if ((png = malloc(sizeof(*png))) == NULL) {
|
||||||
|
goto error_malloc_png;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((error = png_open_file_write(png, argv[6])) < 0) {
|
||||||
|
fprintf(stderr, "%s: %s: %s: %s\n",
|
||||||
|
argv[0], "png_open_file_write()", argv[6], png_error_string(error));
|
||||||
|
|
||||||
|
goto error_png_open_file_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf = buf_malloc(CAMMY_PHOTO_WIDTH, CAMMY_PHOTO_HEIGHT, 3)) == NULL) {
|
||||||
|
fprintf(stderr, "%s: %s: %s\n",
|
||||||
|
argv[0], "malloc()", strerror(errno));
|
||||||
|
|
||||||
|
goto error_buf_malloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cammy_photo_merge(&sram->data->photos[photo_r-1],
|
||||||
|
&sram->data->photos[photo_g-1],
|
||||||
|
&sram->data->photos[photo_b-1], buf, 3);
|
||||||
|
|
||||||
|
if ((error = png_set_data(png, CAMMY_PHOTO_WIDTH, CAMMY_PHOTO_HEIGHT, 8, PNG_TRUECOLOR, buf)) < 0) {
|
||||||
|
fprintf(stderr, "%s: %s: %s: %s\n",
|
||||||
|
argv[0], "png_set_data()", argv[6], png_error_string(error));
|
||||||
|
|
||||||
|
goto error_png_set_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_close_file(png);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
free(png);
|
||||||
|
|
||||||
|
cammy_sram_close(sram);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_png_set_data:
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
error_buf_malloc:
|
||||||
|
png_close_file(png);
|
||||||
|
|
||||||
|
error_png_open_file_write:
|
||||||
|
free(png);
|
||||||
|
|
||||||
|
error_malloc_png:
|
||||||
|
cammy_sram_close(sram);
|
||||||
|
|
||||||
|
error_sram_open:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
char *name;
|
char *name;
|
||||||
int (*fun)(int, char **);
|
int (*fun)(int, char **);
|
||||||
|
@ -327,6 +528,8 @@ static struct {
|
||||||
{ "import", import },
|
{ "import", import },
|
||||||
{ "export", export },
|
{ "export", export },
|
||||||
{ "dither", dither },
|
{ "dither", dither },
|
||||||
|
{ "split", split },
|
||||||
|
{ "merge", merge },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,14 @@ void cammy_image_dither_to_tile(cammy_tile *dest,
|
||||||
size_t height,
|
size_t height,
|
||||||
int depth);
|
int depth);
|
||||||
|
|
||||||
|
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_copy_from_tile(uint8_t *dest,
|
void cammy_image_copy_from_tile(uint8_t *dest,
|
||||||
cammy_tile *src,
|
cammy_tile *src,
|
||||||
size_t width,
|
size_t width,
|
||||||
|
@ -29,4 +37,12 @@ void cammy_image_copy_from_tile(uint8_t *dest,
|
||||||
int depth,
|
int depth,
|
||||||
cammy_tile_palette *palette);
|
cammy_tile_palette *palette);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
#endif /* _CAMMY_IMAGE_H */
|
#endif /* _CAMMY_IMAGE_H */
|
||||||
|
|
|
@ -39,6 +39,18 @@ void cammy_photo_export(cammy_photo *src,
|
||||||
int depth,
|
int depth,
|
||||||
cammy_tile_palette *palette);
|
cammy_tile_palette *palette);
|
||||||
|
|
||||||
|
void cammy_photo_merge(cammy_photo *srcr,
|
||||||
|
cammy_photo *srcg,
|
||||||
|
cammy_photo *srcb,
|
||||||
|
uint8_t *dest,
|
||||||
|
int depth);
|
||||||
|
|
||||||
void cammy_photo_import(cammy_photo *dest, uint8_t *src, int depth);
|
void cammy_photo_import(cammy_photo *dest, uint8_t *src, int depth);
|
||||||
|
|
||||||
|
void cammy_photo_import_rgb(cammy_photo *destr,
|
||||||
|
cammy_photo *destg,
|
||||||
|
cammy_photo *destb,
|
||||||
|
uint8_t *src,
|
||||||
|
int depth);
|
||||||
|
|
||||||
#endif /* _CAMMY_PHOTO_H */
|
#endif /* _CAMMY_PHOTO_H */
|
||||||
|
|
48
src/image.c
48
src/image.c
|
@ -69,6 +69,10 @@ static uint32_t bayer_matrix[256] = {
|
||||||
0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff,
|
0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint8_t level_2bpp_to_8bpp[4] = {
|
||||||
|
0, 85, 171, 255
|
||||||
|
};
|
||||||
|
|
||||||
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) {
|
||||||
return (uint8_t)((CAMMY_IMAGE_Y_COEFFICIENT_R * (float)r)
|
return (uint8_t)((CAMMY_IMAGE_Y_COEFFICIENT_R * (float)r)
|
||||||
+ (CAMMY_IMAGE_Y_COEFFICIENT_G * (float)g)
|
+ (CAMMY_IMAGE_Y_COEFFICIENT_G * (float)g)
|
||||||
|
@ -157,6 +161,28 @@ void cammy_image_dither(uint8_t *dest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (y=0; y<height; y++) {
|
||||||
|
for (x=0; x<width; x++) {
|
||||||
|
uint8_t r, g, b;
|
||||||
|
|
||||||
|
buf_read(src, x, y, width, &r, &g, &b, depth);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void cammy_image_copy_from_tile(uint8_t *dest,
|
void cammy_image_copy_from_tile(uint8_t *dest,
|
||||||
cammy_tile *src,
|
cammy_tile *src,
|
||||||
size_t width,
|
size_t width,
|
||||||
|
@ -195,3 +221,25 @@ void cammy_image_dither_to_tile(cammy_tile *dest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (y=0; y<height; y++) {
|
||||||
|
for (x=0; x<width; x++) {
|
||||||
|
uint8_t r = tile_read(srcr, x, y, width),
|
||||||
|
g = tile_read(srcg, x, y, width),
|
||||||
|
b = tile_read(srcb, x, y, width);
|
||||||
|
|
||||||
|
buf_write(dest, x, y, width, level_2bpp_to_8bpp[r],
|
||||||
|
level_2bpp_to_8bpp[g],
|
||||||
|
level_2bpp_to_8bpp[b], depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
32
src/photo.c
32
src/photo.c
|
@ -17,6 +17,20 @@ void cammy_photo_export(cammy_photo *src,
|
||||||
palette);
|
palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cammy_photo_merge(cammy_photo *srcr,
|
||||||
|
cammy_photo *srcg,
|
||||||
|
cammy_photo *srcb,
|
||||||
|
uint8_t *dest,
|
||||||
|
int depth) {
|
||||||
|
cammy_image_merge_tiles(dest,
|
||||||
|
(cammy_tile *)&srcr->tiles,
|
||||||
|
(cammy_tile *)&srcg->tiles,
|
||||||
|
(cammy_tile *)&srcb->tiles,
|
||||||
|
CAMMY_PHOTO_WIDTH,
|
||||||
|
CAMMY_PHOTO_HEIGHT,
|
||||||
|
depth);
|
||||||
|
}
|
||||||
|
|
||||||
void cammy_photo_import(cammy_photo *dest, uint8_t *src, int depth) {
|
void cammy_photo_import(cammy_photo *dest, uint8_t *src, int depth) {
|
||||||
memset(&dest->thumb, '\xff', sizeof(dest->thumb));
|
memset(&dest->thumb, '\xff', sizeof(dest->thumb));
|
||||||
|
|
||||||
|
@ -26,3 +40,21 @@ void cammy_photo_import(cammy_photo *dest, uint8_t *src, int depth) {
|
||||||
CAMMY_PHOTO_HEIGHT,
|
CAMMY_PHOTO_HEIGHT,
|
||||||
depth);
|
depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cammy_photo_import_rgb(cammy_photo *destr,
|
||||||
|
cammy_photo *destg,
|
||||||
|
cammy_photo *destb,
|
||||||
|
uint8_t *src,
|
||||||
|
int depth) {
|
||||||
|
memset(&destr->thumb, '\xff', sizeof(destr->thumb));
|
||||||
|
memset(&destg->thumb, '\xff', sizeof(destg->thumb));
|
||||||
|
memset(&destb->thumb, '\xff', sizeof(destb->thumb));
|
||||||
|
|
||||||
|
cammy_image_split_to_tiles((cammy_tile *)&destr->tiles,
|
||||||
|
(cammy_tile *)&destg->tiles,
|
||||||
|
(cammy_tile *)&destb->tiles,
|
||||||
|
src,
|
||||||
|
CAMMY_PHOTO_WIDTH,
|
||||||
|
CAMMY_PHOTO_HEIGHT,
|
||||||
|
depth);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue