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.
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).