3
\$\begingroup\$

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:

demonstration of two neighboring rgb values

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;
}
\$\endgroup\$
3
  • \$\begingroup\$ 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). \$\endgroup\$ – Toby Speight Apr 30 at 15:03
  • \$\begingroup\$ 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. \$\endgroup\$ – QuestionLimitGoBrrrrr Apr 30 at 15:24
  • \$\begingroup\$ 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. \$\endgroup\$ – Sumurai8 Apr 30 at 21:18
2
\$\begingroup\$

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.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.