wernsey / bitmap

A C module for manipulating bitmap/raster graphics
MIT No Attribution
69 stars 12 forks source link

Colours get corrupted during rotate #10

Closed sdc-andy closed 2 years ago

sdc-andy commented 2 years ago

I am working with a .tga source file which has been generated by an external application which I am then resizing (from 800x480 to 640x384) and rotating using the bitmap library. In outline the code looks like:

Bitmap *in = bm_load("test.tga");
Bitmap *resized = bm_resample_blin(in, NEW_WIDTH, NEW_HEIGHT);

// Create a new bitmap to hold the rotated image hence NEW_WIDTH and NEW_HEIGHT reversed
Bitmap *rotated = bm_create(NEW_HEIGHT, NEW_WIDTH);
bm_rotate_blit(rotated, 0, 640, resized, 0, 0, 4.71239, 1);

bm_save(rotated, "out.bmp");

The resizing process is working OK but when I perform the rotate operation the colours in the background:

translate

Apologies for not being able to show the full image with all the corrupt colours but to do so would put information into the public domain which isn't yet allowed to be there.

The only option being passed on the command line when bmp.c is compiled is -DBM_LAST_ERROR.

Do you know what I am missing or what I have done wrong?

-Andy.

wernsey commented 2 years ago

Hi Andy, it looks like a bug on my side.

It seems as though all the foreground colours in the rotated image are correct but the white pixels in the background gets replaced with black pixels.

My money is on the alpha channel in the TGA having a value that is misinterpreted by library when it rotates the bitmap.

Can you perhaps provide a TGA file where the issue occurs but with the data you don't want me to see redacted so that I can take a look at what's going on?

sdc-andy commented 2 years ago

I've manipulated the original image in Paint.net so that it just shows the same as the image above. Attached are the .tga source file and the resulting .bmp output file.

images.zip

-Andy.

wernsey commented 2 years ago

Thanks. I haven't had a chance to look at it yet, but I'll try to make some time tomorrow.

wernsey commented 2 years ago

I know what the issue is:

The bm_rotate_blit() function works like bm_maskedblit() in that it compares each pixel on the source to the pen colour of the source bitmap and don't copy the pixels if they match.

Now, the bitmap created by bm_resample_blin() has a white pen colour by default, and the bitmap from bm_create() has a black background initially. So all the white pixels on the source bitmap are not copied and the black background shows through.

This matches the use case I had for it originally where I wanted to rotate graphics with transparent backgrounds, but I should've named the function bm_rotate_maskedblit() instead and then have a bm_rotate_blit() that behaves the same way bm_blit() does.

I think for the next version I'm going to do precisely that. Also, if rotating bitmaps by 90 degrees is something that users require then I should add that.

In the meantime you can work around the issue by calling bm_set_color() on resized, like so:

    Bitmap *resized = bm_resample_blin(in, NEW_WIDTH, NEW_HEIGHT);
    bm_set_color(resized, 0x000000);

Here's a complete version of the program where it works:

#include <stdio.h>

#include "bmp.h"

#define NEW_WIDTH   640
#define NEW_HEIGHT  384

int main(int argc, char *argv[]) {
    Bitmap *in = bm_load("test.tga");
    Bitmap *resized = bm_resample_blin(in, NEW_WIDTH, NEW_HEIGHT);

    bm_set_color(resized, 0x000000);

    // Create a new bitmap to hold the rotated image hence NEW_WIDTH and NEW_HEIGHT reversed
    Bitmap *rotated = bm_create(NEW_HEIGHT, NEW_WIDTH);
    bm_rotate_blit(rotated, 0, 640, resized, 0, 0, 4.71239, 1);

    bm_save(rotated, "out.bmp");
    return 0;
}
wernsey commented 2 years ago

I have pushed a couple of changes:

You can now change your code as follows to achieve the desired effect:

// Bitmap *rotated = bm_create(NEW_HEIGHT, NEW_WIDTH);
// bm_rotate_blit(rotated, 0, 640, resized, 0, 0, 4.71239, 1);
Bitmap *rotated = bm_rotate_ccw(resized);