#include #include #include #include /* 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; }