# Making pixels of RGB barcode suitable for scanning

Similar to Microsoft's HCCB before its discontinuation near 2015, Im trying to make a 2D barcode that uses RGB pixels to encode more than two possible states (Black/White).

Theoretically, at 100% data capacity, you could hold 16,777,216 different integers in a single pixel. However, this level of storage is not feasible.

Consider the two RGB colors 47,213,71 and 47,213,72:

This unperceivable difference would have to be detected reliably even in suboptimal environments and lighting.

This is why Microsoft's HCCB only used 8 pre-determined colors, but I hypothesize modern cameras would still allow for greater detection and accuracy.

I wanted a barcode where you could change the gaps between colors, such that no two neighboring colors were less distant than the amount specified.

This way, a large gap like 128 could make each pixel represent a possible total of 8 colors - like Microsoft's original HCCB; While a small gap like 1 would give you the aforementioned 16,777,216 colors.

Now that I've finished explaining why anyone would want to do this, I can show you my C code. I'm not sure I did a good job at this, and I feel as though either my method or execution should be changed completely, so here's my approach to doing this

#include <stdio.h>
#include <stdint.h>

uint8_t* bind(uint32_t val, uint8_t bound){
static uint8_t rgb[3];
uint32_t buffer[3];
uint32_t max = bound*(256/bound);

buffer[0] = val * bound;
buffer[1] = (buffer[0]/max)*bound;
buffer[2] = (buffer[1]/max)*bound;

rgb[0] = buffer[0] % max;
rgb[1] = buffer[1] % max;
rgb[2] = buffer[2] % max;

return rgb;
}

uint32_t unbind(uint8_t* rgb, uint8_t bound){
uint32_t max = 256/bound;
return (rgb[0]/bound)+(rgb[1]/bound)*max+(rgb[2]/bound)*max*max;
}

int main(void) {
uint32_t data = 1;
uint8_t color_range = 128;

uint8_t* colors = bind(data, color_range);
uint32_t calculated = unbind(colors, color_range);

printf("expected value: %u\nreturned value: %u\n\n", data, calculated);
printf("rgb value: %u,%u,%u\n", colors[0], colors[1], colors[2]);
return 0;
}

• 8 bits per channel is an arbitrary assumption - many printers and monitors support 10 bits or more (not that any more than 5 is likely to be reliably differentiated for data encoding). – Toby Speight Apr 30 at 15:03
• This is true, however i felt that since higher bit depths can always be converted down and not vice-versa, 8 bit would be more suitable for a wider range of applications. Also, Its easier to represent 3, 8-bit values in C rather than 3-10 bit values. – QuestionLimitGoBrrrrr Apr 30 at 15:24
• I can't comment on the code, but from a practical point of view keep in mind that when displaying this barcode wherever, be it on a screen or printed somewhere, versions might differ from each other based on how the screen or printer is calibrated and lighting conditions. – Sumurai8 Apr 30 at 21:18

This:

static uint8_t rgb[3];
return rgb;


is a problem. Two different callers assuming to have two different copies of the return array will actually only have one, and that breaks re-entrance. Better off to return by value instead of return by reference in this case - particularly if you make a utility struct. A common pattern is to union over a three-element array and a nested struct of red, green and blue components. To ensure that this is valid, you'll need to tell your compiler to use tight packing, typically with #pragma pack. If you have misgivings on the portability of this approach and you need to support multiple exotic compilers, you'll need to ditch the union and instead write a conversion function.

bind and unbind can both be marked static since they're in the same translation unit.

The only other minor thing I see here is that two-space indentation is somewhat non-standard, and 4-space will be more legible.

• could i make it take an array pointer rgb as an argument and make the function itself return void? – QuestionLimitGoBrrrrr Apr 30 at 17:04
• Yes, that's also possible. – Reinderien Apr 30 at 17:43