/* https://www.ime.usp.br/~otuyama/stereogram/basic/index.html */ #include #include #include #include #include #include "libff.h" void random_pixel(struct FFImage *img, uint32_t x, uint32_t y) { uint16_t p; if (drand48() > 0.5) p = 0xFFFF; else p = 0x0000; img->data[(y * img->width + x) * 4 + 0] = p; img->data[(y * img->width + x) * 4 + 1] = p; img->data[(y * img->width + x) * 4 + 2] = p; img->data[(y * img->width + x) * 4 + 3] = 0xFFFF; } void fill_random(struct FFImage *res, uint32_t pattern_width) { uint32_t x, y; for (y = 0; y < res->height; ++y) for (x = 0; x < pattern_width; ++x) random_pixel(res, x, y); } void make_step( struct FFImage *disp, struct FFImage *res, uint32_t pattern_width, uint32_t i ) { uint32_t x, y, x_disp, x_res, x_from, x_to; uint32_t shift_max = 16, shift; /* Copy previous pattern. */ for (y = 0; y < res->height; ++y) { for (x = 0; x < pattern_width; ++x) { x_from = x + i * pattern_width; x_to = x + (i + 1) * pattern_width; res->data[(y * res->width + x_to) * 4 + 0] = res->data[(y * res->width + x_from) * 4 + 0]; res->data[(y * res->width + x_to) * 4 + 1] = res->data[(y * res->width + x_from) * 4 + 1]; res->data[(y * res->width + x_to) * 4 + 2] = res->data[(y * res->width + x_from) * 4 + 2]; res->data[(y * res->width + x_to) * 4 + 3] = 0xFFFF; } } /* Distort current pattern. */ for (y = 0; y < disp->height; ++y) { for (x = 0; x < pattern_width; ++x) { x_disp = x + i * pattern_width; x_res = x + (i + 1) * pattern_width; /* Only use red channel in source. */ shift = (double)disp->data[(y * disp->width + x_disp) * 4] / 0xFFFF * shift_max; if (shift > 0) { x_from = x_res; x_to = x_from - shift; res->data[(y * res->width + x_to) * 4 + 0] = res->data[(y * res->width + x_from) * 4 + 0]; res->data[(y * res->width + x_to) * 4 + 1] = res->data[(y * res->width + x_from) * 4 + 1]; res->data[(y * res->width + x_to) * 4 + 2] = res->data[(y * res->width + x_from) * 4 + 2]; res->data[(y * res->width + x_to) * 4 + 3] = 0xFFFF; /* Keeping the original pixel results in ugly repeated * patterns. Make it random. */ random_pixel(res, x_from, y); } } } } void make_stereogram( struct FFImage *disp, struct FFImage *res, uint32_t pattern_width ) { uint32_t i, steps; fill_random(res, pattern_width); steps = disp->width / pattern_width; if (disp->width % pattern_width != 0) ++steps; for (i = 0; i < steps; ++i) make_step(disp, res, pattern_width, i); } int main(int argc, char **argv) { struct FFImage disp, res; uint32_t pattern_width; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } srand48(time(NULL)); if (!ff_load(argv[1], &disp)) return 1; /* 10% of the source width is good. */ pattern_width = disp.width / 10; if (!ff_init_empty(&res, disp.width + pattern_width, disp.height)) return 1; make_stereogram(&disp, &res, pattern_width); if (!ff_save(&res, argv[2])) return 1; return 0; }