libx11 can't take screenshot on Fedora OS C - c

I am not a specialist in C programming and Linux OS development, but I have a task about making screenshots on Ubuntu and Fedora OS. After searching on the internet I found a lot of topics and questions about how to do it using C language and libX11. Finally, I combined all I could find in one method which captures the screenshot and saves to .png file.
I have two virtual machines installed - one is Ubuntu 18.04, the second is Fedora 30. When I run my code on Ubuntu - it works perfectly, when I run it on Fedora - I have a screenshot file with black content.
My code is:
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include <stdio.h>
#include <inttypes.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cairo.h>
#include <cairo-xlib.h>
#include <stdlib.h>
int get_shift (int mask) {
int shift = 0;
while (mask) {
if (mask & 1) break;
shift++;
mask >>=1;
}
return shift;
}
void takeScreenshot() {
Display *d;
int s;
XImage *image;
XShmSegmentInfo shminfo;
d = XOpenDisplay(NULL);
s = DefaultScreen(d);
unsigned int width = DisplayWidth(d,s);
unsigned int height = DisplayHeight(d,s);
image = XShmCreateImage(d,
DefaultVisual(d,s), // Use a correct visual. Omitted for brevity
24, // Determine correct depth from the visual. Omitted for brevity
ZPixmap, NULL, &shminfo, width, height);
shminfo.shmid = shmget(IPC_PRIVATE,
image->bytes_per_line * image->height,
IPC_CREAT|0777);
shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
shminfo.readOnly = False;
XShmAttach(d, &shminfo);
XShmGetImage(d,
RootWindow(d,s),
image,
0,
0,
AllPlanes);
cairo_surface_t *surface;
int stride;
stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, width);
unsigned char *data = malloc(stride * height);
int redShift = get_shift(image->red_mask);
int greenShift = get_shift(image->green_mask);
int blueShift = get_shift(image->blue_mask);
printf("r_shift: %d; g_shift: %d; b_shift: %d\n",redShift, greenShift, blueShift);
printf("byte order: %d\n", image->byte_order);
printf("bytes per line: %d\n", image->bytes_per_line);
printf("bites per pixel: %d\n", image->bits_per_pixel);
printf("r_mask: %lu; g_mask: %lu; b_mask: %lu\n", image->red_mask, image->green_mask, image->blue_mask);
printf("bitmap_bit_order: %d bitmap_pad: %d format: %d xoffset: %d\n", image->bitmap_bit_order, image->bitmap_pad, image->format, image->xoffset);
int x, y;
for (y = 0; y < height; ++y){
for (x = 0; x < width; ++x) {
unsigned long pixel = XGetPixel(image, x, y);
unsigned char red = (image->red_mask & pixel)>>redShift;
unsigned char green = (image->green_mask & pixel)>>greenShift;
unsigned char blue = (image->blue_mask & pixel)>>blueShift;
data[y * stride + x * 4 + 0] = blue;
data[y * stride + x * 4 + 1] = green;
data[y * stride + x * 4 + 2] = red;
}
}
surface = cairo_image_surface_create_for_data(
data,
CAIRO_FORMAT_RGB24,
width, height,
stride);
cairo_status_t surfaceStatus = cairo_surface_status(surface);
const char *r = cairo_status_to_string (surfaceStatus);
printf("%s\n", &r[0]);
int writepngRes = cairo_surface_write_to_png(
surface,
"test.png");
printf("surf status: %d; write result: %d\n", surfaceStatus, writepngRes);
cairo_surface_destroy(surface);
}
int main(int argc, char* argv[]) {
takeScreenshot();
return 0;
}
And I build this code using following command:gcc code.c -o code.so -lXss -lX11 -lXext -fPIC -I/usr/include/cairo -lcairo
The setup is exactly the same on both machines, what I have checked is that bit mask, byte order and bytes per pixel are equal for both systems. I am asking for suggestions about how to find a bug reason, maybe advice which thing to debug. Thank you!
UPDATE:
When I run this code on both platforms I see exactly the same output:
r_shift: 16; g_shift: 8; b_shift: 0
byte order: 0
bytes per line: 5464
bites per pixel: 32
r_mask: 16711680; g_mask: 65280; b_mask: 255
bitmap_bit_order: 0 bitmap_pad: 32 format: 2 xoffset: 0
no error has occurred
surf status: 0; write result: 0

