home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-03-04 | 8.3 KB | 196 lines | [TEXT/KAHL] |
- /*
- PixMapToPostScript.c
- Copyright © 1991,1992 Denis G. Pelli
- This is a simple but reasonably general routine to convert a grayscale PixMap to
- a PostScript file that may be transmitted to a LaserWriter or Linotype to produce
- a halftone image on paper.
- The filename, by convention, should end in ".ps" to indicate that it is a postscript
- file, but this is not enforced. The file's type is set to 'TEXT' with creator
- '4PSU', so that it can be double-clicked to open my favorite PostScript
- downloading program, PostHaste. However, since it's a plain text file, any downloader
- will work, and if you're using a Linotype, you're probably just sending the file
- by modem.
- The PixMap must have 8 bits per pixel. No color tables are used. The raw pixel
- value (Apple calls it an "index") is sent directly to the printer with no
- transformation. PostScript assumes that the number, from 0 to 255 is proportional to
- desired reflectance, from zero to 1. The *rectPtr indicates what part of your
- PixMap is to be used.
- The *pageRectPtr is subtle. It describes, in typographers points (1/72"),
- the rectangle that your image will be mapped onto on the printed page. It is essential
- that you keep in mind that Apple and Adobe use different coordinate systems.
- Both Apple and Adobe increase x from left to right.
- However, Apple has y increasing from top to bottom, whereas Adobe increases y from
- bottom to top. Adobe's origin is the lower left corner of the paper, even though
- that point is usually not printable, since most printers can only print to within
- about a half inch of the edge. The pageRect, though supplied in Apple's Rect data
- structure, must be in Adobe's coordinates, respecting the names of the Rect structure's
- fields: left, top, right, bottom. So, for an image
- to fill most of an 8.5x11 page, with 1" margins, you might use the following:
- SetRect(&pageRect,1*72,10*72,7.5*72,1*72);
- The cellsPerInch parameter is optional in the sense that if cellsPerInch is zero
- it is ignored, leaving the printer at its default setting, which is usually a
- good choice. If you set cellsPerInch to a
- nonzero value then the printer will be asked to print its halftone with that
- many halftone cells per inch. Note that there is no correspondence between pixels in your
- image and cells in the halftone; PostScript automatically resamples your image to
- produce its halftone. There are two common reasons for fiddling with cellsPerInch.
- If you're trying to get a reasonable gray scale out of a LaserWriter (which
- has 300 dots per inch) you'll need to make the cell size big enough to hold at least
- 256 pixels if you want 256 gray levels. This requires 300/sqrt(256)=18.75 cells per
- inch. The other situation is producing a half tone as an original for subsequent
- reproduction in a journal, where you'll want the cells to be coarse enough for
- them to reproduce without re-screening, e.g. 100 cells per inch.
- You should remove(filename) any pre-existing old file of the same name, unless
- you want to append to it. PixMapToPostScript always appends to an existing file with
- the same name, if one exists, to allow you to place several images onto a page.
- (You should offset their pageRects unless you want the images to superimpose.)
- You will need to add a "showpage\n" command at the end of the postscript file.
- This is the command that tells the printer to actually go ahead and print the page.
- Use the command AppendToFile(filename,"showpage\n"), supplied for this purpose. Naturally,
- you could also use to this to add your own postscript commands before or after the
- imaging code inserted by PixMapToPostScript.
- Here's a minimal example of the three commands:
- remove("test.ps");
- PixMapToPostScript("test.ps",*pixMapHandle,&rect,&pageRect,0.0,0);
- AppendToFile("test.ps","showpage\n");
- In case your PostScript manual isn't handy, the easy way to obtain multiple copies
- of the same page is to use the #copies variable that's built into Postscript. Anywhere
- in your file before "showpage", set #copies to the desired value. E.g.
- AppendToFile("test.ps","/#copies 3 def\n");
- There are many free PostScript downloaders, but I find them clumsy to use, especially
- the ones that don't inform you of errors, should they occur. I bought and use
- PostHaste
- from:
- Micro Dynamics, Ltd.
- 8555 16th St., Suite 802
- Silver Spring, MD 20910
- (301)-589-6300
- or
- LaserStatus, a desk accessory that is included in the
- MockPackage Plus Utilities
- from:
- CE Software
- 1854 Fuller Road
- PO Box 65580
- West Des Moines, Iowa 50265
- (515)-224-1995
- You may also want to read:
- Adobe Systems (1985) PostScript Language Reference Manual. Reading, MA: Addison-Wesley.
- Pelli, D. G. (1987) Programming in PostScript: Imaging on paper from a mathematical
- description. BYTE, 12 (5), 185-202.
-
- HISTORY:
- 4/21/91 dgp wrote it
- 7/24/91 dgp added comment about shifting pageRect
- 8/24/91 dgp Made compatible with THINK C 5.0
- 12/7/91 dgp minor editing of comments
- 10/10/92 dgp Added support for Pixmap's that require 32-bit addressing.
- Much faster now, using table-lookup instead of sprintf for
- the hex encoding.
- Deleted obsolete support for THINK C 4.
- */
- #include "VideoToolbox.h"
- #include <assert.h>
- #include <math.h>
- #include <Errors.h>
-
- void PixMapToPostScript(char *filename,PixMap *pm,Rect *rectPtr
- ,Rect *pageRectPtr,double cellsPerInch,int grayLevels)
- {
- FILE *file;
- unsigned char *addr;
- long y,bytes,width;
- register long i;
- register unsigned short *buffer,hex[256];
- register unsigned char *byte;
- short pixelSize;
- short rowBytes;
- time_t ANSITime;
- char string[100];
- char mode;
-
- if(cellsPerInch!=0.0 && grayLevels!=0.0){
- PrintfExit("PixMapToPostScript: you may not specify BOTH cellsPerInch & grayLevels\n\007"
- "Set one to zero.\n");
- }
- file=fopen(filename,"a");
- if(file==NULL)PrintfExit("PixMapToPostScript: Error in opening file \"%s\"\n",filename);
- addr=RectToAddress(pm,rectPtr,&rowBytes,&pixelSize,NULL);
- if(addr==NULL || pixelSize!=8)
- PrintfExit("PixMapToPostScript: Can't deal with this PixMap.\n");
- time(&ANSITime);
- strftime(string,sizeof(string),"%I:%M %p %A, %B %d, %Y",localtime(&ANSITime));
- fprintf(file,
- "\nsave %% %s, %s\n",filename,string);
- fprintf(file,
- "/nx %d def %% pixels per raster line\n",rectPtr->right-rectPtr->left);
- fprintf(file,
- "/ny %d def %% lines in image\n",rectPtr->bottom-rectPtr->top);
- fprintf(file,
- "%d %d translate %% locate lower left of image\n",pageRectPtr->left
- ,pageRectPtr->bottom);
- fprintf(file,
- "%d %d scale %% print image with these dimensions on page\n"
- ,pageRectPtr->right-pageRectPtr->left,pageRectPtr->top-pageRectPtr->bottom);
- fprintf(file,
- "/hypotenuse {dup mul exch dup mul add sqrt} bind def\n"
- "/pixelsPerInch gsave initmatrix 72 0 dtransform hypotenuse grestore def\n");
- if(cellsPerInch!=0.0){
- fprintf(file,
- "/cellsPerInch %.2f def %% halftone dot frequency\n",cellsPerInch);
- fprintf(file,
- "cellsPerInch currentscreen 4 -2 roll pop 3 1 roll setscreen\n");
- }
- if(grayLevels!=0.0){
- fprintf(file,
- "/cellsPerInch pixelsPerInch %.2f div def %% halftone dot frequency\n",sqrt(grayLevels));
- fprintf(file,
- "cellsPerInch currentscreen 4 -2 roll pop 3 1 roll setscreen\n");
- }
- fprintf(file,
- "/s nx string def %% string to hold one raster line\n"
- "nx ny 8 %% dimensions and bits/pixel of source image\n"
- "[nx 0 0 ny neg 0 ny] %% map unit square to PixMap data\n"
- "{currentfile s readhexstring pop} %% read data\n"
- "bind %% speed up reading\n"
- "image\n");
- assert(sizeof(hex[0])==2); // assumed by our algorithm
- assert(sizeof(buffer[0])==2);// assumed by our algorithm
- for(i=0;i<256;i++){
- sprintf(string,"%02x",(int)i);
- hex[i]=*(unsigned short *)string;
- }
- width=rectPtr->right-rectPtr->left;
- bytes=(width+1)*sizeof(*buffer);
- buffer=(unsigned short *)NewPtr(bytes);
- if(buffer==NULL){
- printf("PixMapToPostScript: no room for %ld byte buffer.\n\007",bytes);
- return;
- }
- for(y=rectPtr->top;y<rectPtr->bottom;y++){
- mode=true32b;
- SwapMMUMode(&mode);
- byte=addr;
- for(i=0;i<width;i++){
- buffer[i]=hex[byte[i]];
- }
- buffer[i]=0;
- SwapMMUMode(&mode);
- fprintf(file,"%s\n",(char *)buffer);
- addr+=rowBytes;
- }
- DisposPtr((Ptr)buffer);
- fprintf(file,"restore\n");
- fclose(file);
- SetFileInfo(filename,'TEXT','4PSU');
- }
-
- void AppendToFile(char *filename,char *string)
- {
- FILE *file;
-
- file=fopen(filename,"a");
- if(file==NULL)PrintfExit("AppendToFile: Error in opening file \"%s\"\n",filename);
- fprintf(file,"%s",string);
- fclose(file);
- }