From daa9cb4e04de243a16cd9a4dd485cb96f89a580d Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Wed, 3 May 2017 14:27:09 +0530 Subject: [PATCH] Add cairo framebuffer example --- cairo/.cproject | 65 ++++++++++ cairo/.gitignore | 1 + cairo/.project | 26 ++++ cairo/.settings/language.settings.xml | 14 +++ cairo/cairo.c | 174 ++++++++++++++++++++++++++ 5 files changed, 280 insertions(+) create mode 100644 cairo/.cproject create mode 100644 cairo/.gitignore create mode 100644 cairo/.project create mode 100644 cairo/.settings/language.settings.xml create mode 100644 cairo/cairo.c diff --git a/cairo/.cproject b/cairo/.cproject new file mode 100644 index 0000000..84e8b1d --- /dev/null +++ b/cairo/.cproject @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cairo/.gitignore b/cairo/.gitignore new file mode 100644 index 0000000..3df573f --- /dev/null +++ b/cairo/.gitignore @@ -0,0 +1 @@ +/Debug/ diff --git a/cairo/.project b/cairo/.project new file mode 100644 index 0000000..85c4983 --- /dev/null +++ b/cairo/.project @@ -0,0 +1,26 @@ + + + cairo + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/cairo/.settings/language.settings.xml b/cairo/.settings/language.settings.xml new file mode 100644 index 0000000..d0c36c8 --- /dev/null +++ b/cairo/.settings/language.settings.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/cairo/cairo.c b/cairo/cairo.c new file mode 100644 index 0000000..157c86b --- /dev/null +++ b/cairo/cairo.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DELAY_IN_SECS 5 +#define SCALE_WIDTH 256.0 +#define SCALE_HEIGHT 256.0 + +typedef struct _cairo_linuxfb_device { + int fb_fd; + unsigned char *fb_data; + long fb_screensize; + struct fb_var_screeninfo fb_vinfo; + struct fb_fix_screeninfo fb_finfo; +} cairo_linuxfb_device_t; + +/* Destroy a cairo surface */ +void cairo_linuxfb_surface_destroy(void *device) +{ + cairo_linuxfb_device_t *dev = (cairo_linuxfb_device_t *)device; + + if (dev == NULL) + return; + + munmap(dev->fb_data, dev->fb_screensize); + close(dev->fb_fd); + free(dev); +} + +/* Create a cairo surface using the specified framebuffer */ +cairo_surface_t *cairo_linuxfb_surface_create(const char *fb_name) +{ + cairo_linuxfb_device_t *device; + cairo_surface_t *surface; + + /* Use fb0 if no fram buffer is specified */ + if (fb_name == NULL) { + fb_name = "/dev/fb0"; + } + + device = malloc(sizeof(*device)); + if (!device) { + perror("Error: cannot allocate memory\n"); + exit(1); + } + + // Open the file for reading and writing + device->fb_fd = open(fb_name, O_RDWR); + if (device->fb_fd == -1) { + perror("Error: cannot open framebuffer device"); + goto handle_allocate_error; + } + + // Get variable screen information + if (ioctl(device->fb_fd, FBIOGET_VSCREENINFO, &device->fb_vinfo) == -1) { + perror("Error: reading variable information"); + goto handle_ioctl_error; + } + + // Figure out the size of the screen in bytes + device->fb_screensize = device->fb_vinfo.xres * device->fb_vinfo.yres + * device->fb_vinfo.bits_per_pixel / 8; + + // Map the device to memory + device->fb_data = (unsigned char *)mmap(0, device->fb_screensize, + PROT_READ | PROT_WRITE, MAP_SHARED, + device->fb_fd, 0); + if ((int)device->fb_data == -1) { + perror("Error: failed to map framebuffer device to memory"); + goto handle_ioctl_error; + } + + // Get fixed screen information + if (ioctl(device->fb_fd, FBIOGET_FSCREENINFO, &device->fb_finfo) == -1) { + perror("Error reading fixed information"); + goto handle_ioctl_error; + } + + /* Create the cairo surface which will be used to draw to */ + surface = cairo_image_surface_create_for_data(device->fb_data, + CAIRO_FORMAT_RGB16_565, + device->fb_vinfo.xres, + device->fb_vinfo.yres, + cairo_format_stride_for_width(CAIRO_FORMAT_RGB16_565, + device->fb_vinfo.xres)); + cairo_surface_set_user_data(surface, NULL, device, + &cairo_linuxfb_surface_destroy); + + return surface; + +handle_ioctl_error: + close(device->fb_fd); +handle_allocate_error: + free(device); + exit(1); +} + +int main(int argc, char *argv[]) { + int image_width; + int image_height; + char frame_buffer_number; + char fb_node[16] = {0}; + cairo_surface_t *surface; + cairo_surface_t *image; + cairo_t *cr; + + if (argc != 2) { + printf("Usage: ./cairo /path/to/png/image\n"); + exit(1); + } + + if (strstr(argv[1], ".png") == NULL) { + printf("Only png images are supported with this example\n"); + exit(1); + } + + printf("Enter frame buffer number:\t"); + scanf("%c", &frame_buffer_number); + sprintf(fb_node, "/dev/fb"); + fb_node[strlen(fb_node)] = frame_buffer_number; + fb_node[strlen(fb_node)] = '\0'; + printf("Frame buffer node is: %s\n", fb_node); + + surface = cairo_linuxfb_surface_create(fb_node); + cr = cairo_create(surface); + + /* + * We clear the cairo surface here before drawing + * This is required in case something was drawn on this surface + * previously, the previous contents would not be cleared without this. + */ + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + + cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size(cr, 32.0); + cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); + cairo_move_to(cr, 100, 300); + cairo_show_text(cr, "Toradex Cairo Example!"); + + /* Wait for the result of drawing operation to persist for the user to see */ + sleep(DELAY_IN_SECS); + /* Clear the surface and prepare for a new drawing operation */ + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + + image = cairo_image_surface_create_from_png(argv[1]); + image_width = cairo_image_surface_get_width(image); + image_height = cairo_image_surface_get_height(image); + + /* Scale the image arbitrarily */ + cairo_scale(cr, SCALE_WIDTH/image_width, SCALE_HEIGHT/image_height); + + cairo_set_source_surface(cr, image, 350, 200); + cairo_paint(cr); + /* Wait for the result of the drawing operation to persist for the user to see */ + sleep(DELAY_IN_SECS); + + /* Destroy and release all cairo related contexts */ + cairo_destroy(cr); + cairo_surface_destroy(surface); + + return 0; +}