Created
February 21, 2020 04:53
-
-
Save rustyrussell/f23ed9ae67b01e603686ad0c1344e82d to your computer and use it in GitHub Desktop.
Quick code to scramble / unscramble an image given a key.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ccan/array_size/array_size.h> | |
#include <ccan/asort/asort.h> | |
#include <ccan/crypto/sha256/sha256.h> | |
#include <ccan/err/err.h> | |
#include <ccan/str/hex/hex.h> | |
#include <ccan/short_types/short_types.h> | |
#include <SDL2/SDL.h> | |
#include <SDL2/SDL_image.h> | |
#include <SDL2/SDL_pixels.h> | |
#define GRIDBITS 4 | |
#define GRIDPIX (1 << GRIDBITS) | |
static u8 *pixpos(SDL_Surface *image, size_t x, size_t y) | |
{ | |
u8 *p = image->pixels; | |
/* Get to correct row, then correct byte */ | |
return p + image->pitch * y + image->format->BytesPerPixel * x; | |
} | |
static u32 get_pixelval(const u8 *p, int bytes_per_pixel) | |
{ | |
if (bytes_per_pixel == 3) | |
return ((u32)p[0] << 16) | ((u32)p[1] << 8) | p[2]; | |
else if (bytes_per_pixel == 4) | |
return *(u32 *)p; | |
else | |
errx(1, "FIXME: Support %u BytesPerPixel!", | |
bytes_per_pixel); | |
} | |
static void put_pixelval(u8 *p, int bytes_per_pixel, u32 pixel) | |
{ | |
if (bytes_per_pixel == 3) { | |
p[0] = pixel >> 16; | |
p[1] = pixel >> 8; | |
p[2] = pixel; | |
} else if (bytes_per_pixel == 4) | |
*(u32 *)p = pixel; | |
else | |
errx(1, "FIXME: Support %u BytesPerPixel!", | |
bytes_per_pixel); | |
} | |
struct coord { | |
u16 key; | |
u8 x, y; | |
}; | |
static int cmp_key(const struct coord *a, const struct coord *b, void *unused) | |
{ | |
if (a->key < b->key) | |
return -1; | |
else if (a->key > b->key) | |
return 1; | |
return 0; | |
} | |
static u16 get_16_bits(struct sha256 *val, size_t *bytes_used) | |
{ | |
u16 v; | |
/* Need more bits? Hash again */ | |
if (*bytes_used + 2 > sizeof(*val)) { | |
sha256(val, val, sizeof(*val)); | |
*bytes_used = 0; | |
} | |
v = ((u16)val->u.u8[*bytes_used] << 8) | val->u.u8[*bytes_used + 1]; | |
(*bytes_used) += 2; | |
return v; | |
} | |
/* To make swap reversible, we can only swap pairs once. | |
* Simplest algorithm is sort by a key, and swap in pairs. | |
*/ | |
static void scramble_grid(SDL_Surface *image, | |
size_t x, size_t y, | |
struct sha256 *val) | |
{ | |
struct coord coords[GRIDPIX * GRIDPIX]; | |
size_t bytes_used = 0; | |
for (size_t i = 0; i < ARRAY_SIZE(coords); i++) { | |
coords[i].key = get_16_bits(val, &bytes_used); | |
coords[i].x = i % GRIDPIX; | |
coords[i].y = i / GRIDPIX; | |
} | |
asort(coords, ARRAY_SIZE(coords), cmp_key, NULL); | |
for (size_t i = 0; i < ARRAY_SIZE(coords); i += 2) { | |
u8 *p1 = pixpos(image, x + coords[i].x, y + coords[i].y); | |
u8 *p2 = pixpos(image, x + coords[i+1].x, y + coords[i+1].y); | |
u32 p1val = get_pixelval(p1, image->format->BytesPerPixel); | |
u32 p2val = get_pixelval(p2, image->format->BytesPerPixel); | |
put_pixelval(p1, image->format->BytesPerPixel, p2val); | |
put_pixelval(p2, image->format->BytesPerPixel, p1val); | |
} | |
} | |
int main(int argc, char *argv[]) | |
{ | |
struct sha256 val; | |
if (argc != 4) | |
errx(1, "Usage: permute-image 64-hexchars in.png out.png"); | |
if (!hex_decode(argv[1], strlen(argv[1]), &val, sizeof(val))) | |
errx(1, "Invalid seed"); | |
if (SDL_Init(SDL_INIT_VIDEO) == -1) | |
errx(1, "SDL init failed: %s", SDL_GetError()); | |
SDL_Surface *image = IMG_Load(argv[2]); | |
SDL_LockSurface(image); | |
for (size_t x = 0; x + GRIDPIX <= image->w; x += GRIDPIX) { | |
for (size_t y = 0; y + GRIDPIX <= image->h; y += GRIDPIX) { | |
scramble_grid(image, x, y, &val); | |
} | |
} | |
SDL_UnlockSurface(image); | |
IMG_SavePNG(image, argv[3]); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment