Wednesday, 24 February 2016

Low-level Graphics on Raspberry Pi (more images)

In an earlier post we looked at converting an image to 16 bit 5:6:5 format for direct copying to framebuffer. The obvious drawback of that approach is the requirement on the image size to exactly match the display/framebuffer size (or the width at least).

Modifying the PPM reading code to read into an image object in memory (I chose to use the struct fb_image from linux/fb.h as teh image object) and combining that with the familiar framebuffer drawing code (put_pixel_RGB565 from part 6)
int read_ppm(char *fpath, struct fb_image *image) {
    image->data = malloc(width * height * bytes_per_pixel);
        // store pixel in memory
        unsigned int pix_offset = (y * width + x ) * bytes_per_pixel;
        *((unsigned short *)(image->data + pix_offset)) = rgb565;

void draw(struct fb_image *image) {
    int y;
    int x;
    unsigned char rgb[3];

    for (y = 0; y < image->height; y++) {
        for (x = 0; x < image->width; x++) {
            // get pixel from image
            unsigned int img_pix_offset = (y * image->width + x) * 2;
            unsigned short c = 
                *(unsigned short *)(image->data + img_pix_offset);
            // plot pixel to screen
            unsigned int fb_pix_offset = 
                x * 2 + y * finfo.line_length;
            *((unsigned short*)(fbp + fb_pix_offset)) = c;

int main(int argc, char* argv[])

    // read the image file
    int ret = read_ppm(argv[1], &image);
    if (ret != 0) {
        printf("Reading image failed.\n");
        return ret;

Make sure you have a 24 bit PPM image file to start with - convert one from for example PNG using pngtopnm (any bit depth source file should do) - and make sure the image fits the screen (no bounds checking in the code). Then compile and run:
gcc -O2 -o ppmtofbimg ppmtofbimg.c
./ppmtofbimg test24.ppm
Full source and a test image (test24.ppm) in GitHub.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.