2021年8月25日 星期三

X window 簡單的繪圖及貼圖程式

 主程式 main.cpp:

#include <opencv2/opencv.hpp> // should include first to prevent conflic
#include <opencv2/highgui.hpp>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/cursorfont.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
typedef unsigned char u8int;
typedef const char*   c_str;
Display *display;
Window     child;
GC        gCtx;      
XColor     fgColor, black, white ,red, green, blue;
XImage  *bg = nullptr;
int width   = 0;
int height  = 0;
void drawRect(int x, int y, int w, int h){
    XDrawRectangle(display, child, gCtx, x, y, w, h);
}
void drawLine(int x1, int y1, int x2, int y2){
    XDrawLine(display, child, gCtx, x1, y1, x2, y2);
}
void drawArc(int x, int y, int w, int h, int ang1, int ang2){
    XDrawArc(display, child, gCtx, x, y, w, h, ang1 << 6, ang2 << 6);
}
void setColorMap(XColor &c, const char *str){
    auto colormap = DefaultColormap(display, 0);
    XParseColor(display, colormap, str, &c);
    XAllocColor(display, colormap, &c);
}
void fgSetColor(XColor &c) {
    fgColor = c;
    XSetForeground(display, gCtx, c.pixel);
}
void setBackGround(u8int *src=nullptr, int sw=0, int sh=0, int sch=0){
    if (bg) XDestroyImage(bg);
    XWindowAttributes info;
    XGetWindowAttributes(display, child, &info);
    Visual *v = info.visual;
    width  = info.width ;
    height = info.height;
    int depth = info.depth;
    int sline = sch * sw;
    int dline= 4 * width;
    int size = dline * height;
    u8int *fb = (u8int *)malloc(size);
    if(! fb) {
        bg = nullptr;
        return;
    }
    bg = XCreateImage(display, v, depth,
        ZPixmap, 0, (char *)fb, width, height, 32, 0
    );
    if(! bg) {
        free(fb);
        return;
    }
    if(! src) {
        memset(fb, 0, size);
        return;
    }
    u8int *rgb = src;
    int zch = sch > 4 ? 4 : sch;
    float xs = (float)sw / width;
    float ys = (float)sh / height;
    float fy = 0;
    for(int y = 0; y < height; y ++) {
        float fx = 0;
        int d = 0;
        int s = 0;
        for (int x = 0; x < width; x ++) {
            fb[d] = rgb[s];
            for(int z = 1; z < zch; z ++) fb[d + z] = rgb[s + z];
            fx += xs;
            d += 4;
            s = sch * (int)fx;
        }
        fy += ys;
        fb += dline;
        rgb = src + sline * (int)fy;
    }
    XPutImage(display, child, gCtx, bg, 0, 0, 0, 0, width, height);
}
void setBackGround(cv::Mat &cam){
    return setBackGround((u8int *)cam.data,
        cam.cols,
        cam.rows,
        cam.channels()
    );
}
void bgRestore(int x0, int y0, int sw = 0, int sh = 0) {
    if (x0 < width && y0 < height){
        if (x0 < 0) x0 = 0;
        if (y0 < 0) y0 = 0;
        if (x0 + sw >=  width) sw = width  - x0;
        if (y0 + sh >= height) sh = height - y0;
        if (sw > 0 && sh > 0) XPutImage(display, child, gCtx,
            bg, x0, y0,
            x0, y0, sw, sh
        );
    }
}
int main(int argc, char **argv){    
    if(argc < 2) {
        printf("no file\n");
        return 1;
    }
    cv::Mat jpeg = cv::imread(argv[1]);// 8UC3
    display = XOpenDisplay(getenv("DISPLAY"));
    if (! display)  {
        printf("X error\n");
        return 3;
    }
    child = XCreateSimpleWindow(display,
        XDefaultRootWindow(display),
        0, 0, 600, 600,
        0,// border width
        WhitePixel(display, 0),
        BlackPixel(display, 0)
    );
    XSetStandardProperties(display, child, "MyXapp",
        "Icon", None, nullptr, 0, nullptr
    );
    gCtx = XCreateGC(display, child, 0, 0);
    setColorMap(black , "#000000");
    setColorMap(white , "#FFFFFF");
    setColorMap(red   , "#FF0000");
    setColorMap(green , "#00FF00");
    setColorMap(blue  , "#0000FF");  
    unsigned char shape[8] = {0xff, 0xff,0xff, 0xff, 0xff, 0xff,0xff, 0xff};
    unsigned char mask[8]  = {0xff, 0xff,0xff, 0, 0, 0xff,0xff, 0xff};// 1: show, 0: hidden
    Pixmap shapeid = XCreateBitmapFromData(display, child, (char *)shape, 8, 8);
    Pixmap maskid  = XCreateBitmapFromData(display, child, (char *)mask, 8, 8);
    Cursor cursorID = XCreatePixmapCursor(display, shapeid, maskid, &green, &black, 0, 0);
    XDefineCursor(display, child, cursorID);
    XFreePixmap(display, shapeid);
    XFreePixmap(display, maskid);
    XFreeCursor(display, cursorID);
    XSelectInput(display, child, ExposureMask | ButtonPressMask);
    XMapWindow(display, child);
    XFlush(display);
    fgSetColor(red);
    XEvent evt;
    
    printf("press mouse right button to exit.\n");
    while(true) {
        XNextEvent(display, &evt);
        if (evt.type == Expose) {
            if(evt.xexpose.count > 0) continue; // until count = 0
            setBackGround(jpeg);
            int right = width  - 1;
            int down  = height - 1;
            int cx    = width  / 2;
            int cy    = height / 2;
            drawLine(0, cy, right, cy);
            drawLine(cx, 0, cx, down);
            drawArc(0, 0, right, down, 0, 360);
            drawRect(0, 0, right, down);
            bgRestore(cx - 100, cy - 100, 200, 200);
        }        
        if (evt.type == ButtonPress)  {
            if(evt.xbutton.button == 3) {
                printf("press right\n");
                break;
            }
        }
    }
    if (bg) XDestroyImage(bg);
    XFreeGC(display, gCtx);
    XDestroyWindow(display, child);
    XCloseDisplay(display);    
}

事先準備好一個 test.jpeg, 編譯程式並執行:

g++   main.cpp  -lX11  `pkg-config  --cflags  --libs  opencv4`  && ./a.out  test.jpeg

沒有留言:

張貼留言

使用 pcie 轉接器連接 nvme SSD

之前 AM4 主機板使用 pcie ssd, 但主機板故障了沒辦法上網, 只好翻出以前買的 FM2 舊主機板, 想辦法讓老主機復活, 但舊主機板沒有 nvme 的界面, 因此上網買了 pcie 轉接器用來連接 nvme ssd, 遺憾的是 grub2 bootloader 無法識...