gtk display modified image - c

I'm changing an image's pixbuf data in response to a timer event but the changes only appear if I, for example, cover the window with another window and then uncover it. How can I get the changes to appear as soon as I make them?
#include <gtk/gtk.h>
#include <stdlib.h>
#define ROWS 400
#define COLS 400 // must be divisible by 4
#define BYTES_PER_PIXEL 3
typedef struct {
GtkImage *image;
int stride;
} ImageData;
void free_pixels(guchar *pixels, gpointer data) {
free(pixels);
}
void setrgb(guchar *a, int row, int col, int stride,
guchar r, guchar g, guchar b) {
int p = row * stride + col * BYTES_PER_PIXEL;
a[p] = r; a[p+1] = g; a[p+2] = b;
}
int update_pic(gpointer data) {
static int row = 0;
if (row > 100) return FALSE;
ImageData *id = (ImageData*)data;
GdkPixbuf *pb = gtk_image_get_pixbuf(id->image);
guchar *g = gdk_pixbuf_get_pixels(pb);
for (int c = 0; c < 200; c++)
setrgb(g, row, c, id->stride, 255, 0, 0);
row++;
// this is not enough to get it to show the updated picture
gtk_widget_queue_draw(GTK_WIDGET(id->image));
// adding this does not fix it
while (g_main_context_pending(NULL))
g_main_context_iteration(NULL, FALSE);
return TRUE;
}
int main(int argc, char **argv) {
GtkWidget *window, *image;
GdkPixbuf *pb;
guchar *pixels = calloc(ROWS * COLS, BYTES_PER_PIXEL);
ImageData id;
gtk_init(&argc, &argv);
image = gtk_image_new();
id.image = GTK_IMAGE(image);
id.stride = COLS * BYTES_PER_PIXEL; // COLS is divisible by 4
pb = gdk_pixbuf_new_from_data(
pixels,
GDK_COLORSPACE_RGB, // colorspace
0, // has_alpha
8, // bits-per-sample
COLS, ROWS, // cols, rows
id.stride, // rowstride
free_pixels, // destroy_fn
NULL // destroy_fn_data
);
gtk_image_set_from_pixbuf(GTK_IMAGE(image), pb);
g_object_unref(pb); // should I do this?
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "image");
gtk_window_set_default_size(GTK_WINDOW(window), COLS, ROWS);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_add(GTK_CONTAINER(window), image);
g_timeout_add(250, // milliseconds
update_pic, // handler function
&id); // data
gtk_widget_show_all(window);
gtk_main();
return 0;
}

GtkImage is not a general drawing widget, for that you would need GtkDrawingArea. I think the simplest way to do what you want with the GtkImage is to update your GdkPixBuf then set the GtkImage with the updated image. I have increased the reference count to the PixBuf, but I am not 100% sure that it is needed, but it does not do any harm.
#include <gtk/gtk.h>
#include <stdlib.h>
#define ROWS 400
#define COLS 400 // must be divisible by 4
#define BYTES_PER_PIXEL 3
typedef struct {
GtkImage *image;
GdkPixbuf *pb;
int stride;
} ImageData;
void free_pixels(guchar *pixels, gpointer data) {
free(pixels);
}
void setrgb(guchar *a, int row, int col, int stride,
guchar r, guchar g, guchar b) {
int p = row * stride + col * BYTES_PER_PIXEL;
a[p] = r; a[p+1] = g; a[p+2] = b;
}
int update_pic(gpointer data) {
static int row = 0;
if (row > 100) return FALSE;
ImageData *id = (ImageData*)data;
guchar *g = gdk_pixbuf_get_pixels(id->pb);
for (int c = 0; c < 200; c++)
setrgb(g, row, c, id->stride, 255, 0, 0);
row++;
// Update the image, by setting it.
gtk_image_set_from_pixbuf(GTK_IMAGE(id->image), id->pb);
return TRUE;
}
int main(int argc, char **argv) {
GtkWidget *window;
guchar *pixels = calloc(ROWS * COLS, BYTES_PER_PIXEL);
ImageData id;
gtk_init(&argc, &argv);
id.stride = COLS * BYTES_PER_PIXEL; // COLS is divisible by 4
id.pb = gdk_pixbuf_new_from_data(
pixels,
GDK_COLORSPACE_RGB, // colorspace
0, // has_alpha
8, // bits-per-sample
COLS, ROWS, // cols, rows
id.stride, // rowstride
free_pixels, // destroy_fn
NULL // destroy_fn_data
);
id.image = GTK_IMAGE(gtk_image_new_from_pixbuf(id.pb));
g_object_ref(id.pb);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "image");
gtk_window_set_default_size(GTK_WINDOW(window), COLS, ROWS);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_add(GTK_CONTAINER(window), image);
g_timeout_add(250, // milliseconds
update_pic, // handler function
&id); // data
gtk_widget_show_all(window);
gtk_main();
g_object_unref(id.pb);
return 0;
}

Related

C Argument number to create PGM images

