Png colors are off please help


#1

hello everyone. this is my first post on a forum, and so i
apologize for any strangeness.

i am having trouble displaying png images correctly. the colors
are off. semi-transparent pixels in particular. i am wondering if
there is anything i am doing incorrectly. i read about similar
problems people have had with pre-multiplied alpha or alpha not
being multiplied or added correctly.

here is a quick mock-up that displays the problem.

i am using mingw codeblocks 17.12 and sdl2 2.0.8, sdl2 image 2.0.3,
all 32 bit, on a 64bit windows 7 machine, i7 4790 3.60ghz and nvidia evga gtx760.
everything runs fine, except for this problem.


#include
#include
using namespace std;
#include<SDL.h>
#include<SDL_image.h>

int window_w=1024,window_h=768;
SDL_Renderer *renderer=NULL;
SDL_Rect paint={0,0,0,0};
SDL_Event sdl_ev;
const Uint8 *key_states=SDL_GetKeyboardState(NULL);
int program_loop=0;

int main (int argc,char *argv[]){
int cycle_start=0;
int cycle_end=0;
int cycle_time=0;
int time_limit=1000/60; //time_limit=16.6 repeating to a 7, but will be truncated to int 16

SDL_Init(SDL_INIT_VIDEO);
IMG_Init(IMG_INIT_PNG);
SDL_Window *window=NULL;

window=SDL_CreateWindow(
	"Game Window",
	SDL_WINDOWPOS_UNDEFINED,
	SDL_WINDOWPOS_UNDEFINED,
	window_w,
	window_h,
	SDL_WINDOW_BORDERLESS
);

renderer=SDL_CreateRenderer(
	window,
	-1,
	SDL_RENDERER_ACCELERATED
);

SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_BLEND);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,"0");

//load graphics
SDL_Surface *sf_a=IMG_Load("graphic/a.png");
SDL_Texture *tx_a=SDL_CreateTextureFromSurface(renderer,sf_a);
SDL_FreeSurface(sf_a);

SDL_Surface *sf_b=IMG_Load("graphic/b.png");
SDL_Texture *tx_b=SDL_CreateTextureFromSurface(renderer,sf_b);
SDL_FreeSurface(sf_b);

program_loop=1;

while(program_loop==1){
    	cycle_start=SDL_GetTicks();
	key_states=SDL_GetKeyboardState(NULL);
    	SDL_SetRenderDrawColor(renderer,0,0,0,255);
    	SDL_RenderClear(renderer);

	//quit if corner x is pressed
	while(SDL_PollEvent(&sdl_ev)!=0){
		if(sdl_ev.type==SDL_QUIT){
			program_loop=0;
		}
	}

	//program kill
	if(key_states[SDL_SCANCODE_0]){
		program_loop=0;
	}

	paint.x=0;
	paint.y=0;
	paint.w=window_w;
	paint.h=window_h;
	SDL_RenderCopy(renderer,tx_a,NULL,&paint);
	SDL_RenderCopy(renderer,tx_b,NULL,&paint);
    	SDL_RenderPresent(renderer);

	cycle_end=SDL_GetTicks();
	cycle_time=cycle_end-cycle_start;

	if(cycle_time<time_limit){
		SDL_Delay(time_limit-cycle_time);
	}
}

SDL_DestroyTexture(tx_a);
SDL_DestroyTexture(tx_b);

SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
IMG_Quit();
SDL_Quit();
return 0;

}

i posted some images to clarify. if you open gimp 2.10 or another
digital art program and drop a.png in, and then b.png over top of it,
you will see two identical rows of colored xs on a grey background. (a) is
a grey backdrop with (b) on top and rendered as one png. if i render
(a) in sdl2, it looks like how it did in gimp 2.10. if i render (b) on top, then
the way alpha is handled in sdl2 makes the colors all funny. this can be seen
in the example screenshot.

the colors in both rows are not the same. the difference is subtle here,
but on all of the actual graphics for my game are much more detailed, and so
the effect is coarse on them. even some things like semi-transparent black
shadows are twice as dark as they should be.

i do not think it is just an sdl2 problem though. i made quick similar
projects in love2d and sfml just to see if they had the same issue. it was
there in both of them too. is there something i have to do with my pngs?
should i look into using opengl through sdl2 to get them to display properly?
it is a 2d game. please help, this is a big stumbling block for the art
side of things right now.

i have a budget for this game, and can pay canadian $ for help with
this problem. maybe one of the sdl devs is up for hire for some advice.
anyone else with paypal or someone who knows? i can arrange for a
payment to you in whatever way is possible. thank you for your time.

this forum is only letting put one image here. sorry for any confusion.
the bottom row of xs is the right color, the top row are off.
the top two #include are iostream and string from cpp, it won’t
show them for some reason.


#2

If the transparent areas are being shown too dark then it seems like a problem with alpha premultiplication. It’s possible the Gimp is premultiplying the image when saving and then SDL_image is doing it again when loading, or that the image is premultiplied at some point (either by the Gimp when saving or SDL_image when loading) and then SDL is drawing it using a blend mode for images that aren’t premultiplied.

Either way, you essentially get a double premultiply.

edit: You shouldn’t need the SDL_RenderDrawBlendMode() call; IIRC it’s only for when drawing lines etc.