Related

Using 100% cpu vs using maximum available threads

I made a Mandelbrot set visual presentation using POSIX thread library in C. The output is a .pgm file.
Upon thread implementation three case seems to pop up which are as follows:-
On using only 4-3 thread it works slow, but don't eat up my CPU usage
On using 20 thread it works well, but use 100%-98% of CPU usage
On using 40 thread it works slow, and is only using 25 threads (as shown by windows task manager/process manager)
So, is it wise to use less threads or the use that amount of threads which just touch 100% CPU usage or the use maximum number of threads offered by OS ?
I am using Intel Pentium 4 x86 (2GB RAM) machine and using Windows 7 Ultimate.
The Code for reference
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#define MAX_ITR 100
#define MAX_UNSTABLE 4
#define Xin -1.5
#define Yin 1.0
#define Xf 0.5
#define Yf -1.0
char * arr;
void * function(void * arg)
{
int width = *((int *)arg);
int height = 8000;
int count;
double x=Xin, y=Yin;
double xf = Xf, yf = Yf;
double xinc = (xf-x)/(double)8000;
double yinc = (yf-y)/(double)8000;
double rr,ii,zr=0,zi=0,mag=0;
int i,j;
for(i=0;i<height;i++,x=Xin + xinc*width,y+= yinc)
{
for(j=0+width;j<width+400;j++,x += xinc,count=-1,zr=0,zi=0)
{
mag=0;
while((++count < MAX_ITR) && (mag < MAX_UNSTABLE))
{
rr = zr;
ii = zi; // square of Z
zr = rr*rr - ii*ii;
zi = 2*rr*ii;
zr += x;
zi += y;
mag = pow(zr*zr + zi*zi,0.5);
}
arr[j + i * height] = 255 - (int)(count * 255/MAX_ITR);
}
}
printf("\nthread id >%d\n",width/400 + 1);
printf("xinc %f\nyinc %f\n",xinc,yinc);
printf("from=>(%11.9f, %11.9f)\nto=>(%11.9f, %11.9f)\n",xinc*width,Yin,2*(xinc*width),Yf);
pthread_exit(NULL);
return NULL;
}
int main()
{
int width = 8000, height = 8000,i;
arr = (char *)malloc(sizeof(char) * width * height);
pthread_t threadPoll[20];
int set[20] = {0};
for(i=0;i<20;i++)
{
set[i] = 400*i;
printf("%d ",set[i]);
}
printf("\n");
for(i=0;i<20;i++)
{
pthread_create(&(threadPoll[i]), NULL, function, &(set[i]));
}
for(i=19;i>0;i--)
{
pthread_join(threadPoll[i],NULL);
}
FILE * fp = (FILE*)fopen("out.pgm","wb");
if(fp == NULL)return 1;
fprintf(fp,"P5\n%d %d\n255\n",width,height);
fwrite(arr,sizeof(char)*width*height,1,fp);
fclose(fp);
printf("done!");
free(arr);
return 0;
}

how to create bitmap in C and compile with gcc

