Literals are limited in range to 16.15 (31 bits). The least significant bit is used as a flag for instructions. Variables and math all work with the full 32 bits, so an expression can create the full 32 bit word, such as your packRGBA function.
As a compromise, you could represent data in your code as a real number instead of hex to get the full 31-bit range for a single literal. For example your 0xFDB97531
divided by 65536 becomes ~64953.457778
(6 decimal places is probably plenty), but once encoded would end up being 0xFDB9.7530
(dropping the least significant bit). Humans are least perceptive of red contrast, so you could re-order it so that red was in the least significant byte without losing noticeable perceptual range.
A 31-bit literal is 1 word, the full 32-bit p(0xFDB9,0x7531)
expression takes 3 words, and packRGBA(0xdf,0xbc,0x5b,0x00)
uese 5 words.
By the way, when using array literals you don’t want to pre-allocate an array, the array literal does that for you. Doing it twice orphans the first array making it unusable but still retaining memory.
Change this code:
image = array(256); // allocate row storage
image = [ packRGBA(0xdf,0xbc,0x5b,0x00),packRGBA(0xe1,0xc2,0x6c,0x00),... ]
to just this:
image = [ packRGBA(0xdf,0xbc,0x5b,0x00),packRGBA(0xe1,0xc2,0x6c,0x00),... ]