Understanding some bit magic in the Go standard library

so I sifted through some code in the Go standard library, trying to figure out their image and color packages, but found code that I just can't understand. from http://golang.org/src/pkg/image/color/color.go?s=794:834#L14

In my opinion, it should convert 8 bits of pre-alpha-multiplied RGB values ​​to 16-bit, stored in 32-bit variables, to stop them from overflowing when multiplied by a graphic image.

What I cannot understand are strings like r |= r << 8 , because I understand that this is equivalent to r = r*2^8+r , because r << 8 inserts zeros to the right, and they get or 'ed with old r.

When entering r = 255, this is evaluated as 65535 = 2 ^ 16 - 1, as expected, but it does not make sense for the values ​​in the middle, which actually do not map to something proportional to a larger range. For example, 127 get a comparison with 32639, while I expect 32767 to represent 127. What am I missing? I think this has something to do with pre-alpha multiplication ...

  func (c RGBA) RGBA() (r, g, b, a uint32) { r = uint32(cR) r |= r << 8 g = uint32(cG) g |= g << 8 b = uint32(cB) b |= b << 8 a = uint32(cA) a |= a << 8 return } 
+4
source share
1 answer

No, what you see really makes sense.

Think of one (red, for example) meaning. It dictates the amount of redness in a pixel and, like an 8-bit amount, somewhere between 0 and 255. So you can imagine all the redness values ​​in a range.

If you just reloaded it by eight bits (or multiplied by 256) to get a 16-bit color value, you will get a brief 256 from somewhere between 0 and 255 * 256 (65280) inclusive.

Although this scales the redness relatively well, it does not properly distribute it over the entire 16-bit range.

For example, 255 in the 8-bit range means maximum redness. Simple multiplication by 256 does not give you the maximum amount of redness on a 16-bit scale, which would be 65535.

Multiplying by 256, and then adding the original (effectively multiplying by 257), it is correctly distributed over the range 0..65535.

The same as scaling single-valued integers 0..9 in the range 0..99 . Multiplying by ten is one way, but the best way is to multiply by ten and add the original value (or multiply by eleven):

 nn*10 n*10+n - ---- ------ 0 0 0 1 10 11 2 20 22 3 30 33 4 40 44 5 50 55 6 60 66 7 70 77 8 80 88 9 90 99 
+10
source

Source: https://habr.com/ru/post/1411456/


All Articles