This is ps2pcl.m in view mode; [Download] [Up]
static char *ID = {"By:Kevin Peckover -- July 1995 Ottawa, Canada."};
#import <stdio.h>
#import <strings.h>
#import <bsd/libc.h>
#import <sys/types.h>
#import <servers/netname.h>
#import <mach/message.h>
#import <mach/mach_init.h>
#import <mach/mach_interface.h>
#import <mach/mach_error.h>
#import <mach/cthreads.h>
#import <dpsclient/dpsNeXT.h>
#import <dpsclient/dpsclient.h>
#import <windowserver/printmessage.h>
#import <appkit/NXBitmapImageRep.h>
#import <appkit/Application.h>
#import <appkit/tiff.h>
#define TIFF_SERVER_NAME "tiff_fd"
#define HEADDER_SIZE 1024
#define MAX_DEVICE_NAME_LEN 256
#define MAX_FILE_PATH 256
#define TIFFSERVER_NAME "TIFFServer"
#define DEF_DEVICE_NAME "NeXTLaser-400"
#define DEF_DEVICE ""
#define TIME_TO_WAIT_FOR_ACTIVE_PORT 5 // seconds
#define TIME_OUTOF_RENDEREDPAGE_FROM_WINDOWSERVER 20 // seconds
#define NO_MORE_PAGES 666
#define ASCII_ESC 0x1b
#define ASCII_FF 0x0c
#define HPPCL_BITCOMPMODE_NONE 0
#define HPPCL_BITCOMPMODE_RLENENC 1
#define HPPCL_BITCOMPMODE_TIFFV4 2
#define HPPCL_BITCOMPMODE_DELROW 3
typedef struct ReplyMsg {
msg_header_t h;
msg_type_t t;
} replyMsg;
typedef struct _ChildParam {
char *basename;
int compression;
int res;
} ChildParam;
enum CompressType { none = 0, runLenEnc, TIFF_v40, DeltaRow };
// Global variables
char outName[MAX_DEVICE_NAME_LEN] ={DEF_DEVICE} ;
unsigned char* rleCompressForPCL(unsigned char* origData,
unsigned char* newData, int *length)
{
// Initialize for begining of line
int origDataLength = *length,
indToNewData = 0,
indToOldData = 0;
unsigned char baseByte = *origData;
if (*length < 2) return origData; // essentally a NULL line case
do {
unsigned char byteCount = 0;
while (baseByte == origData[1 + indToOldData + byteCount]
&& byteCount < 255
&& (1 + indToOldData + byteCount) < origDataLength )
byteCount++;
newData[indToNewData++] = (unsigned char)byteCount;
newData[indToNewData++] = (unsigned char)baseByte;
if ( (1+indToOldData + byteCount) >= origDataLength ) {
// Were done! Set length and get out.
*length = indToNewData+1; // adding one makes it a count
return newData;
};
indToOldData += byteCount;
baseByte = origData[indToOldData];
} while (indToNewData < (origDataLength-1)); // will dropp out of loop if longer
return origData; // don't use the compressed version, length did not change
}
void writeHPRast(FILE *stream, char *data, int pWidth, int pixelsHigh,
int bytesWide, int res) {
int i, bytesToSend;
unsigned char *lineOfData = malloc(sizeof(unsigned char)*bytesWide),
*lineToSend = 0;
#define COMPRESS_TYPE '1' /* run length encoding */
fprintf(stream,"%c%s%c%s%d%s%c%s%c%s%d%s%c%s%d%s%c%s",
ASCII_ESC,"*p0x0Y", /* set postion */
ASCII_ESC,"*t", res, "R", /* set resoulution { 75,100,150,300 } */
ASCII_ESC,"*r0F", /* write raster on logical page */
ASCII_ESC,"*r", pWidth,"S", /* width */
ASCII_ESC,"*r", pixelsHigh,"T", /* height */
ASCII_ESC,"*r1A" /* start graphics mode */
);
for(i=0;i<pixelsHigh;i++) {
bytesToSend = bytesWide;
lineToSend = rleCompressForPCL(&data[bytesWide*i],lineOfData,
&bytesToSend);
fprintf(stream,"%c*b%cm%dW", ASCII_ESC,
((unsigned char *)lineToSend == (unsigned char *)
&data[bytesWide*i])?'0':COMPRESS_TYPE,
bytesToSend);
fwrite(lineToSend, 1, bytesToSend, stream);
}
fprintf(stream,"%c%s%c",
ASCII_ESC,"*rB",
ASCII_FF); // stop graphics mode
free(lineOfData);
}
port_t tiff_look_up()
// This function checks for an advertized Mach Port.
{
port_t port;
kern_return_t ret;
// Use "" instead of "*", so we look only on this machine.
ret = netname_look_up(name_server_port, "", TIFF_SERVER_NAME, &port);
if (ret != KERN_SUCCESS) return PORT_NULL;
return port;
}
void server_loop(port_t port, char *baseFileName, int compression, int res)
{
NXPrintPageMessage msg;
replyMsg reply;
kern_return_t ret;
FILE *out = 0;
BOOL getNextPage = TRUE;
char fname[MAX_FILE_PATH];
int pagesPrinted=0;
// The reply message which does not change
reply.h.msg_simple = TRUE;
reply.h.msg_size = sizeof(replyMsg);
reply.h.msg_type = MSG_TYPE_NORMAL ;
reply.h.msg_id = NX_PRINTPAGEMSGID;
reply.t.msg_type_name = MSG_TYPE_INTEGER_32 ;
reply.t.msg_type_size = 32;
reply.t.msg_type_number = 0;
reply.t.msg_type_inline = TRUE;
reply.t.msg_type_longform = FALSE;
do {
msg.msgHeader.msg_local_port = port;
msg.msgHeader.msg_size = sizeof(NXPrintPageMessage);
ret = msg_receive(&msg.msgHeader
, RCV_TIMEOUT, TIME_OUTOF_RENDEREDPAGE_FROM_WINDOWSERVER*1000);
switch(ret) {
case RCV_SUCCESS:
switch(msg.msgHeader.msg_id) {
case NO_MORE_PAGES:
getNextPage = NO;
break;
case NX_PRINTPAGEMSGID:
if(*fname) {
sprintf(fname,"%s", baseFileName);
out = fopen(fname,"wb");
} else out=stdout;
if(out)
{
writeHPRast(out, msg.printerData, msg.pixelsWide,
msg.pixelsHigh, msg.bytesPerRow, res);
if(*fname) fclose(out);
} else fprintf(stderr,"** Could Not open file %s\n", fname);
vm_deallocate(task_self(),
(vm_address_t)msg.printerData,
(vm_size_t)(msg.samplesPerPixel*msg.pixelsWide*
msg.pixelsHigh*msg.bitsPerSample/8));
// Send the reply to Window Server that we are ready for next page
reply.h.msg_local_port = port ; //send to
reply.h.msg_remote_port = msg.msgHeader.msg_remote_port;
reply.h.msg_id = NX_PRINTPAGEMSGID;
ret = msg_send(&reply.h, MSG_OPTION_NONE, 0);
switch(ret) {
case SEND_SUCCESS: // Continue in loop for next page
pagesPrinted++;
break;
case SEND_INVALID_PORT: // There is Probably no more pages
getNextPage = FALSE;
break;
default:
mach_error("TIFFServer:** SEND to Window Server.\n", ret);
};
break;
}
break;
case RCV_TIMED_OUT:
getNextPage = FALSE;
return ; // exit receive loop completely with no error message
default:
mach_error("TIFFServer:** RECV to TIFF routine.\n", ret);
};
} while (getNextPage) ;
if(!*fname) fclose(out);
}
int TIFFReceptorMain(ChildParam *param) {
port_t server_port;
kern_return_t r;
if(!strstr(ID, "Peckover")) exit(1);
r = port_allocate(task_self(), &server_port);
if (r != KERN_SUCCESS) {
mach_error("port_allocate failed",r);
return 0;
}
r = netname_check_in(name_server_port, TIFF_SERVER_NAME,
PORT_NULL, server_port);
if (r != KERN_SUCCESS) {
mach_error("netname_check_in failed ",r);
return 0;
}
server_loop(server_port, param->basename, param->compression, param->res);
return 1;
}
extern void DPSMyTextProc(
DPSContext ctxt,
const char *buf,
long unsigned int count )
{
fprintf(stderr,"Context:\t%s\n", ctxt->priv);
fprintf(stderr,"Message:\t%s\n", buf);
};
extern void DPSMyErrorProc(
DPSContext ctxt,
DPSErrorCode errorCode,
long unsigned int arg1,
long unsigned int arg2 )
{
char *string = (char *)arg1;
string[arg2] = 0;
fprintf(stderr,"PS_ERROR: Context:\t%s\t", ctxt->priv);
fprintf(stderr,"ErrCode:\t%d\t", errorCode);
fprintf(stderr,"A1:\t%s\n", string);
};
void usage(char *progName) {
fprintf(stderr,"Usage: %s [Prf] <infn> <outfn>\n %s %s %s\n",
progName,
"[-r<0|1|2|3>]\t res. 0-75dpi, 1-100dpi, 2-150dpi, 3-300dpi\n",
"[-f<outfn>]\t write each page to file(s)\n",
"[<infn>]\t\t name of PostScript file to convert\n");
exit(1);
};
void main(int argc, char *argv[])
{
port_t server;
DPSContext toWindowServer;
time_t checkInTime, currTime;
char line[BUFSIZ], c,
device_name[MAX_DEVICE_NAME_LEN] = {DEF_DEVICE_NAME},
server_name[MAX_DEVICE_NAME_LEN] = {TIFF_SERVER_NAME};
FILE *psin = 0;
int width = 0, height = 0, topMargin = 0,
leftMargin = 0, vFaxDpi = 75, hFaxDpi ,
compType = NX_TIFF_COMPRESSION_CCITTFAX3;
cthread_t proc=0;
ChildParam param;
NXPrintPageMessage send;
kern_return_t ret;
port_t parentPort;
while ((c = getopt(argc, argv, "r:f:?")) != -1)
switch (c) {
case 'r':
switch(atoi(optarg)) {
case 1:
vFaxDpi = 100;
break;
case 2:
vFaxDpi = 150;
break;
case 3:
vFaxDpi = 300;
break;
default:
vFaxDpi = 75;
}
break;
case 'f':
strncpy(outName, optarg, MAX_DEVICE_NAME_LEN);
break;
case '?':
usage(argv[0]);
};
width = (int)(8.5*vFaxDpi);
height = (int)(11*vFaxDpi);
hFaxDpi = vFaxDpi;
switch(argc - optind){
case 0:
psin = stdin ;
break;
case 1:
if (!(psin = fopen(argv[argc-1],"r"))) {
fprintf(stderr,"** Could not open \'%s\'.\n", argv[argc-1]);
exit(1);
};
break;
default:
usage(argv[0]);
}
// Run the child here.
param.basename = outName;
param.compression = compType;
param.res = hFaxDpi ; // hFaxDpi == vFaxDpi
proc=cthread_fork((cthread_fn_t)TIFFReceptorMain,(any_t)¶m);
// Check if the server is up
time(&checkInTime);
do {
server = tiff_look_up();
time(&currTime);
} while (TIME_TO_WAIT_FOR_ACTIVE_PORT
> difftime(checkInTime, currTime)
&& server == PORT_NULL);
if (server == PORT_NULL)
{
fprintf(stderr, "** Couldn't find the Tiff server.\n");
fclose(psin);
if((int)proc>0) {
thread_suspend((thread_t)proc);
cthread_abort(proc);
cthread_join(proc);
}
exit(5);
}
//Communicating with Window Server
toWindowServer = DPSCreateContext(NULL, NULL,
(DPSTextProc)DPSMyTextProc,
(DPSErrorProc)DPSMyErrorProc) ;
DPSSetContext(toWindowServer) ;
DPSWaitContext(toWindowServer) ;
// Sifft through Comments and insert our headder to send image to port
// immediately after them.
do {
fgets(line, BUFSIZ, psin) ;
DPSPrintf(toWindowServer,"%s", line) ;
} while (strstr(line,"%%")||strstr(line,"%!"));
// This is the next line after the comments. (or mabe within the comments)
// put mach port description here.
DPSPrintf(toWindowServer,"\n");
DPSPrintf(toWindowServer,"/width %d def ", width);
DPSPrintf(toWindowServer,"/height %d def ", height);
DPSPrintf(toWindowServer,"/topdots %d def ", topMargin);
DPSPrintf(toWindowServer,"/leftdots %d def ", leftMargin);
DPSPrintf(toWindowServer,
"width height [ leftdots topdots width leftdots sub height topdots sub]");
DPSPrintf(toWindowServer,
"[%d 72 div 0 0 %d -72 div leftdots height topdots sub] () ",
hFaxDpi, vFaxDpi);
DPSPrintf(toWindowServer,"(%s) %s machportdevice \n\n",
server_name, device_name);
//Continue sending the rest of the postScript
while(!feof(psin))
{ int count;
count=fread((void *)line, sizeof(char), BUFSIZ, psin);
DPSWriteData(toWindowServer, line, count);
};
DPSFlushContext(toWindowServer);
DPSWaitContext(toWindowServer);
DPSSendEOF(toWindowServer);
// Send a termination message for child to expect
ret = port_allocate(task_self(), &parentPort);
if (ret == KERN_SUCCESS) {
send.msgHeader.msg_id = NO_MORE_PAGES ;
send.msgHeader.msg_simple = TRUE;
send.msgHeader.msg_size = sizeof(NXPrintPageMessage);
send.msgHeader.msg_type = MSG_TYPE_NORMAL ;
send.msgHeader.msg_local_port = parentPort ;
send.msgHeader.msg_remote_port = server;
send.integerParams.msg_type_name = MSG_TYPE_INTEGER_32 ;
send.integerParams.msg_type_size = 32;
send.integerParams.msg_type_number = NX_PPMNUMINTS;
send.integerParams.msg_type_inline = TRUE;
send.integerParams.msg_type_longform = FALSE;
ret = msg_send(&send.msgHeader, MSG_OPTION_NONE, 0);
switch(ret) {
case SEND_SUCCESS: // Continue in loop for next page
case SEND_INVALID_PORT: // printing has finished by time-out
break;
default:
mach_error("TIFFServer:** SEND error to Window Server", ret);
};
ret=port_deallocate(task_self(), parentPort);
if (ret != KERN_SUCCESS) {
mach_error("port_deallocate", ret);
exit(1);
}
} else mach_error("port_allocate",ret);
// Wait here for child to finish
cthread_join(proc);
DPSDestroyContext(toWindowServer);
fclose(psin);
exit(0);
};
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.