# Is reviewing AI even possible?

> Source: <https://www.colino.net/wordpress/archives/2026/08/16/is-reviewing-ai-even-possible/>
> Published: 2026-08-17 20:00:30+00:00

Earlier today, I [shared a challenge](/wordpress/archives/2026/08/16/thumbnail-decoding-challenge/). I couldn’t figure out the data encoding in those thumbnails, and I hoped someone well versed in image processing would have ideas. I also feared someone would feed it to an AI and dump me the results.

Well, both happened! One person, Henry, figured out and explained the storage format to me, and I updated my algorithm from his explanation. His explanation was: “It’s actually 40*30 pixels instead of 80*60; and it encodes each pixel in 16 bits, RGGB (4/8/4 bits), in strides of 80 bytes consisting of 40*RGG then 40*B”.

Another person submitted the problem to Claude, and gave me the resulting code.

The code works. It also has implemented a few options, for some reason… but I didn’t use it. I would still be trying to understand the blob of code that Claude regurgitated if Henry hadn’t given me a good explanation.

I tried dismantling Claude’s code to the bare minimum that would work and not have twelve bells and whistles, but it was horribly complicated for absolutely no reason. That really makes me wonder how people who use AI and claim to review its output do it. This is **much more work** than doing it oneself.

I will let you compare.

## The original version

This algorithm was wrongly assuming 4 bits per pixels, but got the stride (60/20 bytes) right:

```
void render_thumbnail(FILE *fp, int w, int h, SDL_Surface *screen) {
  unsigned char i, x, y;
  char input_bytes[80];
  char full_bytes[160];

  /* 80 bytes encode two lines. Pixels are described in blocks of 2x2, using
   * two bytes (four nibbles) per block, with a weird layout. */
  for (y = 0; y < 60; y+=2) {
    /* Read two lines' worth of data */
    fread(input_bytes, 1, 80, fp);

    /* First of all, convert nibbles to full bytes, for simplicity's sake.
     * they're 0-15, we'll shift them << 4 so that they have a usable value. */
    for (i = 0; i < w; i++) {
      unsigned char c           = input_bytes[i];
      unsigned char high_nibble = c & 0xF0;
      unsigned char low_nibble  = c << 4;
      full_bytes[i*2]           = high_nibble;
      full_bytes[i*2 + 1]       = low_nibble;
    }

    /* Now for the fun part. We have 160 bytes, encoding two lines. I
     * figured out that they're encoded in blocks of 2x2, like this,
     * where each block is indicated as ab/cd:
     *
     * 0 <---                            line width                               --> 79
     * abababababababababababababababababababababababababababababababababababababababab     even line
     * cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd     odd line
     *
     * Those four a/b/c/d values come from the input buffer (160 bytes large) as follows:
     * abcabcabcabc...abcddd...ddd
     * where the first 120 bytes contain the 40 a,b,c triplets and the last 40 bytes contain the 40 d.
     *
     * But. I don't think the 160 values directly encode pixel values, as the output is not clean.
     * There must be a transformation.
     *
     */
    for (i = 0, x = 0; i < (w*3)/2; i += 3, x += 2) {
      unsigned char pixel_a, pixel_b, pixel_c, pixel_d;

      pixel_a = full_bytes[i];
      pixel_b = full_bytes[i+1];
      pixel_c = full_bytes[i+2];
      pixel_d = full_bytes[120 + i/3];
      PIXEL_OUTPUT(x,   y,   pixel_a);
      PIXEL_OUTPUT(x+1, y,   pixel_b);
      PIXEL_OUTPUT(x,   y+1, pixel_c);
      PIXEL_OUTPUT(x+1, y+1, pixel_d);
    }
  }
}
```

## The correct algorithm

This version decodes a thumbnail correctly. It does nothing more as nobody asked it to do anything more.

