SFML load, modify, display bitmap

2019-07-28 16:44发布

问题:

I had to work all day to figure out how to load, modify, and display a bitmap. Here's my working program (Lubuntu, CodeBlocks 16.01). I had to add these libraries:-lsfml-graphics,-lsfml-window, and -lsfml-system to project> build options> linker settings> other linker options. Any suggestions for improvements?

#include <SFML/Graphics.hpp>

using namespace std;
using namespace sf;

struct pix {
    unsigned char r;  // could use Uint8
    unsigned char g;
    unsigned char b;
    unsigned char t;
};

// globals

pix pixarray[640][480];
Texture tex;
Sprite spr;

// functions

void loadbitmap();
void modifybitmap();
void displaybitmap();

int main() {

    RenderWindow window(VideoMode(640, 480), "Modify Bitmap");

    loadbitmap();
    modifybitmap();
    displaybitmap();

    while (window.isOpen()) {

        Event event;
        while (window.pollEvent(event)) {

            if (event.type == Event::Closed)
                window.close();
        }

        window.clear();

        window.draw(spr);

        window.display();
    }

    return 0;
}

//-------------------------------------------------------

void loadbitmap() {

    const unsigned char *pixptr;
    Image img;
    int i, j;

    img.loadFromFile("pic.bmp");
    pixptr = img.getPixelsPtr();   // notice its Pixels not Pixel

    // pixptr is read only, move pixels to your array

    for (i = 0; i < 640; ++i) {
        for (j = 0; j < 480; ++j) {
            pixarray[i][j].r = *pixptr++;
            pixarray[i][j].g = *pixptr++;
            pixarray[i][j].b = *pixptr++;
            pixarray[i][j].t = 255;
            pixptr++;
        }
    }
    return;
}

//---------------------------------------------------------

void modifybitmap() {

// turn up red in top half of your array

    int i, j;

    for (i = 0; i < 320; ++i) {
        for (j = 0; j < 480; ++j) {
            pixarray[i][j].r = 255;
        }
    }
    return;
}

//-------------------------------------------------------------

void displaybitmap() {

    Image img;
    unsigned char *ptr1;

    ptr1 = &pixarray[0][0].r;  // point to first byte

    img.create(640, 480, ptr1);
    tex.loadFromImage(img);
    spr.setTexture(tex);

    return;
}

回答1:

First of all, SFML is a multimedia library, no real imaging library. You certainly can do things the way you did, but it's not really optimized for that and there's quite a bit of overhead involved.

However, if you really just want to do pixel by pixel transformations, I'd recommend using SFML to render your target image on the GPU. Doing so is rather trivial:

sf::Texture source;
sf::Sprite sprite;
sf::Shader shader;

// I'll be skipping error checking for simplicity

// Load the shaders (see below)
shader.loadFromFile("shader.fs", sf::Shader::Fragment);

// Tell the shader to use the current texture (i.e. the one bound to the srite)
// This name has to match the one in the shader code; you can bind multiple textures, e.g. for blending
shader.setUniform("texture", sf::Shader::CurrentTexture);

// Load the image
sourceImage.loadFromFile("pic.bmp");

// Assign the texture
sprite.setTexture(sourceImage, true);

// Draw the sprite using the shader
// 'target' can be a 'sf::RenderWindow' or 'sf::RenderTexture'
target.clear();
target.draw(sprite, shader);
target.display();

You'll need one additional file, which has your actual pixel operation. as an alternative, you could put this into a string literal, but this way it's easier to modify.

shader.fs

uniform sampler2D texture;

in vec2 tex_coord;

void main()
{
    // Get this pixel's color
    vec4 pixel = gl_TexCoord[0].xy;

    // Let's set 'red' to full (i.e. 255/1.0)
    pixel.r = 1.0;

    // Return the pixel color
    gl_FragColor = pixel;
}

As an alternative, you could of course also swap the green and blue channels:

float t = pixel.g;
pixel.g = pixel.b;
pixel.b = t;

And pretty much anything else you could think of. Note that this code is untested, but should work (with possibly one or two small issues). You can also check SFML's Shader example for more information.

If you're using a sf::RenderTexture as your target, you can save the file to a new image without being forced to draw it on screen.



标签: bitmap sfml