362 lines
9.2 KiB
C
362 lines
9.2 KiB
C
/* x2pmp.c: Translate xwd window dump format into PMP format for the
|
|
* IBM 3812 PagePrinter.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/XWDFile.h>
|
|
#include <X11/Xfuncs.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#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<<k)? '*': '-', stderr);
|
|
(void) putc('\n', stderr);
|
|
}
|
|
}
|
|
p_set_orientation(out, orient);
|
|
p_restore_cursor(out, 0);
|
|
p_save_cursor(out, 3);
|
|
if (head != NULL) {
|
|
p_move_abs( out, x_pos + (width - strlen(foot)*FONT_WIDTH) >> 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);
|
|
}
|