fxsdk/fxgxa/icon.c

132 lines
3 KiB
C

#include <stdio.h>
#include <string.h>
#include <fxg1a.h>
#include <png.h>
/* icon_print(): Show a monochrome 30*17 icon on stdout */
void icon_print(uint8_t const *icon)
{
for(int y = 0; y < 17; y++)
{
for(int x = 0; x < 30; x++)
{
int v = icon[(y << 2) + (x >> 3)] & (0x80 >> (x & 7));
putchar(v ? '#' : ' ');
putchar(v ? '#' : ' ');
}
putchar('\n');
}
}
/* icon_load(): Load a monochrome PNG image into an array */
uint8_t *icon_load(const char *filename, size_t *width, size_t *height)
{
png_image img;
memset(&img, 0, sizeof img);
img.opaque = NULL;
img.version = PNG_IMAGE_VERSION;
png_image_begin_read_from_file(&img, filename);
if(img.warning_or_error)
{
fprintf(stderr, "libpng %s: %s\n", img.warning_or_error == 1
? "warning": "error", img.message);
if(img.warning_or_error > 1)
{
png_image_free(&img);
return NULL;
}
}
img.format = PNG_FORMAT_GRAY;
void *buffer = calloc(img.width * img.height, 1);
if(!buffer)
{
fprintf(stderr, "error: cannot read %s: %m\n", filename);
png_image_free(&img);
return NULL;
}
png_image_finish_read(&img, NULL, buffer, img.width, NULL);
if(width) *width = img.width;
if(height) *height = img.height;
png_image_free(&img);
return buffer;
}
/* icon_save(): Save an 8-bit array to a PNG image */
int icon_save(const char *filename, uint8_t *input, size_t width,
size_t height)
{
png_image img;
memset(&img, 0, sizeof img);
img.version = PNG_IMAGE_VERSION;
img.width = width;
img.height = height;
img.format = PNG_FORMAT_GRAY;
png_image_write_to_file(&img, filename, 0, input, 0, NULL);
png_image_free(&img);
if(img.warning_or_error)
{
fprintf(stderr, "libpng %s: %s\n", img.warning_or_error == 1
? "warning": "error", img.message);
if(img.warning_or_error > 1) return 1;
}
return 0;
}
/* icon_conv_8to1(): Convert an 8-bit icon to 1-bit */
uint8_t *icon_conv_8to1(uint8_t const *input, size_t width, size_t height)
{
if(!input) return NULL;
uint8_t *mono = calloc(68, 1);
if(!mono) return NULL;
size_t stride = width;
/* If the image is wider than 30 pixels, ignore columns at the right */
if(width > 30) width = 30;
/* Skip the first line if there is enough rows, because in standard
30*19 icons, the first and last lines are skipped */
if(height > 17) input += stride, height--;
/* If height is still larger than 17, ignore rows at the bottom */
if(height > 17) height = 17;
/* Then copy individual pixels on the currently-blank image */
for(size_t y = 0; y < height; y++)
for(size_t x = 0; x < width; x++)
{
int offset = (y << 2) + (x >> 3);
int color = input[y * stride + x] < 128;
uint8_t mask = color << (~x & 7);
mono[offset] |= mask;
}
return mono;
}
/* icon_conv_1to8(): Convert an 1-bit icon to 8-bit */
uint8_t *icon_conv_1to8(uint8_t const *mono)
{
uint8_t *data = calloc(30 * 17, 1);
if(!data) return NULL;
for(int y = 0; y < 17; y++)
for(int x = 0; x < 30; x++)
{
int offset = (y << 2) + (x >> 3);
int bit = mono[offset] & (0x80 >> (x & 7));
data[y * 30 + x] = (bit ? 0x00 : 0xff);
}
return data;
}