This is ps2g3.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/cthreads.h> #import <mach/mach_error.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> #import "PSfaxHeadder.h" #import "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 TIME_TO_WAIT_FOR_ACTIVE_PORT 5 // seconds #define TIME_OUTOF_RENDEREDPAGE_FROM_WINDOWSERVER 20 // seconds #define PS_PAGE_SEARCH_FORMAT "\%\%Page:" #define NO_MORE_PAGES 666 typedef struct ReplyMsg { msg_header_t h; msg_type_t t; } replyMsg; typedef struct _ChildParam { char *basename; int compression; } ChildParam; 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; } long rawTIFFData(NXStream *tiffFile,int imageNum) // Function sets file pointer at begining of data and returns the number // of bytes in that data block. { TIFFHeader TIFFhead; // TIFFDirEntry seledtedDir; // unsigned short itemSize = 0; //Get TIFF Headder NXSeek(tiffFile, 0, NX_FROMSTART); NXRead(tiffFile, &TIFFhead.tiff_magic, sizeof(TIFFhead.tiff_magic)); NXRead(tiffFile, &TIFFhead.tiff_version, sizeof(TIFFhead.tiff_version)); NXRead(tiffFile, &TIFFhead.tiff_diroff, sizeof(TIFFhead.tiff_diroff)); //WARNING: This is a total hack! It works for G3, Probably G4, and probably // any TIFF with one bitmap in it that has been generated by the // NXBitmapImageRep class. This algorithm has only been tested with the // G3 output from the NXBitmapImageRep. // // Image data will follow immediately after the TIFFhead. The image // directory is located at the end if the bitmap. File structure // for one TIFF only is: // // 2 bytes - TIFFhead.tiff_magic // 2 bytes - TIFFhead.tiff_version // 4 bytes - TIFFhead.tiff_diroff <- to first directoy // n bytes - image data // 1 bytes - number of directories (or is it two?) // 2 bytes - seledtedDir.tdir_tag // 2 bytes - seledtedDir.tdir_type // m bytes - not exactly sure from here... // // n = TIFFhead.tiff_diroff - 2 bytes // // NOTE: TIFFhead.tiff_diroff is offset from the first byte of the // offset number. NOT the byte following that number. // // A correct treatment of this issue of stripping bitmap data out of a // TIFF file would be MUCH appreciated. // // I would think that the 3 should be a one or a two but...it isn't return (TIFFhead.tiff_diroff-sizeof(TIFFhead.tiff_diroff)-3); }; void server_loop(port_t port, char *baseFileName, int compression) { id renderingImage; int pagesPrinted=0; NXPrintPageMessage msg; replyMsg reply; kern_return_t ret; NXStream *stream ; FILE *out; BOOL getNextPage = TRUE; char fname[MAX_FILE_PATH]; // 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: sprintf(fname,"%s.%.3d", baseFileName, msg.pageNum); if((out=fopen(fname,"wb"))) { NXStream *tmpFile; tmpFile = NXOpenMemory(0, 0, NX_READWRITE); stream = NXOpenFile(fileno(out), NX_WRITEONLY); renderingImage = [[NXBitmapImageRep alloc] initData:msg.printerData pixelsWide:(int)msg.pixelsWide pixelsHigh:(int)msg.pixelsHigh bitsPerSample:msg.bitsPerSample samplesPerPixel:msg.samplesPerPixel hasAlpha:NO isPlanar:msg.isPlanar colorSpace:msg.colorSpace bytesPerRow:0 bitsPerPixel:0 ]; [renderingImage writeTIFF:tmpFile usingCompression:compression]; [renderingImage free]; NXWrite(stream, tmpFile->buf_ptr, rawTIFFData(tmpFile,1)); NXClose(stream); NXCloseMemory(tmpFile, NX_FREEBUFFER); 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; // sent from 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 error 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 error.\n", ret); }; } while (getNextPage) ; } 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); 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 [Pwhrgudc] <infn> <outfn>\n %s %s %s %s %s %s %s %s %s\n", progName, "[-w<0|1|2>]\t width of 0-215 mm, 1-255 mm, 2-303 mm (def=0)\n", "[-h<0|1|2>]\t hight of 0-281 mm, 1-297 mm, 2-364 mm (def=0)\n", "[-r<0|1>]\t vert.res.of 0-98 lpi or 1-196 lpi (def=0)\n", "[-g<0|1>]\t comp.type 0-G3 Fax, 1-G4 Fax (def=0)\n", "[-u<string>]\t user name for headder\n", "[-d<string>]\t date and/or time for headder\n", "[-c<string>]\t csi identification for headder \n", "<infn>\t\t name of PostScript file to convert\n", "<outfn>\t base name for G3/4 files\n"); exit(1); }; int insertHeadder(DPSContext context, char *line, int count, char *name, char *time, char *csi) { static int pageCount = 0; /* should only initialize the first time.*/ char *ptr = 0; int subCount = 0; if((ptr=strstr(line,PS_PAGE_SEARCH_FORMAT))) { char page[MAX_DEVICE_NAME_LEN] = {""}; pageCount++; sprintf(page,"Page %d",pageCount); DPSWriteData(context, line,(subCount=((int)ptr-(int)line))); PSfaxHeadder(name,time,csi,page); DPSWriteData(context, ptr, count-subCount); return 1; /* made insert and printed line */ } else { /* line could be broken between data blocks. Account for it. */ return 0; } } 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}, user[MAX_DEVICE_NAME_LEN] = {""}, date[MAX_DEVICE_NAME_LEN] = {""}, csi[MAX_DEVICE_NAME_LEN] = {""}, server_name[MAX_DEVICE_NAME_LEN] = {TIFF_SERVER_NAME} ; FILE *psin = 0; int addheadder = 0; int width = 1728, height = 2166, topMargin = 0, leftMargin = 0, vFaxDpi = 98, compType = NX_TIFF_COMPRESSION_CCITTFAX3; const float hFaxDpi = 204.1451; cthread_t proc=0; ChildParam param; NXPrintPageMessage send; kern_return_t ret; port_t parentPort; while ((c = getopt(argc, argv, "w:h:r:g:u:d:c:")) != -1) switch (c) { case 'w': width = (atoi(optarg)==1)?2048:(atoi(optarg)==2)?2432:1728 ; break; case 'h': height = (atoi(optarg)==1)?2292:(atoi(optarg)==2)?2810:2166 ; break; case 'r': vFaxDpi = (atoi(optarg)==0)?98:196 ; break; case 'g': compType = (atoi(optarg)==1) ?NX_TIFF_COMPRESSION_CCITTFAX4 :NX_TIFF_COMPRESSION_CCITTFAX3 ; break; case 'u': strncpy(user,optarg,MAX_DEVICE_NAME_LEN); addheadder = 1; break; case 'd': strncpy(date,optarg,MAX_DEVICE_NAME_LEN); addheadder = 1; break; case 'c': strncpy(csi,optarg,MAX_DEVICE_NAME_LEN); addheadder = 1; break; case '?': usage(argv[0]); }; if (vFaxDpi == 98) height /= 2; switch(argc - optind){ case 1: psin = stdin ; break; case 2: if (!(psin = fopen(argv[argc-2],"r"))) { fprintf(stderr,"** Could not open \'%s\'.\n", argv[argc-2]); exit(1); }; break; default: usage(argv[0]); } // Run the child here. param.basename = argv[argc-1]; param.compression = compType; 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) ; if(!insertHeadder(toWindowServer,line, strlen(line), user, date, csi) && addheadder ) 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, "[%f 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); if(!insertHeadder(toWindowServer,line, count, user, date, csi) && addheadder) DPSWriteData(toWindowServer, line, count); }; DPSFlushContext(toWindowServer); DPSWaitContext(toWindowServer); DPSSendEOF(toWindowServer); // Send the number of pages 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.