I have to do a task for university in C. The program creates images in PGM format.The program compiles successfully, however, I can't run the program correctly. At the beginning of the main function the if operator needs 2 argc, but every time I try to run the program I just have one argc and I get the result
"Error: missing or bad parameters, usage a3 [imagefile]"
The code is:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
const double PI = 3.1415926535897932;
int** loadImage (const char *filename, int* width, int* height);
bool saveImage (const char *filename, int **pixels,
const unsigned int width, const unsigned int height);
/* *** task (a) *** */
int normalize(int value) {
return 0; // Dummy return
}
/* *** task (b) *** */
int** createImage(unsigned int width, unsigned int height, int value){
return NULL; // Dummy return
}
/* *** task (c) *** */
void freeImage(int** pixels, unsigned int width, unsigned int height){
}
/* *** task (d) *** */
int** inverter (int **pixels, int width, int height)
{
return NULL; // Dummy return
}
/* *** task (e) *** */
int** laplace (int **pixels, int width, int height)
{
return NULL; // Dummy return
}
/* *** task (f) *** */
int** rotate (int** pixels, int width, int height, double angle, int background)
{
return NULL; // Dummy return
}
int main (int argc, char **argv)
{
if (argc == 2)
{
int width=0, height=0;
int **image = loadImage (argv[1], &width, &height);
if (image != NULL)
{
int **image1 = inverter (image, width, height);
int **image2 = laplace (image, width, height);
int **image3 = rotate (image, width, height, 150, 128);
saveImage ("image0.pgm", image, width, height);
saveImage ("image1.pgm", image1, width, height);
saveImage ("image2.pgm", image2, width, height);
saveImage ("image3.pgm", image3, width, height);
freeImage (image, width, height);
freeImage (image1, width, height);
freeImage (image2, width, height);
freeImage (image3, width, height);
}
}
else {
printf ("Error: missing or bad parameters, usage a3 [imagefile]\n");
}
return 0;
}
/* *** Bild aus Datei laden *** */
int** loadImage (const char *filename, int* width, int* height)
{
const char *delimiter = " \n\r\t";
FILE *file = fopen (filename, "rt");
int** pixels;
bool isValid = true;
if (file != NULL)
{
char line [80];
int n = 0, params [3];
if (fgets (line, 80, file) == NULL) isValid = false;
if (strlen (line) != 3 || strncmp (line, "P2", 2)) isValid = false;
while (isValid && fgets (line, 80, file) != NULL)
{
if (strlen (line) <= 71)
{
if (line[0] == '#') continue;
char *p = strtok (line, delimiter);
while (isValid && p != NULL)
{
if (n < 3)
{
int a = atoi (p);
if (a <= 0) {isValid = false;}
else {params[n++] = a;}
}
else
{
if (n == 3)
{
if (params[2] != 255) {isValid = false;}
else {
pixels = createImage (params[0], params[1], 0);
*width = params[0];
*height = params[1];
}
}
if (n-3 < *width * *height)
{
int x = (n-3) % *width;
int y = (n-3) / *width;
int value = atoi (p);
pixels[y][x] = normalize(value);
n++;
}
else {isValid = false;}
}
p = strtok (NULL, delimiter);
}
}
else { isValid = false;}
}
fclose (file);
if (n-3 != *width * *height) {isValid = false;}
if (!isValid) freeImage (pixels, *width, *height);
}
return isValid ? pixels : NULL;
}
/* *** Bild in Datei speichern *** */
bool saveImage (const char *filename, int **pixels, unsigned int width, unsigned int height)
{
FILE *file = fopen (filename, "wt");
if (file != NULL && pixels != NULL)
{
fprintf (file, "P2\n");
fprintf (file, "%d %d\n", width, height);
fprintf (file, "%d\n", 255);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
fprintf (file, "%d\n", pixels[y][x]);
}
}
fclose (file);
return true;
}
return false;
}
The professor also said we should add following argument to the task in VSCode:
"args": [
"-g",
"-std=c99",
"-Wall",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}",
"-lm"
],
Your program a3.exe requires an argument which is the file name. To run it from command line, enter
.\a3.exe YourFilename
replacing YourFilename with the actual file name you want to use.

Handle is invalid

