// Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. // See LICENSE.md for license information. // SPDX-License-Identifier: MIT // // pngProbe.c - small questions the gates ask of a screenshot. // // pngProbe size PNG prints WxH // pngProbe pixel PNG X Y prints R G B // pngProbe count PNG X Y W H R G B prints how many of the W x H // pixels from (X, Y) are R G B // // pixel fails (exit 1) when the point is off the screenshot; count counts // only the part of its box on it. A bad command line exits 2. #include #include #include "gateArg.h" #include "gateImage.h" #include "toolFile.h" #define TOOL_NAME "pngProbe" #define SAMPLE_MAX 255 // The arguments after a mode's name: the screenshot, a point, a box's // size, and a colour. #define ARG_PNG 0u #define ARG_X 1u #define ARG_Y 2u #define ARG_W 3u #define ARG_H 4u #define ARG_RGB 5u static int probeCount(char **args); static int probePixel(char **args); static int probeSize(char **args); static const GateModeT kModes[] = { { "size", 1, probeSize }, { "pixel", 3, probePixel }, { "count", 8, probeCount } }; static const char *const kGunNames[GATE_RGB_BYTES] = { "red", "green", "blue" }; static const char *const kUsage[] = { "usage:", " pngProbe size PNG prints WxH", " pngProbe pixel PNG X Y prints R G B", " pngProbe count PNG X Y W H R G B prints how many of the W x H pixels", " from (X, Y) are R G B" }; static int probeCount(char **args) { GateImageT img; uint8_t want[GATE_RGB_BYTES]; long x0; long y0; long w; long h; long x; long y; long count; long gun; uint32_t i; x0 = gateArgLong("x", args[ARG_X]); y0 = gateArgLong("y", args[ARG_Y]); w = gateArgLong("width", args[ARG_W]); h = gateArgLong("height", args[ARG_H]); for (i = 0; i < GATE_RGB_BYTES; i++) { gun = gateArgLong(kGunNames[i], args[ARG_RGB + i]); if (gun < 0 || gun > SAMPLE_MAX) { gateArgBad(kGunNames[i], args[ARG_RGB + i]); } want[i] = (uint8_t)gun; } gateImageLoad(args[ARG_PNG], &img); count = 0; for (y = (y0 < 0) ? 0 : y0; y < y0 + h && y < (long)img.height; y++) { for (x = (x0 < 0) ? 0 : x0; x < x0 + w && x < (long)img.width; x++) { if (memcmp(gateImagePixel(&img, (uint32_t)x, (uint32_t)y), want, GATE_RGB_BYTES) == 0) { count++; } } } printf("%ld\n", count); gateImageFree(&img); return 0; } static int probePixel(char **args) { GateImageT img; const uint8_t *rgb; long x; long y; x = gateArgLong("x", args[ARG_X]); y = gateArgLong("y", args[ARG_Y]); gateImageLoad(args[ARG_PNG], &img); if (!gateImageHas(&img, x, y)) { toolFail("%ld,%ld is off the %ux%u screenshot", x, y, (unsigned)img.width, (unsigned)img.height); } rgb = gateImagePixel(&img, (uint32_t)x, (uint32_t)y); printf("%u %u %u\n", (unsigned)rgb[0], (unsigned)rgb[1], (unsigned)rgb[2]); gateImageFree(&img); return 0; } static int probeSize(char **args) { GateImageT img; gateImageLoad(args[ARG_PNG], &img); printf("%ux%u\n", (unsigned)img.width, (unsigned)img.height); gateImageFree(&img); return 0; } int main(int argc, char **argv) { int exitCode; toolFileName(TOOL_NAME); if (!gateModeRun(kModes, GATE_COUNT_OF(kModes), argc, argv, &exitCode)) { return gateUsage(kUsage, GATE_COUNT_OF(kUsage)); } return exitCode; }