Is reviewing AI even possible? – colin@colino.net
Skip to content
colin@colino.net
2026/08/16<br>About 10 minutes read
Earlier today, I shared a 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) {<br>unsigned char i, x, y;<br>char input_bytes[80];<br>char full_bytes[160];
/* 80 bytes encode two lines. Pixels are described in blocks of 2x2, using<br>* two bytes (four nibbles) per block, with a weird layout. */<br>for (y = 0; y 79<br>* abababababababababababababababababababababababababababababababababababababababab even line<br>* cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd odd line<br>* Those four a/b/c/d values come from the input buffer (160 bytes large) as follows:<br>* abcabcabcabc...abcddd...ddd<br>* where the first 120 bytes contain the 40 a,b,c triplets and the last 40 bytes contain the 40 d.<br>* But. I don't think the 160 values directly encode pixel values, as the output is not clean.<br>* There must be a transformation.<br>*/<br>for (i = 0, x = 0; i
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) {<br>unsigned char i, j, x, y;<br>char input_bytes[80];
/* 80 bytes encode one 40 pixels line. Pixels are described in blocks of<br>* 16 bits, with a weird layout. */<br>for (y = 0; y
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, #define QW 40 /* quads across */<br>#define QH 30 /* quads down */<br>#define NQUADS (QW * QH)<br>#define IW (QW * 2) /* 80 luma samples across */<br>#define IH (QH * 2) /* 60 luma samples down */<br>#define THUMB_BYTES 2400
/* plane[0..3] = the a, b, c, d sample of every quad, each 0..15.<br>* a = top-left, b = top-right, c = bottom-left, d = bottom-right. */<br>static unsigned char plane[4][NQUADS];
/* Relative sensitivity of the four filter positions. Dividing each plane by its<br>* gain and subtracting its offset is what removes the 2x2 checkerboard. */<br>static const double CFA_GAIN[4] = { 1.118, 0.979, 0.992, 0.910 };<br>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).<br>* Fitted least-squares over 1200 quads; R^2 = 0.937, 0.887, 0.786.<br>* The large opposing coefficients are the chroma amplification described above. */<br>static const double CCM[3][5] = {<br>{ 15.602, -7.763, -0.626, 8.720, 5.059 }, /* R */<br>{ -8.812, 15.116, -1.019, 8.402, 22.012 }, /* G */<br>{ -11.359, 9.929, 6.424, 6.018, 4.753 } /* B */<br>};
/* ------------------------------------------------------------------ */<br>/* Unpacking -- unchanged from the original, which had this right */<br>/* ------------------------------------------------------------------ */
static int unpack(const char *path)<br>unsigned char band[80], nib[160];<br>FILE *fp;<br>long sz;<br>int b, i, k, q = 0;
fp = fopen(path, "rb");<br>if (!fp) {<br>fprintf(stderr, "can't open %s (%s)\n", path, strerror(errno));<br>return -1;<br>if (fseek(fp, 0, SEEK_END) == 0) {<br>sz = ftell(fp);<br>if (sz != THUMB_BYTES)<br>fprintf(stderr, "warning: %s is %ld bytes, expected %d\n",<br>path, sz, THUMB_BYTES);<br>rewind(fp);
for (b = 0; b 160 nibbles, high nibble first */<br>for (i = 0; i > 4) & 0x0F;<br>nib[i * 2 + 1] = band[i] & 0x0F;<br>/* nibbles 0..119 are 40 x (a,b,c); nibbles 120..159 are the 40 d */<br>for (k = 0; k...