```
void render_thumbnail(FILE *fp, int w, int h, SDL_Surface *screen) {
  unsigned char i, j, x, y;
  char input_bytes[80];

  /* 80 bytes encode one 40 pixels line. Pixels are described in blocks of
   * 16 bits, with a weird layout. */
  for (y = 0; y < 60; y+=2) {
    /* Read two lines' worth of data */
    fread(input_bytes, 1, 80, fp);

    /* Now for the fun part. We have 80 bytes, encoding 40 pixels. They
     * are encoded as RGGB (4/8/4 bits), and ordered as 40*RGG then 40*B.
     */
    for (i = 0, x = 0; i < 60;) {
      unsigned char r, g, b;

      r = (input_bytes[i] & 0xF0);
      g = (input_bytes[i] & 0x0F) | (input_bytes[i+1] & 0xF0);
      b = (input_bytes[60 + i/3] & 0x0F) << 4;
      PIXEL_OUTPUT(x,   y,   r, g, g);
      PIXEL_OUTPUT(x+1, y,   r, g, g);
      PIXEL_OUTPUT(x,   y+1, r, g, g);
      PIXEL_OUTPUT(x+1, y+1, r, g, g);
      i += 2;
      x += 2;

      r = (input_bytes[i-1] & 0x0F) << 4;
      g = input_bytes[i];
      b = (input_bytes[60 + i/3] & 0xF0);

      PIXEL_OUTPUT(x,   y,   r, g, g);
      PIXEL_OUTPUT(x+1, y,   r, g, g);
      PIXEL_OUTPUT(x,   y+1, r, g, g);
      PIXEL_OUTPUT(x+1, y+1, r, g, g);
      i += 1;
      x += 2;
    }
  }
}
```

## Claude’s algorithm

Claude’s algorithm also works. Given the correct flags, it does output vaguely the same thumbnail as the correct algorithm (the colors are more saturated). I am not even sure it is correct, as I didn’t test it with other thumbnails. It does not make its potential correctness clear. It outputs different variations with different flags. It replaced the SDL display with a PNG writer. And I am sorry to inform you that it is **not** contained in a single, < 50 lines function. I **did** remove the plumbing, main(), and the PNG writer from this paste:

