Bad text quality on transparent texture

Hello,

I’m trying to write texts on transparent buttons so on transparent texture.

I first display an image like follow:

SDL_Surface* surface = IMG_Load( imgName );
widget->backgroundImage = SDL_CreateTextureFromSurface( renderer, surface );

Then I create a texture for by button where I’ll be able to draw:

    widget->texture = SDL_CreateTexture(
        renderer,
	SDL_PIXELFORMAT_ARGB8888,
	SDL_TEXTUREACCESS_TARGET,
	widget->size.w,
	widget->size.h);
    SDL_SetTextureBlendMode(widget->texture, SDL_BLENDMODE_BLEND);

Then I draw my background image in the widget’s texture:

    SDL_SetRenderTarget(renderer, widget->texture);
    SDL_SetRenderDrawColor(renderer, (Uint8) widget->backgroundColor.r, (Uint8) widget->backgroundColor.g, (Uint8) widget->backgroundColor.b, (Uint8) widget->backgroundColor.a);
    SDL_RenderClear(renderer);
    SDL_RenderCopy( renderer, widget->backgroundImage, &src, &dst );

Finally I want to draw a label on my button:

    SDL_Surface *txtSurf = TTF_RenderUTF8_Blended(font, string, textColor); // font is arial.ttf
    SDL_Texture *strTexture = SDL_CreateTextureFromSurface(renderer, txtSurf );
    SDL_FreeSurface( txtSurf );
    SDL_SetTextureBlendMode(strTexture, SDL_BLENDMODE_BLEND); // also tried SDL_BLENDMODE_NONE
    SDL_RenderCopy( renderer, strTexture, &src, &dest );
    SDL_DestroyTexture(strTexture);

I made a test with a transparent background image (SPORT) and an opaque background image (FITNESS) and here is the result:

Imgur

We clearly see on this screenshot that the text displayed on transparent image (SPORT) is of bad quality compare to ‘FITNESS’ displayed on opaque texture.

How to solve this problem??

Al

What format is the images you load? Do they have proper alpha channels?

Does the text on the transparent version look fine if you load it into GIMP or PhotoShop or something, and add an opaque layer under it?

@David_Olofson Hello,

These are both png originally made on Photoshop I think, and I made a copy and paint it on gimp with an opaque color.
According to the properties seen on gimp, both images are identical, with 1 calc with alpha transparency.

About your second question, not sure to really understand it but if I load the transparent one in gimp and write a text on it, it’s ok.

images are here for reference.

Thks,
Al

Well, yes; I’d expect GIMP to do the right thing internally - but what about the text in your original post? I was assuming that’s pre-rendered into the images, and you just render them on screen?

It’s kind of hard to tell from the aggressively compressed image, but are these images scaled/filtered when rendered? If so, it’s very important that ALL pixels have correct color data - even the fully transparent pixels. This used to be a problem with PS IIRC, but GIMP has an option “Save color values from transparent pixels” that you should use in this case. And of course, you need to make sure those pixels actually have the correct colors as well. In this case, the general area of the text needs to be all white, and the text it self should just be in the alpha channel.

No, images are empty, I create the text with TTF_RenderUTF8_Blended().

No operation is done they are displayed at their original size.

Could you please elaborate??
I would expect that transparency was simpler to manage in SDL2 with texture than in SDL1 with surfaces.
But according to what you said and my tests, it seems to be a bit still difficult.
So to try to understand I made the following tests

As I said, I create a texture with SDL_PIXELFORMAT_ARGB8888 and then, I RenderCopy the image in the texture, I create the text and also RenderCopy it in the texture/

On the left image, I load the png, I set the background color to full white. So the text is of, but the image is bad, the gradient on blue line is replaced by white.
On the right image, I load the png, I set the background to full black. The image is ok, but the text is bad.

Imgur

Well, it seems I have to choose between the image and the text ! which is not an option.
How to correctly manage this kind of case?

Al

Oh! I didn’t read the label part of the code properly. The problem is somewhere around that area.

If you render anti-aliased (blended) text over an image that already has alpha information, the alpha channels need to be combined properly. I believe SDL2 can do that, but I’m not entirely sure what you need to do to set that up.

I’ll look into this later. (I think I ran into this in some project of mine recently.)

I tried something without success
I supposed that I had to rendercopy the text’s texture in an intermediate texture with the background color set to the text’s color to correctly manage the anti-aliasing, then I could rendercopy this intermediate texture in any other texture.
But it’s not better…

This is what I tried without success…

if (widget->texture == NULL) {
	SDL_ClearError();
	if ((widget->texture = SDL_CreateTexture(
			widget->parent->renderer,
			SDL_PIXELFORMAT_ARGB8888,
			SDL_TEXTUREACCESS_TARGET,
			widget->size.w, 
			widget->size.h)) == NULL)
	{
		return WID_KO;
	} else {
		SDL_SetTextureBlendMode(widget->texture, SDL_BLENDMODE_BLEND);
	}
}

if (widget->texture != NULL)
{
	SDL_ClearError();
	if (SDL_SetRenderTarget(widget->parent->renderer, widget->texture) != 0) {
		fprintf(stderr, "SDL_SetRenderTarget error %s\n", SDL_GetError());
		return WID_KO;
	}

	SDL_SetRenderDrawColor(
			widget->parent->renderer,
			(Uint8) widget->backgroundColor.r,
			(Uint8) widget->backgroundColor.g,
			(Uint8) widget->backgroundColor.b,
			(Uint8) widget->backgroundColor.a);

	SDL_RenderClear(widget->parent->renderer);
	if (widget->backgroundImage != NULL)
	{
		// calc src and dest.....
		SDL_RenderCopy( widget->parent->renderer, widget->backgroundImage, &src, &dst );
	}
	widget->refresh = true;
}

// Then about the text

SDL_Texture *txtSurf = TTF_RenderUTF8_Blended(
	police,
	string,
	textColor);

SDL_Texture *strTexture = SDL_CreateTextureFromSurface( text->widget.parent->renderer, txtSurf );

SDL_FreeSurface( txtSurf );

SDL_SetTextureBlendMode(strTexture, SDL_BLENDMODE_NONE); // tried BLEND also...

if (widget->backgroundImage != NULL) {
	SDL_Texture *texture;
	if ((texture = SDL_CreateTexture(
			text->widget.parent->renderer,
			SDL_PIXELFORMAT_ARGB8888,
			SDL_TEXTUREACCESS_TARGET,
			txtSurf->w,
			txtSurf->h)) == NULL)
	{
		return WID_KO;
	} else {
		SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE); // tried BLEND also...

		if (SDL_SetRenderTarget(text->widget.parent->renderer, texture) != 0) {
			fprintf(stderr, "SDL_SetRenderTarget error %s\n", SDL_GetError());
			return WID_KO;
		}

	    if (text->widget.backgroundColor.a == 0)
	    {
			SDL_SetRenderDrawColor(
					widget->parent->renderer,
					(Uint8) text->attributes.color.r,
					(Uint8) text->attributes.color.g,
					(Uint8) text->attributes.color.b,
					(Uint8) 0);
	    }
		SDL_RenderClear(widget->parent->renderer);
	}

	SDL_RenderCopy( text->widget.parent->renderer, strTexture, NULL, NULL );

	if (SDL_SetRenderTarget(text->widget.parent->renderer, widget->texture) != 0) {
		fprintf(stderr, "SDL_SetRenderTarget error %s\n", SDL_GetError());
		return WID_KO;
	}

	SDL_RenderCopy( text->widget.parent->renderer, texture, &src, &dest );
}

You could use an intermediate texture, I suppose, but it shouldn’t be necessary.

SDL_BLENDMODE_BLEND already does dstA = srcA + (dstA * (1-srcA)), which should work - provided it knows that both source and destination actually have active alpha channels. I believe the last part is where the problem is.

I tried to use SDL_SetTextureBlendMode(widget->texture, SDL_BLENDMODE_NONE); just before the last RenderCopy and it’s better.
I can see a difference with (better) and without an intermediate texture but it’s quite heavy.
If you have a better solution, I’m interested…

Al

In fact SDL_SetTextureBlendMode(widget->texture, SDL_BLENDMODE_NONE); is not a solution for the last RenderCopy because if I copy my text on a no transparent texture, I see an opaque rectangle under the text !!!

Argh!!! I don’t see what to do to get it working in any cases.

Al