Trying to use SetConsoleScreenBufferSize but it fails and puts "The handle is invalid." In the last error. Will post all code, but here are some highlights:
Using this to resize buffer:
int TGHandleResizeEvent(struct TGHandle *tgHandle, INPUT_RECORD record) {
if (record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
WINDOW_BUFFER_SIZE_RECORD size = record.Event.WindowBufferSizeEvent;
sizeTGDrawBuffer(&tgHandle->drawBuffer, size.dwSize.X, size.dwSize.Y);
clearTGDrawBuffer(&tgHandle->drawBuffer);
COORD bufferNewSize = {
size.dwSize.X,
size.dwSize.Y
};
return SetConsoleScreenBufferSize(&tgHandle->screenBufferHandle, bufferNewSize);
}
}
Using this to allocate handle:
struct TGHandle TG() {
struct TGHandle tgHandle;
tgHandle.screenBufferHandle = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(tgHandle.screenBufferHandle, &info);
tgHandle.drawBuffer = createTGDrawBuffer(info.dwSize.X, info.dwSize.Y);
// Create the input buffer
tgHandle.inputBufferSize = 32;
tgHandle.inputBuffer = malloc(sizeof(INPUT_RECORD) * tgHandle.inputBufferSize);
// Hook up the input handle
tgHandle.inputHandle = GetStdHandle(STD_INPUT_HANDLE);
return tgHandle;
}
Here is full code.
tg.h
#ifndef TG_H
#define TG_H
#include <Windows.h>
#include <memory.h>
#define FOREGROUND_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
#define BACKGROUND_WHITE BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
// A drawing buffer, for general purposes
struct TGDrawBuffer {
COORD size;
CHAR_INFO *buffer;
};
struct TGDrawBuffer createTGDrawBuffer(int, int); // Function to allocate a drawing buffer
void sizeTGDrawBuffer(struct TGDrawBuffer*, int, int); // Resize a draw buffer
void clearTGDrawBuffer(struct TGDrawBuffer*); // Fill a buffer with blank cells
void TGDrawPixel(struct TGDrawBuffer*, int, int, CHAR_INFO); // Draw to a single cell on the buffer
void TGDrawAttribute(struct TGDrawBuffer*, int, int, int); // Modify a single attribute. X, Y, Attr
void TGDrawCharInfoString(struct TGDrawBuffer*, int, int, CHAR_INFO*, int); // X, Y, string, int. Draws to max X
CHAR_INFO* TGCharToCharInfo(char*, int); // Convert basic characters to CHAR_INFO. String, length.
void TGDrawString(struct TGDrawBuffer*, int, int, char*, int); // X, Y, string, length. Draws to max X
void freeTGDrawBuffer(struct TGDrawBuffer*); // Function to de-allocate a drawing buffer
int CharInfoStrlen(CHAR_INFO*); // Get length of a CHAR_INFO as if it were a string
// Essentially a drawing context to the screen
struct TGHandle {
HANDLE screenBufferHandle, inputHandle;
struct TGDrawBuffer drawBuffer;
INPUT_RECORD *inputBuffer;
int inputBufferSize;
};
struct TGHandle TG(); // Initialization function, which returns a drawing context to the screen
void useTGHandle(struct TGHandle*); // Make a screen drawing context active
void updateTGHandle(struct TGHandle*); // Displays what has been drawn
void setTGHandleCursorVisibility(struct TGHandle*, int); // True / False
int getTGInput(struct TGHandle*, INPUT_RECORD*, int); // Fill input into a buffer
int getTGNextInput(struct TGHandle*, INPUT_RECORD*); // Get a single INPUT_RECORD or return false
int TGHandleResizeEvent(struct TGHandle*, INPUT_RECORD); // Resize is not handled automatically
#endif
tg.c
#include "tg.h"
#include <string.h>
struct TGDrawBuffer createTGDrawBuffer(int width, int height) {
struct TGDrawBuffer tgDrawBuffer;
tgDrawBuffer.buffer = NULL; // Init the buffer to NULL
sizeTGDrawBuffer(&tgDrawBuffer, width, height);
return tgDrawBuffer;
}
void sizeTGDrawBuffer(struct TGDrawBuffer* drawBuffer, int width, int height) {
// Using free/ malloc here because we aren't interested in retaining data
if (drawBuffer->buffer) {
free(drawBuffer->buffer);
}
drawBuffer->buffer = malloc(sizeof(CHAR_INFO) * (width * height));
// Copy the size to the buffer record
drawBuffer->size.X = width;
drawBuffer->size.Y = height;
}
void clearTGDrawBuffer(struct TGDrawBuffer *tgBuffer) {
int i = 0, limit = tgBuffer->size.X * tgBuffer->size.Y;
// Create a blank CHAR_INFO
CHAR_INFO clearChar;
clearChar.Char.AsciiChar = ' ';
clearChar.Char.UnicodeChar = ' ';
clearChar.Attributes = FOREGROUND_WHITE; // Would be confusing without this
// Set everything to that buffer
while (i < limit) {
tgBuffer->buffer[i] = clearChar;
i++;
}
}
void TGDrawPixel(struct TGDrawBuffer *tgBuffer, int x, int y, CHAR_INFO character) {
tgBuffer->buffer[(tgBuffer->size.X * y) + x] = character;
}
void TGDrawAttribute(struct TGDrawBuffer *tgBuffer, int x, int y, int attr) {
tgBuffer->buffer[(tgBuffer->size.X * y) + x].Attributes = attr;
}
void TGDrawCharInfoString(struct TGDrawBuffer *tgDrawBuffer, int x, int y, CHAR_INFO *string, int length) {
int charsToWrite = length;
int distanceToEnd = (tgDrawBuffer->size.Y - 1) - y;
if (distanceToEnd < charsToWrite)
distanceToEnd = charsToWrite;
int startPos = x + (tgDrawBuffer->size.X * y);
int i = 0;
while (i < distanceToEnd) {
tgDrawBuffer->buffer[startPos + x] = string[i];
i++;
}
}
CHAR_INFO* TGCharToCharInfo(char* string, int length) {
if (length == -1)
length = strlen(string);
// TODO
}
void TGDrawString(struct TGDrawBuffer *tgDrawBuffer, int x, int y, char *string, int length) {
int charsToWrite = length;
int distanceToEnd = (tgDrawBuffer->size.Y - 1) - y;
if (distanceToEnd < charsToWrite)
charsToWrite = distanceToEnd;
int startPos = x + (tgDrawBuffer->size.X * y);
int i = 0;
while (i < charsToWrite) {
tgDrawBuffer->buffer[startPos + i].Char.AsciiChar = string[i];
tgDrawBuffer->buffer[startPos + i].Char.UnicodeChar = string[i];
i++;
}
}
void freeTGDrawBuffer(struct TGDrawBuffer *drawBuffer) {
free(drawBuffer->buffer);
}
struct TGHandle TG() {
struct TGHandle tgHandle;
tgHandle.screenBufferHandle = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(tgHandle.screenBufferHandle, &info);
tgHandle.drawBuffer = createTGDrawBuffer(info.dwSize.X, info.dwSize.Y);
// Create the input buffer
tgHandle.inputBufferSize = 32;
tgHandle.inputBuffer = malloc(sizeof(INPUT_RECORD) * tgHandle.inputBufferSize);
// Hook up the input handle
tgHandle.inputHandle = GetStdHandle(STD_INPUT_HANDLE);
return tgHandle;
}
void useTGHandle(struct TGHandle *tgHandle) {
SetConsoleActiveScreenBuffer(tgHandle->screenBufferHandle);
// Update the buffer sizes
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(tgHandle->screenBufferHandle, &info);
sizeTGDrawBuffer(&tgHandle->drawBuffer, info.dwSize.X, info.dwSize.Y);
clearTGDrawBuffer(&tgHandle->drawBuffer);
}
void updateTGHandle(struct TGHandle *tgHandle) {
COORD size = { tgHandle->drawBuffer.size.X, tgHandle->drawBuffer.size.Y }; // Buffer size
COORD pos = { 0, 0 }; // Start of the buffer coord
SMALL_RECT rect = {
.Left = 0,
.Top = 0,
.Right = size.X - 1,
.Bottom = size.Y - 1
}; // Rect to draw to on destination
WriteConsoleOutput(
tgHandle->screenBufferHandle,
tgHandle->drawBuffer.buffer,
size,
pos,
&rect
);
}
void setTGHandleCursorVisibility(struct TGHandle *tgHandle, int visible) {
// Copy the already-available cursor info
CONSOLE_CURSOR_INFO info;
GetConsoleCursorInfo(tgHandle->screenBufferHandle, &info);
// Modify the cursor visibility
info.bVisible = visible;
SetConsoleCursorInfo(tgHandle->screenBufferHandle, &info);
}
// You should be able to use a TGHandle's input buffer rather than creating your own
// for maximum memory conservation
int getTGInput(struct TGHandle *tgHandle, INPUT_RECORD *inputBuffer, int max) {
int availableRecords;
GetNumberOfConsoleInputEvents(tgHandle->inputHandle, &availableRecords);
int amountToRead = max;
if (availableRecords < max) {
amountToRead = availableRecords;
}
int numberRead;
ReadConsoleInput(
tgHandle->inputHandle,
inputBuffer,
amountToRead,
&numberRead
);
return numberRead;
}
// This function should be pretty performant if someone would not like to use
// the above function and mess around with buffers.
// Input record info: https://learn.microsoft.com/en-us/windows/console/input-record-str
int getTGNextInput(struct TGHandle *tgHandle, INPUT_RECORD *record) {
int availableRecords;
GetNumberOfConsoleInputEvents(tgHandle->inputHandle, &availableRecords);
if (availableRecords == 0) {
return 0;
}
ReadConsoleInput(
tgHandle->inputHandle,
tgHandle->inputBuffer,
1,
&availableRecords
);
*record = tgHandle->inputBuffer[0];
return 1;
}
int TGHandleResizeEvent(struct TGHandle *tgHandle, INPUT_RECORD record) {
if (record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
WINDOW_BUFFER_SIZE_RECORD size = record.Event.WindowBufferSizeEvent;
sizeTGDrawBuffer(&tgHandle->drawBuffer, size.dwSize.X, size.dwSize.Y);
clearTGDrawBuffer(&tgHandle->drawBuffer);
COORD bufferNewSize = {
size.dwSize.X,
size.dwSize.Y
};
return SetConsoleScreenBufferSize(&tgHandle->screenBufferHandle, bufferNewSize);
}
}
test.c
#include "tg.h"
#include <time.h>
#include <stdio.h>
void getMessageAsStr(char *buf) {
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), 0,
buf, 256, NULL);
}
int main() {
// Error buffer
char buf[256];
// Create a drawing context to the screen
struct TGHandle context = TG();
useTGHandle(&context);
setTGHandleCursorVisibility(&context, 0); // Hide the cursor of course
struct TGDrawBuffer *buffer = &context.drawBuffer;
// Create a CHAR_INFO to draw with
CHAR_INFO info;
info.Attributes = BACKGROUND_BLUE | FOREGROUND_WHITE;
info.Char.AsciiChar = ' ';
info.Char.UnicodeChar = ' ';
INPUT_RECORD input;
const int STRING_BUF_SIZE = 64;
char *fpsCountBuffer = malloc(sizeof(char) * STRING_BUF_SIZE);
long start, end;
start = QueryPerformanceCounter(&start);
int running = 1;
while (running) {
// Start off with a nice clean slate
//clearTGDrawBuffer(buffer);
// Collect input to react to resize
while (getTGNextInput(&context, &input)) {
if (input.EventType == WINDOW_BUFFER_SIZE_EVENT) {
if (!TGHandleResizeEvent(&context, input)) {
OutputDebugString("Couldn't resize:\n");
getMessageAsStr(buf);
OutputDebugString(buf);
}
}
}
// Draw line along top and bottom
int i = 0;
while (i < buffer->size.X) {
TGDrawPixel(buffer, i, 0, info);
TGDrawPixel(buffer, i, buffer->size.Y - 1, info);
i++;
}
i = 0;
// Draw vertical lines
while (i < buffer->size.Y) {
TGDrawPixel(buffer, 0, i, info);
TGDrawPixel(buffer, buffer->size.X - 1, i, info);
i++;
}
// FPS count!
// Get time elapsed in millis
QueryPerformanceCounter(&end);
long fps = 1000000 / (end - start);
// Put it into the screen buffer
snprintf(fpsCountBuffer, STRING_BUF_SIZE, "Running at %ldhz, %dx%d", fps, buffer->size.X, buffer->size.Y);
TGDrawString(buffer, 1, 1, fpsCountBuffer, strlen(fpsCountBuffer));
start = end;
updateTGHandle(&context);
}
}
Spotted it right after I posted it. You can see that I'm taking the pointer location of the handle in TGHandleResizeEvent:
return SetConsoleScreenBufferSize(&tgHandle->screenBufferHandle, bufferNewSize);
This is, in fact, an invalid handle. Corrected code:
return SetConsoleScreenBufferSize(tgHandle->screenBufferHandle, bufferNewSize);

