Select › Color Range: sampled colours, Fuzziness, Invert, a live preview and the panel (13.3b)

This commit is contained in:
ZacharyZhang-NY committed 2026-10-01 06:30:26 -04:00
1 parent 462fe805b1
commit 0b7eb6cb6f
29 files changed
+1535 -71

No files matched your search

+31
View File
@@ -172,3 +172,34 @@ fail:
free(lens);
return -1;
}
static inline int color_near(const int *rgb, const uint8_t *colors, int count, int fuzziness) {
for (int i = 0; i < count; ++i) {
const uint8_t *c = colors + i * 3;
if (abs(rgb[0] - c[0]) <= fuzziness && abs(rgb[1] - c[1]) <= fuzziness && abs(rgb[2] - c[2]) <= fuzziness) return 1;
}
return 0;
}
long color_range_mask(const uint8_t *rgba, size_t width, size_t height, size_t stride,
const uint8_t *include, int includeCount, const uint8_t *exclude, int excludeCount,
int fuzziness, int invert, uint8_t *mask) {
long count = 0;
for (size_t y = 0; y < height; ++y) {
const uint8_t *row = rgba + y * stride;
uint8_t *out = mask + y * width;
for (size_t x = 0; x < width; ++x) {
const uint8_t *px = row + x * 4;
int matches = 0;
if (px[3]) {
int rgb[3];
for (int c = 0; c < 3; ++c) rgb[c] = (px[c] * 255 + px[3] / 2) / px[3];
matches = color_near(rgb, include, includeCount, fuzziness) && !color_near(rgb, exclude, excludeCount, fuzziness);
}
if (invert) matches = !matches;
out[x] = matches ? 255 : 0;
count += matches;
}
}
return count;
}
+7
View File
@@ -10,6 +10,13 @@
// `mask` (width * height bytes). Returns the number selected, or -1 when memory runs out.
long wand_mask(const uint8_t *rgba, size_t width, size_t height, size_t stride,
size_t seedX, size_t seedY, size_t radius, int tolerance, int contiguous, uint8_t *mask);
// Select > Color Range over premultiplied RGBA (as above). A pixel matches when every color channel is within
// `fuzziness` of one of the `includeCount` colors in `include` and of none in `exclude` (straight sRGB, 3 bytes
// each). Transparent pixels never match. With `invert`, the pixels that don't match are selected instead. Writes
// 255 for selected, 0 elsewhere, into `mask`, and returns the number selected.
long color_range_mask(const uint8_t *rgba, size_t width, size_t height, size_t stride,
const uint8_t *include, int includeCount, const uint8_t *exclude, int excludeCount,
int fuzziness, int invert, uint8_t *mask);
// Outline of the nonzero pixels of `mask`, along pixel edges, as closed loops of corner points
// (x, y pairs in pixel-edge coordinates). Outer boundaries run clockwise and holes
// counterclockwise in top-left coordinates, so the winding rule fills exactly those pixels.