```
#define QW      40                  /* quads across            */
#define QH      30                  /* quads down              */
#define NQUADS  (QW * QH)
#define IW      (QW * 2)            /* 80 luma samples across  */
#define IH      (QH * 2)            /* 60 luma samples down    */
#define THUMB_BYTES 2400

/* plane[0..3] = the a, b, c, d sample of every quad, each 0..15.
 * a = top-left, b = top-right, c = bottom-left, d = bottom-right. */
static unsigned char plane[4][NQUADS];

/* Relative sensitivity of the four filter positions. Dividing each plane by its
 * gain and subtracting its offset is what removes the 2x2 checkerboard. */
static const double CFA_GAIN[4]   = { 1.118, 0.979, 0.992, 0.910 };
static const double CFA_OFFSET[4] = { 0.482, -0.267, -0.480, 0.265 };

/* Colour correction matrix: display-referred R, G, B from (a, b, c, d, 1).
 * Fitted least-squares over 1200 quads; R^2 = 0.937, 0.887, 0.786.
 * The large opposing coefficients are the chroma amplification described above. */
static const double CCM[3][5] = {
  { 15.602, -7.763, -0.626, 8.720,  5.059 },   /* R */
  { -8.812, 15.116, -1.019, 8.402, 22.012 },   /* G */
  { -11.359, 9.929,  6.424, 6.018,  4.753 }    /* B */
};

/* ------------------------------------------------------------------ */
/* Unpacking -- unchanged from the original, which had this right     */
/* ------------------------------------------------------------------ */

static int unpack(const char *path)
{
  unsigned char band[80], nib[160];
  FILE *fp;
  long sz;
  int b, i, k, q = 0;

  fp = fopen(path, "rb");
  if (!fp) {
    fprintf(stderr, "can't open %s (%s)\n", path, strerror(errno));
    return -1;
  }
  if (fseek(fp, 0, SEEK_END) == 0) {
    sz = ftell(fp);
    if (sz != THUMB_BYTES)
      fprintf(stderr, "warning: %s is %ld bytes, expected %d\n",
              path, sz, THUMB_BYTES);
    rewind(fp);
  }

  for (b = 0; b < QH; b++) {
    if (fread(band, 1, 80, fp) != 80) {
      fprintf(stderr, "short read at band %d\n", b);
      fclose(fp);
      return -1;
    }
    /* 80 bytes -> 160 nibbles, high nibble first */
    for (i = 0; i < 80; i++) {
      nib[i * 2]     = (band[i] >> 4) & 0x0F;
      nib[i * 2 + 1] =  band[i]       & 0x0F;
    }
    /* nibbles 0..119 are 40 x (a,b,c); nibbles 120..159 are the 40 d */
    for (k = 0; k < QW; k++, q++) {
      plane[0][q] = nib[k * 3];
      plane[1][q] = nib[k * 3 + 1];
      plane[2][q] = nib[k * 3 + 2];
      plane[3][q] = nib[120 + k];
    }
  }
  fclose(fp);
  return 0;
}

/* ------------------------------------------------------------------ */
/* Decoding                                                           */
/* ------------------------------------------------------------------ */

static double clampd(double v, double lo, double hi)
{
  return v < lo ? lo : (v > hi ? hi : v);
}

/* Per-position corrected sample, 0..15. This is the checkerboard fix. */
static double corrected(int p, int q)
{
  return clampd((plane[p][q] - CFA_OFFSET[p]) / CFA_GAIN[p], 0.0, 15.0);
}

/* Per-quad colour, 0..255, optionally grey-world balanced. */
static void quad_colour(double wb[3], double out[NQUADS][3])
{
  int q, c;
  for (q = 0; q < NQUADS; q++) {
    for (c = 0; c < 3; c++) {
      double v = CCM[c][0] * plane[0][q] + CCM[c][1] * plane[1][q]
               + CCM[c][2] * plane[2][q] + CCM[c][3] * plane[3][q]
               + CCM[c][4];
      out[q][c] = clampd(v * wb[c], 0.0, 255.0);
    }
  }
}

/* Bilinear sample of the 40x30 colour grid at quad-space position (u, v). */
static double bilerp(double grid[NQUADS][3], int c, double u, double v)
{
  int x0, y0, x1, y1;
  double fx, fy, a, b;

  u = clampd(u, 0.0, QW - 1.0);
  v = clampd(v, 0.0, QH - 1.0);
  x0 = (int)floor(u); y0 = (int)floor(v);
  x1 = x0 + 1 < QW ? x0 + 1 : x0;
  y1 = y0 + 1 < QH ? y0 + 1 : y0;
  fx = u - x0; fy = v - y0;

  a = grid[y0 * QW + x0][c] * (1.0 - fx) + grid[y0 * QW + x1][c] * fx;
  b = grid[y1 * QW + x0][c] * (1.0 - fx) + grid[y1 * QW + x1][c] * fx;
  return a * (1.0 - fy) + b * fy;
}

/* Build the 80x60 RGB image.
 * Colour comes from the interpolated 40x30 grid; the 2x2 detail the format
 * still carries is reapplied as a luma ratio inside each quad. */
static void decode_colour(unsigned char *rgb, int grey_world, int smooth)
{
  static double grid[NQUADS][3];
  double wb[3] = { 1.0, 1.0, 1.0 };
  int q, p, c, x, y;

  if (grey_world) {
    double sum[3] = { 0, 0, 0 }, mx = 0;
    static double tmp[NQUADS][3];
    double unit[3] = { 1.0, 1.0, 1.0 };
    quad_colour(unit, tmp);
    for (q = 0; q < NQUADS; q++)
      for (c = 0; c < 3; c++) sum[c] += tmp[q][c];
    for (c = 0; c < 3; c++) { sum[c] /= NQUADS; if (sum[c] > mx) mx = sum[c]; }
    for (c = 0; c < 3; c++) wb[c] = sum[c] > 1e-6 ? mx / sum[c] : 1.0;
  }
  quad_colour(wb, grid);

  /* Colour is inherently 40x30: the four samples of a quad are four colour
   * measurements of one 2x2 cell, not four independent luma samples.
   *
   * An earlier version of this function tried to recover 80x60 detail by
   * modulating each quad's colour with the per-position luma ratio
   * L[p]/mean(L). That reintroduces the checkerboard, because after the
   * gain/offset correction what remains of the spread between a, b, c and d is
   * mostly chroma, not spatial detail. Painting chroma as luma is the original
   * bug in a new place. The honest output is one colour per quad, interpolated.
   */
  for (q = 0; q < NQUADS; q++) {
    int qx = q % QW, qy = q / QW;
    for (p = 0; p < 4; p++) {
      x = qx * 2 + (p & 1);
      y = qy * 2 + (p >> 1);
      for (c = 0; c < 3; c++) {
        double base = smooth
          ? bilerp(grid, c, (x + 0.5) / 2.0 - 0.5, (y + 0.5) / 2.0 - 0.5)
          : grid[q][c];
        rgb[(y * IW + x) * 3 + c] =
          (unsigned char)(clampd(base, 0.0, 255.0) + 0.5);
      }
    }
  }
}

/* Clean greyscale: luma of the reconstructed colour. Because the colour matrix
 * has already accounted for each position's chroma, this is free of the
 * checkerboard even on strongly coloured areas. Effectively 40x30. */
static void decode_grey(unsigned char *rgb, int smooth)
{
  static double grid[NQUADS][3];
  double wb[3] = { 1.0, 1.0, 1.0 };
  int q, p, c, x, y;

  quad_colour(wb, grid);
  for (q = 0; q < NQUADS; q++) {
    int qx = q % QW, qy = q / QW;
    for (p = 0; p < 4; p++) {
      double r, g, b, v;
      x = qx * 2 + (p & 1);
      y = qy * 2 + (p >> 1);
      if (smooth) {
        double u = (x + 0.5) / 2.0 - 0.5, t = (y + 0.5) / 2.0 - 0.5;
        r = bilerp(grid, 0, u, t); g = bilerp(grid, 1, u, t); b = bilerp(grid, 2, u, t);
      } else {
        r = grid[q][0]; g = grid[q][1]; b = grid[q][2];
      }
      v = clampd(0.299 * r + 0.587 * g + 0.114 * b, 0.0, 255.0);
      for (c = 0; c < 3; c++) rgb[(y * IW + x) * 3 + c] = (unsigned char)(v + 0.5);
    }
  }
}

/* 80x60 greyscale from the per-position gain/offset correction alone.
 * Sharper than mode "grey" because it uses all four samples as separate
 * pixels, but residual checkerboard remains wherever the scene is strongly
 * coloured (look at the red tank top in the reference frame), since the
 * spread between positions there is chroma rather than detail. */
static void decode_grey80(unsigned char *rgb)
{
  int q, p, c;
  for (q = 0; q < NQUADS; q++) {
    int qx = q % QW, qy = q / QW;
    for (p = 0; p < 4; p++) {
      int x = qx * 2 + (p & 1), y = qy * 2 + (p >> 1);
      unsigned char v = (unsigned char)(corrected(p, q) / 15.0 * 255.0 + 0.5);
      for (c = 0; c < 3; c++) rgb[(y * IW + x) * 3 + c] = v;
    }
  }
}

/* The four planes side by side, as a 80x60 diagnostic. */
static void decode_planes(unsigned char *rgb)
{
  int p, x, y, c;
  for (p = 0; p < 4; p++) {
    int ox = (p % 2) * QW, oy = (p / 2) * QH;
    for (y = 0; y < QH; y++)
      for (x = 0; x < QW; x++) {
        unsigned char v = (unsigned char)(plane[p][y * QW + x] / 15.0 * 255.0 + 0.5);
        for (c = 0; c < 3; c++) rgb[((oy + y) * IW + ox + x) * 3 + c] = v;
      }
  }
}
```

## Seriously, how is that progress?

For comparison, a screenshot of my editor, zoomed out, with my algorithm selected in the left pane and Claude’s in the right pane:
