home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat España 21
/
macformat_21.iso
/
Shareware
/
Programación
/
VideoToolbox
/
VideoToolboxSources
/
WindowToEPS.c
< prev
next >
Wrap
Text File
|
1995-07-27
|
14KB
|
352 lines
/*
WindowToEPS.c
Copyright © 1994,1995 Denis G. Pelli
WindowToEPS(window,filename,rectPtr,pageRectPtr,cellsPerInch,grayLevels,reflectance);
WindowToEPS converts a grayscale image (in a window or GWorld) to a PostScript
file that a LaserWriter or Linotype will accurately render on paper. The output
file is a standard Encapsulated PostScript File, with file type 'EPSF', commonly
referred to as an "eps" file. Most word processors, e.g. Word and PageMaker, know
how to import eps files. Macintoshes only understand QuickDraw, not PostScript,
so they don't know what image the PostScript code would produce. That's why the
eps file includes a PICT resource that provides an on-screen preview, so the
image will look approximately right on your monitor screen, e.g. in Word. To
import in Word, use the Insert:Picture or Insert:File command. Once imported, you
can get Word to rescale the image by dragging the image's lower right corner
while holding down the shift key. Try the VideoToolbox demo Grating.
Bear in mind that on-screen you're looking at the PICT, whereas, when you print
on a LaserWriter, the image is produced by the PostScript code. When in your word
processor, the on-screen images will look best if you use the Monitors control
panel to set your monitor to 256 Grays, but this won't affect printing.
The filename, by convention, should end in ".eps" to indicate that it's an
encapsulated postscript file, but this is not enforced. The file's type is set to
'EPSF' with creator 'R*ch'. (This creator corresponds to BBEdit, so
double-clicking will open it as a text file in BBEdit, which includes a
Special:SendPostScript command for downloading poscript images to the
laserwriter. You can change the creator to be anything you want.)
The supplied PixMap must have 8 bits per pixel. The window's color table is
ignored. The raw pixel value (which Apple calls an "index") is transformed by the
optional reflectance array (if present), and then sent directly to the printer.
If "reflectance" is NULL, then the pixel value, from 0 to 255 is interpreted by
PostScript as proportional to desired reflectance, from zero to 1. If you supply
a "reflectance" array the values should range from 0.0 to 1.0. The *rectPtr
indicates what part of your PixMap is to be used.
The color table attached to the PICT resource, which provides the on-screen preview
in word processors, is created to match the PostScript one, using the reflectance
array if supplied, otherwise creating a gray color table running from black to white.
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 page, 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 0.5" margins, you might use the following:
SetRect(&pageRect,0.5*72,10.5*72,8*72,0.5*72);
In printing PostScript halftones the halftone cell size determines
both the spatial and graylevel resolutions of the resulting image. For
the convenience of the user this can be specified by setting either the
cellsPerInch or the grayLevels argument to the desired value; the other
one should be zero. If both are zero then the printer will be left at
its default cell size, which is usually a good choice. Note that there
need not be any particular correspondence between pixels in your image
and cells in the halftone; the printer automatically resamples your
image to produce the halftone.
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. E.g.
to produce a halftone original for subsequent one-to-one reproduction in
a journal, you'll want the cells to be coarse enough for them to
reproduce without re-screening, e.g. 100 cells per inch.
Alternatively, if you set grayLevels to a nonzero value then the
printer will be asked to print its halftone with cells containing
grayLevels-1 printer pixels, yielding the specified number of gray
levels. E.g. you might want to force your 300 dpi LaserWriter to use big
cells yielding 256 gray levels.
Here's a minimal example:
WindowToEPS(window,"test.eps",&rect,&pageRect,0.0,0,NULL);
To print a screen to disk, preserving the size and scale of the
image, try this:
pageRect=window->portRect;
pageRect.top*=-1; // convert from Apple to Adobe coordinates
pageRect.bottom*=-1; // convert from Apple to Adobe coordinates
SetRect(&paperRect,0,11*72,8.5*72,0);
CenterRectInRect(&pageRect,&paperRect);
WindowToEPS(window,"test.eps",&window->portRect,&pageRect,0,0,NULL);
Tiling is something we often want to do, creating a huge image by
taping many pages together. Simply import your EPS file into a good
graphics program, e.g. PageMaker, and print with tiling.
REFERENCES
Adobe Systems (1985) PostScript Language Reference Manual, Second Edition.
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.
4/29/93 dgp & jas Added explanation of how to do tiling.
5/27/93 dgp minor editing for speed and clarity
6/15/93 dgp Fixed silly bug introduced 5/27/93 that suppressed all hex data.
Call StripAddress.
6/29/93 dgp Changed call interface to accept a pixmap handle instead of a pointer.
The problem with accepting a pointer is that the user must remember
to lock the handle before dereferencing it to get the pointer, and
lots of people forget, leading to a mysterious crash. Now the locking
is handled internally, automatically.
6/30/93 dgp Added example, above, showing how to print screen to disk.
7/9/93 dgp check for 32-bit addressing capability.
12/15/93 dgp added filename argument to the diagnostic messages.
Corrected grayLevels to grayLevels-1 in computing
the required number of pixels in the halftone cell.
6/18/94 dgp can32 is now computed by calling TrapAvailable(_SwapMMUMode), which
returns the correct answer even on Macs with dirty ROMs.
9/5/94 dgp removed assumption in printf's that int==short.
5/23/95 dgp Apple changed the prototype in the header file from SwapMMUMode(char *) to
SwapMMUMode(signed char *). To retain compatibility with both old and new
headers, I cast the argument (void *).
6/30/95 dgp changed TYPE from TEXT to EPSF. Added explanation, above, for how to
import into Word.
6/30/95 dgp add PICT resource preview of image, so we're producing a standard eps file.
Revised the first several paragraphs of the documentation above to reflect the
fact that we now produce a standard EPSF file. Make PICT's color table consistent
with the PostScript.
*/
#include "VideoToolbox.h"
#ifndef __TRAPS__
#include <Traps.h> // _SwapMMUMode
#endif
#define TYPE 'EPSF'
#define CREATOR 'R*ch' /* for BBEdit */
PicHandle PixMapToPicture(PixMap **pm,Rect *rectPtr,int pixelSize,ColorTable **cTable);
void WindowToEPS(CWindowPtr window,char *filename,Rect *rectPtr
,Rect *pageRectPtr,double cellsPerInch,int grayLevels,float reflectance[256])
{
PixMap **pm;
FILE *file;
unsigned char *addr;
long y,bytes,width;
register long i;
unsigned short *buffer,*buffer32;
register unsigned short *word,hex[256];
register unsigned char *byte;
short pixelSize;
short rowBytes;
time_t ANSITime;
char string[100];
signed char mode;
char pmState;
static Boolean can32,is32,firstTime=1;
long gestalt;
int error,oldResFile,resFile=0;
Boolean ok;
PicHandle pic;
ColorTable **ct;
Str63 volumeName="\p";
ColorSpec *colorSpecPtr;
// Create file's data fork: PostScript text.
assert(StackSpace()>5000);
if(firstTime){
Gestalt(gestaltAddressingModeAttr,&gestalt);
is32=gestalt&(1L<<gestalt32BitAddressing);
can32=TrapAvailable(_SwapMMUMode);
firstTime=0;
}
if(IsGWorldPtr(window)){
// It's a GWorldPtr, lock the pixels.
ok=LockPixels(GetGWorldPixMap((GWorldPtr)window));
if(!ok)PrintfExit("%s: can't LockPixels on GWorld.\n",__FILE__);
pm=GetGWorldPixMap((GWorldPtr)window);
}else if(window->portVersion<0){ // Is it a CGrafPort or a GrafPort?
// It's a CGrafPort.
pm=window->portPixMap;
}else{
// It's a GrafPort.
PrintfExit("%s: source must be GWorld or color Window.\n",__FILE__);
}
if(cellsPerInch!=0.0 && grayLevels!=0.0)PrintfExit("%s(%s): "
"you may not specify BOTH cellsPerInch & grayLevels.\n"
"Set one to zero.\n",__FILE__,filename);
file=fopen(filename,"w");
if(file==NULL)PrintfExit("%s: Error in opening file “%s”.\n"
,__FILE__,filename);
pmState=HGetState((Handle)pm);
HLock((Handle)pm);
addr=RectToAddress(*pm,rectPtr,&rowBytes,&pixelSize,NULL);
if(addr==NULL)PrintfExit("%s(%s): Bad PixMap.\n",__FILE__,filename);
if(pixelSize!=8)PrintfExit("%s(%s): "
"Sorry, pixelSize must be 8, not %d.\n",__FILE__,filename,(int)pixelSize);
time(&ANSITime);
strftime(string,sizeof(string),"%I:%M %p %A, %B %d, %Y",localtime(&ANSITime));
fprintf(file,
"%%!PS-Adobe-2.0 EPSF-1.2\n");
fprintf(file,
"%%%%Creator:%s\n",IdentifyApplication());
fprintf(file,
"%%%%For:%s\n",IdentifyOwner());
fprintf(file,
"%%%%Title:%s\n",filename);
fprintf(file,
"%%%%CreationDate:%s\n",string);
fprintf(file,
"%%%%Pages: 0\n"
"%%%%BoundingBox:%d %d %d %d\n"
,(int)pageRectPtr->left,(int)pageRectPtr->bottom
,(int)pageRectPtr->right,(int)pageRectPtr->top);
fprintf(file,
"%%%%EndComments\n"
"%%%%BeginProlog\n"
"%%%%EndProlog\n"
"%%%%BeginSetup\n"
"/VideoToolbox dup 25 dict def load begin\n"
"end\n"
"VideoToolbox begin\n"
"gsave\n"
"%%%%EndSetup\n");
fprintf(file,
"/nx %d def %% pixels per raster line\n",(int)(rectPtr->right-rectPtr->left));
fprintf(file,
"/ny %d def %% lines in image\n",(int)(rectPtr->bottom-rectPtr->top));
fprintf(file,
"/hypotenuse {dup mul exch dup mul add sqrt} bind def\n"
"/pixelsPerInch gsave initmatrix 72 0 dtransform hypotenuse grestore def\n"
"%d %d translate %% locate lower left of image\n"
,(int)pageRectPtr->left,(int)pageRectPtr->bottom);
fprintf(file,
"%d %d scale %% print image with these dimensions on page\n"
,(int)(pageRectPtr->right-pageRectPtr->left),(int)(pageRectPtr->top-pageRectPtr->bottom));
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){
fprintf(file,
"/cellsPerInch pixelsPerInch %.2f div def %% halftone dot frequency\n"
,sqrt(grayLevels-1));
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(*byte)==1); // required by our algorithm
assert(sizeof(*word)==2); // required by our algorithm
if(reflectance==NULL)for(i=0;i<256;i++){
sprintf(string,"%02x",(int)i);
hex[i]=*(unsigned short *)string;
}else for(i=0;i<256;i++){
int j;
j=0.5+255*reflectance[i];
if(j<0)j=0;
if(j>255)j=255;
sprintf(string,"%02x",j);
hex[i]=*(unsigned short *)string;
}
width=rectPtr->right-rectPtr->left;
bytes=(width+1)*sizeof(*word);
buffer=(unsigned short *)NewPtr(bytes);
if(buffer==NULL)PrintfExit("%s(%s): "
"no room for %ld byte buffer.\n\007",__FILE__,filename,bytes);
buffer32=(unsigned short *)StripAddress(buffer);
for(y=rectPtr->top;y<rectPtr->bottom;y++){
mode=true32b;
if(can32)SwapMMUMode((void *)&mode);
byte=addr;
word=buffer32;
for(i=0;i<width;i++) *word++ = hex[*byte++];
*word=0;
if(can32)SwapMMUMode((void *)&mode);
fprintf(file,"%s\n",(char *)buffer);
addr+=rowBytes;
}
HSetState((Handle)pm,pmState);
DisposPtr((Ptr)buffer);
fprintf(file,
"%%%%Trailer\n"
"grestore\n"
"end\n"
"showpage\n"
"%%%%EOF\n");
fclose(file);
SetFileInfo(filename,TYPE,CREATOR);
// Create file's resource fork: a PICT resource.
if(1){
// add PICT resource to file
FSSpec spec;
long version;
pixelSize=8;
ct=GetCTable(pixelSize+32); // gray ramp
colorSpecPtr=(**ct).ctTable;
if(reflectance==NULL){
for(i=0;i<=(**ct).ctSize;i++){
colorSpecPtr->rgb.red=colorSpecPtr->rgb.green=colorSpecPtr->rgb.blue
=0xffffL*i/(**ct).ctSize;
colorSpecPtr++;
}
}else{
for(i=0;i<=(**ct).ctSize;i++){
colorSpecPtr->rgb.red=colorSpecPtr->rgb.green=colorSpecPtr->rgb.blue
=0xffffL*reflectance[i];
colorSpecPtr++;
}
}
pic=PixMapToPicture(pm,rectPtr,pixelSize,ct);
DisposeCTable(ct);
oldResFile=CurResFile();
error=HGetVol(NULL,&spec.vRefNum,&spec.parID);
strcpy((char *)spec.name,filename);
c2pstr((char *)spec.name);
Gestalt(gestaltSystemVersion,&version);
if(version>=0x700){
FSpCreateResFile(&spec,CREATOR,TYPE,smRoman);
resFile=FSpOpenResFile(&spec,fsRdWrPerm);
}else{
HCreateResFile(spec.vRefNum,spec.parID,spec.name);
resFile=HOpenResFile(spec.vRefNum,spec.parID,spec.name,fsRdWrPerm);
}
if(resFile==-1)printf("%s %d: OpenResFile error %d\n",__FILE__,__LINE__,ResError());
else{
AddResource((Handle)pic,'PICT',256,"\pPreview");
UseResFile(oldResFile);
CloseResFile(resFile);
}
}
}