ncruces/go-image

srgb.go LinearToSRGB8 maybe incorrect?

Closed this issue · 1 comments

Below is modified version of LinearToSRGB8 and a use case for generating mipmaps. I double-checked the code is transcribed correctly (could be wrong of course) and the first test I did has li equal to 23,566,590 that's said to be out of the range (see the //comments) of divsqr257rnd and produces a value larger than 255 (357). The input (from the mipmap) is 248. The input to LinearToSRGB8 is 61517 (f04d). I think there must be an error. I've read every letter of the code 3 or 4 times, but please by all means check my work.

For the record, the resulting image is bright and littered with glitches.

static BYTE Ex_mipmap_LinearToSRGB8(WORD lin)
{
	// piecewise linear
	//div, mod := divmod257(uint32(lin))
	DWORD div,mod;
	{
		// valid for x=[0..256*65535[
		QWORD mul = QWORD(lin)*0xff0100; 
		mod = mul*257>>32;
		div = mul>>32;
	}
	DWORD l0 = Ex_mipmap_l8s16[(BYTE)(div)];
	DWORD l1 = Ex_mipmap_l8s16[(BYTE)(div+1)];
	DWORD li = 257*l0+mod*(l1-l0);
	//return uint8(divsqr257rnd(li))
	{
		// valid for x=[0..257*65535[
		QWORD mul = QWORD(li+0x8100)*0x1fc05f9;
		div = mul>>41;
		return (BYTE)div;
	}
}

extern BYTE Ex_mipmap_sRGB(DWORD b4)
{
	DWORD sum = 0;
	for(int i=4;i-->0;b4>>=8)
	sum+=Ex_mipmap_s8l16[b4&0xFF];
	sum/=4;
	return Ex_mipmap_LinearToSRGB8((WORD)sum);
}

Oh yes, I remembered some casts, and thought they might be truncating. Sorry for a false flag. Maybe 0xFFFFFFFF&mul is a better way to write truncation with all of the casting going on in this code, maybe to satisfy diagnostics. Below is my code with changes:

mod = QWORD((DWORD)mul)*257>>32;

P.S. Thanks for code! It's very helpful 👍