Can't change data in GstBuffer

I am trying to create a set of gstreamer plugins for image processing routines. I have successfully created a source element that reads the image and the metadata into a GstBuffer, and a sink element that writes the data in the buffer to disk (along with the accompanying metadata) as desired. I have successfully tested these, and achieve the desired output (identical to the input with no filters in place).
I have also created a stretching element, that utilizes an external library to fill the dynamic range available (ie a 16-bit image with only 12-bits used per pixel can be stretched to fill the whole 16-bits available).
If I simply push the unchanged buffer out on the srcpad for the Stretching element, I get what I would expect (an unchanged image). However, if I try to perform any sort of manipulation of the data in the buffer, the data in the buffer is set to 0's.
Here is the current implementation of the chain() function for my Stretching plugin:
static GstFlowReturn
gst_stretching_chain(GstPad *pad, GstObject *parent, GstBuffer *buf)
{
GstStretching *filter;
filter = GST_STRETCHING(parent);
g_print("Stretching...\n");
guint num_rows;
g_object_get(G_OBJECT(parent), "num_rows", &num_rows, NULL);
guint num_cols;
g_object_get(G_OBJECT(parent), "num_cols", &num_cols, NULL);
guint bit_depth;
g_object_get(G_OBJECT(parent), "bit_depth", &bit_depth, NULL);
guint sig_bits;
g_object_get(G_OBJECT(parent), "sig_bits", &sig_bits, NULL);
gchar *product;
g_object_get(G_OBJECT(parent), "product", &product, NULL);
GstMapInfo info_in;
gst_buffer_map(buf, &info_in, GST_MAP_WRITE);
guint8 *in = info_in.data;
GstMemory *mem;
mem = gst_allocator_alloc(NULL, num_rows*num_cols*bit_depth/8, NULL);
GstMapInfo info_out;
gst_memory_map(mem, &info_out, GST_MAP_WRITE);
guint8 *out = info_out.data;
float *rad_gain[4] = {NULL, NULL, NULL, NULL};
float *rad_offset[4] = {NULL, NULL, NULL, NULL};
StretchingImage((unsigned short int *)in, num_rows, num_cols, sig_bits,
bit_depth, rad_gain, rad_offset, 0, product, (unsigned short int *)out);
gst_buffer_unmap(buf, &info_in);
gst_buffer_replace_all_memory(buf, mem);
return gst_pad_push(filter->srcpad, buf);
}
When this did not work, I also tried a simple change of the data manually (to see if I would get the expected output):
static GstFlowReturn
gst_stretching_chain(GstPad *pad, GstObject *parent, GstBuffer *buf)
{
GstStretching *filter;
filter = GST_STRETCHING(parent);
g_print("Stretching...\n");
guint num_rows;
g_object_get(G_OBJECT(parent), "num_rows", &num_rows, NULL);
guint num_cols;
g_object_get(G_OBJECT(parent), "num_cols", &num_cols, NULL);
guint bit_depth;
g_object_get(G_OBJECT(parent), "bit_depth", &bit_depth, NULL);
guint sig_bits;
g_object_get(G_OBJECT(parent), "sig_bits", &sig_bits, NULL);
gchar *product;
g_object_get(G_OBJECT(parent), "product", &product, NULL);
GstMapInfo info_in;
gst_buffer_map(buf, &info_in, GST_MAP_WRITE);
guint8 *in = info_in.data;
GstMemory *mem;
mem = gst_allocator_alloc(NULL, num_rows*num_cols*bit_depth/8, NULL);
GstMapInfo info_out;
gst_memory_map(mem, &info_out, GST_MAP_WRITE);
guint8 *out = info_out.data;
int i;
for (i=0; i<num_rows*num_cols*bit_depth/8; i++) {
out[i] = 255;
}
float *rad_gain[4] = {NULL, NULL, NULL, NULL};
float *rad_offset[4] = {NULL, NULL, NULL, NULL};
StretchingImage((unsigned short int *)in, num_rows, num_cols, sig_bits,
bit_depth, rad_gain, rad_offset, 0, product, (unsigned short int *)out);
gst_buffer_unmap(buf, &info_in);
gst_buffer_replace_all_memory(buf, mem);
return gst_pad_push(filter->srcpad, buf);
}
Even with this, I still obtain all 0's when I examine the output. I am assuming I am doing something wrong when trying to access the data in the buffer, but haven't yet been able to figure out what it may be. Any ideas?
The
gst_buffer_map(buf, &info_in, GST_MAP_WRITE);
should be
gst_buffer_map(buf, &info_in, GST_MAP_READ);
Also fyi, you can simplfy the code
guint num_rows, num_cols, ...;
g_object_get(G_OBJECT(parent),
"num_rows", &num_rows,
"num_cols", &num_cols,
...
NULL);

