Created
July 9, 2020 15:01
-
-
Save taoky/053dcf9f5abc2f7b8491fa978d147434 to your computer and use it in GitHub Desktop.
Printing a 800x600 XPM image to framebuffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Modified from https://gist.github.com/FredEckert/3425429, with some bug fixes | |
// This following program requires at least 800x600, 32bpp to run | |
#include <fcntl.h> | |
#include <linux/fb.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/ioctl.h> | |
#include <sys/mman.h> | |
#include <unistd.h> | |
// test.xpm is your image in XPM format | |
#pragma GCC diagnostic push | |
#pragma GCC diagnostic ignored "-Wwrite-strings" | |
#include "test.xpm" | |
#pragma GCC diagnostic pop | |
#include <iostream> | |
#include <map> | |
#include <string> | |
#define MINX 800 | |
#define MINY 600 | |
#define MINBPP 32 | |
extern char *test_xpm[]; | |
std::map<std::string, std::string> color_table; | |
int main() { | |
int fbfd = 0; | |
struct fb_var_screeninfo vinfo; | |
struct fb_fix_screeninfo finfo; | |
long int screensize = 0; | |
char *fbp = 0; | |
long int location = 0; | |
// Open the file for reading and writing | |
fbfd = open("/dev/fb0", O_RDWR); | |
if (fbfd == -1) { | |
perror("Error: cannot open framebuffer device"); | |
exit(EXIT_FAILURE); | |
} | |
printf("The framebuffer device was opened successfully.\n"); | |
// Get fixed screen information | |
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) { | |
perror("Error reading fixed information"); | |
exit(EXIT_FAILURE); | |
} | |
// Get variable screen information | |
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) { | |
perror("Error reading variable information"); | |
exit(EXIT_FAILURE); | |
} | |
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); | |
if (vinfo.xres < MINX || vinfo.yres < MINY || vinfo.bits_per_pixel < MINBPP) { | |
printf("This program requires at least %dx%d, %dbpp.\n", MINX, MINY, | |
MINBPP); | |
exit(EXIT_FAILURE); | |
} | |
// Figure out the size of the screen in bytes | |
screensize = vinfo.yres * finfo.line_length; | |
// Map the device to memory | |
fbp = | |
(char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); | |
if (fbp == MAP_FAILED) { | |
perror("Error: failed to map framebuffer device to memory"); | |
exit(EXIT_FAILURE); | |
} | |
printf("The framebuffer device was mapped to memory successfully.\n"); | |
printf("Buffer size: %ld\n", screensize); | |
printf("vinfo.xoffset = %d, vinfo.yoffset = %d, finfo.line_length = %d\n", | |
vinfo.xoffset, vinfo.yoffset, finfo.line_length); | |
// Handle XPM file format | |
// Assuming it's valid and its color keys are all 'c' | |
int image_width, image_height, colors, chars_per_pixel; | |
sscanf(test_xpm[0], "%d %d %d %d", &image_width, &image_height, &colors, | |
&chars_per_pixel); | |
if (image_width > MINX || image_height > MINY) { | |
printf("This image is too large.\n"); | |
exit(EXIT_FAILURE); | |
} | |
for (int i = 1; i <= colors; i++) { | |
std::string color_string = std::string(test_xpm[i]); | |
color_table[color_string.substr(0, chars_per_pixel)] = | |
color_string.substr(color_string.size() - 6, 6); | |
} | |
// Figure out where in memory to put the pixel | |
for (int y = 0; y < image_height; y++) { | |
for (int x = 0; x < image_width; x++) { | |
// Fetch current pixel info | |
char *pixel = test_xpm[colors + y + 1] + x * chars_per_pixel; | |
std::string color = color_table[std::string(pixel, chars_per_pixel)]; | |
int color_integer = std::stoul(color, nullptr, 16); | |
location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + | |
(y + vinfo.yoffset) * finfo.line_length; | |
*(fbp + location) = color_integer & 0xFF; // Blue | |
*(fbp + location + 1) = (color_integer >> 8) & 0xFF; // Green | |
*(fbp + location + 2) = (color_integer >> 16) & 0xFF; // Red | |
*(fbp + location + 3) = 0; // Transparency | |
} | |
} | |
munmap(fbp, screensize); | |
close(fbfd); | |
return 0; | |
} | |
// vim: set ai et sta ts=2 sts=2 sw=2: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment