I have a small code snippet which loads an image from a PNG file, then modifies the image data in memory by making a specific color transparent (setting alpha to 0 for that color). Here's the code itself:
static gboolean expose (GtkWidget *widget, GdkEventExpose *event, gpointer userdata)
{
int width, height, stride, x, y;
cairo_t *cr = gdk_cairo_create(widget->window);
cairo_surface_t* image;
char* ptr;
if (supports_alpha)
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); /* transparent */
else
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* opaque white */
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
image = cairo_image_surface_create_from_png ("bg.png");
width = cairo_image_surface_get_width (image);
height = cairo_image_surface_get_height (image);
stride = cairo_image_surface_get_stride (image);
cairo_surface_flush (image);
ptr = (unsigned char*)malloc (stride * height);
memcpy (ptr, cairo_image_surface_get_data (image), stride * height);
cairo_surface_destroy (image);
image = cairo_image_surface_create_for_data (ptr, CAIRO_FORMAT_ARGB32, width, height, stride);
cairo_surface_flush (image);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
char alpha = 0;
unsigned int z = *((unsigned int*)&ptr [y * stride + x * 4]);
if ((z & 0xffffff) == 0xffffff) {
z = (z & ~0xff000000) | (alpha & 0xff000000);
*((unsigned int*) &ptr [y * stride + x * 4]) = z;
}
}
}
cairo_surface_mark_dirty (image);
cairo_surface_write_to_png (image, "image.png");
gtk_widget_set_size_request (GTK_OBJECT (window), width, height);
gtk_window_set_resizable (GTK_OBJECT (window), FALSE);
cairo_set_source_surface (cr, image, 0, 0);
cairo_paint_with_alpha (cr, 0.9);
cairo_destroy (cr);
cairo_surface_destroy (image);
free (ptr);
return FALSE;
}
When I dump the modified data to PNG, transparency is actually there. But when the same data is used as a source surface for painting, there's no transparency. What might be wrong?
Attachments:
image.png - modified data dumped to file for debugging purposes,
demo.png - actual result
bg.png - source image, is omitted due to stackoverflow restrictions, it's simply black rounded rectangle on the white background. Expected result is black translucent rectangle and completely transparent fields, not white, like these on the demo.png.
Setting alpha to 0 means that the color is completely transparent. Since cairo uses pre-multiplied alpha, you have to set the pixel to 0, since otherwise the color components could have higher values than the alpha channels. I think cairo chokes on those super-luminscent pixels.
So instead of this code:
if ((z & 0xffffff) == 0xffffff) {
z = (z & ~0xff000000) | (alpha & 0xff000000);
*((unsigned int*) &ptr [y * stride + x * 4]) = z;
}
You should try the following:
if ((z & 0xffffff) == 0xffffff) {
*((unsigned int*) &ptr [y * stride + x * 4]) = 0;
}
And while we are at it:
Doesn't (z & 0xffffff) == 0xffffff check if the green, blue and alpha channels are all at 100% and ignores the red channel? Are you sure that's really what you want? z == 0xffffffff would be opaque white.
Instead of using unsigned int, it would be better if you used uint32_t for accessing the pixel data. Portability!
Your code assumes that cairo_image_surface_create_from_png() always gives you an image surface with format ARGB32. I don't think that's necessarily always correct and e.g. RGB24 is possible as well.
I think I would do something like this:
for (y = 0; y < height; y++) {
uint32_t row = (uint32_t *) &ptr[y * stride];
for (x = 0; x < width; x++) {
uint32_t px = row[x];
if (is_expected_color(px))
row[x] = 0;
}
}
Related
I'm new to OpenGL, and I'm trying to move an object using the mouse. I'm using OpenGL 4.4 Core Profile, MinGW32, freeGLUT, GLU, and GLEW, programming in C.
The program draw an hexagon with GL_LINE_LOOP and the color (0.5, 0.5, 0.5, 1.0).
The problem is when I move it using the mouse, the object is softly blinking, the color changes to a darker grey. The blinking also occurs when drawing with the color (1.0, 1.0, 1.0, 1.0), but it is less visible.
I tried to change the swap interval using wglSwapIntervalEXT(), but it accepts only values 0 and 1. I also tried to enable Triple Buffering and "wait for Vsync" parameter of my graphic card. Changing these three parameters doesn't solve the problem.
The code is very simple, the vertex shader takes an Uniform vector t that corresponds to the translation to apply to the object.
Vertex shader program:
#version 440 core
in vec3 vertex_position;
uniform vec3 vertex_color;
uniform vec4 t;
uniform mat4 matrix;
out vec4 color;
vec4 vp;
void main() {
color = vec4(vertex_color,1.0);
vp = matrix * vec4(vertex_position,1.0);
gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);
}
Fragment shader program:
#version 440 core
in vec4 color;
void main()
{
gl_FragColor = color;
}
The draw function is very simple, and I have a timer function that call glutPostRedisplay() every 16 ms, in order to have arround 60 FPS. I tried without the timer function, it increases the FPS, but the blinking even occurs.
The draw function:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static int init = 1;
if(init == 1) {
glUseProgram(shader_program_core);
matrixloc = glGetUniformLocation(shader_program_core,"matrix");
// Load the matrix into the vertex shader:
glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
// translation localisation:
tloc = glGetUniformLocation(shader_program_core,"t");
init = 0;
}
glUniform3f(colorloc,0.5,0.5,0.5);
// translation:
glUniform4f(tloc,tx,ty,tz,tw);
glBindVertexArray(vao);
glDrawArrays(GL_LINE_LOOP, 0, 6);
glBindVertexArray(0);
glutSwapBuffers();
The complete source code that shows the problem is here:
#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
// coordinates of the hexagon:
GLfloat hexagon[18];
GLuint vao;
GLuint vbo;
// translations:
GLfloat tx = 0.0;
GLfloat ty = 0.0;
GLfloat tz = 0.0;
GLfloat tw = 0.0;
// window dimensions:
GLint width;
GLint height;
int window;
// coordinates of clicked point
int clicked_x;
int clicked_y;
// set to 1 if clicked down:
int clicked_down = 0;
/////////////////////////////////////////////////////////
//
// Shader programs for core profile:
//
const char * vsprog_core =
"#version 440 core\n"
"in vec3 vertex_position;\n"
"uniform vec3 vertex_color;\n"
"uniform vec4 t;\n"
"uniform mat4 matrix;\n"
" \n"
"out vec4 color;\n"
" \n"
"vec4 vp;\n"
" \n"
"void main() {\n"
" color = vec4(vertex_color,1.0);\n"
" vp = matrix * vec4(vertex_position,1.0);\n"
" gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);\n"
"}\n";
const char * fsprog_core =
"#version 440 core\n"
"in vec4 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = color;\n"
"}\n";
// uniforms locations:
GLint tloc;
GLint colorloc;
GLint matrixloc;
GLuint shader_program_core;
GLfloat PMVmatrix[16] = {
0.500000, 0.000000, 0.000000, 0.000000,
0.000000, 0.500000, 0.000000, 0.000000,
0.000000, 0.000000, 0.500000, 0.000000,
0.000000, 0.000000, 0.000000, 1.000000
};
void Draw()
{
int i,j;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static int init = 1;
if(init == 1) {
glUseProgram(shader_program_core);
matrixloc = glGetUniformLocation(shader_program_core,"matrix");
// Load the matrix into the vertex shader:
glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
// translation localisation:
tloc = glGetUniformLocation(shader_program_core,"t");
init = 0;
}
glUniform3f(colorloc,0.5,0.5,0.5);
// translation:
glUniform4f(tloc,tx,ty,tz,tw);
glBindVertexArray(vao);
glDrawArrays(GL_LINE_LOOP, 0, 6);
glBindVertexArray(0);
glutSwapBuffers();
//glutPostRedisplay();
}
void onMouseClick(int button, int state, int x, int y) {
if(state == GLUT_UP && button == GLUT_LEFT_BUTTON) clicked_down = 0;
if(state == GLUT_DOWN && button == GLUT_LEFT_BUTTON) {
clicked_down = 1;
clicked_x = x;
clicked_y = y;
}
}
void onMouseMove(int x, int y) {
int i,j;
if(clicked_down == 1) {
// compute x coordinate of the clicked point from the clicked x pixel:
GLfloat x1 = (clicked_x)*2.0/width - 1.0;
// compute x coordinate of the actual point from the actual x pixel:
GLfloat x2 = (x)*2.0/width - 1.0;
// compute y coordinate of the clicked point from the clicked y pixel:
GLfloat y1 = (clicked_y)*2.0/height - 1.0;
// compute y coordinate of the actual point from the actual y pixel:
GLfloat y2 = (y)*2.0/height - 1.0;
tx += x2 - x1;
ty += y1 - y2;
// save actual coordinates as previous ones, for the next move:
clicked_x = x;
clicked_y = y;
}
}
void timer( int value )
{
glutPostRedisplay();
glutTimerFunc( 16, timer, 0 );
}
int main( int argc, char *argv[ ], char *envp[ ] )
{
int i,j;
glutInitContextVersion(4, 4);
glutInitContextFlags(GLUT_FORWARD_COMPATIBLE/* | GLUT_DEBUG*/);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640,480);
window = glutCreateWindow("Program");
//glutFullScreen();
width = glutGet(GLUT_WINDOW_WIDTH);
height = glutGet(GLUT_WINDOW_HEIGHT);
// get version info
const GLubyte* renderer;
const GLubyte* version;
///////////////////////////////////////////////////////////////////////
//
// start GLEW extension handler
//
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return(-1);
}
fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
// get version info
renderer = glGetString(GL_RENDERER); // get renderer string
version = glGetString(GL_VERSION); // version as a string
printf("\nRenderer: %s", renderer);
printf("\nOpenGL version supported %s", version);
fflush(stdout);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
//////////////////////////////////////////////////////////
//
// Shaders:
//
GLint params;
GLint len;
GLuint vscore = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vscore, 1, &vsprog_core, NULL);
glCompileShader(vscore);
glGetShaderiv(vscore,GL_COMPILE_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetShaderInfoLog(vscore,100000,&len,log);
printf("\n\n%s\n\n",log);
return(-1);
}
GLuint fscore = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fscore, 1, &fsprog_core, NULL);
glCompileShader(fscore);
glGetShaderiv(fscore,GL_COMPILE_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetShaderInfoLog(fscore,100000,&len,log);
printf("\n\n%s\n\n",log);
return(-1);
}
shader_program_core = glCreateProgram();
glAttachShader(shader_program_core, fscore);
glAttachShader(shader_program_core, vscore);
glLinkProgram(shader_program_core);
glGetProgramiv(shader_program_core,GL_LINK_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetProgramInfoLog(shader_program_core,100000,&len,log);
printf("\n\n%s\n\n",log);
fflush(stdout);
return(-1);
}
//
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
//
// Compute coordinates of the hexagon:
//
hexagon[0] = cos(0.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[1] = sin(0.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[2] = 0.0;
hexagon[3] = cos(1.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[4] = sin(1.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[5] = 0.0;
hexagon[6] = cos(2.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[7] = sin(2.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[8] = 0.0;
hexagon[9] = cos(3.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[10] = sin(3.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[11] = 0.0;
hexagon[12] = cos(4.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[13] = sin(4.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[14] = 0.0;
hexagon[15] = cos(5.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[16] = sin(5.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[17] = 0.0;
// VAO:
glGenVertexArrays(1, &(vao));
glBindVertexArray(vao);
// VBO:
glGenBuffers(1,&(vbo));
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), hexagon, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0*sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
// End VAO:
glBindVertexArray(0);
glutMouseFunc(onMouseClick);
glutMotionFunc(onMouseMove);
glutDisplayFunc(Draw);
glutTimerFunc(0,timer,0);
glutMainLoop();
return 0;
}
The shaders are defined in two char* constants. Left-clicking and moving the mouse allow to move the object.
From your description, my (wild) guess is you have texturing enabled but you're not providing any texture information.
So, just call glDisable(GL_TEXTURE_2D); before drawing your cube.
I define my SDL2 window as follows:
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); // red: 8 bits
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); // green: 8 bits
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); // blue: 8 bits
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); // alpha: 8 bits
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32); // r + g + b + a = 32 bits
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
graphWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL);
Then, with the following struct, I create an array of pixels and use that array as the buffer that is passed to SDL:
typedef struct {
float r;
float g;
float b;
float a;
} Pixel;
// ...
void main(void) {
Pixel *pixels;
// ...
pixels = malloc(width * height * sizeof(Pixel));
// ...
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
while (graphNotClosed) {
glDrawPixels(width, height, GL_RGBA, GL_FLOAT, pixels);
// do some number cruching and change some elements of array "pixels"
// ...
SDL_GL_SwapWindow(graphWindow);
}
}
The thing that bothers me is, though the code sometimes change one and only one pixel in the while loop, I still keep passing the whole array (with width * height) to the SDL (via glDrawPixels) in each iteration.
And my question: Is this a must (and only way) to pass the whole array to SDL or is it possible to inform the SDL just the pixel(s) that had been altered from the previous state, in the name of accelerating the graphics process.
I am trying to get screenshot of NinevehGL object which is 3D library build on top of OpenGL. So i think OpenGL commands would work here as well.
Problem is screenshot works fine in iOS 5 or earlier but not with iOS6. It works fine in iOS6 simulator as well but not on iOS 6 device. It gives me black background. I have read many posts most of them suggest to put
CAEAGLLayer *eaglLayer = (CAEAGLLayer *) [self theNGLView].layer;
[eaglLayer setDrawableProperties:#{
kEAGLDrawablePropertyRetainedBacking: [NSNumber numberWithBool:YES],
kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
}];
in init method. which i did but with no luck.
I am using below method to get screenshot.
-(UIImage *)getImage{
GLint width;
GLint height;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
NSLog(#"%d %d",width,height);
NSInteger myDataLength = width * height * 4;
// allocate array and read pixels into it.
GLubyte *buffer = (GLubyte *) malloc(myDataLength);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// gl renders "upside down" so swap top to bottom into new array.
// there's gotta be a better way, but this works.
GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width * 4; x++)
{
buffer2[((height - 1) - y) * width * 4 + x] = buffer[y * 4 * width + x];
}
}
// make data provider with data.
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
// prep the ingredients
int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
// make the cgimage
CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
// then make the uiimage from that
UIImage *myImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpaceRef);
free(buffer);
free(buffer2);
return myImage;
}
I got that code to get the pixel color from current mouse position.
It works well but the only problem is, I can't get it from an d3d application...
I tried it few times, but it only get only black color -
Red: 0
Green: 0
Blue: 0
Here's my code -
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <d3d9.h>
HWND hWindow;
HDC hScreen;
HDC hdcMem;
HBITMAP hBitmap;
HGDIOBJ hOld;
int sX, sY, x, y;
BYTE* sData = 0;
POINT cursorPos;
int main()
{
int Red, Green, Blue;
hScreen = GetDC(hWindow);
sX = GetDeviceCaps(hScreen, HORZRES);
sY = GetDeviceCaps(hScreen, VERTRES);
hdcMem = CreateCompatibleDC (hScreen);
hBitmap = CreateCompatibleBitmap(hScreen, sX, sY);
BITMAPINFOHEADER bm = {0};
bm.biSize = sizeof(BITMAPINFOHEADER);
bm.biPlanes = 1;
bm.biBitCount = 32;
bm.biWidth = sX;
bm.biHeight = -sY;
bm.biCompression = BI_RGB;
bm.biSizeImage = 0; // 3 * sX * sY;
while (1) {
hOld = SelectObject(hdcMem, hBitmap);
BitBlt(hdcMem, 0, 0, sX, sY, hScreen, 0, 0, SRCCOPY);
SelectObject(hdcMem, hOld);
free(sData);
sData = (BYTE*)malloc(4 * sX * sY);
GetDIBits(hdcMem, hBitmap, 0, sY, sData, (BITMAPINFO*)&bm, DIB_RGB_COLORS);
GetCursorPos(&cursorPos);
x = cursorPos.x;
y = cursorPos.y;
Red = sData[4 * ( (y * sX) + x) +2];
Green = sData[4 * ( ( y * sX) + x) +1];
Blue = sData[4 * ( (y * sX) + x)];
printf("\nRed: %d\nGreen: %d\nBlue: %d\n", Red, Green, Blue);
Sleep(300);
}
}
Thanks!
Which kind of d3d application do you use? if the application use an Overlay surface, you can't get anything with code above. Overlay surface is widely used in Video players, it's totally different with normal surfaces in DirectX, the normal screen shot software can only catch data from primary surface, and Microsoft didn't provide any public interface to get data from Overlay surfaces, but some software can do this, the most common way is to hook DirectX, that's a different topic.
If your d3d application didn't use Overlay surface, you can use DiretX to get the data from screen, then get the pixel from the screen data you want.
Use CreateOffscreenPlainSurface to create an offscreen surface
Use GetFrontBufferData to get the data from screen
Lock the surface and read the pixel to get the color
I'm trying to write a Cairo program to black-fill the entire image and then draw another rectangle inside of it a different color. Eventually, I'm going to make this a program that generates a .png of the current time that looks like a digital clock. For now, this is where I'm getting hung up.
Here's my code:
#include <stdio.h>
#include <cairo.h>
//on color: 0.6, 1.0, 0
//off color: 0.2, 0.4, 0
int prop_number_width;
int prop_number_height;
int prop_width;
int prop_height;
int prop_space_width;
int prop_space_height;
double width;
double height;
double w_unit;
double h_unit;
void draw_number(cairo_t* cr, int unit_width, int num);
int main(int argc, char** argv) {
/* proportional sizes:
* the widths and heights of the diagram
*/
prop_number_width = 5; //how many spaces the number takes up
prop_number_height = 6;
prop_space_width = 1; //extra width on each side
prop_space_height = 1; //extra height on each side
prop_width = 25 + (2 * prop_space_width); //width of diagram
prop_height = 6 + (2 * prop_space_height); //height of diagram
/* actual sizes:
* the pixel value of different sizes
*/
width = 200.0;
height = 100.0;
w_unit = width / prop_width;
h_unit = height / prop_height;
//begin cairo stuff
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int)width, (int)height);
cairo_t* cr = cairo_create(surface);
//black fill
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_rectangle(cr, 0.0, 0.0, width, height); //cr ref, x, y, width, height
cairo_fill_preserve(cr);
//draw numbers from left to right
draw_number(cr, 0, 1);
//draw_number(cr, 6, 3);
//draw_number(cr, 14, 3);
//draw_number(cr, 20, 7);
//draw in colons
cairo_destroy(cr);
cairo_surface_write_to_png(surface, "test.png");
cairo_surface_destroy(surface);
return 0;
}
void draw_number(cairo_t* cr, int unit_width, int num) {
//determine the box size that the number will be drawn in
double box_x = w_unit * (prop_space_width + unit_width);
double box_y = h_unit * prop_space_height;
double box_width = w_unit * prop_number_width;
double box_height = h_unit * prop_number_height;
printf("{box_x: %lf box_y: %lf} {box_width: %lf box_height: %lf}\n", box_x, box_y, box_width, box_height);
cairo_set_source_rgb(cr, 0.2, 0.4, 0);
cairo_rectangle(cr, box_x, box_y, box_width, box_height);
cairo_fill_preserve(cr);
}
The problem is with this code it draws the rectangle to take up the whole image where from the printf's it should only take up a small part. Does anybody know how I can make this rectangle show up as the correct size?
I should have looked at the API more carefully. I needed to do cairo_fill() instead of cairo_fill_preserve(). Apparently, the first call to cairo_fill_preserve() was keeping the original rectangle and always filling that one.