/* xws_cla.c 20 January 1999 */ /* Cell Array Graphical Primitive Translation * * The translation of cell arrays can be presented as three cases, * organized according to the orientation and skewing of the picture rectangle * on the device display: * 1. Picture rectangle in axis-parallel position. * 2. Picture rectangle in general position. * 3. Picture rectangle as parallelogram. * The first case allows cell array translation only in the cases that the cell * array axes are parallel to the device axes. This allows for rotation of the * cell array in 90 degree increments, and allows flipping of the cell array * about its center vertical and horizontal axis. The second case allows * arbitrary rotations, and flipping; the end result is still a rectangle. * The third case allows skewing as well as rotations and flipping. * * This code implements translation of the first case only. The * algorithm is taken from the book "GKS Theory and Practice", edited by Bono, * P.R. and Herman, I.; Springer-Verlag, 1987; in the article: "A Method of * Displaying Transformed Picture Rectangles Using GKS Raster Functions", by * Schumann, H. and Kotzauer, A.; pages 137-144. This article was originally * published in Computer Graphics Forum, 1986. The article discusses the cell * array translation problem and outlines algorithms for all three cases of * cell array translation. The following paragraphs contain the entire * presentation of the algorithm for the first case. The cell array is * referred to as the picture matrix. * * "With the picture rectangle parallel to the axes of the output raster, * each element of the picture matrix corresponds to a (not necessarily * integer) number of pixels of the output raster. That means a scaling of * the picture contents described by means of the picture matrix. * "The basis for the solution of this problem consists of the division * of scaling by a real factor into two scalings by integer factors, relating * both the picture matrix and the pixels covered by the picture rectangle to * a virtual raster. In what follows the picture matrix consists of M x N * elements and the picture rectangle covers M' x N' pixels in the output * raster. * * 1st Scaling: Producing the virtual raster * * The virtual raster consists of M1 x N1 with * M1 = LCM(M, M') * N1 = LCM(N, N') * (LCM = Lowest Common Multiple) * In this raster, a picture cell consists of K x L pixels with * K = M1 / M (K, L are integers) * L = N1 / N * There is not necessarily a special place in the memory for the virtual * raster. * * 2nd Scaling: Transmission of the virtual raster to the output raster * * The transmission takes place in the following steps: * Mapping of K1 x L1 pixels of the virtual raster to one pixel of the * output raster with * K1 = M1 / M' * L1 = N1 / N' * * Computing the value of the pixel (grey scale or color) of the output * raster by the K1 x L1 pixels of the virtual raster (for example by * averaging). * * If K,L >> K1,L1 the value of many pixels is known and the second scaling * can be done very efficiently." */ # include # include #ifdef VMS #include #else /* UNIX */ #include #endif #include "defs.h" #include "xws_defs.h" #define OFFSET 0 /* no horizontal scanline offset for image */ #define BYTES_PER_LINE 0 /* X will figure it out for me */ #define SRC_X 0 /* no horizontal offset into image data */ #define SRC_Y 0 /* no vertical offset into image data */ #define COUNT_INIT 0 /* this has to be zero, see comment in code */ #define PARALLELOGRAM_POINTS 4 /* four points to describe a parallelogram */ extern void free(); /* C library free memory allocation */ extern unsigned char *cla_dc_row(); /* gplot's get a row of direct color */ extern unsigned char *cla_i_row(); /* gplot's get a row of indexed color */ extern int cla_p_fb(); /* gplot's polygon fallback routine */ /* Macro to add an arbitrary precision color value, byte aligned or not */ /* in should be an unsigned integer at least precision bits long */ /* ptr points to unsigned chars, initially zero filled */ /* bit is an int representing desired bit offset */ #define mask_1_bit 1 #define mask_2_bits 3 #define mask_4_bits 15 #define mask_8_bits 255 #define mcr_ptcv(ptr, precision, in, bit) switch (precision){ \ case 32: *ptr++ = ( in & (mask_8_bits << 24) ) >> 24; \ case 24: *ptr++ = ( in & (mask_8_bits << 16) ) >> 16; \ case 16: *ptr++ = ( in & (mask_8_bits << 8) ) >> 8; \ case 8: *ptr++ = ( in & mask_8_bits ); break; \ case 4: *ptr = *ptr | ((in & mask_4_bits) << (4-bit)); bit= bit+4; \ if (bit == 8) { bit = 0; ++ptr; }; break; \ case 2: *ptr = *ptr | ((in & mask_2_bits) << (6-bit)); bit= bit+2; \ if (bit == 8) { bit = 0; ++ptr; }; break; \ case 1: *ptr = *ptr | ((in & mask_1_bit) << (7-bit)); bit= bit+1; \ if (bit == 8) { bit = 0; ++ptr; }; }; /* PROCEDURE DECLARATIONS */ static int lcm ( int a, int b ); /* This routine returns true if the default visual bits per pixel is one which xws_compress_pixels() can handle. */ static enum boolean xws_can_compress() { int bpp; bpp= sample_image->bits_per_pixel; return( (enum boolean)((bpp==1) || (bpp==2) || (bpp==4) || (bpp==8) || (bpp==16) || (bpp==24) || (bpp==32)) ); } static void swap_bits(b, n) register unsigned char *b; register long n; { static unsigned char _reverse_byte[0x100]= { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff }; do { *b= (char) _reverse_byte[*b]; b++; } while (--n > 0); } static void swap_short(bp, n) register char *bp; register long n; { register char c; register char *ep = bp + n; do { c = *bp; *bp = *(bp + 1); bp++; *bp = c; bp++; } while (bp < ep); } static void swap_long(bp, n) register char *bp; register long n; { register char c; register char *ep = bp + n; register char *sp; do { sp = bp + 3; c = *sp; *sp = *bp; *bp++ = c; sp = bp + 1; c = *sp; *sp = *bp; *bp++ = c; bp += 2; } while (bp < ep); } /* Pack pixel data into a bit stream of appropriate bits per pixel. */ static char * xws_compress_pixels( pixels, scanlength, backwards ) Pixeltype pixels[]; /* pixels to pack */ int scanlength; /* number of pixels to pack */ enum boolean backwards; /* on if they should be packed in reverse order */ { static char *packbuf= NULL; /* pointer to buffer to pack into */ register int ipix, bit; /* pixel to pack, bit offset */ register unsigned char *ptr; /* ptr into packing buffer */ int bufsiz; /* size of packing buffer */ /* If pixels is NULL, exit returning NULL (an error condition) */ if (!pixels) return( (char *)NULL ); bufsiz= (sample_image->bits_per_pixel * scanlength) + 8; /* in bits */ bufsiz= ( bufsiz - (bufsiz % 8) ) / 8; /* in bytes */ /* Create packing buffer. This memory will end up being freed by XDestroyImage. */ packbuf= (char *)calloc( (unsigned)bufsiz, sizeof(unsigned char) ); if (!packbuf) { fprintf(stderr, "%s: xws_compress_pixels: not enough memory for row compression.\n", ProgramName); return( (char *)NULL ); } /* Zero the packing buffer */ for (ipix=0; ipix=0; ipix--) { mcr_ptcv( ptr, sample_image->bits_per_pixel, pixels[ipix], bit ); } else for (ipix= 0; ipixbits_per_pixel, pixels[ipix], bit ); } /* Patch to cover apparent error in DEC's direct color visual */ #ifdef ultrix if ( sample_image->depth==24 && sample_image->bitmap_bit_order==LSBFirst && my_bit_order==MSBFirst ) swap_long(packbuf,bufsiz); #endif return( packbuf ); } xws_carray(p, q, r, nx, ny, precision, data, mode, no_bytes) int p[2], q[2], r[2]; /* defining location of the picture matrix */ int nx, ny; /* defining size of the cell array */ int precision; /* cell array color precision */ unsigned char *data; /* cell array data */ int mode; /* cell array encoding mode */ int no_bytes; /* no. of data bytes */ { int i; /* generic loop counter */ int limit; /* generic loop limit */ typedef struct two_d /* dimensions of picture matrix and rasters */ { int m; /* horizontal dimension before any transformations */ int n; /* vertical dimension before any transformations */ } two_d; two_d picture_matrix; /* dimensions of the picture matrix */ two_d virtual_raster; /* dimensions of the virtual raster */ two_d device_raster; /* dimensions of the device raster */ int k; /* horizontal cell copies in virtual raster */ int kcounter; /* 0 <= kcounter <= k */ int l; /* vertical cell copies in virtual raster */ int lcounter; /* 0 <= lcounter <= l */ int k1; /* horizontal virtual pixels in device pixel */ int k1counter; /* 0 <= k1counter <= k1 */ int l1; /* vertical virtual pixels in device pixel */ int l1counter; /* 0 <= l1counter <= l1 */ int total_scanlines; /* total calls to XPutImage() that we'll do */ int scanline; /* count of current XPutImage() call */ int scanlength; /* total pixels set in one XPutImage() call */ int pixel; /* pixel counter in the image 'scanline' */ typedef struct iparms /* run time constants for XPutImage()'s image */ { unsigned int width; /* image width */ unsigned int height; /* image height */ int x; /* image x coordinate, in X coordinate space */ int y; /* image y coordinate, in X coordinate space */ int inc_x; /* image x coordinate increment in X coordinate space */ int inc_y; /* image y coordinate increment in X coordinate space */ int start_x;/* starting x coordinate, in X coordinate space */ int start_y;/* starting y coordinate, in X coordinate space */ enum boolean backwards; /* true if 'backwards', i.e. inc=-1 */ } iparms; char *image_data; /* the image data structure - one 'scanline' */ iparms ip; /* run time constants for image building */ XImage *image; /* X data structure for XPutImage() */ int dst_x, dst_y; /* X coordinates for image destination */ int inc_x, inc_y; /* X coord increments for image destination */ /* for indexed color metafiles only */ int *ica; /* one row of the cell array in indices */ int *irs; /* one row of raster */ int pvc; /* pixel variable count for one output pixel */ typedef int count_accumulator; count_accumulator *c_acc; /* accumulator for color index frequency */ typedef unsigned char index_accumulator; index_accumulator *i_acc; /* accumulator for color index values */ int most_frequent_index; /* the most frequently occuring color index */ /* end for indexed color metafiles only */ /* for direct color metafiles only */ float *rca, *gca, *bca; /* one row of cell array red, green, & blue */ float *r_acc, *g_acc, *b_acc; /* accumulators for red, green, and blue */ float *rrs, *grs, *brs; /* one row of raster red, green, & blue */ RGBtuple diff; /* end for direct color metafiles only */ /*--------------- Initializations -----------------------*/ /* horizontal scanlines */ if ((p[1] == r[1]) && (r[0] == q[0]) && (int)xws_can_compress()) { picture_matrix.m = nx; picture_matrix.n = ny; device_raster.m = abs(r[0] - p[0]) + 1; device_raster.n = abs(r[1] - q[1]) + 1; total_scanlines = device_raster.n; scanlength = device_raster.m; ip.width = device_raster.m; ip.height = 1; inc_x = 0; inc_y = (q[1] < p[1]) ? (1) : (-1); ip.start_y= ip.inc_y= 0; if (p[0] < r[0]) /* fill image vector left to right */ { dst_x = p[0]; dst_y = MaxY - p[1]; ip.start_x= 0; ip.inc_x= 1; ip.backwards= off; } else /* fill image vector right to left */ { dst_x = r[0]; dst_y = MaxY - r[1]; ip.start_x= scanlength - 1; ip.inc_x= -1; ip.backwards= on; } } /* vertical scanlines */ else if ((p[0] == r[0]) && (r[1] == q[1]) && (int)xws_can_compress()) { picture_matrix.m = ny; picture_matrix.n = nx; device_raster.m = abs(r[0] - q[0]) + 1; device_raster.n = abs(p[1] - r[1]) + 1; total_scanlines = device_raster.m; scanlength = device_raster.n; ip.width = 1; ip.height = device_raster.n; inc_x = (p[0] < q[0]) ? (1) : (-1); inc_y = 0; ip.start_x= ip.inc_x= 0; if (p[1] > r[1]) /* fill image vector top to bottom */ { dst_x = p[0]; dst_y = MaxY - p[1]; ip.start_y= 0; ip.inc_y= 1; ip.backwards= off; } else /* fill image vector bottom to top */ { dst_x = r[0]; dst_y = MaxY - r[1]; ip.start_y= scanlength - 1; ip.inc_y= -1; ip.backwards= on; } } /* Simulate a cell array with polygons. */ else if ((i = cla_p_fb(p, q, r, nx, ny, precision, data, mode)) == GPLOT_SUCCESS) return(GPLOT_SUCCESS); /* Otherwise draw the parallelogram according to the filled-area * edge attributes. CGM Std, Annex D4 */ else { int xedge[PARALLELOGRAM_POINTS]; int yedge[PARALLELOGRAM_POINTS]; xedge[0] = p[0]; xedge[1] = r[0]; xedge[2] = q[0]; xedge[3] = q[0] + (p[0] - r[0]); yedge[0] = p[1]; yedge[1] = r[1]; yedge[2] = q[1]; yedge[3] = p[1] + (q[1] - r[1]); xws_edge(PARALLELOGRAM_POINTS, xedge, yedge); (void) fprintf(stderr, "%s: xws_carray: arbitrary cell \ array orientations not supported\n", ProgramName); return(GPLOT_DRIVER_INCAPABLE); } virtual_raster.m = lcm(picture_matrix.m, device_raster.m); virtual_raster.n = lcm(picture_matrix.n, device_raster.n); k = virtual_raster.m / picture_matrix.m; l = virtual_raster.n / picture_matrix.n; k1 = virtual_raster.m / device_raster.m; l1 = virtual_raster.n / device_raster.n; if (CGMClass2->c_s_mode == i_c_mode) { ica = (int *) calloc((unsigned) nx, sizeof(int)); irs = (int *) calloc((unsigned) scanlength, sizeof(int)); /* pvc = maximum number of different cell array elements which * are referenced while producing a single pixel in the output raster. * pvc is an acronym for pixel variable count. We want to determine * the maximum number of different pixel values which will be used * to produce a single pixel in the output raster. * pvc = (max # of cell array elments in a cell array row that are * mapped to the same output pixel) multiplied by (max number of cell * array rows that are mapped to the same output pixel). */ pvc = (1 + (k1 - 1) / k + (((k1 - 1) % k) ? 1 : 0)) * (1 + (l1 - 1) / l + (((l1 - 1) % l) ? 1 : 0)); if (pvc > DEVICE_COLOR_TABLE_SIZE) pvc = DEVICE_COLOR_TABLE_SIZE; c_acc = (count_accumulator *) calloc((unsigned) (pvc * scanlength), sizeof(count_accumulator)); i_acc = (index_accumulator *) calloc((unsigned) (pvc * scanlength), sizeof(index_accumulator)); if (irs == NULL || ica == NULL || c_acc == NULL || i_acc == NULL) { (void) fprintf(stderr, "%s: xws_carray: Not enough memory.\n", ProgramName); return(GPLOT_DRIVER_INCAPABLE); } } else { rca = (float *) calloc((unsigned) nx, sizeof(float)); gca = (float *) calloc((unsigned) nx, sizeof(float)); bca = (float *) calloc((unsigned) nx, sizeof(float)); rrs = (float *) calloc((unsigned) scanlength, sizeof(int)); grs = (float *) calloc((unsigned) scanlength, sizeof(int)); brs = (float *) calloc((unsigned) scanlength, sizeof(int)); r_acc = (float *) calloc((unsigned) scanlength, sizeof(float)); g_acc = (float *) calloc((unsigned) scanlength, sizeof(float)); b_acc = (float *) calloc((unsigned) scanlength, sizeof(float)); if (rrs == NULL || grs == NULL || brs == NULL || rca == NULL || gca == NULL || bca == NULL || r_acc == NULL || g_acc == NULL || b_acc == NULL) { (void) fprintf(stderr, "%s: xws_carray: Not enough memory.\n", ProgramName); return(GPLOT_DRIVER_INCAPABLE); } } /*------------- Cell Array Translation ---------------------*/ /* Read in and process an entire row of the cell array at a time. * Paint the screen one 'scanline' at a time. * For indexed color cell arrays, select the most frequently * occurring color index among all the pixels of the virtual raster * that are mapped to a single pixel in the output raster. * For direct color cell arrays, take the average of the r,g,b * values of all the pixels of the virtual raster that are mapped * to a single pixel in the output raster. */ lcounter = l; for (scanline = 1; scanline <= total_scanlines; scanline++) { /* initialize the accumulator */ if (CGMClass2->c_s_mode == i_c_mode) { limit = pvc * scanlength; for (i=0; i < limit; i++) c_acc[i] = COUNT_INIT; } else { for(i=0; i < scanlength; i++) r_acc[i] = g_acc[i] = b_acc[i] = 0.0; diff.r = diff.g = diff.b = 0.0; } l1counter = 0; while (l1counter < l1) { int cell; /* index into cell array row, giving one cell */ int column_dup; /* cell element duplication count */ int row_dup; /* picture matrix row duplication count */ if (lcounter == l) { lcounter = 0; /* read in the next row of the cell array */ if (CGMClass2->c_s_mode == i_c_mode) data = cla_i_row(data, nx, ica, precision, mode); else data = cla_dc_row(data, nx, rca, gca, bca, precision, mode); } row_dup = MIN((l1 - l1counter), (l - lcounter)); lcounter += row_dup; l1counter += row_dup; cell = kcounter = 0; for (pixel = 0; pixel < scanlength; pixel++) { k1counter = 0; while (k1counter < k1) { column_dup = MIN((k1-k1counter), (k-kcounter)); kcounter += column_dup; k1counter += column_dup; if (CGMClass2->c_s_mode == i_c_mode) { /* Advance to the appropriate accumulator element. * * i = (pixel * pvc) = first element we want to test. * limit = i + pvc = one beyond last element to test. * to advance to the limit index is an error. */ limit = (pixel + 1) * pvc; for (i=pixel*pvc; c_acc[i] != COUNT_INIT && i < limit; i++) if (i_acc[i] == ica[cell]) break; if (i == limit) /* this should never happen */ (void) fprintf(stderr, "%s: xws_carray: \ algorithmic error: pvc too small.n", ProgramName); /* c_acc count depends on COUNT_INIT being exactly 0 */ c_acc[i] += (column_dup * row_dup); i_acc[i] = ica[cell]; } else /* direct color mode */ { r_acc[pixel] += (rca[cell] * column_dup * row_dup); g_acc[pixel] += (gca[cell] * column_dup * row_dup); b_acc[pixel] += (bca[cell] * column_dup * row_dup); } /* Go to next cell in picture vector if appropriate */ if (kcounter == k) { kcounter = 0; cell++; } } /* end while */ } /* end for - have processed one row of virtual pixels */ } /* end while - have processed one 'scanline' of device output */ /* Load up the X image data vector with device pixel values. * In the case of indexed cell arrays, for each * pixel in the scanline, take the pixel value which most frequently * occurs among all the (k1 * l1) virtual pixels which are mapped to a * single device pixel. In case of a several pixel indices occurring * with equal highest frequency, the choice among these is arbitrary. * Among the (k1 * l1) virtual pixels, we know that there are a * maximum of (pvc) different pixel values. When the count of pixel * value frequency is equal to the initialization value, we have * considered all the different virtual pixel values which are used in * determining a single pixel on the output device. */ ip.x= ip.start_x; ip.y= ip.start_y; for (pixel = 0; pixel < scanlength; pixel++) { if (CGMClass2->c_s_mode == i_c_mode) { int frequency; frequency = most_frequent_index = 0; i = pixel * pvc; limit = i + pvc; while ((c_acc[i] != COUNT_INIT) && (i < limit)) { if (c_acc[i] > frequency) { frequency = c_acc[i]; most_frequent_index = i_acc[i]; } i++; } *(irs+pixel)= most_frequent_index; } else /* direct color mode */ { RGBtuple average; /* Determine average r,g,b values for this pixel */ average.r = r_acc[pixel] / (double)(l1 * k1); average.g = g_acc[pixel] / (double)(l1 * k1); average.b = b_acc[pixel] / (double)(l1 * k1); /* Insist that r,g,b requests are within [0.0 .. 1.0] */ if (average.r < 0.0) average.r = 0.0; else if (average.r > 1.0) average.r = 1.0; if (average.g < 0.0) average.g = 0.0; else if (average.g > 1.0) average.g = 1.0; if (average.b < 0.0) average.b = 0.0; else if (average.b > 1.0) average.b = 1.0; /* This is the r, g, b for the pixel. */ *(rrs+pixel)= average.r; *(grs+pixel)= average.g; *(brs+pixel)= average.b; } ip.x += ip.inc_x; ip.y += ip.inc_y; } /* We now have indices, r, g, and b for a row */ /* Now convert the gathered indices and colors to pixel values, and compress the pixel values into an appropriate data stream for XCreateImage. Getting a NULL from xws_compress_pixels signals an error condition, probably due to memory unavailability. If this occurs, an error message has already been written. */ image_data= xws_compress_pixels( (*xws_get_row)(rrs, grs, brs, irs, scanlength, scanline-1), scanlength, ip.backwards ); if (!image_data) return( GPLOT_DRIVER_INCAPABLE ); /* Now create an XImage from the row. * It is significantly faster to create the image before each * call to XPutImage() and to destroy the image after each * call to XPutImage(), than it is to create and destroy the * image once per routine invocation and to use XPutPixel() * for each pixel in the image_data. Once the image is * created, its data can only be set through the Xlib call * XPutPixel(). XPutPixel is notably slow. The call to it * would be: * XPutPixel(image, ip.x, ip.y, (*xws_get_pixel)( r,g,b,i )); * where color is the device's color index. */ image = XCreateImage(Dpy, DefaultVisual(Dpy, Scr), (unsigned int) DefaultDepth(Dpy, Scr), ZPixmap, OFFSET, image_data, ip.width, ip.height, BitmapPad(Dpy), BYTES_PER_LINE); /* Now change some of the attributes of the image away from * the defaults to those of the actual data. This will * force XPutImage to convert the image to the proper format * on the way to the server. */ image->byte_order= my_byte_order; image->bitmap_bit_order= my_bit_order; image->bitmap_unit= 8; image->bitmap_pad= 8; /* Send out the X image data, one scanline on the device */ XPutImage(Dpy, Win, CellArrayGC, image, SRC_X, SRC_Y, dst_x, dst_y, ip.width, ip.height); dst_x += inc_x; dst_y += inc_y; XDestroyImage(image); } /* end cell array translation */ if (CGMClass2->c_s_mode == i_c_mode) { free((char *) ica); free((char *) irs); free((char *) c_acc); free((char *) i_acc); } else { free((char *) rca); free((char *) gca); free((char *) bca); free((char *) rrs); free((char *) grs); free((char *) brs); free((char *) r_acc); free((char *) g_acc); free((char *) b_acc); } return(GPLOT_SUCCESS); } /* Determine the least common multiple of two positive integers */ static int lcm ( int a, int b ) { register int m; int larger; int smaller; m = larger = (a > b) ? a : b; smaller = (a < b) ? a : b; while (m % smaller) m += larger; /* how dull... */ return (m); }