rgb data processing in C, for visual data
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// RGB Data Generator prototype.
// Works with 24-bit aligned unsigned data
// Targeted for images.
// rgb_t is considered to be 24-bit aligned unsigned data.
// Thus, unsigned char is suitable.
typedef unsigned char rgb_t;
// Enum used in rule type to signify whether,
// The rule sets the current, previous,
enum rgb_pos_t {
RGB_POS_PREV,
RGB_POS_CUR,
RGB_POS_NEXT
};
// Data structure to encapsulate a rule to apply to color.
// Note, the set_<> fields represent what to set the directed
// color value to, the regular fields indicate the condition.
struct rgb_rule_t {
enum rgb_pos_t place;
rgb_t red;
rgb_t green;
rgb_t blue;
rgb_t set_red;
rgb_t set_green;
rgb_t set_blue;
};
#define RGBC_WIDTH (sizeof(unsigned char) * 3)
// Macro aligns the idea of memory size with 24-bit integer
// data.
#define RGBC_SIZE(space) (sizeof(unsigned char) * 3 * space)
// Macros to evaluate to the red, green, and blue channels
#define RGBC_RED(r) (r[0])
#define RGBC_GREEN(r) (r[1])
#define RGBC_BLUE(r) (r[2])
// Pointer movement macros
#define RGBC_NEXT(r) (r + RGBC_WIDTH)
#define RGBC_PREV(r) (r - RGBC_WIDTH)
#define RGBC_OFFSET(r, change) (r + RGBC_SIZE(change))
// Color comparison macros
#define RGBC_EQ(r, red, green, blue) (RGBC_RED(r) == (red) && RGBC_GREEN(r) == (green) && RGBC_BLUE(r) == (blue))
#define RGBC_NEQ(r, red, green, blue) (!RGBC_EQ(r, red, green, blue))
// color specific compare
#define RGBC_EQ_RED(r, red) (RGBC_RED(r) == red)
#define RGBC_EQ_GREEN(r, green) (RGBC_GREEN(r) == green)
#define RGBC_EQ_BLUE(r, blue) (RGBC_BLUE(r) == blue)
// Setting macros
#define RGBC_SET_RED(r, n) (RGBC_RED(r) = n)
#define RGBC_SET_GREEN(r, n) (RGBC_GREEN(r) = n)
#define RGBC_SET_BLUE(r, n) (RGBC_BLUE(r) = n)
#define RGBC_SET_ALL(r, red, green, blue) do { \
RGBC_RED(r) = red; \
RGBC_GREEN(r) = green; \
RGBC_BLUE(r) = blue ; \
} while(0)
// Conditional macros
#define RGBC_IF_EQ(r, red, green, blue, action) if(RGBC_EQ(r, red, green, blue)){action;}
#define RGBC_IF_NEQ(r, red, green, blue, action)if(RGBC_NEQ(r, red, green, blue)){action;}
// conditional set macros
#define RGBC_IF_EQ_SET(r, red, green, blue, r_set, g_set, b_set) RGBC_IF_EQ(r, red, green, blue, RGBC_SET_ALL(r, r_set, g_set, b_set))
#define RGBC_IF_EQ_SET_NEXT(r, red, green, blue, r_set, g_set, b_set) RGBC_IF_EQ_SET(RGBC_NEXT(r), red, green, blue, r_set, g_set, b_set)
#define RGBC_IF_EQ_SET_PREV(r, red, green, blue, r_set, g_set, b_set) RGBC_IF_EQ_SET(RGBC_PREV(r), red, green, blue, r_set, g_set, b_set)
static rgb_t COLOR_DATA[RGBC_SIZE(1000)] = {0};
static void rgb_init_rule(struct rgb_rule_t* rule,
enum rgb_pos_t posi,
rgb_t red,
rgb_t green,
rgb_t blue,
rgb_t set_red,
rgb_t set_green,
rgb_t set_blue) {
rule->place = posi;
rule->red = red;
rule->green = green;
rule->blue = blue;
rule->set_red = set_red;
rule->set_green = set_green;
rule->set_blue = set_blue;
}
static void rgb_apply_rule(rgb_t* data, struct rgb_rule_t* rule) {
switch(rule->place) {
case RGB_POS_PREV:
RGBC_IF_EQ_SET_PREV(data, rule->red, rule->green, rule->blue, rule->set_red, rule->set_green, rule->set_blue);
return;
case RGB_POS_CUR:
RGBC_IF_EQ_SET(data, rule->red, rule->green, rule->blue, rule->set_red, rule->set_green, rule->set_blue);
return;
case RGB_POS_NEXT:
RGBC_IF_EQ_SET_NEXT(data, rule->red, rule->green, rule->blue, rule->set_red, rule->set_green, rule->set_blue);
return;
}
}
static void rgb_print_pixels(rgb_t* begin, rgb_t* end) {
while(begin != end) {
printf("rgb(%u, %u, %u)\n", RGBC_RED(begin), RGBC_GREEN(begin), RGBC_BLUE(begin));
begin += RGBC_WIDTH;
}
}
static int
rgb_to_file(rgb_t* color, size_t color_len, const char* path) {
FILE* fp;
fp = fopen(path, "wb");
if(fp == NULL) {
fprintf(stderr, "IO Error: Cannot open file at %s, exiting.\n", path);
exit(1);
}
fwrite(color, sizeof(unsigned char), color_len, fp);
fclose(fp);
return 1;
}
int main(void) {
rgb_t* color_ptr = COLOR_DATA;
struct rgb_rule_t rule1;
rgb_init_rule(&rule1, RGB_POS_NEXT, 0, 0, 0, 10, 40, 200);
rgb_apply_rule(color_ptr, &rule1);
rgb_print_pixels(color_ptr, color_ptr + RGBC_SIZE(20));
return 0;
}