xref: /petsc/src/sys/classes/draw/impls/x/ximage.c (revision 0619917b5a674bb687c64e7daba2ab22be99af31)
1 /*
2     Code for getting raster images out of a X image or pixmap
3 */
4 
5 #include <../src/sys/classes/draw/impls/x/ximpl.h>
6 
7 PETSC_INTERN PetscErrorCode PetscDrawGetImage_X(PetscDraw, unsigned char[PETSC_DRAW_MAXCOLOR][3], unsigned int *, unsigned int *, unsigned char *[]);
8 
9 static inline PetscErrorCode PetscArgSortPixVal(const PetscDrawXiPixVal v[PETSC_DRAW_MAXCOLOR], int idx[], int right)
10 {
11   PetscDrawXiPixVal vl;
12   int               i, last, tmp;
13 #define SWAP(a, b) \
14   do { \
15     tmp = a; \
16     a   = b; \
17     b   = tmp; \
18   } while (0)
19   PetscFunctionBegin;
20   if (right <= 1) {
21     if (right == 1) {
22       if (v[idx[0]] > v[idx[1]]) SWAP(idx[0], idx[1]);
23     }
24     PetscFunctionReturn(PETSC_SUCCESS);
25   }
26   SWAP(idx[0], idx[right / 2]);
27   vl   = v[idx[0]];
28   last = 0;
29   for (i = 1; i <= right; i++)
30     if (v[idx[i]] < vl) {
31       last++;
32       SWAP(idx[last], idx[i]);
33     }
34   SWAP(idx[0], idx[last]);
35   PetscCall(PetscArgSortPixVal(v, idx, last - 1));
36   PetscCall(PetscArgSortPixVal(v, idx + last + 1, right - (last + 1)));
37 #undef SWAP
38   PetscFunctionReturn(PETSC_SUCCESS);
39 }
40 
41 /*
42    Map a pixel value to PETSc color value (index in the colormap)
43 */
44 static inline int PetscDrawXiPixelToColor(PetscDraw_X *Xwin, const int arg[PETSC_DRAW_MAXCOLOR], PetscDrawXiPixVal pix)
45 {
46   const PetscDrawXiPixVal *cmap = Xwin->cmapping;
47   int                      lo, mid, hi = PETSC_DRAW_MAXCOLOR;
48   /* linear search the first few entries */
49   for (lo = 0; lo < 8; lo++)
50     if (pix == cmap[lo]) return lo;
51   /* binary search the remaining entries */
52   while (hi - lo > 1) {
53     mid = lo + (hi - lo) / 2;
54     if (pix < cmap[arg[mid]]) hi = mid;
55     else lo = mid;
56   }
57   return arg[lo];
58 }
59 
60 PetscErrorCode PetscDrawGetImage_X(PetscDraw draw, unsigned char palette[PETSC_DRAW_MAXCOLOR][3], unsigned int *out_w, unsigned int *out_h, unsigned char *out_pixels[])
61 {
62   PetscDraw_X *Xwin = (PetscDraw_X *)draw->data;
63   PetscMPIInt  rank;
64 
65   PetscFunctionBegin;
66   if (out_w) *out_w = 0;
67   if (out_h) *out_h = 0;
68   if (out_pixels) *out_pixels = NULL;
69   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)draw), &rank));
70 
71   /* make sure the X server processed requests from all processes */
72   PetscDrawCollectiveBegin(draw);
73   XSync(Xwin->disp, True);
74   PetscDrawCollectiveEnd(draw);
75   PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)draw)));
76 
77   /* only the first process return image data */
78   PetscDrawCollectiveBegin(draw);
79   if (rank == 0) {
80     Window         root;
81     XImage        *ximage;
82     int            pmap[PETSC_DRAW_MAXCOLOR];
83     unsigned char *pixels = NULL;
84     unsigned int   w, h, dummy;
85     int            x, y, p;
86     /* copy colormap palette to the caller */
87     PetscCall(PetscMemcpy(palette, Xwin->cpalette, sizeof(Xwin->cpalette)));
88     /* get image out of the drawable */
89     XGetGeometry(Xwin->disp, PetscDrawXiDrawable(Xwin), &root, &x, &y, &w, &h, &dummy, &dummy);
90     ximage = XGetImage(Xwin->disp, PetscDrawXiDrawable(Xwin), 0, 0, w, h, AllPlanes, ZPixmap);
91     PetscCheck(ximage, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot XGetImage()");
92     /* build indirect sort permutation (a.k.a argsort) of the color -> pixel mapping */
93     for (p = 0; p < PETSC_DRAW_MAXCOLOR; p++) pmap[p] = p; /* identity permutation */
94     PetscCall(PetscArgSortPixVal(Xwin->cmapping, pmap, 255));
95     /* extract pixel values out of the image and map them to color indices */
96     PetscCall(PetscMalloc1(w * h, &pixels));
97     for (p = 0, y = 0; y < (int)h; y++)
98       for (x = 0; x < (int)w; x++) {
99         PetscDrawXiPixVal pix = XGetPixel(ximage, x, y);
100         pixels[p++]           = (unsigned char)PetscDrawXiPixelToColor(Xwin, pmap, pix);
101       }
102     XDestroyImage(ximage);
103     *out_w      = w;
104     *out_h      = h;
105     *out_pixels = pixels;
106   }
107   PetscDrawCollectiveEnd(draw);
108   PetscFunctionReturn(PETSC_SUCCESS);
109 }
110