1

I found an interesting thing that I'm not able to debug but I'd like to solve because it's crucial for the development of a small tool I need.

Basically all reduces to the fact that I load into an SDL_Surface a PNG loaded with IMG_Load("filename.png"). The skeleton of the code is

surface = IMG_Load("filename.png");

Then this tool should copy this surface pixel by pixel to another by applying a color map (which is just an unordered_map<u32,u32>). This basically works, but many pixel have a slight change in their RGB values so this substitution fails.

For example, while a pixel 255,255,255 is correctly stored as 0xFFFFFFFF in the surface, another pixel, let's say 81,60,48 becomes 82,62,51. I thought about gamma correction but the image itself is not drawn since the color switch is applied before two surfaces, and the latter gets drawn to a texture just afterwards.

Any clues? I'm not interested in finding another solution to my problem since I require to be able to do precise pixel color switching with a fixed map, I'd just like to understand why this is happening (since PNG should just contain exact values, being lossless) and solve it.

Jack
  • 131,802
  • 30
  • 241
  • 343
  • Does your monitor have some kind of color calibration applied to it? – Mark Ransom Jul 28 '14 at 00:55
  • @Mark Ransom: No, I'm running on OSX and it has its default calibration. Indeed I tried to obtain the default gamma ramp through `SDL_GetWindowGammaRamp` but the values seemed just linear. I like to emphasize the fact that I'm working on raw data, displaying it is just a later stage. – Jack Jul 28 '14 at 00:56

1 Answers1

3

Ok, I found the cause and fixed it. The problem resides in how the PNG is loaded through the OS X frameworks. According to this thread, this is related to the embedded calibration which is somehow taked into account while loading the image. The proposed fix is the following:

CGFloat whitePoint[3] = { 1, 1, 1 };
CGFloat blackPoint[3] = { 0, 0, 0 };
CGFloat gamma[3] = { 2.2, 2.2, 2.2 };
CGFloat matrix[9] = {
    1, 1, 1,
    1, 1, 1,
    1, 1, 1
};
CGColorSpaceRef color_space =
    CGColorSpaceCreateCalibratedRGB(
                                whitePoint, blackPoint, gamma, matrix
                                );

By patching ImageIO.m of SDL_Image and rebuilding it from sources the problem resolved itself. I wonder why it hasn't been included in SDL_Image (or rather, just a version with custom values).

Jack
  • 131,802
  • 30
  • 241
  • 343