changing value of int defined in struct

I defined a struct Board with an int n, the value of which is a small integer. Before this method is called by the gtk signal "clicked", board->n has the correct value.
However, when calling this funciton, the value of n printed out by the first printf statement is something really large 32665.
draw_token (GtkButton *button, cairo_t *cr, Board *board){
printf("n: %d\n", board->n);
printf("button clicked\n");
//parse label of a button into the corresponding column number
guint col = (int)strtol(gtk_button_get_label(button), NULL, 0);
if (make_move(board, col) == false){
printf("draw cairo\n");
}
}
the struct:
typedef struct board Board;
struct board{
int k;
int n;
char *moves;
int player;
};
function where the callback is located:
void gui_make_buttons(GtkWidget *box, Board *board){
guint n = board->n;
for (int i = 1 ; i <= n ; i++){
GtkWidget *button = gtk_button_new();
//make label for button
char label[3];
sprintf(label, "%d", i-1);
gtk_button_set_label((GtkButton*)button,label);
// gtk_widget_show(button);
gtk_container_add(GTK_CONTAINER(box), button);
g_signal_connect(button, "clicked",G_CALLBACK(gui_draw_token), board);
}
}
Could someone please explain to me why the value of n has changed to large values like 36751 whenever the button is clicked?
Thank you very much
complete code with main
gui.c:
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <stdbool.h>
#include "gui.h"
#include "board.h"
#include "connect.h"
gboolean draw_board (GtkWidget *widget, cairo_t *cr, gpointer board){
guint width, height;
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
guint row = height/((Board*)board)->n;
guint col = width/((Board*)board)->n;
printf("%d\n", row);
printf("%d\n", col);
// cairo_set_source_rgb (cr, 100, 100, 255);
// cairo_paint (cr);
cairo_set_source_rgb(cr, 0, 0, 255);
for (int i = 1; i < ((Board*)board)->n ; i++){
//draw horizontal grids;
cairo_move_to (cr, 0, row*i);
cairo_line_to (cr, width, row*i);
//draw vertical grids;
cairo_move_to (cr, col*i, 0);
cairo_line_to (cr, col*i, height);
}
// cairo_arc (cr, 100, 100, 50, 0, 2 * G_PI);
// cairo_move_to (cr, 30, 30);
// cairo_line_to (cr, 50, 50);
cairo_stroke (cr);
return false;
}
int main (int argc, char *argv[]){
//check for correct number of arguments.
if (!check_argument(argc, argv))
return EXIT_FAILURE;
int k = strtol(argv[1], NULL, 0);
int n = strtol(argv[2], NULL, 0);
play_game(k, n);
return EXIT_SUCCESS;
}
//show widgets and get gtk going
CGUI *gui_start_gtk(Board *board){
//assigns board to the gui struct at beginning of game
CGUI *gui = make_gui (board);
// gtk_widget_queue_draw (gui->drawing_area);
// gui_draw_init_board(gui);
gtk_widget_show_all (gui->window);
gtk_main ();
return gui;
}
/*
void gui_draw_init_board(GtkWidget *widget, cairo_t *cr, CGUI *gui){
printf("HI\n");
if (gui) {
guint k = gui->board->k;
guint n = gui->board->n;
printf("%d\n", k);
}
}
*/
void gui_make_buttons(GtkWidget *box, Board *board){
// guint n = board->n;
for (int i = 1 ; i <= (board->n) ; i++){
GtkWidget *button = gtk_button_new();
//make label for button
char label[3];
// sprintf(label, "%d", i-1);
sprintf(label, "%d", i-1);
gtk_button_set_label((GtkButton*)button,label);
// gtk_widget_show(button);
gtk_container_add(GTK_CONTAINER(box), button);
g_signal_connect(button, "clicked",G_CALLBACK(gui_draw_token), board);
}
}
void gui_draw_token (GtkButton *button, cairo_t *cr, gpointer board){
printf("button clicked\n");
printf("n: %d\n", ((Board*)board)->n);
//parse label of a button into the corresponding column number
guint col = (int)strtol(gtk_button_get_label(button), NULL, 0);
printf("%d\n", col);
printf("n: %d\n", ((Board*)board)->n);
if (make_move(board, col) == false){
printf("draw cairo\n");
}
}
CGUI *make_gui(Board *board){
CGUI *gui = (CGUI*) malloc(sizeof(CGUI));
//assign variables to gui object
gui->board = board;
GtkWidget *window;
GtkWidget *frame;
GtkWidget *drawing_area;
gtk_init(NULL, NULL);
//set up initial window
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Connect-N-K");
gtk_window_set_default_size (GTK_WINDOW(window), 600, 650);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_widget_show(window);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), gui);
// g_signal_connect (window, "draw", G_CALLBACK (gui_draw_buttons), board);
//create boxes to fit buttons and drawing area
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
GtkWidget *draw_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
GtkWidget *button_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
//make all buttons take up even amount of space
gtk_box_set_homogeneous((GtkBox*)button_box, true);
gtk_widget_set_size_request(button_box, 600, 50);
// gtk_box_pack_start (box, window, false, false, false);
gtk_container_add(GTK_CONTAINER(window), box);
gtk_container_add(GTK_CONTAINER(box), draw_box);
gtk_container_add(GTK_CONTAINER(box), button_box);
//set up initial frame
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_widget_set_size_request(frame, 600, 600);
gtk_container_add(GTK_CONTAINER(draw_box), frame);
//create and pack buttons.
gui_make_buttons(button_box, board);
//set up drawing area
drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request(drawing_area, 600, 600);
gtk_container_add (GTK_CONTAINER (frame), drawing_area);
g_signal_connect (drawing_area, "draw", G_CALLBACK (draw_board), board);
printf("n: %d\n", board->n);
// printf("board in gui: %d\n", *board);
gui->window = window;
gui->frame = frame;
gui->drawing_area = drawing_area;
/*
//show widgets
connect.c :
/* connect.c */
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "gui.h"
#include "board.h"
#include "connect.h"
#define BUFFER_SIZE 10
/*
static int check_argument(int argc, char *argv[]);
static void play_game(int k, int n);
*/
/*
int main(int argc, char *argv[]){
//check for correct number of arguments.
if (!check_argument(argc, argv))
return EXIT_FAILURE;
int k = strtol(argv[1], NULL, 0);
int n = strtol(argv[2], NULL, 0);
play_game(k, n);
return EXIT_SUCCESS;
}
*/
int check_argument(int argc, char *argv[]){
if(argc < 3 || argc >3){
fprintf(stderr, "Parameters entered incorrectly. Input two integers for k and n respectively.\n");
return false;
}
else
return true;
}
//go through all steps of the game
void play_game(int k, int n){
//check to see if k and n are appropriate
if(k>n){
fprintf(stderr, "k is greater than n, game will never be won.\n");
return;
}
Board *board = make_board(k, n);
// print_board(board);//print initial board
//initiate gui
// CGUI *gui = make_gui();//set first three vars
// gui_set_board(gui, board);//set the fourth var
// CGUI *gui = gui_start_gtk(board);
// connect_play_game_text(board);
connect_play_game_gui(board);
/* int player = 1; //let first player go first
char *s = (char*)malloc(BUFFER_SIZE);//allocate memory for int to read
int move_result;
do{
fgets(s, BUFFER_SIZE, stdin);
int cols = strtol(s, NULL, 0);
move_result = make_move(board,cols,player);
//switch players if legal move and no one wins
if(move_result == false)
player = 3-player;
//do nothing is move is illegal(move_result = -1, thus letting
//the same player choose again.
}
while(move_result != true);
//free up resources
free(s);
destroy_board(board);
*/
}
int connect_play_game_gui(Board *board){
printf("n in connect: %d\n", board->n);
CGUI *gui = gui_start_gtk(board);
// gui_set_board(gui, board);//set the fourth var
// int player = 1; //let first player go first
// char *s = (char*)malloc(BUFFER_SIZE);//allocate memory for int to read
// int move_result;
// fgets(s, BUFFER_SIZE, stdin);
// int cols = strtol(s, NULL, 0);
// move_result = make_move(board,cols,player);
//switch players if legal move and no one wins
// if(move_result == false){
// player = 3-player;
return true;
// }
//do nothing if move is illegal(move_result = -1, thus letting
//the same player choose again.
// while(move_result != true);
//free up resources
// free(s);
// destroy_board(board);
}
int connect_make_move_gui(int col, Board *board, int player){
return 1;
}
void connect_play_game_text(Board *board){
print_board(board);//print initial board
char *s = (char*)malloc(BUFFER_SIZE);//allocate memory for int to read
int move_result;
do{
fgets(s, BUFFER_SIZE, stdin);
int cols = strtol(s, NULL, 0);
move_result = make_move(board,cols);
}
while(move_result != true);
//free up resources
free(s);
destroy_board(board);
}
//initiate gui
//static void connect_init_gui
board.c:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "board.h"
#define DRAW 2
#define ILLEGAL_MOVE -1
static char set_player_char(int player);
static int check_draw(Board *board);
//make a new board
Board *make_board(int k, int n){
Board *board = (Board *) malloc(sizeof(Board));
board->moves = (char *)malloc(n*n);
(board->k) = k;
(board->n) = n;
board->player = 1;
//make an array of empty slots based of size n^2
for(int i = 0; i < n*n; i++){
board->moves[i] = '.';
}
return board;
}
//print board with updated moves, print last row first.
void print_board(Board *board){
int n = board->n;
//loop through each row
for(int i = n-1; i >= 0; i--){
//loop through each column
for(int j = 0; j<n; j++){
printf("%c", (board->moves)[i*n+j]);
printf(" ");//add space between columns
}
printf("\n"); //wrap around each row
}
printf("\n");
}
//set char for player
static char set_player_char(int player){
char player_char;
if (player == 1)
player_char = 'o';
else
player_char = '*';
return player_char;
}
//update board based on player's input, return the row move is made
int make_move(Board *board, int x){
printf("inmakemove n: %d\n", board->n);
// printf("board in make_move: %d\n", &board);
//if move is illegal, return
if (!check_legal_move(board, x))
return ILLEGAL_MOVE;
int n = board->n;
int row;
//loop through the rows of the given column to find an empty spot.
for (int i = 0; i < n; i++){
if ((board->moves)[i*n+x] == '.'){
(board->moves)[i*n+x] = set_player_char(board->player);
row = i;
break;
}
}
print_board(board);
//Check to see if a player has won the game.;
int stat = check_win(board, x, row);
if (stat == true){
fprintf(stdout, "Player %d won the game.\n", board->player);
return true;
}
//if all slots are filled, game is a draw.
if(stat == DRAW){
fprintf(stdout, "Game was a draw.\n");
return true;
}
//if no one won, game continues.
else{
board->player = 3-(board->player);
return false;
}
}
//check to see if move x is legal
int check_legal_move(Board *board, int x){
int n = board->n;
//see if column entered is legal.
if (x >= (board->n) || x<0){
fprintf(stderr, "Illegal move by player %d at column %d\
, number entered outside range of available columns.\n", board->player, x);
return false;
}
//see if column entered is already filled
if ((board->moves)[(n-1)*n+x] != '.'){
fprintf(stderr, "Illegal move by player %d at column %d\
, column is already filled.\n", board->player, x);
return false;
}
return true;
}
//check for winning move
int check_win(Board* board, int x, int row){
int n = board->n;
int k = board->k;
int current_move = row*n+x; //slot that the current move fills
char *moves = board->moves;
char player_char = set_player_char(board->player);
int score;
score = 1;
//Check to see how many continuous slots are filled with the current player'
//s token horizontally.
//going right
for (int i = 1; i<k && x+i<n; i++){
if(moves[current_move+i] == player_char)
score ++;
else
break;
}
//going left
for(int i = 1; i<k && x-i>=0; i++){
if(moves[current_move-i] == player_char)
score++;
else
break;
}
//if horizontally connect to k, the player wins.
if (score>=k)
return true;
//if not, check vertical.
score = 1;
//going up
for (int i = 1; i<k && row+i<n; i++){
if(moves[current_move+n*i] == player_char)
score ++;
else
break;
}
//going down
for(int i = 1; i<k && row-i>=0; i++){
if(moves[current_move-n*i] == player_char)
score ++;
else
break;
}
//if vertically connect to k, the player wins.
if (score>=k)
return true;
//if not, check rising to right diagnol. Reset score like previously.
score = 1;
//going right and up
for(int i = 1; i<k && row+i<n && x+i<n; i++){
if(moves[current_move+n*i+i] == player_char)
score ++;
else
break;
}
//going left and down
for(int i = 1; i<k && row-i>=0 && x-i>=0; i++){
if(moves[current_move-n*i-i] == player_char)
score ++;
else
break;
}
//if right diagonally connect to k, the player wins.
if (score>=k)
return true;
//if not, check left rising diagonal.
score = 1;
//check right and down
for(int i = 1; i<k && x+i<n && row-i>=0; i++){
if(moves[current_move-n*i+i] == player_char)
score ++;
else
break;
}
//check left and up
for(int i = 1; i<k && x-i>=0 && row+i<n; i++){
if(moves[current_move+n*i-i] == player_char)
score ++;
else
break;
}
//if left diagonally connect to k, the player wins.
if (score>=k)
return true;
if(check_draw(board))
return DRAW;
//if no k connect is made in any direction, game is not won.
return false;
}
//check to see if game has come to a draw
static int check_draw(Board *board){
int n = board->n;
//loop through the top row to see if there are any empty slots left
for (int i = 0; i<n; i++){
if((board->moves)[n*(n-1)+i] == '.')
return false;
}
//if no empty slots left, game was a draw.
return true;
}
//Free up resources.
void destroy_board(Board *board){
free(board->moves);
free(board);
}
I'm sorry this is long and messy, I'm still working on the code and new to C.
You need to change void gui_draw_token (GtkButton *button, cairo_t *cr, gpointer board) to void gui_draw_token (GtkButton *button, gpointer board)
You can't just make up callback signatures and hope things work. For signatures you need to look at the documentation appropriate to the signal. For example in this case the GtkButton clicked signal documentation.
It would also help us to answer your question if you would remove all the unnecessary code and commented out code.
not that I know gtk, but a quick google, it seems, the board you are getting in your callback isn't actually a board you are passing. Your callback signature for the clicked event is incorrect
it should look a little like
void button_clicked(GtkWidget *widget, gpointer data)
EDIT: Yeah don't pay attention to this. I thought the char label[3] was initialized outside the loop and he was updating the label[0] three times, resulting in undefined output for label[1] and label[2]
That's what I get for a cursory look at 739782781 lines of code. Sorry about that everyone.
you're not telling the label which one to update in the sprintf
char label[3];
sprintf(label, "%d", i-1);
^ is wrong
it should be
char label[3];
sprintf(label[n-1], "%d", i-1);
I think.

