Can't change data in GstBuffer - c

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);

Related

GTK C - get value of pointer to gint64 to feed the gtk_list_store_set

I guess i have a pure C problem here and that it has nothing to do with GTK, but i'm not sure.
I have this function in which i'm retreiving the content of a GtkEntry, converting the gchar to gint64 with another function, and then i want to add it to the list. Thou, while the first printf gives me the right value, the second one gives an incorrect value.
So, i can't figure out how to pass this value contained in the *c to the gtk_list_store_set.
void on_button_add_clicked (GtkButton *button, app_widgets *app_wid) {
GtkTreeIter iter;
//get the entry content
gint64 *c = mult_by_100_char2int(gtk_entry_get_text(GTK_ENTRY(app_wid->ent_mont)));
printf("c=%li\n",*c);
gint64 cval = *c;
printf("cval=%li\n",cval);
//put in the liststore
GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app_wid->treeview)));
gtk_list_store_append(store, &iter); // Acquire an iterator
gtk_list_store_set(store, &iter,
AMOUNT_COLUMN, cval, //the column requires a gint64
-1);
}
//prototype of other function is:
gint64* mult_by_100_char2int (const gchar* number)
Edit: (added functions - in reverse order)
gint64* mult_by_100_char2int (const gchar* number) {
const gchar* buf1 = mult_by_100(number);
gint64 buf2 = g_ascii_strtoll(buf1,NULL,10);
gint64 *buf3 = &buf2;
return buf3;
}
gchar* mult_by_100 (const gchar *number) {
int thesize = strlen(number);
gchar *entiers = substring(number,0,thesize-3);
gchar *centimes = substring(number,thesize-2,2);
gchar *result = g_strjoin("",entiers,centimes,NULL);
return result;
g_free(result);
}
gchar* substring(const gchar* s, int p, int l) {
char sub[128] = "";
char schar[128] = "";
gchar* result;
int i;
strcat(schar,s);
for(i=0;i<l;i++) {
sub[i] = schar[p+i];
//printf("i=%d - sub=%s\n",i,sub);
}
sub[i+1] = '\0';
result = g_strdup(sub);
return result;
g_free(result);
}
buf3 is an address of a variable local to mult_by_100_char2int. This variable does not exist anymore once mult_by_100_char2int returns. Your program has no right to access it.
It is an unlucky coincidence that the first printf produced a correct result. We may theorize why it did happen (I wouldn't be surprised is removal of first printf make the second one appear to work correctly), but the bottomline is that the behavior is undefined.
This is a generic question about pointers, nothing to do, as you stated, with Gtk. The #user58697 answer explain the why this happens.
The solve this problem, the mult_by_100_char2int function should return a gint64 instead of a pointer to a local variable.
It should look something like this:
gint64 mult_by_100_char2int (const gchar* number) {
gchar* buf1 = mult_by_100(number);
gint64 retval = g_ascii_strtoll(buf1,NULL,10);
g_free (buf1);
return retval;
}
Then, your callback function should be:
void on_button_add_clicked (GtkButton *button, app_widgets *app_wid) {
GtkTreeIter iter;
//get the entry content
gint64 c = mult_by_100_char2int(gtk_entry_get_text(GTK_ENTRY(app_wid->ent_mont)));
printf("c=%li\n",c);
//put in the liststore
GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app_wid->treeview)));
gtk_list_store_append(store, &iter); // Acquire an iterator
gtk_list_store_set(store, &iter,
AMOUNT_COLUMN, c, //the column requires a gint64
-1);
}
The other functions, as stated in the comments, have redundant g_free's, so they should be something like this (notice that i've only looked at the g_free calls, no other action taken, the code could be improved):
gchar* mult_by_100 (const gchar *number) {
int thesize = strlen(number);
gchar *entiers = substring(number,0,thesize-3);
gchar *centimes = substring(number,thesize-2,2);
gchar *result = g_strjoin("",entiers,centimes,NULL);
g_free(entiers);
g_free(centimes);
return result;
}
gchar* substring(const gchar* s, int p, int l) {
char sub[128] = "";
char schar[128] = "";
gchar* result;
int i;
strcat(schar,s);
for(i=0;i<l;i++) {
sub[i] = schar[p+i];
//printf("i=%d - sub=%s\n",i,sub);
}
sub[i+1] = '\0';
result = g_strdup(sub);
return result;
}
Haven't tested the code but it should work now.

Memory issue by loading struct-data with fread from binary file and load in a gtk liststore in C

