|
|
@@ -74,6 +74,9 @@ static const uint32_t *unichars; |
|
|
|
* this value breaks compatibility with other images. */ |
|
|
|
#define POINTS_PER_CELL 2 |
|
|
|
|
|
|
|
/* Start with a random image (1), or with a good estimate (0)? */ |
|
|
|
#define RANDOM_START 0 |
|
|
|
|
|
|
|
/* |
|
|
|
* These values can be overwritten at runtime |
|
|
|
*/ |
|
|
@@ -115,8 +118,7 @@ static int MAX_ITERATIONS; |
|
|
|
static unsigned int TOTAL_CELLS; |
|
|
|
|
|
|
|
#define RANGE_XY (RANGE_Y*RANGE_X) |
|
|
|
#define RANGE_XYXY (RANGE_XY*RANGE_XY) |
|
|
|
//#define RANGE_XYXY (RANGE_Y*RANGE_X*(RANGE_Y*RANGE_X+1)/2) |
|
|
|
#define RANGE_XY2 (RANGE_Y*RANGE_X*(RANGE_Y*RANGE_X+1)/2) |
|
|
|
#define RANGE_RXY (RANGE_Y*RANGE_X*RANGE_R) |
|
|
|
#define RANGE_GRXY (RANGE_Y*RANGE_X*RANGE_R*RANGE_G) |
|
|
|
#define RANGE_BGRXY (RANGE_Y*RANGE_X*RANGE_R*RANGE_G*RANGE_B) |
|
|
@@ -146,14 +148,11 @@ void compute_ranges(int width, int height) |
|
|
|
TOTAL_BITS = MAX_MSG_LEN * logf(NUM_CHARACTERS) / logf(2); |
|
|
|
HEADER_BITS = logf(RANGE_W * RANGE_H) / logf(2); |
|
|
|
DATA_BITS = TOTAL_BITS - HEADER_BITS; |
|
|
|
#if POINTS_PER_CELL == 1 |
|
|
|
CELL_BITS = logf(RANGE_SBGRXY) / logf(2); |
|
|
|
#if POINTS_PER_CELL == 2 |
|
|
|
CELL_BITS = (2 * logf(RANGE_SBGR) + logf(RANGE_XY2)) / logf(2); |
|
|
|
//CELL_BITS = 2 * logf(RANGE_SBGRXY) / logf(2); |
|
|
|
#else |
|
|
|
// TODO: implement the following shit |
|
|
|
//float coord_bits = logf((RANGE_Y * RANGE_X) * (RANGE_Y * RANGE_X + 1) / 2); |
|
|
|
//float other_bits = logf(RANGE_R * RANGE_G * RANGE_B * RANGE_S); |
|
|
|
//CELL_BITS = (coord_bits + 2 * other_bits) / logf(2); |
|
|
|
CELL_BITS = 2 * logf(RANGE_SBGRXY) / logf(2); |
|
|
|
CELL_BITS = logf(RANGE_SBGRXY) / logf(2); |
|
|
|
#endif |
|
|
|
TOTAL_CELLS = (int)(DATA_BITS / CELL_BITS); |
|
|
|
MAX_ITERATIONS = ITERATIONS_PER_POINT * POINTS_PER_CELL * TOTAL_CELLS; |
|
|
@@ -508,17 +507,17 @@ static inline void set_point(int index, float x, float y, float r, |
|
|
|
float fx = (x - dx * RANGE_X) / RANGE_X; |
|
|
|
float fy = (y - dy * RANGE_Y) / RANGE_Y; |
|
|
|
|
|
|
|
int is = range2int(s, RANGE_S); |
|
|
|
|
|
|
|
int ix = range2int(fx, RANGE_X); |
|
|
|
int iy = range2int(fy, RANGE_Y); |
|
|
|
int ix = range2int(fx, RANGE_X); |
|
|
|
|
|
|
|
int ir = range2int(r, RANGE_R); |
|
|
|
int ig = range2int(g, RANGE_G); |
|
|
|
int ib = range2int(b, RANGE_B); |
|
|
|
|
|
|
|
points[index] = iy + RANGE_Y * (ix + RANGE_X * (ib + RANGE_B * |
|
|
|
(ig + (RANGE_R * ir + (RANGE_S * is))))); |
|
|
|
int is = range2int(s, RANGE_S); |
|
|
|
|
|
|
|
points[index] = iy + RANGE_Y * (ix + RANGE_X * (ir + RANGE_R * |
|
|
|
(ig + (RANGE_G * ib + (RANGE_B * is))))); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void get_point(int index, float *x, float *y, float *r, |
|
|
@@ -532,20 +531,20 @@ static inline void get_point(int index, float *x, float *y, float *r, |
|
|
|
float fy = int2midrange(pt % RANGE_Y, RANGE_Y); pt /= RANGE_Y; |
|
|
|
float fx = int2midrange(pt % RANGE_X, RANGE_X); pt /= RANGE_X; |
|
|
|
|
|
|
|
*x = (fx + dx) * RANGE_X /*+ 0.5 * (index & 1)*/; |
|
|
|
*y = (fy + dy) * RANGE_Y /*+ 0.5 * (index & 1)*/; |
|
|
|
*x = (fx + dx) * RANGE_X /*+ 0.5 * (index & 1)*/; |
|
|
|
|
|
|
|
if(final) |
|
|
|
{ |
|
|
|
*b = int2fullrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R; |
|
|
|
*r = int2fullrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R; |
|
|
|
*g = int2fullrange(pt % RANGE_G, RANGE_G); pt /= RANGE_G; |
|
|
|
*r = int2fullrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B; |
|
|
|
*b = int2fullrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
*b = int2midrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R; |
|
|
|
*r = int2midrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R; |
|
|
|
*g = int2midrange(pt % RANGE_G, RANGE_G); pt /= RANGE_G; |
|
|
|
*r = int2midrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B; |
|
|
|
*b = int2midrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B; |
|
|
|
} |
|
|
|
|
|
|
|
*s = int2fullrange(pt % RANGE_S, RANGE_S); pt /= RANGE_S; |
|
|
@@ -557,20 +556,37 @@ static void add_point(float x, float y, float r, float g, float b, float s) |
|
|
|
npoints++; |
|
|
|
} |
|
|
|
|
|
|
|
static uint32_t pack_coords(int x1, int y1, int x2, int y2) |
|
|
|
static uint32_t pack_coords(int x1, int y1, int x2, int y2, bool *swap) |
|
|
|
{ |
|
|
|
return ((y2 * RANGE_X + x2) * RANGE_Y + y1) * RANGE_X + x1; |
|
|
|
int k1 = y1 * RANGE_X + x1; |
|
|
|
int k2 = y2 * RANGE_X + x2; |
|
|
|
|
|
|
|
/* XXX: this should not happen */ |
|
|
|
if(k1 == k2) |
|
|
|
k1 += (x1 > 0 ? -1 : 1); |
|
|
|
|
|
|
|
*swap = k1 > k2; |
|
|
|
|
|
|
|
if(*swap) |
|
|
|
{ |
|
|
|
int tmp = k1; k1 = k2; k2 = tmp; |
|
|
|
} |
|
|
|
|
|
|
|
return k2 * (k2 + 1) / 2 + k1; |
|
|
|
} |
|
|
|
|
|
|
|
static void unpack_coords(uint32_t pack, int *x1, int *y1, int *x2, int *y2) |
|
|
|
{ |
|
|
|
*x1 = pack % RANGE_X; pack /= RANGE_X; |
|
|
|
*y1 = pack % RANGE_Y; pack /= RANGE_Y; |
|
|
|
*x2 = pack % RANGE_X; pack /= RANGE_X; |
|
|
|
*y2 = pack % RANGE_Y; |
|
|
|
int k2 = ((int)sqrt(1.0 + 8 * pack) - 1) / 2; |
|
|
|
int k1 = pack - k2 * (k2 + 1) / 2; |
|
|
|
|
|
|
|
*x1 = k1 % RANGE_X; |
|
|
|
*y1 = k1 / RANGE_X; |
|
|
|
*x2 = k2 % RANGE_X; |
|
|
|
*y2 = k2 / RANGE_X; |
|
|
|
} |
|
|
|
|
|
|
|
#if 0 |
|
|
|
#if RANDOM_START == 1 |
|
|
|
static void add_random_point() |
|
|
|
{ |
|
|
|
points[npoints] = det_rand(RANGE_SBGRXY); |
|
|
@@ -845,34 +861,36 @@ static void analyse(pipi_image_t *src) |
|
|
|
else |
|
|
|
wmin = 0.0, wmax = 1.0; |
|
|
|
|
|
|
|
#if 0 |
|
|
|
#if RANDOM_START == 1 |
|
|
|
# if POINTS_PER_CELL == 2 |
|
|
|
add_random_point(); |
|
|
|
# endif |
|
|
|
add_random_point(); |
|
|
|
#else |
|
|
|
/* 0.80 and 0.20 were chosen empirically, it gives a 10% better |
|
|
|
* initial distance. Definitely worth it. */ |
|
|
|
#if POINTS_PER_CELL == 1 |
|
|
|
# if POINTS_PER_CELL == 1 |
|
|
|
if(total < min + (max - min) / 2) |
|
|
|
{ |
|
|
|
#endif |
|
|
|
# endif |
|
|
|
add_point(xmin, ymin, |
|
|
|
data[4 * (xmin + ymin * p->w) + 0] * 0.80 + mr * 0.20, |
|
|
|
data[4 * (xmin + ymin * p->w) + 1] * 0.80 + mg * 0.20, |
|
|
|
data[4 * (xmin + ymin * p->w) + 2] * 0.80 + mb * 0.20, |
|
|
|
wmin); |
|
|
|
#if POINTS_PER_CELL == 1 |
|
|
|
# if POINTS_PER_CELL == 1 |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
#endif |
|
|
|
# endif |
|
|
|
add_point(xmax, ymax, |
|
|
|
data[4 * (xmax + ymax * p->w) + 0] * 0.80 + mr * 0.20, |
|
|
|
data[4 * (xmax + ymax * p->w) + 1] * 0.80 + mg * 0.20, |
|
|
|
data[4 * (xmax + ymax * p->w) + 2] * 0.80 + mb * 0.20, |
|
|
|
wmax); |
|
|
|
#if POINTS_PER_CELL == 1 |
|
|
|
# if POINTS_PER_CELL == 1 |
|
|
|
} |
|
|
|
#endif |
|
|
|
# endif |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
@@ -938,8 +956,8 @@ int main(int argc, char *argv[]) |
|
|
|
ITERATIONS_PER_POINT = 10 * atof(myoptarg); |
|
|
|
if(ITERATIONS_PER_POINT < 0) |
|
|
|
ITERATIONS_PER_POINT = 0; |
|
|
|
else if(ITERATIONS_PER_POINT > 100) |
|
|
|
ITERATIONS_PER_POINT = 100; |
|
|
|
else if(ITERATIONS_PER_POINT > 200) |
|
|
|
ITERATIONS_PER_POINT = 200; |
|
|
|
break; |
|
|
|
case 'd': |
|
|
|
DEBUG_MODE = true; |
|
|
@@ -953,7 +971,7 @@ int main(int argc, char *argv[]) |
|
|
|
printf(" -o, --output <filename> output resulting image to filename\n"); |
|
|
|
printf(" -l, --length <size> message length in characters (default 140)\n"); |
|
|
|
printf(" -c, --charset <block> character set to use (ascii, [cjk], symbols)\n"); |
|
|
|
printf(" -q, --quality <rate> set image quality (0 - 10) (default 5)\n"); |
|
|
|
printf(" -q, --quality <rate> set image quality (0 - 20) (default 5)\n"); |
|
|
|
printf(" -d, --debug print debug information\n"); |
|
|
|
printf(" -h, --help display this help and exit\n"); |
|
|
|
printf("\n"); |
|
|
@@ -1095,7 +1113,7 @@ int main(int argc, char *argv[]) |
|
|
|
{ revert; compute_ranges(width, height); } \ |
|
|
|
} while(0) |
|
|
|
|
|
|
|
for(int i = 0; i < 5; i++) |
|
|
|
for(int i = 0; i < 2; i++) |
|
|
|
{ |
|
|
|
TRY(RANGE_G++, RANGE_G--); |
|
|
|
TRY(RANGE_R++, RANGE_R--); |
|
|
@@ -1141,9 +1159,9 @@ int main(int argc, char *argv[]) |
|
|
|
if(srcname) |
|
|
|
{ |
|
|
|
/* Resize and filter image to better state */ |
|
|
|
tmp = pipi_resize(src, dw * RANGE_X, dh * RANGE_Y); |
|
|
|
tmp = pipi_gaussian_blur(src, 0.5 * dw * RANGE_X / width); |
|
|
|
pipi_free(src); |
|
|
|
src = pipi_median_ext(tmp, 1, 1); |
|
|
|
src = pipi_resize(tmp, dw * RANGE_X, dh * RANGE_Y); |
|
|
|
pipi_free(tmp); |
|
|
|
|
|
|
|
/* Analyse image */ |
|
|
@@ -1181,14 +1199,14 @@ int main(int argc, char *argv[]) |
|
|
|
/* Compute the affected image zone */ |
|
|
|
float fx, fy, fr, fg, fb, fs; |
|
|
|
get_point(pt, &fx, &fy, &fr, &fg, &fb, &fs); |
|
|
|
int zonex = (int)fx / RANGE_X - 1; |
|
|
|
int zoney = (int)fy / RANGE_Y - 1; |
|
|
|
int zonew = 3; |
|
|
|
int zoneh = 3; |
|
|
|
if(zonex < 0) { zonex = 0; zonew--; } |
|
|
|
if(zoney < 0) { zoney = 0; zoneh--; } |
|
|
|
if(zonex + zonew >= (int)dw) { zonew--; } |
|
|
|
if(zoney + zoneh >= (int)dh) { zoneh--; } |
|
|
|
int zonex = (int)fx / RANGE_X - 2; |
|
|
|
int zoney = (int)fy / RANGE_Y - 2; |
|
|
|
int zonew = 4; |
|
|
|
int zoneh = 4; |
|
|
|
if(zonex < 0) { zonew += zonex; zonex = 0; } |
|
|
|
if(zoney < 0) { zoneh += zoney; zoney = 0;; } |
|
|
|
if(zonex + zonew > (int)dw) { zonew = dw - zonex; } |
|
|
|
if(zoney + zoneh > (int)dh) { zoneh = dh - zoney; } |
|
|
|
|
|
|
|
/* Choose random operations and measure their effect */ |
|
|
|
uint8_t op1 = rand_op(); |
|
|
@@ -1246,10 +1264,10 @@ int main(int argc, char *argv[]) |
|
|
|
success++; |
|
|
|
|
|
|
|
/* Save image! */ |
|
|
|
//char buf[128]; |
|
|
|
//sprintf(buf, "twit%08i.bmp", success); |
|
|
|
//if((success % 10) == 0) |
|
|
|
// pipi_save(tmp, buf); |
|
|
|
char buf[128]; |
|
|
|
sprintf(buf, "twit%08i.bmp", success); |
|
|
|
if((success % 10) == 0) |
|
|
|
pipi_save(tmp, buf); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
@@ -1298,11 +1316,13 @@ int main(int argc, char *argv[]) |
|
|
|
y1 = points[i] % RANGE_Y; |
|
|
|
x2 = (points[i + 1] / RANGE_Y) % RANGE_X; |
|
|
|
y2 = points[i + 1] % RANGE_Y; |
|
|
|
uint32_t pack = pack_coords(x1, y1, x2, y2); |
|
|
|
|
|
|
|
b.push(points[i] / RANGE_XY, RANGE_SBGR); |
|
|
|
b.push(points[i + 1] / RANGE_XY, RANGE_SBGR); |
|
|
|
b.push(pack, RANGE_XYXY); |
|
|
|
bool swap; |
|
|
|
uint32_t pack = pack_coords(x1, y1, x2, y2, &swap); |
|
|
|
|
|
|
|
b.push(points[i + (swap ? 1 : 0)] / RANGE_XY, RANGE_SBGR); |
|
|
|
b.push(points[i + (swap ? 0 : 1)] / RANGE_XY, RANGE_SBGR); |
|
|
|
b.push(pack, RANGE_XY2); |
|
|
|
#else |
|
|
|
b.push(points[i], RANGE_SBGRXY); |
|
|
|
#endif |
|
|
@@ -1321,10 +1341,11 @@ int main(int argc, char *argv[]) |
|
|
|
for(int i = dw * dh; i--; ) |
|
|
|
{ |
|
|
|
#if POINTS_PER_CELL == 2 |
|
|
|
uint32_t pack = b.pop(RANGE_XYXY); |
|
|
|
uint32_t pack = b.pop(RANGE_XY2); |
|
|
|
uint32_t p2 = b.pop(RANGE_SBGR); |
|
|
|
uint32_t p1 = b.pop(RANGE_SBGR); |
|
|
|
int x1, y1, x2, y2; |
|
|
|
|
|
|
|
unpack_coords(pack, &x1, &y1, &x2, &y2); |
|
|
|
points[i * 2] = p1 * RANGE_XY + x1 * RANGE_Y + y1; |
|
|
|
points[i * 2 + 1] = p2 * RANGE_XY + x2 * RANGE_Y + y2; |
|
|
|