How do I create a GtkImage from a Cairo surface?

I want to be able to make a GtkImage from a Cairo surface (without writing a temp file).
I currently write the surface as PNG to a char array which I then feed to a PixbufLoader to get a Pixbuf which I use to create the GtkImage:
typedef struct
{
unsigned char *pos;
unsigned char *end;
} closure_t;
static cairo_status_t
png_to_array (void *closure, const unsigned char *data, unsigned int length)
{
closure_t *cl = (closure_t *) closure;
if ((cl->pos + length) > (cl->end))
return CAIRO_STATUS_WRITE_ERROR;
memcpy (cl->pos, data, length);
cl->pos += length;
return CAIRO_STATUS_SUCCESS;
}
// later in the code
cairo_surface_t *surface = ...
...
// how would i determine the right size?
unsigned char arr[...];
closure_t cl;
GtkWidget *image;
GdkPixbufLoader *pbloader;
GdkPixbuf *pb;
// copy surface png to arr
cl.pos = arr;
cl.end = arr + sizeof(arr);
cairo_surface_write_to_png_stream (surface,
(cairo_write_func_t) png_to_array,
&cl);
...
// write to pixbufloader, get pixbuf, create image
pbloader = gdk_pixbuf_loader_new();
gdk_pixbuf_loader_write(pbloader, arr, sizeof(arr), NULL);
gdk_pixbuf_loader_close(pbloader, NULL);
pb = gdk_pixbuf_loader_get_pixbuf(pbloader);
image = gtk_image_new_from_pixbuf(pb);
This seems rather cumbersome - isn't there an easier way to do this?
How would I determine the size of the array in my example?
One function will save you a lot of effort here. Look up gdk_pixbuf_get_from_surface. It gets a Pixbuf from a cairo_surface_t. Of coarse, realising as he writes it, that is only available if you use Gdk-3.0, which also means using Gtk+-3.0.
Of coarse if you want to use Gtk+-2.0 then you can create a pixmap, get a cairo_t from it then copy your other cairo_surface_t to it by
cairo_set_source_surface (cr, surface, x0, y0);
cairo_rectangle (cr, x0 + x, y0 + y, width, height);
cairo_fill (cr);
A example of how to create a pixmap is below, I'll let you fill in the rest.
#include <gtk/gtk.h>
#include <cairo/cairo.h>
int main(gint argc, gchar *argv[])
{
GdkPixmap *pixmap;
GtkWidget *image;
GtkWidget *window;
cairo_t *cr;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
pixmap = gdk_pixmap_new(window->window, 100, 100, -1);
cr = gdk_cairo_create(pixmap);
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_rectangle(cr, 10, 10, 80, 80);
cairo_fill(cr);
cairo_destroy(cr);
cr = NULL;
image = gtk_image_new_from_pixmap(pixmap, NULL);
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show(image);
gtk_main();
return 0;
}
Just a hint, I'm not sure how to determine the size of the array but I'm sure how long should be the size of the array since what your png_to_array callback will be called several times the size of your array should be the sum of all lengths
I'm using the stride to determine the size of array but at the end the total_lenght will determine the size of the png
int total_lenght = 0;
typedef struct
{
unsigned char *pos;
unsigned char *end;
} closure_t;
static cairo_status_t
png_to_array (void *closure, const unsigned char *data, unsigned int length)
{
closure_t *cl = (closure_t *) closure;
if ((cl->pos + length) > (cl->end))
return CAIRO_STATUS_WRITE_ERROR;
memcpy (cl->pos, data, length);
cl->pos += length;
total_lenght += lenght;
return CAIRO_STATUS_SUCCESS;
}
// later in the code
cairo_surface_t *surface = ...
...
int stride = cairo_image_surface_get_stride(surface);
unsigned char *arr = (unsigned char *) malloc(stride);
closure_t cl;
GtkWidget *image;
GdkPixbufLoader *pbloader;
GdkPixbuf *pb;
// copy surface png to arr
cl.pos = arr;
cl.end = arr + stride;
cairo_surface_write_to_png_stream (surface,
(cairo_write_func_t) png_to_array,
&cl);
...
// write to pixbufloader, get pixbuf, create image
pbloader = gdk_pixbuf_loader_new();
gdk_pixbuf_loader_write(pbloader, arr, total_lenght), NULL);
gdk_pixbuf_loader_close(pbloader, NULL);
pb = gdk_pixbuf_loader_get_pixbuf(pbloader);
image = gtk_image_new_from_pixbuf(pb);

Resources