Ignore:
Timestamp:
May 25, 2009, 2:16:50 AM (11 years ago)
Author:
Sam Hocevar
Message:

Add proper Unicode handling to img2twit. This includes an UTF-8 encoder/decoder
and a special bit stack that can handle arbitrary bases within its stream. The
image encoder and decoder are now separate code paths.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libpipi/trunk/examples/img2twit.cpp

    r3520 r3521  
    1616 */
    1717
     18/* Debug mode */
     19#define DEBUG 1
     20
     21/* Encoding iterations: 1000 gives a fast answer, 10000 gives good quality */
     22#define MAX_ITERATIONS 10000
     23
    1824/* The maximum message length */
    1925#define MAX_MSG_LEN 140
    2026
    21 /* The number of characters at disposal */
    22 //#define NUM_CHARACTERS 0x7fffffff // The sky's the limit
    23 //#define NUM_CHARACTERS 1111998 // Full valid Unicode set
    24 //#define NUM_CHARACTERS 100507 // Full graphic Unicode
    25 #define NUM_CHARACTERS 32768 // Chinese characters
    26 //#define NUM_CHARACTERS 127 // ASCII
     27/* The Unicode characters at disposal - XXX: must be _ordered_ */
     28static const uint32_t unichars[] =
     29{
     30    /* Printable ASCII (except space) */
     31    0x0021, 0x007f,
     32
     33    /* Stupid symbols and Dingbats shit */
     34    //0x25a0, 0x2600, /* Geometric Shapes */
     35    //0x2600, 0x269e, 0x26a0, 0x26bd, 0x26c0, 0x26c4, /* Misc. Symbols */
     36    //0x2701, 0x2705, 0x2706, 0x270a, 0x270c, 0x2728, 0x2729, 0x274c,
     37    //  0x274d, 0x274e, 0x274f, 0x2753, 0x2756, 0x2757, 0x2758, 0x275f,
     38    //  0x2761, 0x2795, 0x2798, 0x27b0, 0x27b1, 0x27bf, /* Dingbats */
     39
     40    /* Chinese-looking stuff */
     41    //0x2e80, 0x2e9a, 0x2e9b, 0x2ef4, /* CJK Radicals Supplement */
     42    //0x2f00, 0x2fd6, /* Kangxi Radicals */
     43    //0x3400, 0x4db6, /* CJK Unified Ideographs Extension A */
     44    //0x4e00, 0x9fa6, /* CJK Unified Ideographs */
     45
     46    /* Korean - most people don't know the difference anyway */
     47    0xac00, 0xd7a4, /* Hangul Syllables */
     48
     49    /* More Chinese */
     50    //0xf900, 0xfa2e, 0xfa30, 0xfa6b, 0xfa70, 0xfada, /* CJK Compat. Idgphs. */
     51
     52    /* TODO: there's also the U+20000 and U+2f800 planes, but they're
     53     * not supported by the Twitter Javascript filter (yet?). */
     54
     55    /* End of list marker - XXX: don't remove! */
     56    0x0000, 0x0000
     57};
    2758
    2859/* The maximum image size we want to support */
     
    5485static float HEADER_BITS;
    5586static float DATA_BITS;
    56 static float POINT_BITS;
    57 
     87static float CELL_BITS;
     88
     89static int NUM_CHARACTERS;
    5890static unsigned int TOTAL_CELLS;
    5991
     
    78110static Delaunay_triangulation dt;
    79111
     112/*
     113 * Unicode stuff handling
     114 */
     115
     116/* Return the number of chars in the unichars table */
     117static int count_unichars(void)
     118{
     119    int ret = 0;
     120
     121    for(int u = 0; unichars[u] != unichars[u + 1]; u += 2)
     122        ret += unichars[u + 1] - unichars[u];
     123
     124    return ret;
     125}
     126
     127/* Get the ith Unicode character in our list */
     128static uint32_t index2uni(uint32_t i)
     129{
     130    for(int u = 0; unichars[u] != unichars[u + 1]; u += 2)
     131        if(i < unichars[u + 1] - unichars[u])
     132            return unichars[u] + i;
     133        else
     134            i -= unichars[u + 1] - unichars[u];
     135
     136    return 0; /* Should not happen! */
     137}
     138
     139/* Convert a Unicode character to its position in the compact list */
     140static uint32_t uni2index(uint32_t x)
     141{
     142    uint32_t ret = 0;
     143
     144    for(int u = 0; unichars[u] != unichars[u + 1]; u += 2)
     145        if(x < unichars[u + 1])
     146            return ret + x - unichars[u];
     147        else
     148            ret += unichars[u + 1] - unichars[u];
     149
     150    return ret; /* Should not happen! */
     151}
     152
     153static uint8_t const utf8_trailing[256] =
     154{
     155    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     156    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     157    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     158    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     159    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     160    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     161    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
     162    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
     163};
     164
     165static uint32_t const utf8_offsets[6] =
     166{
     167    0x00000000UL, 0x00003080UL, 0x000E2080UL,
     168    0x03C82080UL, 0xFA082080UL, 0x82082080UL
     169};
     170
     171static uint32_t fread_utf8(FILE *f)
     172{
     173    int ch, i = 0, todo = -1;
     174    uint32_t ret = 0;
     175
     176    for(;;)
     177    {
     178        ch = fgetc(f);
     179        if(!ch)
     180            return 0;
     181        if(todo == -1)
     182            todo = utf8_trailing[ch];
     183        ret += ((uint32_t)ch) << (6 * (todo - i));
     184        if(todo == i++)
     185            return ret - utf8_offsets[todo];
     186    }
     187}
     188
     189static void fwrite_utf8(FILE *f, uint32_t x)
     190{
     191    static const uint8_t mark[7] =
     192    {
     193        0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
     194    };
     195
     196    char buf[8];
     197    char *parser = buf;
     198    size_t bytes;
     199
     200    if(x < 0x80)
     201    {
     202        fprintf(f, "%c", x);
     203        return;
     204    }
     205
     206    bytes = (x < 0x800) ? 2 : (x < 0x10000) ? 3 : 4;
     207    parser += bytes;
     208    *parser = '\0';
     209
     210    switch(bytes)
     211    {
     212        case 4: *--parser = (x | 0x80) & 0xbf; x >>= 6;
     213        case 3: *--parser = (x | 0x80) & 0xbf; x >>= 6;
     214        case 2: *--parser = (x | 0x80) & 0xbf; x >>= 6;
     215    }
     216    *--parser = x | mark[bytes];
     217
     218    fprintf(f, "%s", buf);
     219}
     220
     221/*
     222 * Our nifty non-power-of-two bitstack handling
     223 */
     224
     225class bitstack
     226{
     227public:
     228    bitstack() { init(0); }
     229
     230    char const *tostring()
     231    {
     232        int pos = sprintf(str, "0x%x", digits[msb]);
     233
     234        for(int i = msb - 1; i >= 0; i--)
     235            pos += sprintf(str + pos, "%08x", digits[i]);
     236
     237        return str;
     238    }
     239
     240    void push(uint32_t val, uint32_t range)
     241    {
     242        if(!range)
     243            return;
     244
     245        mul(range);
     246        add(val % range);
     247    }
     248
     249    uint32_t pop(uint32_t range)
     250    {
     251        if(!range)
     252            return 0;
     253
     254        return div(range);
     255    }
     256
     257    bool isempty()
     258    {
     259        for(int i = msb; i >= 0; i--)
     260            if(digits[i])
     261                return false;
     262
     263        return true;
     264    }
     265
     266private:
     267    bitstack(uint32_t i) { init(i); }
     268
     269    void init(uint32_t i)
     270    {
     271        memset(digits, 0, sizeof(digits));
     272        digits[0] = i;
     273        msb = 0;
     274    }
     275
     276    /* Could be done much faster, but we don't care! */
     277    void add(uint32_t x) { add(bitstack(x)); }
     278    void sub(uint32_t x) { sub(bitstack(x)); }
     279
     280    void add(bitstack const &_b)
     281    {
     282        /* Copy the operand in case we get added to ourselves */
     283        bitstack b = _b;
     284        uint64_t x = 0;
     285
     286        if(msb < b.msb)
     287            msb = b.msb;
     288
     289        for(int i = 0; i <= msb; i++)
     290        {
     291            uint64_t tmp = (uint64_t)digits[i] + (uint64_t)b.digits[i] + x;
     292            digits[i] = tmp;
     293            if((uint64_t)digits[i] == tmp)
     294                x = 0;
     295            else
     296            {
     297                x = 1;
     298                if(i == msb)
     299                    msb++;
     300            }
     301        }
     302    }
     303
     304    void sub(bitstack const &_b)
     305    {
     306        /* Copy the operand in case we get substracted from ourselves */
     307        bitstack b = _b;
     308        uint64_t x = 0;
     309
     310        /* We cannot substract a larger number! */
     311        if(msb < b.msb)
     312        {
     313            init(0);
     314            return;
     315        }
     316
     317        for(int i = 0; i <= msb; i++)
     318        {
     319            uint64_t tmp = (uint64_t)digits[i] - (uint64_t)b.digits[i] - x;
     320            digits[i] = tmp;
     321            if((uint64_t)digits[i] == tmp)
     322                x = 0;
     323            else
     324            {
     325                x = 1;
     326                if(i == msb)
     327                {
     328                    /* Error: carry into MSB! */
     329                    init(0);
     330                    return;
     331                }
     332            }
     333        }
     334
     335        while(msb > 0 && digits[msb] == 0) msb--;
     336    }
     337
     338    void mul(uint32_t x)
     339    {
     340        bitstack b = *this;
     341        init(0);
     342
     343        while(x)
     344        {
     345            if(x & 1)
     346                add(b);
     347            x /= 2;
     348            b.add(b);
     349        }
     350    }
     351
     352    uint32_t div(uint32_t x)
     353    {
     354        bitstack b = *this;
     355
     356        for(int i = msb; i >= 0; i--)
     357        {
     358            uint64_t tmp = b.digits[i] + (((uint64_t)b.digits[i + 1]) << 32);
     359            uint32_t res = tmp / x;
     360            uint32_t rem = tmp % x;
     361            digits[i]= res;
     362            b.digits[i + 1] = 0;
     363            b.digits[i] = rem;
     364        }
     365
     366        while(msb > 0 && digits[msb] == 0) msb--;
     367
     368        return b.digits[0];
     369    }
     370
     371    int msb;
     372    uint32_t digits[MAX_MSG_LEN + 1]; /* This is a safe max value */
     373    char str[(MAX_MSG_LEN + 1) * 8 + 1];
     374};
     375
     376/*
     377 * Point handling
     378 */
     379
    80380static unsigned int det_rand(unsigned int mod)
    81381{
     
    157457}
    158458
     459#if 0
    159460static void add_random_point()
    160461{
     
    162463    npoints++;
    163464}
     465#endif
    164466
    165467#define NB_OPS 20
     
    439741{
    440742    int opstats[2 * NB_OPS];
     743    bitstack b;
    441744    pipi_image_t *src, *tmp, *dst;
    442745    double error = 1.0;
    443746    int width, height, ret = 0;
    444 
    445     /* Compute bit allocation */
    446     fprintf(stderr, "Available characters: %i\n", NUM_CHARACTERS);
    447     fprintf(stderr, "Maximum message size: %i\n", MAX_MSG_LEN);
     747    bool decode = (argc >= 2 && !strcmp(argv[1], "-o"));
     748
     749    if(!((argc == 2 && !decode) || (argc == 3 && decode)))
     750    {
     751        fprintf(stderr, "img2twit: wrong argument count\n");
     752        fprintf(stderr, "Usage: img2twit <image>        Encode image and print result to stdout\n");
     753        fprintf(stderr, "       img2twit -o <image>     Read data from stdin and decode image to file\n");
     754        return EXIT_FAILURE;
     755    }
     756
     757    pipi_set_gamma(1.0);
     758
     759    /* Precompute bit allocation */
     760    NUM_CHARACTERS = count_unichars();
    448761    TOTAL_BITS = MAX_MSG_LEN * logf(NUM_CHARACTERS) / logf(2);
    449     fprintf(stderr, "Available bits: %f\n", TOTAL_BITS);
    450     fprintf(stderr, "Maximum image resolution: %ix%i\n", MAX_W, MAX_H);
    451762    HEADER_BITS = logf(MAX_W * MAX_H) / logf(2);
    452     fprintf(stderr, "Header bits: %f\n", HEADER_BITS);
    453763    DATA_BITS = TOTAL_BITS - HEADER_BITS;
    454     fprintf(stderr, "Bits available for data: %f\n", DATA_BITS);
    455764#if POINTS_PER_CELL == 1
    456     POINT_BITS = logf(RANGE_SYXRGB) / logf(2);
     765    CELL_BITS = logf(RANGE_SYXRGB) / logf(2);
    457766#else
    458     float coord_bits = logf((RANGE_Y * RANGE_X) * (RANGE_Y * RANGE_X + 1) / 2);
    459     float other_bits = logf(RANGE_R * RANGE_G * RANGE_B * RANGE_S);
    460     POINT_BITS = (coord_bits + 2 * other_bits) / logf(2);
    461 #endif
    462     fprintf(stderr, "Cell bits: %f\n", POINT_BITS);
    463     TOTAL_CELLS = (int)(DATA_BITS / POINT_BITS);
    464     fprintf(stderr, "Available cells: %i\n", TOTAL_CELLS);
    465     fprintf(stderr, "Wasted bits: %f\n", DATA_BITS - POINT_BITS * TOTAL_CELLS);
    466 
    467     /* Load image */
    468     pipi_set_gamma(1.0);
    469     src = pipi_load(argv[1]);
    470     width = pipi_get_image_width(src);
    471     height = pipi_get_image_height(src);
     767    // TODO: implement the following shit
     768    //float coord_bits = logf((RANGE_Y * RANGE_X) * (RANGE_Y * RANGE_X + 1) / 2);
     769    //float other_bits = logf(RANGE_R * RANGE_G * RANGE_B * RANGE_S);
     770    //CELL_BITS = (coord_bits + 2 * other_bits) / logf(2);
     771    CELL_BITS = 2 * logf(RANGE_SYXRGB) / logf(2);
     772#endif
     773    TOTAL_CELLS = (int)(DATA_BITS / CELL_BITS);
     774
     775    if(decode)
     776    {
     777        /* Decoding mode: read UTF-8 text from stdin, find each
     778         * character's index in our character list, and push it to our
     779         * wonderful custom bitstream. */
     780        uint32_t data[MAX_MSG_LEN];
     781        for(int i = 0; i < MAX_MSG_LEN; i++)
     782            data[i] = uni2index(fread_utf8(stdin));
     783        for(int i = MAX_MSG_LEN; i--; )
     784            b.push(data[i], NUM_CHARACTERS);
     785
     786        /* Read width and height from bitstream */
     787        src = NULL;
     788        width = b.pop(MAX_W);
     789        height = b.pop(MAX_H);
     790    }
     791    else
     792    {
     793        /* Argument given: open image for encoding */
     794        src = pipi_load(argv[1]);
     795
     796        if(!src)
     797        {
     798            fprintf(stderr, "Error loading %s\n", argv[1]);
     799            return EXIT_FAILURE;
     800        }
     801
     802        width = pipi_get_image_width(src);
     803        height = pipi_get_image_height(src);
     804    }
    472805
    473806    /* Compute best w/h ratio */
     
    489822    while((dh + 1) * dw <= TOTAL_CELLS) dh++;
    490823    while(dw * (dh + 1) <= TOTAL_CELLS) dw++;
     824
     825    /* Print debug information */
     826#if DEBUG
     827    fprintf(stderr, "Maximum message size: %i\n", MAX_MSG_LEN);
     828    fprintf(stderr, "Available characters: %i\n", NUM_CHARACTERS);
     829    fprintf(stderr, "Available bits: %f\n", TOTAL_BITS);
     830    fprintf(stderr, "Maximum image resolution: %ix%i\n", MAX_W, MAX_H);
     831    fprintf(stderr, "Image resolution: %ix%i\n", width, height);
     832    fprintf(stderr, "Header bits: %f\n", HEADER_BITS);
     833    fprintf(stderr, "Bits available for data: %f\n", DATA_BITS);
     834    fprintf(stderr, "Cell bits: %f\n", CELL_BITS);
     835    fprintf(stderr, "Available cells: %i\n", TOTAL_CELLS);
     836    fprintf(stderr, "Wasted bits: %f\n", DATA_BITS - CELL_BITS * TOTAL_CELLS);
     837
    491838    fprintf(stderr, "Chosen image ratio: %i:%i (wasting %i point cells)\n",
    492839            dw, dh, TOTAL_CELLS - dw * dh);
    493840    fprintf(stderr, "Total wasted bits: %f\n",
    494             DATA_BITS - POINT_BITS * dw * dh);
    495 
    496     /* Resize and filter image to better state */
    497     tmp = pipi_resize(src, dw * RANGE_X, dh * RANGE_Y);
    498     pipi_free(src);
    499     src = pipi_median_ext(tmp, 1, 1);
    500     pipi_free(tmp);
    501 
    502     /* Analyse image */
    503     analyse(src);
    504 
    505     /* Render what we just computed */
    506     tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y);
    507     render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y);
    508     error = pipi_measure_rmsd(src, tmp);
    509 
    510     fprintf(stderr, "Distance: %2.10g\n", error);
    511 
    512     memset(opstats, 0, sizeof(opstats));
    513     for(int iter = 0, stuck = 0, failures = 0, success = 0;
    514         /*stuck < 5 && */iter < 10000;
    515         iter++)
    516     {
    517         if(failures > 500)
    518         {
    519             stuck++;
    520             failures = 0;
    521         }
    522 
    523         pipi_image_t *scrap = pipi_copy(tmp);
    524 
    525         /* Choose a point at random */
    526         int pt = det_rand(npoints);
    527         uint32_t oldval = points[pt];
    528 
    529         /* Compute the affected image zone */
    530         float fx, fy, fr, fg, fb, fs;
    531         get_point(pt, &fx, &fy, &fr, &fg, &fb, &fs);
    532         int zonex = (int)fx / RANGE_X - 1;
    533         int zoney = (int)fy / RANGE_Y - 1;
    534         int zonew = 3;
    535         int zoneh = 3;
    536         if(zonex < 0) { zonex = 0; zonew--; }
    537         if(zoney < 0) { zoney = 0; zoneh--; }
    538         if(zonex + zonew >= (int)dw) { zonew--; }
    539         if(zoney + zoneh >= (int)dh) { zoneh--; }
    540 
    541         /* Choose random operations and measure their effect */
    542         uint8_t op1 = rand_op();
    543         //uint8_t op2 = rand_op();
    544 
    545         uint32_t candidates[3];
    546         double besterr = error + 1.0;
    547         int bestop = -1;
    548         candidates[0] = apply_op(op1, oldval);
    549         //candidates[1] = apply_op(op2, oldval);
    550         //candidates[2] = apply_op(op1, apply_op(op2, oldval));
    551 
    552         for(int i = 0; i < 1; i++)
    553         //for(int i = 0; i < 3; i++)
    554         {
    555             if(oldval == candidates[i])
    556                 continue;
    557 
    558             points[pt] = candidates[i];
    559 
    560             render(scrap, zonex * RANGE_X, zoney * RANGE_Y,
    561                    zonew * RANGE_X, zoneh * RANGE_Y);
    562 
    563             double newerr = pipi_measure_rmsd(src, scrap);
    564             if(newerr < besterr)
     841            DATA_BITS - CELL_BITS * dw * dh);
     842#endif
     843
     844    if(src)
     845    {
     846        /* Resize and filter image to better state */
     847        tmp = pipi_resize(src, dw * RANGE_X, dh * RANGE_Y);
     848        pipi_free(src);
     849        src = pipi_median_ext(tmp, 1, 1);
     850        pipi_free(tmp);
     851
     852        /* Analyse image */
     853        analyse(src);
     854
     855        /* Render what we just computed */
     856        tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y);
     857        render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y);
     858        error = pipi_measure_rmsd(src, tmp);
     859
     860#if DEBUG
     861        fprintf(stderr, "Distance: %2.10g\n", error);
     862#endif
     863
     864        memset(opstats, 0, sizeof(opstats));
     865        for(int iter = 0, stuck = 0, failures = 0, success = 0;
     866            iter < MAX_ITERATIONS /* && stuck < 5 && */;
     867            iter++)
     868        {
     869            if(failures > 500)
    565870            {
    566                 besterr = newerr;
    567                 bestop = i;
     871                stuck++;
     872                failures = 0;
    568873            }
    569         }
    570 
    571         opstats[op1 * 2]++;
    572         //opstats[op2 * 2]++;
    573 
    574         if(besterr < error)
    575         {
    576             points[pt] = candidates[bestop];
    577             /* Redraw image if the last check wasn't the best one */
    578             if(bestop != 2)
     874
     875#if !DEBUG
     876            if(!(iter % 16))
     877                fprintf(stderr, "\rEncoding... %i%%",
     878                        iter * 100 / MAX_ITERATIONS);
     879#endif
     880
     881            pipi_image_t *scrap = pipi_copy(tmp);
     882
     883            /* Choose a point at random */
     884            int pt = det_rand(npoints);
     885            uint32_t oldval = points[pt];
     886
     887            /* Compute the affected image zone */
     888            float fx, fy, fr, fg, fb, fs;
     889            get_point(pt, &fx, &fy, &fr, &fg, &fb, &fs);
     890            int zonex = (int)fx / RANGE_X - 1;
     891            int zoney = (int)fy / RANGE_Y - 1;
     892            int zonew = 3;
     893            int zoneh = 3;
     894            if(zonex < 0) { zonex = 0; zonew--; }
     895            if(zoney < 0) { zoney = 0; zoneh--; }
     896            if(zonex + zonew >= (int)dw) { zonew--; }
     897            if(zoney + zoneh >= (int)dh) { zoneh--; }
     898
     899            /* Choose random operations and measure their effect */
     900            uint8_t op1 = rand_op();
     901            //uint8_t op2 = rand_op();
     902
     903            uint32_t candidates[3];
     904            double besterr = error + 1.0;
     905            int bestop = -1;
     906            candidates[0] = apply_op(op1, oldval);
     907            //candidates[1] = apply_op(op2, oldval);
     908            //candidates[2] = apply_op(op1, apply_op(op2, oldval));
     909
     910            for(int i = 0; i < 1; i++)
     911            //for(int i = 0; i < 3; i++)
     912            {
     913                if(oldval == candidates[i])
     914                    continue;
     915
     916                points[pt] = candidates[i];
     917
    579918                render(scrap, zonex * RANGE_X, zoney * RANGE_Y,
    580919                       zonew * RANGE_X, zoneh * RANGE_Y);
    581920
    582             pipi_free(tmp);
    583             tmp = scrap;
    584             //fprintf(stderr, "%08i %2.010g %2.010g after op%i(%i)\n",
    585             //        iter, besterr - error, error, op1, pt);
    586             fprintf(stderr, "%08i -.%08i %2.010g after op%i(%i)\n", iter,
    587                     (int)((error - besterr) * 100000000), error, op1, pt);
    588             error = besterr;
    589             opstats[op1 * 2 + 1]++;
    590             //opstats[op2 * 2 + 1]++;
    591             failures = 0;
    592             success++;
    593 
    594             /* Save image! */
    595             //char buf[128];
    596             //sprintf(buf, "twit%08i.bmp", success);
    597             //if((success % 10) == 0)
    598             //    pipi_save(tmp, buf);
    599         }
    600         else
    601         {
    602             pipi_free(scrap);
    603             points[pt] = oldval;
    604             failures++;
    605         }
    606     }
    607 
    608     for(int j = 0; j < 2; j++)
    609     {
    610         fprintf(stderr,   "operation: ");
    611         for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++)
    612             fprintf(stderr, "%4i ", i);
    613         fprintf(stderr, "\nattempts:  ");
    614         for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++)
    615             fprintf(stderr, "%4i ", opstats[i * 2]);
    616         fprintf(stderr, "\nsuccesses: ");
    617         for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++)
    618             fprintf(stderr, "%4i ", opstats[i * 2 + 1]);
    619         fprintf(stderr, "\n");
    620     }
    621 
    622     fprintf(stderr, "Distance: %2.10g\n", error);
    623 
    624     dst = pipi_resize(tmp, width, height);
    625     pipi_free(tmp);
    626 
    627     /* Save image and bail out */
    628     pipi_save(dst, "lol.bmp");
    629     pipi_free(dst);
     921                double newerr = pipi_measure_rmsd(src, scrap);
     922                if(newerr < besterr)
     923                {
     924                    besterr = newerr;
     925                    bestop = i;
     926                }
     927            }
     928
     929            opstats[op1 * 2]++;
     930            //opstats[op2 * 2]++;
     931
     932            if(besterr < error)
     933            {
     934                points[pt] = candidates[bestop];
     935                /* Redraw image if the last check wasn't the best one */
     936                if(bestop != 2)
     937                    render(scrap, zonex * RANGE_X, zoney * RANGE_Y,
     938                           zonew * RANGE_X, zoneh * RANGE_Y);
     939
     940                pipi_free(tmp);
     941                tmp = scrap;
     942#if DEBUG
     943                fprintf(stderr, "%08i -.%08i %2.010g after op%i(%i)\n", iter,
     944                        (int)((error - besterr) * 100000000), error, op1, pt);
     945#endif
     946                error = besterr;
     947                opstats[op1 * 2 + 1]++;
     948                //opstats[op2 * 2 + 1]++;
     949                failures = 0;
     950                success++;
     951
     952                /* Save image! */
     953                //char buf[128];
     954                //sprintf(buf, "twit%08i.bmp", success);
     955                //if((success % 10) == 0)
     956                //    pipi_save(tmp, buf);
     957            }
     958            else
     959            {
     960                pipi_free(scrap);
     961                points[pt] = oldval;
     962                failures++;
     963            }
     964        }
     965
     966        fprintf(stderr, "\r                    \r");
     967
     968#if DEBUG
     969        for(int j = 0; j < 2; j++)
     970        {
     971            fprintf(stderr,   "operation: ");
     972            for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++)
     973                fprintf(stderr, "%4i ", i);
     974            fprintf(stderr, "\nattempts:  ");
     975            for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++)
     976                fprintf(stderr, "%4i ", opstats[i * 2]);
     977            fprintf(stderr, "\nsuccesses: ");
     978            for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++)
     979                fprintf(stderr, "%4i ", opstats[i * 2 + 1]);
     980            fprintf(stderr, "\n");
     981        }
     982
     983        fprintf(stderr, "Distance: %2.10g\n", error);
     984#endif
     985
     986#if 0
     987        dst = pipi_resize(tmp, width, height);
     988        pipi_free(tmp);
     989
     990        /* Save image and bail out */
     991        pipi_save(dst, "lol.bmp");
     992        pipi_free(dst);
     993#endif
     994
     995        /* Push our points to the bitstream */
     996        for(int i = 0; i < npoints; i++)
     997            b.push(points[i], RANGE_SYXRGB);
     998        b.push(height, MAX_H);
     999        b.push(width, MAX_W);
     1000
     1001        /* Pop Unicode characters from the bitstream and print them */
     1002        for(int i = 0; i < MAX_MSG_LEN; i++)
     1003            fwrite_utf8(stdout, index2uni(b.pop(NUM_CHARACTERS)));
     1004        fprintf(stdout, "\n");
     1005    }
     1006    else
     1007    {
     1008        /* Pop points from the bitstream */
     1009        for(int i = dw * dh; i--; )
     1010        {
     1011#if POINTS_PER_CELL == 2
     1012            points[i * 2 + 1] = b.pop(RANGE_SYXRGB);
     1013            points[i * 2] = b.pop(RANGE_SYXRGB);
     1014#else
     1015            points[i] = b.pop(RANGE_SYXRGB);
     1016#endif
     1017        }
     1018        npoints = dw * dh * POINTS_PER_CELL;
     1019
     1020        /* Render these points to a new image */
     1021        tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y);
     1022        render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y);
     1023
     1024        /* TODO: render directly to the final image; scaling sucks */
     1025        dst = pipi_resize(tmp, width, height);
     1026        pipi_free(tmp);
     1027
     1028        /* Save image and bail out */
     1029        pipi_save(dst, argv[2]);
     1030        pipi_free(dst);
     1031    }
    6301032
    6311033    return ret;
Note: See TracChangeset for help on using the changeset viewer.