I have a memory issue in my GTK programm and I don't know how to fix it.
The data in the liststore of my programm saved with fwrite in a binary file when I close the programm. The code seems to work:
void on_window_destroy (GtkWidget *object, gpointer user_data)
{
gint i;
GtkTreeIter iter;
GtkTreeModel *model = GTK_TREE_MODEL(gtk_builder_get_object (builder,"liststore"));
gint n_rows = gtk_tree_model_iter_n_children( model, NULL ); //count the rows
FILE *pfile = fopen("Data", "wb" );
gtk_tree_model_get_iter_first (model, &iter);//set iter postion to the first row
data *pdata = malloc(sizeof(data));
for (i = 0 ; i < n_rows; i++)
{
gtk_tree_model_get (model, &iter,
SPALTE_ArtName, &pdata->ArtBez,
SPALTE_ArtNr, &pdata->ArtNr,
SPALTE_LBest, &pdata->LBest,
-1);
//just to check the data
g_printf("Zeile %d: %s | %d | %d\n",i, pdata->ArtBez, pdata->ArtNr, pdata->LBest);
fwrite(pdata,sizeof(data),1,pfile);
gtk_tree_model_iter_next (model, &iter); //iter = next row
}
free(pdata);
fclose(pfile);
g_printf("Saved successfully!\n\n");
gtk_main_quit();
}
After this when I start the program again it should read the binary file with fread and add the data in the empty liststore
I tried this like this:
data *pdata = malloc (sizeof(data));
FILE *pfile = fopen("Data","rb");
if (pfile == NULL)
{
g_printf("Error: Data File not Found! Creating new list....\n");
}
else
{
while (fread (pdata,sizeof(data),1,pfile))
{
g_printf("Test 1 \n\n\n");
gtk_list_store_append(GTK_LIST_STORE(model), &iter); //add new row
g_printf("Test 1 \n\n\n");
gtk_list_store_set (GTK_LIST_STORE(model), &iter,
SPALTE_ArtName,pdata->ArtBez,
SPALTE_ArtNr,pdata->ArtNr,
SPALTE_LBest,pdata->LBest,
-1);
}
free(pdata);
fclose(pfile);
}
Here is the data struct used from pdata:
typedef struct _data
{
gchar *ArtBez;
gint *ArtNr;
gint *LBest;
}data;
The issue must has to do with the pdata->ArtBez because when I tab it out it works fine.
EDIT:
After I red the answer from stark (Thank you so much!) I changed the "data" struct to a struct without Pointers
typedef struct _data
{
gchar ArtBez[128];
gint ArtNr;
gint LBest;
}data;
Then I changed the write function from above to:
void on_window_destroy (GtkWidget *widget, gpointer user_data)
{
gint i, *BufArtNr, *BufLBest;
gchar *BufArtBez;
GtkTreeIter iter;
GtkTreeModel *model = GTK_TREE_MODEL(gtk_builder_get_object (builder, "liststore")); //Hole liststore aus glade-Datei
gint n_rows = gtk_tree_model_iter_n_children( model, NULL ); //count rows
FILE *pfile = fopen("Data", "wb" );
gtk_tree_model_get_iter_first (model, &iter); //Zeiger auf erste Zeile setzen
data *pdata = malloc(sizeof(data)*n_rows);
for (i = 0 ; i < n_rows; i++) //For every row
{
gtk_tree_model_get (model, &iter, //Get data from row
SPALTE_ArtNr, &BufArtNr,
SPALTE_ArtBez, &BufArtBez,
SPALTE_LBest, &BufLBest,
-1);
//Schreibe Daten in Struct
pdata[i].ArtNr = BufArtNr;
strcpy(pdata[i].ArtBez, BufArtBez);
pdata[i].LBest = BufLBest;
fwrite(&pdata[i],sizeof(data),1,pfile); //Write data to file
gtk_tree_model_iter_next (model, &iter); //Next row
}
free(pdata);free(BufArtBez);
fclose(pfile);
g_printf("Saved successfully\n\n");
}
That works, but when I compile the program, the compiler gets me a warning:
warning: assignment makes integer from pointer without a cast [enabled by default]
pdata[i].ArtNr = BufArtNr;
Same warning for pdata[i].LBest = BufLBest;
Where is my mistake?
pdata only contains pointers, which are not useful to save and restore. Instead of
fwrite(pdata,sizeof(data),1,pfile);
you need to do
fwrite(pdata->ArtBez,...
fwrite(pdata->ArtNr,...
fwrite(pdata->LBest,...
and then build a new structure when you read them back.

Problems with drag and drop in Gtk

I'm building an application that uses drag and drop using GTK in C language but I have a problem with this part of code
void view_onDragDataReceived(GtkWidget *wgt, GdkDragContext *context, int x, int y,GtkSelectionData *seldata, guint info, guint time,gpointer userdata)
{
GtkTreeModel *model;
GtkTreeIter iter;
model = GTK_TREE_MODEL(userdata);
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_URI,(gchar*)seldata->data, -1);
pathh=(char*)seldata->data;
}
I call this Function from this line of code
g_signal_connect(view, "drag_data_received",G_CALLBACK(view_onDragDataReceived), liststore);
the problem i'm having is that when i try to use that pathh variable in an other function i find it empty even though it's declared a global variable type char*
Try this way
struct SelectionData
{
GtkListStore *listStore;
gchar *path;
}
and then in the caller function
struct SelectionData *data;
data = malloc(sizeof(*data));
if (data == NULL)
handleMallocFailureAndPleaseDoNotContinue();
data->listStore = liststore;
data->path = NULL;
g_signal_connect(view, "drag_data_received",G_CALLBACK(view_onDragDataReceived), data);
and then
void view_onDragDataReceived(GtkWidget *wgt, GdkDragContext *context, int x, int y,GtkSelectionData *seldata, guint info, guint time, gpointer userdata)
{
GtkTreeModel *model;
GtkTreeIter iter;
SelectionData *selectionData;
size_t length;
selectionData = (SelectionData *)userdata;
model = GTK_TREE_MODEL(selectionData->liststore);
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_URI,(gchar*)seldata->data, -1);
length = strlen((char*)seldata->data);
if (selectionData->path != NULL) /* for subsequent calls */
free(selectionData->path);
selectionData->path = malloc(1 + length);
if (selectionData->path != NULL)
memcpy(selectionData->path, seldata->data, 1 + length);
}
and then you can access selectionData somewhere else and thus it's path field, which must be freed after you finish using it.
Try to avoid global variables as much as possible.
You can also use the same technique to copy seldata->data into your pathh global variable, but rethink your design and try not to use pathh global variable, since you are going to use malloc to allocate space for the string, and the global variable will be a pointer to it, so it will be very dificult to understand where and how you must free it.

Passing struct to GPU with OpenCL that contains an array of floats

I currently have some data that I would like to pass to my GPU and the multiply it by 2.
I have created a struct which can be seen here:
struct GPUPatternData
{
cl_int nInput,nOutput,patternCount, offest;
cl_float* patterns;
};
This struct should contain an array of floats. The array of floats I will not know untill run time as it is specified by the user.
The host code:
typedef struct GPUPatternDataContatiner
{
int nodeInput,nodeOutput,patternCount, offest;
float* patterns;
} GPUPatternData;
__kernel void patternDataAddition(__global GPUPatternData* gpd,__global GPUPatternData* output)
{
int index = get_global_id(0);
if(index < gpd->patternCount)
{
output.patterns[index] = gpd.patterns[index]*2;
}
}
Here is the Host code:
GPUPattern::GPUPatternData gpd;
gpd.nodeInput = ptSet->getInputCount();
gpd.nodeOutput = ptSet->getOutputCount();
gpd.offest = gpd.nodeInput+gpd.nodeOutput;
gpd.patternCount = ptSet->getCount();
gpd.patterns = new cl_float [gpd.patternCount*gpd.offest];
GPUPattern::GPUPatternData gridC;
gridC.nodeInput = ptSet->getInputCount();
gridC.nodeOutput = ptSet->getOutputCount();
gridC.offest = gpd.nodeInput+gpd.nodeOutput;
gridC.patternCount = ptSet->getCount();
gridC.patterns = new cl_float [gpd.patternCount*gpd.offest];
All the data is initialized then initialized with values and then passed to the GPU
int elements = gpd.patternCount;
size_t ofsdf = sizeof(gridC);
size_t dataSize = sizeof(GPUPattern::GPUPatternData)+ (sizeof(cl_float)*elements);
cl_mem bufferA = clCreateBuffer(gpu.context,CL_MEM_READ_ONLY,dataSize,NULL,&err);
openCLErrorCheck(&err);
//Copy the buffer to the device
err = clEnqueueWriteBuffer(queue,bufferA,CL_TRUE,0,dataSize,(void*)&gpd,0,NULL,NULL);
//This buffer is being written to only
cl_mem bufferC = clCreateBuffer(gpu.context,CL_MEM_WRITE_ONLY,dataSize,NULL,&err);
openCLErrorCheck(&err);
err = clEnqueueWriteBuffer(queue,bufferC,CL_TRUE,0,dataSize,(void*)&gridC,0,NULL,NULL);
Everything is built which I check just watching the error which stays at 0
cl_program program = clCreateProgramWithSource(gpu.context,1, (const char**) &kernelSource,NULL,&err);
////Build program
err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
char build[2048];
clGetProgramBuildInfo(program, gpu.device, CL_PROGRAM_BUILD_LOG, 2048, build, NULL);
////Create kernal
cl_kernel kernal = clCreateKernel(program, "patternDataAddition",&err);
////Set kernal arguments
err = clSetKernelArg(kernal, 0, sizeof(cl_mem), &bufferA);
err |= clSetKernelArg(kernal, 1, sizeof(cl_mem), &bufferC);
It is then kicked off
size_t globalWorkSize = 1024;
size_t localWorkSize = 512;
err = clEnqueueNDRangeKernel(queue, kernal, 1, NULL, &globalWorkSize, &localWorkSize, 0, NULL, NULL);
clFinish(queue);
Its at this point it all goes wrong
err = clEnqueueReadBuffer(queue, bufferC, CL_TRUE, 0, dataSize, &gridC, 0, NULL, NULL);
clFinish(queue);
The error in this case is -5 (CL_OUT_OF_RESOURCES).
Also if I change the line:
err = clEnqueueReadBuffer(queue, bufferC, CL_TRUE, 0, dataSize, &gridC, 0, NULL,
to:
err = clEnqueueReadBuffer(queue, bufferC, CL_TRUE, 0, dataSize*1000, &gridC, 0, NULL, NULL);
I get the error -30 (CL_INVALID_VALUE).
So my question is why am i getting the errors I am when reading back the buffer. Also I am not sure if I am unable to use a pointer to my float array as could this be giving me the wrong sizeof() used for datasize which gives me the wrong buffer size.
You cannot pass a struct that contains pointers into OpenCL
http://www.khronos.org/registry/cl/specs/opencl-1.2.pdf (Section 6.9)
You can either correct as Eric Bainville pointed out or if you are not very restrict on memory you can do something like
struct GPUPatternData
{
cl_int nInput,nOutput,patternCount, offest;
cl_float patterns[MAX_SIZE];
};
EDIT: OK if memory is an issue. Since you only use the patterns and patternCount you can copy the patterns from the struct and pass them to the kernel separately.
struct GPUPatternData
{
cl_int nInput,nOutput,patternCount, offest;
cl_float patterns*;
};
copy patterns to GPU from gpd and allocate space for patterns in gridC on GPU.
then
You can pass the buffers separately
__kernel void patternDataAddition(int gpd_patternCount,
__global const float * gpd_Patterns,
__global float * gridC_Patterns) {
int index = get_global_id(0);
if(index < gpd_patternCount)
{
gridC_Patterns[index] = gpd_Patterns[index]*2;
}
}
when you come back from the kernel copy the data back to gridC.patterns directly
One more :
You don't have to change your CPU struct. It stays the same. However this part
size_t dataSize = sizeof(GPUPattern::GPUPatternData)+ (sizeof(cl_float)*elements);
cl_mem bufferA = clCreateBuffer(gpu.context,CL_MEM_READ_ONLY,dataSize,NULL,&err);
openCLErrorCheck(&err);
//Copy the buffer to the device
err = clEnqueueWriteBuffer(queue,bufferA,CL_TRUE,0,dataSize,(void*)&gpd,0,NULL,NULL);
should be changed to something like
size_t dataSize = (sizeof(cl_float)*elements); // HERE
float* gpd_dataPointer = gpd.patterns; // HERE
cl_mem bufferA = clCreateBuffer(gpu.context,CL_MEM_READ_ONLY,dataSize,NULL,&err);
openCLErrorCheck(&err);
// Now use the gpd_dataPointer
err = clEnqueueWriteBuffer(queue,bufferA,CL_TRUE,0,dataSize,(void*)&(gpd_dataPointer),0,NULL,NULL);
Same thing goes for the gridC
And when you copy back, copy it to gridC_dataPointer AKA gridC.dataPointer
And then continue using the struct as if nothing happened.
The problem is probably with the pointer inside your struct.
In this case, I would suggest to pass nInput,nOutput,patternCount,offset as kernel args, and the patterns as a buffer of float:
__kernel void patternDataAddition(int nInput,int nOutput,
int patternCount,int offset,
__global const float * inPatterns,
__global float * outPatterns)
I know that it is not actual now, but i passed this problem in other way:
Your code for allocation memory for struct with data stay same, but struct should bu changed to
typedef struct GPUPatternDataContatiner
{
int nodeInput, nodeOutput, patternCount, offest;
float patterns[0];
} GPUPatternData;
Using this "feature" i have created vectors for OpenCL

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