Changeset 2212 for www/labs


Ignore:
Timestamp:
Jan 23, 2008, 12:32:01 AM (15 years ago)
Author:
Sam Hocevar
Message:
  • Add support for inverse video on attribute change.
  • Improve Floyd-Steinberg coefficient values.
Location:
www/labs
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • www/labs/img2oric.c

    r2209 r2212  
    55 *
    66 *  $Id$
     7 *
     8 *  Changes:
     9 *   Jan 18, 2008: initial release
     10 *   Jan 23, 2008: add support for inverse video on attribute change
     11 *                 improve Floyd-Steinberg coefficient values
    712 *
    813 *  This program is free software. It comes without any warranty, to
     
    2833/*
    2934 * Image dimensions and recursion depth. DEPTH = 2 is a reasonable value,
    30  * higher values may improve the results but at the cost of significantly
    31  * longer computation times.
     35 * DEPTH = 3 gives good quality, and higher values may improve the results
     36 * even more but at the cost of significantly longer computation times.
    3237 */
    3338#define WIDTH 240
     
    5257 *     +-------+-------+-------+
    5358 */
    54 #define FS0 12
     59#define FS0 15
    5560#define FS1 6
    56 #define FS2 12
     61#define FS2 9
    5762#define FS3 1
    5863#define FSX 32
     
    114119static inline void domove(uint8_t move, uint8_t *bg, uint8_t *fg)
    115120{
    116     if(move < 8)
    117         *bg = move;
    118     else if(move < 16)
    119         *fg = move - 8;
     121    if(move < 16)
     122        *fg = move & 0x7;
     123    else if(move < 32)
     124        *bg = move & 0x7;
     125}
     126
     127/*
     128 * Clamp pixel value to avoid colour bleeding. Deactivated because it
     129 * does not give satisfactory results.
     130 */
     131#define CLAMP 0x1000
     132static inline int clamp(int p)
     133{
     134#if 0
     135    /* FIXME: doesn’t give terribly good results on eg. eatme.png */
     136    if(p < - CLAMP) return - CLAMP;
     137    if(p > 0xffff + CLAMP) return 0xffff + CLAMP;
     138#endif
     139    return p;
    120140}
    121141
     
    144164        {
    145165            /* Experiment shows that this is important at small depths */
    146             int a = in[i * 3 + c] + tmperr[c];
     166            int a = clamp(in[i * 3 + c] + tmperr[c]);
    147167            int b = out[i * 3 + c];
    148168            tmperr[c] = (a - b) * FS0 / FSX;
     
    182202                        int *error, int *out)
    183203{
    184     int voidvec[3], bestrgb[6 * 3], tmprgb[6 * 3], tmpvec[3];
    185     int const *voidrgb, *vec, *rgb;
    186     int besterror, curerror, suberror, statice, voide;
     204    int voidvec[3], nvoidvec[3], bestrgb[6 * 3], tmprgb[6 * 3], tmpvec[3];
     205    int const *voidrgb, *nvoidrgb, *vec, *rgb;
     206    int besterror, curerror, suberror, statice, voide, nvoide;
    187207    int i, c;
    188208    uint8_t command, bestcommand;
    189209
    190     /* Precompute error for the case where we don’t print pixels */
     210    /* Precompute error for the case where we change the foreground colour
     211     * and hence only print the background colour or its negative */
    191212    voidrgb = palette[bg];
    192213    voide = geterror(in, errvec, voidrgb, voidvec);
     214    nvoidrgb = palette[7 - bg];
     215    nvoide = geterror(in, errvec, nvoidrgb, nvoidvec);
    193216
    194217    /* Precompute sub-error for the case where we print pixels (and hence
     
    202225
    203226    /* Check every likely command:
    204      * 0-7: change background to 0-7
    205      * 8-15: change foreground to 0-7
    206      * 16: normal stuff
    207      * 17: inverse video stuff */
     227     * 0-7: change foreground to 0-7
     228     * 8-15: change foreground to 0-7, print negative background
     229     * 16-23: change background to 0-7
     230     * 24-31: change background to 0-7, print negative background
     231     * 32: normal stuff
     232     * 33: inverse video stuff */
    208233    besterror = 0x7ffffff;
    209234    bestcommand = 16;
    210235    memcpy(bestrgb, voidrgb, 6 * 3 * sizeof(int));
    211     for(command = 0; command < 18; command++)
    212     {
    213         if(command < 16)
     236    for(command = 0; command < 34; command++)
     237    {
     238        uint8_t newbg = bg, newfg = fg;
     239        domove(command, &newbg, &newfg);
     240
     241        /* Keeping bg and fg is useless, because we could use commands
     242         * 32 and 33 instead */
     243        if(command < 32 && newbg == bg && newfg == fg)
     244            continue;
     245
     246        /* I *think* having newfg == newbg is useless, too, but I don’t
     247         * want to miss some corner case where swapping bg and fg may be
     248         * interesting, so we continue anyway. */
     249
     250        if(command < 8)
    214251        {
    215252            curerror = voide;
     
    217254            vec = voidvec;
    218255        }
     256        else if(command < 16)
     257        {
     258            curerror = nvoide;
     259            rgb = nvoidrgb;
     260            vec = nvoidvec;
     261        }
     262        else if(command < 24)
     263        {
     264            rgb = palette[newbg];
     265            curerror = geterror(in, errvec, rgb, tmpvec);
     266            vec = tmpvec;
     267        }
     268        else if(command < 32)
     269        {
     270            rgb = palette[7 - newbg];
     271            curerror = geterror(in, errvec, rgb, tmpvec);
     272            vec = tmpvec;
     273        }
    219274        else
    220275        {
    221276            int const *bgcolor, *fgcolor;
    222277
    223             bgcolor = palette[bg + (command - 16) * (7 - 2 * bg)];
    224             fgcolor = palette[fg + (command - 16) * (7 - 2 * fg)];
     278            if(command == 32)
     279            {
     280                bgcolor = palette[bg]; fgcolor = palette[fg];
     281            }
     282            else
     283            {
     284                bgcolor = palette[7 - bg]; fgcolor = palette[7 - fg];
     285            }
    225286
    226287            memcpy(tmpvec, errvec, 3 * sizeof(int));
     
    237298                {
    238299                    int delta1, delta2;
    239                     delta1 = in[i * 3 + c] + tmpvec[c] - bgcolor[c];
     300                    delta1 = clamp(in[i * 3 + c] + tmpvec[c]) - bgcolor[c];
    240301                    vec1[c] = delta1 * FS0 / FSX;
    241302                    smalle1 += delta1 / 256 * delta1;
    242                     delta2 = in[i * 3 + c] + tmpvec[c] - fgcolor[c];
     303                    delta2 = clamp(in[i * 3 + c] + tmpvec[c]) - fgcolor[c];
    243304                    vec2[c] = delta2 * FS0 / FSX;
    244305                    smalle2 += delta2 / 256 * delta2;
     
    274335        if(depth == 0)
    275336            suberror = 0; /* It’s the end of the tree */
    276         else if(command < 16)
    277         {
    278             uint8_t newbg = bg, newfg = fg;
    279             domove(command, &newbg, &newfg);
    280             /* Keeping bg and fg is useless, because we could use commands
    281              * 16 and 17 instead */
    282             if(newbg == bg && newfg == fg)
    283                 continue;
    284 
     337        else if(command < 32)
     338        {
    285339            bestmove(in + 6 * 3, newbg, newfg, vec, depth - 1,
    286340                     besterror - curerror, &suberror, NULL);
    287341
     342#if 0
    288343            /* Penalty for background changes; they're hard to revert. The
    289344             * value of 2 was determined empirically. 1.5 is not enough and
     
    291346            if(newbg != bg)
    292347                suberror *= 2;
     348#endif
    293349        }
    294350        else
     
    373429                {
    374430                    int error = srcl[i * 3 + c] - dstl[i * 3 + c];
    375                     srcl[i * 3 + c + 3] += error * FS0 / FSX;
     431                    srcl[i * 3 + c + 3] =
     432                            clamp(srcl[i * 3 + c + 3] + error * FS0 / FSX);
    376433                    srcl[i * 3 + c + stride - 3] += error * FS1 / FSX;
    377434                    srcl[i * 3 + c + stride] += error * FS2 / FSX;
    378435                    srcl[i * 3 + c + stride + 3] += error * FS3 / FSX;
    379436                }
     437
     438                for(i = -1; i < 7; i++)
     439                    srcl[i * 3 + c + stride] = clamp(srcl[i * 3 + c + stride]);
    380440            }
    381441            /* Iterate */
  • www/labs/img2oric.html

    r2210 r2212  
    3131
    3232<p> The graphical part of the Oric screen has 240×200 pixels and can only
    33 display 8 different colours (black, blue, red, green, cyan, magenta, yellow and
    34 white). Each horizontal group of 6 pixels can only use two different colours:
    35 either the foreground and the background colours, or the negative values
    36 thereof. The background <i>or</i> the foreground colour may also be changed
    37 (one at a time), but while doing so the next 6 pixels cannot be chosen: they
    38 will use the background colour instead. </p>
     33display 8 different colours (black, blue, red, green, cyan, magenta, yellow
     34and white). Each horizontal group of 6 pixels can only use two different
     35colours: the foreground and the background colours. The background <i>or</i>
     36the foreground colour may also be changed (one at a time), but while doing
     37so the next 6 pixels cannot be chosen: they will use the background colour
     38instead. Finally, a special bit may be activated to display the current group
     39of pixels in reverse video. </p>
    3940
    4041<h2 style="clear: both;"> Downloads </h2>
     
    4243<p> No downloads are available yet. However, the file <tt><a
    4344href="img2oric.c">img2oric.c</a></tt> may be compiled on Linux to obtain an
    44 almost functional, yet extremely slow (around 1 minute to process an image on a
    45 modern computer) program. </p>
     45almost functional, yet extremely slow (around 2 minutes to process an image on
     46a modern computer) program. </p>
    4647
    4748<h2> Screenshots </h2>
     
    8990
    9091<p> The following images use real Oric artwork, taken from the Buggy Boy
    91 and the VIP 4 demos. As can be seen, the result is not perfect, but is still
    92 rather acceptable. </p>
     92and the VIP 4 demos: they are almost pixel-perfect. </p>
    9393
    9494<p style="text-align: center;">
     
    110110</p>
    111111
     112<h2> Credits </h2>
     113
     114<p> <tt>img2oric</tt> was written by Sam Hocevar. Thanks to Jean-Yves
     115Lamoureux, Mickaël Pointier, Robert Chéramy and Fabrice Frances for their
     116help, their work and the information they provided. </p>
     117
    112118<?php $rev = '$Id$';
    113119      include($_SERVER['DOCUMENT_ROOT'].'/footer.inc'); ?>
Note: See TracChangeset for help on using the changeset viewer.