/* x2pmp.c: Translate xwd window dump format into PMP format for the * IBM 3812 PagePrinter. */ #include #include #include #include #include #include #include "pmp.h" #include "xpr.h" #define max_(a, b) ((a) > (b) ? (a) : (b)) #define min_(a, b) ((a) < (b) ? (a) : (b)) #define abs_(a) ((a) < 0 ? -(a) : (a)) /* Local prototypes */ static unsigned char *magnification_table(int scale); static int bits_set(int n); static void leave(const char *s) _X_NORETURN; static void p_move_abs(FILE *p, int x, int y); static void p_save_cursor(FILE *p, int reg); static void p_restore_cursor(FILE *p, int reg); static void p_set_orientation(FILE *p, enum orientation orient); static void p_bitmap( FILE *p, unsigned int h, int w, unsigned long buflen, unsigned char *buf); static int plane = 0; #define FONT_HEIGHT 40 #define FONT_HEIGHT_PIXELS (FONT_HEIGHT*75/PPI) #define FONT_WIDTH 24 void x2pmp(FILE *in, FILE *out, int scale, int p_width, int p_length, int x_pos, int y_pos, /* in pels (units of PPI) */ char *head, char *foot, enum orientation orient, int invert) { unsigned char *buffer, *win_name; unsigned int win_name_size, width, height, ncolors; unsigned int buffer_size, one_plane_size, byte_width, fixed_width; int no_of_bits; unsigned long swaptest = 1; XWDFileHeader header; /* Read header from file */ if (fread((char *)&header, sizeof(header), 1, in) != 1) { if (feof(in)) return; else leave("fread"); } if (*(char *) &swaptest) _swaplong((char *) &header, sizeof(header)); if (header.file_version != XWD_FILE_VERSION) { fprintf(stderr,"%s: file format version %d, not %d\n", progname, (int)header.file_version, XWD_FILE_VERSION); } win_name_size = abs_(header.header_size - sizeof(header)); if ((win_name = (unsigned char *) calloc(win_name_size, (unsigned) sizeof(char))) == NULL) leave("Can't calloc window name storage."); /* Read window name from file */ if (fread((char *) win_name, sizeof(char), (int) win_name_size, in) != win_name_size) leave("Unable to read window name from dump file."); DEBUG(>= 1) fprintf(stderr,"win_name =%s\n", win_name); width = header.pixmap_width; height = header.pixmap_height; fixed_width = 8 * (byte_width = header.bytes_per_line); one_plane_size = byte_width * height; buffer_size = one_plane_size * ((header.pixmap_format == ZPixmap)? header.pixmap_depth: 1); /* Determine orientation and scale if not specified */ if (orient == UNSPECIFIED) orient = (fixed_width <= height)? PORTRAIT: LANDSCAPE; if (scale <= 0) { int real_height = height; if (head) real_height += FONT_HEIGHT_PIXELS << 1; if (foot) real_height += FONT_HEIGHT_PIXELS << 1; switch(orient) { default: case PORTRAIT: case UPSIDE_DOWN: scale = min_((p_width - 2*x_pos) / fixed_width, (p_length - 2*y_pos) / real_height); break; case LANDSCAPE: case LANDSCAPE_LEFT: scale = min_((p_length - 2*y_pos) / fixed_width, (p_width - 2*x_pos) / real_height); break; } if (scale <= 0) leave("PixMap doesn't fit on page."); else DEBUG(>1) fprintf(stderr, "scaling by %d to yield %d x %d image\n", scale, fixed_width*scale, height*scale); } ncolors = header.ncolors; if (ncolors) { int i; XColor *colors = (XColor *)malloc((unsigned) (header.ncolors * sizeof(XColor))); if (fread((char *)colors, sizeof(XColor), ncolors, in) != ncolors) leave("Unable to read colormap from dump file."); if (*(char *) &swaptest) { for (i = 0; i < ncolors; i++) { _swaplong((char *) &colors[i].pixel, (long)sizeof(long)); _swapshort((char *) &colors[i].red, (long) (3 * sizeof(short))); } } if (ncolors == 2 && INTENSITY(&colors[0]) > INTENSITY(&colors[1])) invert = !invert; free( colors ); } invert = !invert; /* 3812 puts ink (i.e. black) on 1-bits */ if ((buffer = (unsigned char *) calloc(buffer_size, 1)) == NULL) leave("Can't calloc data buffer."); bzero((char *) buffer, (int) buffer_size); /* Read bitmap from file */ if (fread((char *) buffer, sizeof(char), (int) buffer_size, in) != buffer_size) leave("Unable to read pixmap from dump file."); if (header.bitmap_bit_order == LSBFirst) { unsigned char bitswap[256], *bp; int c; for(c = 256; c--;) { bitswap[c] = ((c & 01) << 7) + ((c & 02) << 5) + ((c & 04) << 3) + ((c & 010) << 1) + ((c & 020) >> 1) + ((c & 040) >> 3) + ((c & 0100) >> 5) + ((c & 0200) >> 7); if (invert) bitswap[c] = ~bitswap[c]; } /* Here's where we do the bitswapping. */ for(bp = buffer+buffer_size; bp-- > buffer;) *bp = bitswap[*bp]; } else if (invert) { unsigned char *bp; for(bp = buffer+buffer_size; bp-- > buffer;) *bp = ~*bp; } /* we don't want the last bits up to the byte/word alignment set */ if ((no_of_bits = fixed_width - width)) { int i, j, mask = ~bits_set(no_of_bits % 8); for(i = 0; i < height; i++) { unsigned char *s = buffer + (i+1) * byte_width ; for(j = no_of_bits / 8; j--;) *--s = 0; *--s &= mask; } } DEBUG(>= 1) fprintf(stderr,"read %d bytes for a %d (%d bytes) x %d image\n", buffer_size, (int) width, byte_width, (int) height); /* Scale the bitmap */ if (scale > 1) { unsigned char *tbl = magnification_table(scale); unsigned char *scale_buf; int i, j, k; if ((scale_buf = (unsigned char *) calloc((unsigned) (buffer_size *= scale*scale), sizeof(char))) == NULL) leave("Can't calloc scaled buffer."); for(i = 0; i < height; i++) { unsigned char *src, *ss; src = buffer + i * byte_width ; ss = scale_buf + i * scale * scale * byte_width; for(j = 0; j < byte_width; j++) { unsigned char *dst = ss+j*scale; unsigned char *expansion = tbl+scale*src[j]; for(k = 0; k < scale; k++, dst += byte_width*scale) { memmove((char *) dst, (char *) expansion, scale); } } } free((char *) buffer); free((char *) tbl); buffer = scale_buf; byte_width *= scale; width *= scale; fixed_width *= scale; height *= scale; one_plane_size *= scale*scale; } DEBUG(==3) { int i, j, k; unsigned char *s; fprintf(stderr, "dumping %d x %d grid\n", fixed_width, height); for(i = 0; i < height; i++) { s = buffer + i * byte_width ; for(j = 0; j < byte_width; j++) for(k = 8; k--;) (void) putc((s[j] & 1<> 1, y_pos - FONT_HEIGHT ); fprintf(out, "%s\n", head); } if (foot != NULL) { p_move_abs( out, x_pos + (width - strlen(foot)*FONT_WIDTH) >> 1, y_pos + height + (FONT_HEIGHT << 1) ); fprintf(out, "%s\n", foot); } p_move_abs(out, x_pos, y_pos); p_bitmap(out, height, fixed_width, (unsigned long) one_plane_size, buffer + plane * one_plane_size); free((char *) win_name); free((char *) buffer); } static unsigned char *magnification_table(int scale) { unsigned char *tbl; int c; if ((tbl = (unsigned char *) calloc((unsigned) (scale*256), sizeof(char))) == NULL) leave("Can't calloc magnification table."); bzero((char *) tbl, scale*256); for(c = 256; c--;) { int b = c, bit; unsigned char *entry = tbl+c*scale; while (b) { int i, last, mask; bit = 1; mask = b; while (! (mask & 1)) { bit++; mask = mask >> 1; } last = scale*(bit-1); for(i = scale*bit; i-- > last ;) entry[(scale - 1) - i / 8] |= 1 << (i % 8); b &= ~(1 << bit-1); } } return tbl; } /* returns 2^n-1, i.e. a number with bits n-1 through 0 set. * (zero for n == 0) */ static int bits_set(int n) { int ans = 0; while(n--) ans |= 1 << n; return ans; } static void leave(const char *s) { fprintf(stderr, "\n%s: ", progname); if (errno != 0) perror(s); else fprintf(stderr, "%s", s); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } /* move to coordinates x, y (in pels) */ static void p_move_abs(FILE *p, int x, int y) { if (x >= 0) { PMP(p, 3); (void) putc('\340', p); p_wput(x, p); } if (y >= 0) { PMP(p, 3); (void) putc('\341', p); p_wput(y, p); } } /* save current cursor position into (printer) register reg */ static void p_save_cursor(FILE *p, int reg) { PMP(p, 1); (void) putc(reg + '\200', p); } /* restore current cursor position from (printer) register reg */ static void p_restore_cursor(FILE *p, int reg) { PMP(p, 1); (void) putc(reg + '\220', p); } /* set the page orientation to orient (see pmp.h) */ static void p_set_orientation(FILE *p, enum orientation orient) { PMP(p, 2); fprintf(p, "\322%c", (int) orient); } /* generate bitmap */ static void p_bitmap( FILE *p, unsigned int h, int w, unsigned long buflen, unsigned char *buf) { PMP(p, 9); (void) fwrite("\365\0", 1, 2, p); puthl2(h, p); puthl2(w, p); puthl3(buflen, p); while(buflen) { int len; len = min(buflen, MAX_VECTOR_LEN); PMP(p, len); (void) fwrite((char *) buf, 1, len, p); buf += len; buflen -= len; } (void) fflush(p); }