Created attachment 6288 [details] proof of correctness for the patched version Ideally fz_mul255(a,b) in mupdf/fitz/fitz_base.h should return round(float(a)*float(b)/255.) for all the couples (a,b) in the discrete set [0,255]x[0,255] (ie. the approximation with the lowest error energy over the set [0,255]x[0,255]). This is not the case for the current implementation which is returning a less then optimal value for half of the possible couples (a,b). The attached patch fixes this. It also makes the multiplication around 20% faster on my machine.
Created attachment 6289 [details] perf test (redirect output if you want to do any measures)
Created attachment 6290 [details] the actual patch
Note that the suggested patch does not round correctly for negative input. See bug 690631 for problems caused by fz_mul255 not treating negative numbers correctly.
If I understand correctly that the best thing to do is fixing the callers passing negative arguments to fz_mull255 one could deal whith interpolations by introducing something like: #define fz_convex255(a,b,lambda) \ ({ unsigned int tmp; \ unsigned char _a = a; \ unsigned char _b = b; \ unsigned char _lambda = lambda; \ tmp = _a*_lambda + _b*(255 ^ _lambda) + 0x80; \ tmp += tmp >> 8; \ tmp >> 8; }) [which has zero error-energy against round((float(a*lambda) + float(b*(255-lambda)))/255.) over the set [0,255]^3] and switching those call-sites to the new helper.
I have applied Lev Bishop's earlier patches for this same problem.