i decided to learn C, and i try to follow this tutorial http://ricardolovelace.com/creating-bitmap-images-with-c-on-windows.html
but when i try to compile my code with gcc as this >gcc -Wall testc o app
he doesn't know type_rgb, can i define this type and how? and where in my code ?
#include <stdio.h>
struct rgb_data {
float r, g, b;
};
void save_bitmap( const char *file_name, int width, int height, int dpi, type_rgb *pixel_data);
/*
next steps of the tutorial
*/
rgb_data *pixels = new rgb_data[width * height];
for( int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
int a = y * width +x;
{
if ((x > 50 && x < 350) && (y > y && y < 350))
{
pixels[a].r = 255;
pixels[a].g = 255;
pixels[a].b = 0;
}else{
pixels[a].r = 55;
pixels[a].g = 55;
pixels[a].b = 55;
}
}
}
save_bitmap("black_border.bmp", width, height, dpi, pixels);
Bitmap file format is rather complicated. This is not the best way to learn C. It's better to start with something much simpler.
Having said that, the bitmap format starts with a bitmap header BITMAPFILEHEADER structure which is 14 bytes long, followed by BITMAPINFOHEADER structure 40 bytes long. These structures are defined in "Windows.h"
You have to write in various information in these structures and write them to file before writing the actual pixels.
You can have 1, 4, 8, 16, 24, and 32-bit bitmap. This is an example to read a 32-bit bitmap. This code assumes sizeof(short) is 2, sizeof(int) is 4.
int main()
{
int row, column;
int width = 100;
int height = 100;
int size = width * height * 4; //for 32-bit bitmap only
char header[54] = { 0 };
strcpy(header, "BM");
memset(&header[2], (int)(54 + size), 1);
memset(&header[10], (int)54, 1);//always 54
memset(&header[14], (int)40, 1);//always 40
memset(&header[18], (int)width, 1);
memset(&header[22], (int)height, 1);
memset(&header[26], (short)1, 1);
memset(&header[28], (short)32, 1);//32bit
memset(&header[34], (int)size, 1);//pixel size
unsigned char *pixels = malloc(size);
for(row = height - 1; row >= 0; row--) {
for(column = 0; column < width; column++) {
int p = (row * width + column) * 4;
pixels[p + 0] = 64; //blue
pixels[p + 1] = 128;//green
pixels[p + 2] = 192;//red
}
}
FILE *fout = fopen("32bit.bmp", "wb");
fwrite(header, 1, 54, fout);
fwrite(pixels, 1, size, fout);
free(pixels);
fclose(fout);
return 0;
}
Note the first pixel is blue, followed by green and read. The last pixel is not used in 32-bit bitmap. Also the height goes from bottom to top. This is another odd feature of bitmap. 24-bit bitmaps are more complicated because they need padding. 8-bit and lower will need an additional palette.
struct rgb_data {
float r, g, b;
};
float is not the right type for pixels. Each color goes from 0 to 255. This fits in unsigned char. You need instead
struct rgb_data {
unsigned r, g, b, alpha;
};
The alpha is the extra byte for 32-bit bitmap (which we won't use). Notice the size of this structure is 4. You can allocate this as
struct rgb_data *rgb = malloc(size);
Now you can access the pixels as follows:
int p = (row * width + column);
rgb[p].r = 255;
rgb[p].g = 0;
rgb[p].b = 0;
...
fwrite(rgb, 4, width * height, fout);

Implementing basic Raytracer in C

So I am currently working on a tutorial to implement a very basic raytracer (currently just drawing solid spheres). Said tutorial is located here: http://thingsiamdoing.com/intro-to-ray-tracing/
The tutorial is completely language agnostic and deals only in pseudocode. I attempted to convert this pseudocode into C but have encountered difficulty. My program compiles fine, yet the outputted .ppm image file experiences an early EOF error. The lack of information about the problem has left me stuck.
Here is my C code, which is meant to be a direct translation of the pseudocode:
#include <stdio.h>
#include <math.h>
#define WIDTH 512
#define HEIGHT 512
typedef struct {
float x, y, z;
} vector;
float vectorDot(vector *v1, vector *v2) {
return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
}
void writeppm(char *filename, unsigned char *img, int width, int height){
FILE *f;
f = fopen(filename, "w");
fprintf(f, "P6 %d %d %d\n", width, height, 255);
fwrite(img, 3, width*height, f);
fclose(f);
}
float check_ray(px, py, pz, dx, dy, dz, r) {
vector v1 = {px, py, pz};
vector v2 = {dx, dy, dz};
float det, b;
b = -vectorDot(&v1, &v2);
det = b*b - vectorDot(&v1, &v1) + r*r;
if (det<0)
return -1;
det = sqrtf(det);
float t1 = b - det;
float t2 = b + det;
return t1;
}
int main(void) {
int img[WIDTH*HEIGHT*3], distToPlane;
float cameraY, cameraZ, cameraX, pixelWorldX, pixelWorldY, pixelWorldZ, amp, rayX, rayY, rayZ;
for (int px = 0; px<WIDTH; px++) {
for (int py = 0; py<HEIGHT; py++) {
distToPlane = 100;
pixelWorldX = distToPlane;
pixelWorldY = (px - WIDTH / 2) / WIDTH;
pixelWorldZ = (py - HEIGHT / 2) / WIDTH;
rayX = pixelWorldX - cameraX;
rayY = pixelWorldY - cameraY;
rayZ = pixelWorldZ - cameraZ;
amp = 1/sqrtf(rayX*rayX + rayY*rayY + rayZ*rayZ);
rayX *= amp;
rayY *= amp;
rayZ *= amp;
if (check_ray(50, 50, 50, rayX, rayY, rayZ, 50)) {
img[(py + px*WIDTH)*3 + 0] = 0;
img[(py + px*WIDTH)*3 + 1] = 0;
img[(py + px*WIDTH)*3 + 2] = 128;
}
else {
img[(py + px*WIDTH)*3 + 0] = 255;
img[(py + px*WIDTH)*3 + 1] = 255;
img[(py + px*WIDTH)*3 + 2] = 255;
}
}
}
writeppm("image.ppm", "img", WIDTH, HEIGHT);
}
I am fairly confident the error does not lie with my function to write the .ppm file as I have used this for other work and it has been fine.
You may want to remove the quotes from around "img" in the following line of code:
writeppm("image.ppm", "img", WIDTH, HEIGHT);
seeing as how its prototype is void writeppm(char *, unsigned char *, int, int), although I am surprised that your compiler didn't at least give you a warning about a type mismatch.
Also, for the record, I would suggest putting some error checking code (like checking the return value of fwrite, or checking the return value of fopen)--- but that's just me.
Also, if you are not, please compile with all the warning enabled (eg with gcc use -ansi -Wall -pedantic), this will help you catch type mismatches and other little gotcha-ya's
I see two errors in main
int img[WIDTH*HEIGHT*3];
...
writeppm("image.ppm", "img", WIDTH, HEIGHT);
should be
unsigned char img[WIDTH*HEIGHT*3];
...
writeppm("image.ppm", img, WIDTH, HEIGHT);

Pixman compositing vs. alpha blending

Below is a small test program (works on little endian machines).
As is, the result is already strange to me :
in: r=20 g=20 b=80 a=FF (#202080FF, ok!)
out: r=90 g=90 b=C0 a=FF (#9090C0FF, strange...)
Where as I expected the fill color #FFFFFFFF x the mask 0x80 = #FFFFFF80 and so an output of #9090FFFF...
Now, if I set the fill color to #FFFFFF80 by changing "cfill.alpha = uint16_t(0x80) << 8;" , the result seems really wrong :
in: r=20 g=20 b=80 a=FF
out: r=98 g=98 b=E0 a=FF
I would expect fill x mask => #FFFFFF40 and thus an output of: #606060C0FF.
I especially do not understand how a lower alpha input color can end up in a lighter output on the target image.
What I am doing wrong here ?
Is there another PIXMAP_OP_xxx that would work as I expect ?
Thanks.
#include <stdlib.h>
#include <stdio.h>
#include "pixman.h"
union C {
uint32_t value;
struct RGBA8888 {
uint8_t a;
uint8_t b;
uint8_t g;
uint8_t r;
} rgba;
};
int main()
{
// create target image full with r=0x20 g=0x20 b=0x80 a=0xFF
size_t w = 100; // multiple of 4 for alignment
size_t h = 100;
C *target = (C*)malloc(w * h * sizeof(C));
for(size_t i = 0; i < w * h; ++i)
target[i].value = 0x202080FF;
printf("in: r=%02X g=%02X b=%02X a=%02X\n",
target[0].rgba.r, target[0].rgba.g, target[0].rgba.b, target[0].rgba.a);
// connect target to pixman image
pixman_image_t *ptarget = pixman_image_create_bits(PIXMAN_r8g8b8a8, w, h, (uint32_t*)target, w * sizeof(uint32_t));
// create fill
pixman_color_t cfill;
cfill.red = uint16_t(0xFF) << 8;
cfill.green = uint16_t(0xFF) << 8;
cfill.blue = uint16_t(0xFF) << 8;
cfill.alpha = uint16_t(0xFF) << 8;
pixman_image_t *pfill = pixman_image_create_solid_fill(&cfill);
// create mask with a=0x80
uint8_t *mask = (uint8_t*)malloc(w * h);
for(size_t i = 0; i < w * h; ++i)
mask[i] = 0x80;
pixman_image_t *pmask = pixman_image_create_bits(PIXMAN_a8, w, h, (uint32_t*)mask, w);
// do compositing
pixman_image_composite(
PIXMAN_OP_OVER,
pfill, pmask, ptarget,
// src_x, src_y
0, 0,
// mask_x, mask_y
0, 0,
// dest_x, dest_y, width, height
0, 0, w, h);
// display one pixel of target
printf("out: r=%02X g=%02X b=%02X a=%02X\n",
target[0].rgba.r, target[0].rgba.g, target[0].rgba.b, target[0].rgba.a);
}
I turns out that Pixman works with premultiplied alpha !
So the white with alpha should be #80808080 and subsequently #40404040 and not #FFFFFF80 and #FFFFFF40.
Hope it helps somebody else ;)

What is the simplest RGB image format?

I am working in C on a physics experiment, Young's interference experiment and I made a program who prints to file a huge bunch of pixels:
for (i=0; i < width*width; i++)
{
fwrite(hue(raster_matrix[i]), 1, 3, file);
}
Where hue, when given a value [0..255], gives back a char * with 3 bytes, R,G,B.
I would like to put a minimal header in my image file in order to make this raw file a valid image file.
More concise, switching from:
offset
0000 : height * width : data } my data, 24bit RGB pixels
to:
offset
0000 : dword : magic \
: /* ?? */ \
0012 : dword : height } Header <--> common image file
0016 : dword : width /
: /* ?? */ /
0040 : height * width : data } my data, 24bit RGB pixels
You probably want to use the PPM format which is what you're looking for: a minimal header followed by raw RGB.
TARGA (file name extension .tga) may be the simplest widely supported binary image file format if you don't use compression and don't use any of its extensions. It's even simpler than Windows .bmp files and is supported by ImageMagick and many paint programs. It has been my go-to format when I just need to output some pixels from a throwaway program.
Here's a minimal C program to generate an image to standard output:
#include <stdio.h>
#include <string.h>
enum { width = 550, height = 400 };
int main(void) {
static unsigned char pixels[width * height * 3];
static unsigned char tga[18];
unsigned char *p;
size_t x, y;
p = pixels;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
*p++ = 255 * ((float)y / height);
*p++ = 255 * ((float)x / width);
*p++ = 255 * ((float)y / height);
}
}
tga[2] = 2;
tga[12] = 255 & width;
tga[13] = 255 & (width >> 8);
tga[14] = 255 & height;
tga[15] = 255 & (height >> 8);
tga[16] = 24;
tga[17] = 32;
return !((1 == fwrite(tga, sizeof(tga), 1, stdout)) &&
(1 == fwrite(pixels, sizeof(pixels), 1, stdout)));
}
The recently created farbfeld format is quite minimal, though there is not much software supporting it (at least so far).
Bytes │ Description
8 │ "farbfeld" magic value
4 │ 32-Bit BE unsigned integer (width)
4 │ 32-Bit BE unsigned integer (height)
(2+2+2+2)*width*height │ 4*16-Bit BE unsigned integers [RGBA] / pixel, row-major
Here's a minimal example that writes your image file with a minimal PPM header. Happily, I was able to get it to work with the exact for loop you've provided:
#include <math.h> // compile with gcc young.c -lm
#include <stdio.h>
#include <stdlib.h>
#define width 256
int main(){
int x, y, i; unsigned char raster_matrix[width*width], h[256][3];
#define WAVE(x,y) sin(sqrt( (x)*(x)+(y)*(y) ) * 30.0 / width)
#define hue(i) h[i]
/* Setup nice hue palette */
for (i = 0; i <= 85; i++){
h[i][0] = h[i+85][1] = h[i+170][2] = (i <= 42)? 255: 40+(85-i)*5;
h[i][1] = h[i+85][2] = h[i+170][0] = (i <= 42)? 40+i*5: 255;
h[i][2] = h[i+85][0] = h[i+170][1] = 40;
}
/* Setup Young's Interference image */
for (i = y = 0; y < width; y++) for (x = 0; x < width; x++)
raster_matrix[i++] = 128 + 64*(WAVE(x,y) + WAVE(x,width-y));
/* Open PPM File */
FILE *file = fopen("young.ppm", "wb"); if (!file) return -1;
/* Write PPM Header */
fprintf(file, "P6 %d %d %d\n", width, width, 255); /* width, height, maxval */
/* Write Image Data */
for (i=0; i < width*width; i++)
fwrite(hue(raster_matrix[i]), 1, 3, file);
/* Close PPM File */
fclose(file);
/* All done */
return 0;
}
The header code is based on the specs at http://netpbm.sourceforge.net/doc/ppm.html. For this image, the header is just a string of fifteen bytes: "P6 256 256 255\n".

Resources