diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 3bbfc37..9a1cc8b 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,3 +1,4 @@ add_executable(ddl_ar ddl_ar.cpp ddl_ar_class.cpp) +add_executable(pcx_diff_tool pcx_diff_tool.c) set_property(TARGET ddl_ar PROPERTY CXX_STANDARD 20) diff --git a/tools/pcx_diff_tool.c b/tools/pcx_diff_tool.c new file mode 100644 index 0000000..a9562e3 --- /dev/null +++ b/tools/pcx_diff_tool.c @@ -0,0 +1,176 @@ +// pcx_diff_tool.c +// Jednoduchý nástroj pro porovnání dvou PCX souborů (8-bit) a uložení rozdílu do nového PCX + +#include +#include +#include +#include + +#define PCX_HEADER_SIZE 128 +#define PALETTE_SIZE 768 + +typedef struct { + uint8_t *data; + int width, height; + uint8_t palette[PALETTE_SIZE]; +} PCXImage; + +// ------------------------ PCX Dekodovani ------------------------ + +int pcx_decode_rle(FILE *f, uint8_t *out, int size) { + int count = 0; + while (count < size) { + int byte = fgetc(f); + if (byte == EOF) return -1; + + if ((byte & 0xC0) == 0xC0) { + int reps = byte & 0x3F; + int val = fgetc(f); + if (val == EOF) return -1; + for (int i = 0; i < reps && count < size; ++i) out[count++] = val; + } else { + out[count++] = byte; + } + } + return 0; +} + +PCXImage *pcx_load(const char *filename) { + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + + uint8_t header[PCX_HEADER_SIZE]; + fread(header, 1, PCX_HEADER_SIZE, f); + + if (header[0] != 0x0A || header[3] != 8 || header[65] != 1) { + fclose(f); + return NULL; // Neplatný formát + } + + int x1 = header[4] | (header[5] << 8); + int y1 = header[6] | (header[7] << 8); + int x2 = header[8] | (header[9] << 8); + int y2 = header[10] | (header[11] << 8); + + int width = x2 - x1 + 1; + int height = y2 - y1 + 1; + + PCXImage *img = calloc(1, sizeof(PCXImage)); + img->width = width; + img->height = height; + img->data = malloc(width * height); + + pcx_decode_rle(f, img->data, width * height); + + fseek(f, -PALETTE_SIZE - 1, SEEK_END); // -1 pro 0x0C + int palette_marker = fgetc(f); + if (palette_marker != 0x0C) { + fclose(f); + free(img->data); + free(img); + return NULL; // Paleta není přítomna + } + fread(img->palette, 1, PALETTE_SIZE, f); + + fclose(f); + return img; +} + +void pcx_free(PCXImage *img) { + if (!img) return; + free(img->data); + free(img); +} + +// ------------------------ PCX Ulozeni ------------------------ + +void pcx_write_rle(FILE *f, uint8_t *data, int size, int width) { + int w = width; + for (int i = 0; i < size;) { + uint8_t val = data[i]; + int count = 1; + while (count < 63 && count < w && i + count < size && data[i + count] == val) count++; + if (count > 1 || (val & 0xC0) == 0xC0) { + fputc(0xC0 | count, f); + fputc(val, f); + } else { + fputc(val, f); + } + w -= count; + i += count; + if (w == 0) { + w = width; + } + } +} + +int pcx_save(const char *filename, PCXImage *img) { + FILE *f = fopen(filename, "wb"); + if (!f) return -1; + + uint8_t header[PCX_HEADER_SIZE] = {0}; + header[0] = 0x0A; // manufacturer + header[1] = 5; // version + header[2] = 1; // encoding + header[3] = 8; // bits per pixel + header[4] = 0; header[5] = 0; // xmin + header[6] = 0; header[7] = 0; // ymin + header[8] = (img->width - 1) & 0xFF; + header[9] = (img->width - 1) >> 8; + header[10] = (img->height - 1) & 0xFF; + header[11] = (img->height - 1) >> 8; + header[12] = 72; header[13] = 0; // hres (72 dpi) + header[14] = 72; header[15] = 0; // vres (72 dpi) + header[65] = 1; // planes + header[66] = img->width & 0xFF; + header[67] = img->width >> 8; // bytes per line + header[68] = 1; header[69] = 0; // palette type (1 = color) + + fwrite(header, 1, PCX_HEADER_SIZE, f); + pcx_write_rle(f, img->data, img->width * img->height, img->width); + + fputc(0x0C, f); // Palette ID + fwrite(img->palette, 1, PALETTE_SIZE, f); + + fclose(f); + return 0; +} + +// ------------------------ Hlavní funkce ------------------------ + +int main(int argc, char **argv) { + if (argc != 4) { + printf("Použití: %s \n", argv[0]); + return 1; + } + + PCXImage *ref = pcx_load(argv[1]); + PCXImage *src = pcx_load(argv[2]); + + if (!ref || !src) { + printf("Chyba při čtení PCX souborů\n"); + return 1; + } + + if (ref->width != src->width || ref->height != src->height) { + printf("Rozměry nesouhlasí!\n"); + return 1; + } + + PCXImage out = {0}; + out.width = ref->width; + out.height = ref->height; + out.data = malloc(out.width * out.height); + memcpy(out.palette, src->palette, PALETTE_SIZE); + + for (int i = 0; i < out.width * out.height; i++) { + out.data[i] = src->data[i] ^ ref->data[i]; + } + + pcx_save(argv[3], &out); + + pcx_free(ref); + pcx_free(src); + free(out.data); + return 0; +}