Search code examples
clinuxx11xlib

XPutImage() isnt displaying the image correctly


Welp im not a guy to quit... But ive wasted around a full day and i have not reached even close

As with one comment pointed out i kinda forgot to say what was the objective/problem, well i want to open a X window, and display a simple png image with XPutImage. When i don't use a Pixmap it scatters seemingly random pixels everywhere regardless of how i format the incoming data. When i do use Pixmap the window remains black regardless of what i have tried... Everything's compiling with some minor unused variable warning's(which i solved since pushing to the repo)

image=readpng_verificar(args.decode_arg, &rowbytes, &pwidth, &pheight);
uint8_t *pont=MatrizParaVetor((uint8_t **)image.vetor, pheight, rowbytes);
pont=displaygrap_winrite(pont,pwidth, pheight, 8, rowbytes, args.decode_arg);

image is where i store 3 things namely 2 pointers related to pnglib(no probs) there and the last pointer which is a unsigned char ** for this we will only need to focus on the double pointed uint8 variable so i pass that variable throught image.vetor so its transformed from a unsigned char ** into a simple unsigned char * (concatenating the different heights into a single vector instead of a matrix) heres the code inside MatrizParaVetor()

uint8_t * MatrizParaVetor(uint8_t** matriz, uint32_t hei, size_t rwb){
    uint8_t *vetor=NULL;
    vetor =calloc(hei*rwb,sizeof(uint8_t));
    FILE * ok; 
    ok = fopen("teste.txt", "w");
    for (uint32_t y = 0; y < hei; y++){
        //memcpy(vetor[y], matriz[y], 30);
        //vetor=memmove(&(vetor[y*rwb]), matriz[y], 10);
        for (size_t x = 0; x < rwb; x+=4){
            vetor[y*x]=matriz[y][x];
            vetor[y*x+1]=matriz[y][x+1];
            vetor[y*x+2]=matriz[y][x+2];
            vetor[y*x+3]=0;
            //fprintf(ok, "%d\t%d\t%d\n",vetor[y*x],vetor[y*x+1],vetor[y*x+2]);
        }
        
    }
    fclose(ok);
    return vetor;
}

Some lines are just there for debugging(including the file IO) and yes im doing this in the steady and slow way(since others have failed).I just want it working for now. I tried memcpy functions but it seemed to abort regardless of the size to copy or to move(even if it was extremely short values).

Ok now were putting that vector inside the last function where i spent hours trying to make it work

uint8_t *displaygrap_winrite(uint8_t *vetor, uint32_t wid, uint32_t hei, uint8_t bitdepth,size_t rwb, const char *title){
    XImage *img;
    gfx_open(&wid, &hei, (const char *)title); 
    img=gfxvetor_image(vetor, bitdepth, wid, hei, rwb);
    gfx_image(img, wid, hei);
    //gfx_flush();
    if(waitForKey((uint8_t)XK_Escape,&wid, &hei)==1){
        
    }
    gfx_close();
    return vetor;
}

And this will go to my heavily modified gfx library, which is was just a very basic graphics library that used X11 to display things on screen.

void gfx_image(XImage *image, uint32_t wid, uint32_t hei){

//  GC gc;
    //XGCValues values;
    //gc = XCreateGC(gfx_display, gfx_window, 0, &values);
    Pixmap bitmap;
    
    bitmap = XCreatePixmap(gfx_display,gfx_window, wid, hei, image->depth);
    //TODO FIX OFFSET FIX DEST MAYBE DO MULTITHREADED ACTIOn
    
    XInitImage(image);
    //int a= XDrawRectangle(gfx_display, gfx_window,gfx_gc,10,10,wid+10,hei+10);
    //image->byte_order = MSBFirst;
    //image->bitmap_bit_order = MSBFirst;
    XPutImage(gfx_display,bitmap,gfx_gc,image, 0,0,0,0,wid,hei);
    //XCopyArea(gfx_display, image, bitmap, gfx_gc, 0,0,wid, hei, 0, 0);
    XSetWindowBackgroundPixmap(gfx_display, gfx_window,bitmap);
    //int           /* bitmap_pad */,
    //XImage
}
XImage *gfxvetor_image(uint8_t *data, uint8_t bitdepth, uint32_t wid, uint32_t hei, size_t rwb){
    XImage *image;
    
    Visual *visual = DefaultVisual(gfx_display,0);
    int screen = DefaultScreen(gfx_display);
    int dplanes = DisplayPlanes(gfx_display, screen);
    //image=(XImage *)malloc(sizeof(XImage));
    //image = XGetImage(gfx_display,gfx_display,0,0,wid,hei,dplanes, ZPixmap);
    //printf("\n%d\n",dplanes);
    //image->f.create_image(gfx_display, visual, dplanes, ZPixmap, 0, (char *)data, wid, hei, (int)bitdepth, (int)rwb);
    image = XCreateImage(gfx_display, visual, dplanes, ZPixmap, 0, (char *)data, wid, hei, (int)bitdepth, (int)rwb);
    //image->byte_order=MSBFirst;

    //image->bytes_per_line=rwb;
    //image->bits_per_pixel=32;
    //XInitImage(image);

    return image;
}

I have already done the objective which was decoding a png image and using Xlib to display it on screen. Althought the method i used to display it, putting a dot and coloring it was ultra slow and this was one thing i wanted to do of my 100000 todo things the repo of the project is at https://github.com/Imeguras/xertin for the full extent of the code

I just want the picture to appear on screen and the Xlib manual isnt helping my fatigue I am sorry, i sound a bit erratic, i am very tired but thanks for any feedback or help


Solution

  • I took a look at your code and I think the following are the problems you are experiencing.

    It looks like you are trying to fix byte order issues in the function MatrizParaVetor. It would be better to have the PNG library do that for you, so I suggest simplifying this function to the following:

    uint8_t * MatrizParaVetor(uint8_t** matriz, uint32_t hei, size_t rwb){
        uint8_t *vetor = calloc(hei*rwb,sizeof(uint8_t));
        uint8_t *pCurrent = vetor;
        for (uint32_t row = 0; row < hei; row++)
        {
            uint8_t *pRow = matriz[row];
            memcpy(pCurrent, pRow, rwb);
            pCurrent += rwb;
        }
        return vetor;
    }
    

    This just converts the array of pointers to rows to a contiguous pixel map.

    If the image is in the correct format, the function gfxvector_image can be simplified to:

    XImage *gfxvetor_image(uint8_t *data, uint8_t bitdepth, uint32_t wid, uint32_t hei, size_t rwb){
        XImage *image;
        Visual *visual = DefaultVisual(gfx_display,0);
        int screen = DefaultScreen(gfx_display);
        int dplanes = DisplayPlanes(gfx_display, screen);
        image = XCreateImage(gfx_display, visual, dplanes, ZPixmap, 0, (char *)data, wid, hei, (int)bitdepth, (int)rwb);
        return image;
    }
    

    Similarly gfx_image can be simplified to:

    void gfx_image(XImage *image, uint32_t wid, uint32_t hei){
        XPutImage(gfx_display,gfx_window,gfx_gc,image, 0,0,0,0,wid,hei);
    }
    

    If you now run your code and you see the red colored image in test.png, then all is good. If the image appears blue, then you need to modify you readpng_verificar function. Search for the call to png_set_alpha_mode and afterward add:

    png_set_bgr(png_ptr);
    

    This switches the decoding from red-green-blue component order to blue-green-red component order.