diff --git a/examples/img2twit.cpp b/examples/img2twit.cpp index 0fb5352..32fa2b7 100644 --- a/examples/img2twit.cpp +++ b/examples/img2twit.cpp @@ -65,7 +65,8 @@ static const uint32_t *unichars; #define RANGE_W 4000 #define RANGE_H 4000 -/* How does the algorithm work: one point per cell, or two */ +/* How does the algorithm work: one point per cell, or two? XXX: changing + * this value breaks compatibility with other images. */ #define POINTS_PER_CELL 2 /* @@ -128,6 +129,47 @@ static int npoints = 0; /* Global triangulation */ static Delaunay_triangulation dt; +/* + * Bit allocation handling + */ + +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_SYXRGB) / 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_SYXRGB) / logf(2); +#endif + TOTAL_CELLS = (int)(DATA_BITS / CELL_BITS); + MAX_ITERATIONS = ITERATIONS_PER_POINT * POINTS_PER_CELL * TOTAL_CELLS; + + /* Compute "best" w/h ratio */ + dw = 1; dh = TOTAL_CELLS; + for(unsigned int i = 1; i <= TOTAL_CELLS; i++) + { + int j = TOTAL_CELLS / i; + + float r = (float)width / (float)height; + float ir = (float)i / (float)j; + float dwr = (float)dw / (float)dh; + + if(fabs(logf(r / ir)) < fabs(logf(r / dwr))) + { + dw = i; + dh = TOTAL_CELLS / dw; + } + } + while((dh + 1) * dw <= TOTAL_CELLS) dh++; + while(dh * (dw + 1) <= TOTAL_CELLS) dw++; +} + /* * Unicode stuff handling */ @@ -444,12 +486,8 @@ static inline float int2fullrange(int val, int range) static inline void index2cell(int index, int *dx, int *dy) { - // This check will be used once we add points to our list - //if(index < dw * dh * POINTS_PER_CELL) - { - *dx = (index / POINTS_PER_CELL) % dw; - *dy = (index / POINTS_PER_CELL) / dw; - } + *dx = (index / POINTS_PER_CELL) % dw; + *dy = (index / POINTS_PER_CELL) / dw; } static inline void set_point(int index, float x, float y, float r, @@ -1021,39 +1059,40 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - 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_SYXRGB) / 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_SYXRGB) / logf(2); -#endif - TOTAL_CELLS = (int)(DATA_BITS / CELL_BITS); - MAX_ITERATIONS = ITERATIONS_PER_POINT * POINTS_PER_CELL * TOTAL_CELLS; - - /* Compute "best" w/h ratio */ - dw = 1; dh = TOTAL_CELLS; - for(unsigned int i = 1; i <= TOTAL_CELLS; i++) + compute_ranges(width, height); + + /* Try to cram some more information into our points as long as it + * does not change the cell distribution. This cannot be too clever, + * because we want the computation to depend only on the source image + * coordinates. */ +#define TRY(op, revert) \ + do { \ + unsigned int olddw = dw, olddh = dh; \ + op; compute_ranges(width, height); \ + if(dw != olddw || dh != olddh) \ + { revert; compute_ranges(width, height); } \ + } while(0) + + for(int i = 0; i < 5; i++) { - int j = TOTAL_CELLS / i; - - float r = (float)width / (float)height; - float ir = (float)i / (float)j; - float dwr = (float)dw / (float)dh; + TRY(RANGE_G++, RANGE_G--); + TRY(RANGE_R++, RANGE_R--); + TRY(RANGE_B++, RANGE_B--); + } - if(fabs(logf(r / ir)) < fabs(logf(r / dwr))) + for(int i = 0; i < 10; i++) + { + if((float)width / dw >= (float)height / dh) { - dw = i; - dh = TOTAL_CELLS / dw; + TRY(RANGE_X++, RANGE_X--); + TRY(RANGE_Y++, RANGE_Y--); + } + else + { + TRY(RANGE_Y++, RANGE_Y--); + TRY(RANGE_X++, RANGE_X--); } } - while((dh + 1) * dw <= TOTAL_CELLS) dh++; - while(dh * (dw + 1) <= TOTAL_CELLS) dw++; /* Print debug information */ if(DEBUG_MODE)