Saturday 15 June 2013

Screen shot capture in Linux using Cairo with GUI

There have been quite a lot of tutorials around on how to get screen-shots in Linux. This tutorial uses Cairo API (in C )to get screen-shot and show them on GTK window, one can store it as .png files if needed. 

OS: Ubuntu

#include <gtk/gtk.h>
#include <cairo.h>
#include <cairo-xlib.h>
#include <pthread.h>
#include <X11/Xlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

// variables to be used to catch status and errors.
static cairo_status_t status; // to get the error status.
static const char *PNGError; // to get the string representation of error.

void *writeToFile(void *PSurface)
{

    printf("In Write thread, with ID: %u\n",(unsigned int) pthread_self());
    cairo_surface_t *DispSurface;
    DispSurface = PSurface;

    status = cairo_surface_write_to_png(DispSurface, "test.png");
    if (!status) {
  printf("No problems in writing to File!\n");
    } else {
  printf("The error status number is: %d\n", status);
    }

    PNGError = cairo_status_to_string(status);
    printf("Cairo API says: %s\n", PNGError);
    printf("-----------------------------------------------------------------\n");
    cairo_surface_destroy(DispSurface);
    printf("Memory freed!\n");
    printf("-----------------------------------------------------------------\n");

}// End of write function and Thread!


void Dshow(GtkWidget * widget, gpointer drawArea)
{

    GdkPixbuf *pix;
    GError *err = NULL;

    printf("we are inside the show");
    /* Create pixbuf */
    pix = gdk_pixbuf_new_from_file("/home/ramu/Desktop/PeriodicCapture/test.png", &err);
    pix = gdk_pixbuf_scale_simple(pix, 850, 600, GDK_INTERP_BILINEAR);
    if (err) {
  printf("Error : %sn", err->message);
  g_error_free(err);
  return;
    }

    GdkDrawable *draw = gtk_widget_get_window(drawArea);
    /* Draw pixbuf */
    gdk_draw_pixbuf(draw, NULL, pix, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
    return;
}

// Capture Function starts here!
void Scapture(GtkWidget * widget, gpointer drawArea)
{

    Display *disp;
    Window root;
    cairo_surface_t *surface;
    int scr;

    pthread_t writeThread;// Thread to write the capture screen.

    disp = XOpenDisplay(NULL);
    scr = DefaultScreen(disp);
    root = DefaultRootWindow(disp);
    surface = cairo_xlib_surface_create(disp, root, DefaultVisual(disp, scr), DisplayWidth(disp, scr), DisplayHeight(disp, scr));

// Display error for threads!
    if (pthread_create(&writeThread, NULL, writeToFile, (void *)surface)) {
  printf("Unable to create thread!\n");
  exit(1);
    }
}// End of capture fucntion

void *displayUI()
{

// UI Functionality starts here!

    printf("UI thread started here with id: %u \n", (unsigned int) pthread_self());

    GtkWidget *window; // GTK Widgets pointers
    GtkWidget *frame;
    GtkWidget *capture;
    GtkWidget *show;
    GtkWidget *label;
    GtkWidget *drawArea;
    drawArea = gtk_drawing_area_new();

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL); // Top level Window here!
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE);// window with center position
    gtk_window_set_default_size(GTK_WINDOW(window), 1200, 650); // size of the window
    gtk_window_set_title(GTK_WINDOW(window), "screen capture"); // Title to the window

    frame = gtk_fixed_new(); // get a new frame/box to hold widgets
    gtk_container_add(GTK_CONTAINER(window), frame);// add the frame to the window

 /*Apparently, widgets are hooked to the frame.*/

    gtk_widget_set_size_request(drawArea, 850, 800); // sets the size
    gtk_fixed_put(GTK_FIXED(frame), drawArea, 50, 80); // and the location on frame.

    capture = gtk_button_new_with_label("capture"); // Button with labels, position and dimensions
    gtk_widget_set_size_request(capture, 80, 35); // sets the button size
    gtk_fixed_put(GTK_FIXED(frame), capture, 50, 20); // and the location on frame.

    show = gtk_button_new_with_label("show"); // same here
    gtk_widget_set_size_request(show, 80, 35); // -do-
    gtk_fixed_put(GTK_FIXED(frame), show, 150, 20); // -do-

    label = gtk_label_new("Logs Here!");  // TBD
    gtk_fixed_put(GTK_FIXED(frame), label, 950, 100);

    gtk_widget_show_all(window); //show them all

    g_signal_connect(window, "destroy", // call back function to quit.
     G_CALLBACK(gtk_main_quit), NULL);

    g_signal_connect(capture, "clicked", G_CALLBACK(Scapture), drawArea);

    g_signal_connect(show, "clicked", G_CALLBACK(Dshow), drawArea);

}

// Start of Main thread

int main(int argc, char **argv)
{

    printf("Main thread started here with id: %u\n", (unsigned int) pthread_self());

    gtk_init(&argc, &argv); // Initialize GTK

    pthread_t dpThread; // Thread for UI

    if (pthread_create(&dpThread, NULL, displayUI, NULL)) {
  printf("Unable to create User Interface Thread");
    }

    gtk_main(); // Main loop to listen for events.
    return 0;
}

In the next version, I will try to get a screen-shot in a fastest way. Probably from the frame-buffer.

No comments:

Post a Comment