fs2port/port/tools/sampleRow.c
2026-05-13 21:32:05 -05:00

107 lines
3.7 KiB
C

// sampleRow: print color symbols at sampled X positions for a Y range.
// Reads PPM (P6) images. Used to visually inspect specific rows of a
// rendered scene without ever Read'ing the PNG file (which the user has
// banned for context-corruption reasons).
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int readToken(FILE *f, char *buf, size_t sz) {
int c;
while ((c = fgetc(f)) != EOF) {
if (c == '#') {
while ((c = fgetc(f)) != EOF && c != '\n') {}
continue;
}
if (!isspace(c)) {
break;
}
}
if (c == EOF) {
return -1;
}
size_t i = 0;
do {
if (i + 1 >= sz) {
return -1;
}
buf[i++] = (char)c;
c = fgetc(f);
} while (c != EOF && !isspace(c));
buf[i] = '\0';
return (int)i;
}
int main(int argc, char **argv) {
if (argc < 4) {
fprintf(stderr, "usage: %s img.ppm yStart yEnd [scaleY]\n", argv[0]);
return 2;
}
FILE *f = fopen(argv[1], "rb");
if (f == NULL) {
fprintf(stderr, "cannot open %s\n", argv[1]);
return 1;
}
char tok[32];
if (readToken(f, tok, sizeof(tok)) < 0 || strcmp(tok, "P6") != 0) {
fprintf(stderr, "not P6\n");
fclose(f);
return 1;
}
readToken(f, tok, sizeof(tok)); int w = atoi(tok);
readToken(f, tok, sizeof(tok)); int h = atoi(tok);
readToken(f, tok, sizeof(tok));
unsigned char *p = malloc((size_t)w * h * 3);
if (p == NULL || fread(p, 1, (size_t)w * h * 3, f) != (size_t)w * h * 3) {
fclose(f);
free(p);
return 1;
}
fclose(f);
int yStart = atoi(argv[2]);
int yEnd = atoi(argv[3]);
int scaleY = (argc > 4) ? atoi(argv[4]) : (h / 192);
int sampleW = (w >= 70) ? 70 : w;
int xStep = w / sampleW;
for (int hy = yStart; hy <= yEnd; hy++) {
int sy = hy * scaleY + scaleY/2;
if (sy >= h) {
break;
}
printf("y=%3d: ", hy);
for (int sx = 0; sx < w && sx < sampleW * xStep; sx += xStep) {
unsigned char *px = &p[((size_t)sy * w + sx) * 3];
int r = px[0];
int g = px[1];
int b = px[2];
char c;
if (r < 30 && g < 30 && b < 30) {
c = '.';
} else if (b > r + 30 && b > g + 30) {
c = 'B';
} else if (g > r + 30 && g > b + 30) {
c = 'G';
} else if (r > 200 && g > 200 && b > 200) {
c = 'W';
} else if (r > 100 && b > 100 && g < (r + b) / 4) {
c = 'V';
} else if (r > 200 && g > 100 && b < 80) {
c = 'O';
} else if (r > 100 && b > 100) {
c = 'M';
} else if (g > 100 && b > 100) {
c = 'C';
} else {
c = '?';
}
putchar(c);
}
putchar('\n');
}
free(p);
return 0;
}