This is ImportEPSF.c in view mode; [Download] [Up]
/*
* $RCSfile: ImportEPSF.c,v $
*
* Copyright (C) 1992 by Adobe Systems Incorporated.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notices appear in all copies and that
* both those copyright notices and this permission notice appear in
* supporting documentation and that the name of Adobe Systems
* Incorporated not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. If any portion of this software is changed, it cannot be
* marketed under Adobe's trademarks and/or copyrights unless Adobe, in
* its sole discretion, approves by a prior writing the quality of the
* resulting implementation.
*
* ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR
* ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
* ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE
* TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT
* PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE.
*
* PostScript, Display PostScript, and Adobe are trademarks of Adobe Systems
* Incorporated registered in the U.S.A. and other countries.
*
* Author: Adobe Systems Incorporated
*/
#include "Import.h"
/*************************************************************
**
** FUNCTION: freeResourceList
**
** DESCRIPTION: Free the entries in a resource list
**
** PARAMETERS: type Pointer to resource list
**
** RETURN: None
**
*************************************************************/
void freeResourceList(type)
ResourceType *type;
{
ResourceType *t;
Resource *r, *r1;
while (type != NULL) {
XtFree((XtPointer) type->name);
r = type->list;
while (r != NULL) {
XtFree((XtPointer) r->name);
if (r->version != NULL) XtFree((XtPointer) r->version);
if (r->revision != NULL) XtFree((XtPointer) r->revision);
r1 = r->next;
XtFree((XtPointer) r);
r = r1;
}
t = type->next;
XtFree((XtPointer) type);
type = t;
}
} /* end freeResourceList() */
/*************************************************************
**
** FUNCTION: addResource
**
** DESCRIPTION: Add a resource to an element's resource list
**
** PARAMETERS: e Element
** type Type of resource
** name Name of resource
** supplied Whether resource is included in file
**
** RETURN: Possibly new resource entry
**
*************************************************************/
static Resource *addResource(e, type, name, supplied)
Element *e;
char *type;
char *name;
Boolean supplied;
{
ResourceType *t;
Resource *r;
/*
** Try to find the resource type, and if it fails add a new type entry
*/
for (t = e->resources; t != NULL; t = t->next) {
if (strcmp(t->name, type) == 0) break;
}
if (t == NULL) {
t = XtNew(ResourceType);
t->name = XtNewString(type);
t->list = NULL;
t->next = e->resources;
e->resources = t;
}
/*
** Try to find the resource name. If successful, update the include
** flag and return the resource entry
*/
for (r = t->list; r != NULL; r = r->next) {
if (strcmp(r->name, name) == 0) {
if (supplied) r->included = True;
return r;
}
}
/*
** Add a new resource entry
*/
r = XtNew(Resource);
r->name = XtNewString(name);
r->version = r->revision = NULL;
r->included = supplied;
r->next = t->list;
t->list = r;
return r;
} /* end addResource() */
/*************************************************************
**
** FUNCTION: addResources
**
** DESCRIPTION: Parse a buffer for resource names and add them
** to the resources for an element
**
** PARAMETERS: e Element to add resources to
** type Type of resource
** buf Buffer holding resource names
** supplied Whether resources are included in file
**
** RETURN: None
**
*************************************************************/
static void addResources(e, type, buf, supplied)
Element *e;
char *type;
char *buf;
Boolean supplied;
{
char *ch, savech;
Resource *r;
while (1) {
/*
** Find the next resource name in the buffer
*/
while (*buf == ' ' || *buf == '\t') buf++;
if (*buf == '\0' || *buf == '\n') return;
ch = buf;
while (*ch != ' ' && *ch != '\t' && *ch != '\n' && *ch != '\0') ch++;
savech = *ch;
*ch = '\0';
/*
** Add it to the resources for the element
*/
r = addResource(e, type, buf, supplied);
*ch = savech;
/*
** If the type is ProcSet, the resource name is followed by
** the version and revision
*/
if (strcmp(type, "ProcSet") == 0) {
buf = ch;
while (*buf == ' ' || *buf == '\t') buf++; /* skip white space */
if (*buf == '\0' || *buf == '\n') return;
ch = buf;
/* skip version */
while (*ch != ' ' && *ch != '\t' &&
*ch != '\n' && *ch != '\0') ch++;
savech = *ch;
*ch = '\0';
r->version = XtNewString(buf);
*ch = savech;
buf = ch;
while (*buf == ' ' || *buf == '\t') buf++; /* skip white space */
if (*buf == '\0' || *buf == '\n') return;
ch = buf;
/* skip revision */
while (*ch != ' ' && *ch != '\t' &&
*ch != '\n' && *ch != '\0') ch++;
savech = *ch;
*ch = '\0';
r->revision = XtNewString(buf);
*ch = savech;
}
buf = ch;
}
} /* end addResources() */
/*
** List of resources known to be resident in the server
*/
static ResourceType *residentResources = NULL;
/*************************************************************
**
** FUNCTION: markResident
**
** DESCRIPTION: Mark a resource as being resident in the server
**
** PARAMETERS: type Type of resource
** name Name of resource
**
** RETURN: None
**
*************************************************************/
static void markResident(type, name)
char *type, *name;
{
ResourceType *t;
Resource *r;
/*
** Look for resource type in list of resident resources; add
** if necessary
*/
for (t = residentResources; t != NULL; t = t->next) {
if (strcmp(type, t->name) == 0) break;
}
if (t == NULL) {
t = XtNew(ResourceType);
t->name = XtNewString(type);
t->next = residentResources;
t->list = NULL;
residentResources = t;
}
/*
** Add a new resource to the list for the type
*/
r = XtNew(Resource);
r->name = XtNewString(name);
r->version = r->revision = NULL;
r->next = t->list;
t->list = r;
} /* end markResident() */
/*************************************************************
**
** FUNCTION: residentFont
**
** DESCRIPTION: Checks if a font name is resident in the server
**
** PARAMETERS: name Name of font to check
**
** RETURN: Whether font is resident
**
*************************************************************/
static Boolean residentFont(name)
char *name;
{
ResourceType *t;
Resource *r;
int resident;
/*
** First check our list for a FontOutline resource with this name
*/
for (t = residentResources; t != NULL; t = t->next) {
if (strcmp("FontOutline", t->name) == 0) break;
}
if (t != NULL) {
for (r = t->list; r != NULL; r = r->next) {
if (strcmp(r->name, name) == 0) return True;
}
}
/*
** We don't know yet whether it's resident, so ask the server.
** Store the result in our list.
*/
PSWCheckFontResident(AppData.imageCtxt, name, &resident);
if (resident) markResident("FontOutline", name);
return resident;
} /* end residentFont() */
/*************************************************************
**
** FUNCTION: residentResource
**
** DESCRIPTION: Checks whether a resource is resident in the server.
**
** PARAMETERS: type Type of resource
** name Name of resource
**
** RETURN: None
**
*************************************************************/
static Boolean residentResource(type, name)
char *type, *name;
{
ResourceType *t;
Resource *r;
/*
** Look in our list. If it's not there, assume not resident
*/
for (t = residentResources; t != NULL; t = t->next) {
if (strcmp(type, t->name) == 0) break;
}
if (t == NULL) return False;
for (r = t->list; r != NULL; r = r->next) {
if (strcmp(name, r->name) == 0) return True;
}
return False;
} /* end residentResource() */
/*************************************************************
**
** FUNCTION: downloadResource
**
** DESCRIPTION: Store a resource in the interpreter
**
** PARAMETERS: type Type of resource
** name Name of resource
**
** RETURN: Whether resource was successfully downloaded
**
*************************************************************/
static Boolean downloadResource(type, name)
char *type, *name;
{
int numFiles;
char **names, **files;
FILE *f;
#define BUFLEN 256
char buf[BUFLEN];
/*
** Try to find the name of a file that defines this resource.
*/
numFiles = ListPSResourceFiles(NULL, ".", type, name,
&names, &files);
if (numFiles == 0) return False;
/*
** Try to open the resource file
*/
f = fopen(files[0], "r");
if (f == NULL) {
free(names);
free(files);
return False;
}
/*
** Switch to shared VM and write contents of file to the server
*/
DPSPrintf(AppData.imageCtxt, "\ncurrentshared true setshared\n");
while (fgets(buf, BUFLEN, f) != NULL) {
DPSWritePostScript(AppData.imageCtxt, buf, strlen(buf));
}
DPSPrintf(AppData.imageCtxt, "\nsetshared\n");
fclose(f);
free(names);
free(files);
/*
** Mark the resource as being resident for future tests
*/
markResident(type, name);
return True;
#undef BUFLEN
} /* end downloadResource() */
/*************************************************************
**
** FUNCTION: downloadResources
**
** DESCRIPTION: Downloads all the resources in a list to the interpreter
**
** PARAMETERS: t List of resources
**
** RETURN: None
**
*************************************************************/
static void downloadResources(t)
ResourceType *t;
{
Resource *r;
for (/* */; t != NULL; t = t->next) {
if (strcmp (t->name, "FontOutline") == 0) {
/*
** If a font resource, try to download. But if
** unsuccessful just go on, since font substitution
** will occur
*/
for (r = t->list; r != NULL; r = r->next) {
if (r->included) continue;
if (!residentFont(r->name)) {
(void) downloadResource(t->name, r->name);
}
}
} else {
/*
** For other types, issue a warning if the download is
** unsuccessful. File execution will probably fail, but
** continue on in case the file was lying about whether the
** resource was included
*/
for (r = t->list; r != NULL; r = r->next) {
if (r->included) continue;
if (!residentResource(t->name, r->name)) {
if (!downloadResource(t->name, r->name)) {
fprintf(stderr, "Warning, resource type %s named %s\n",
t->name, r->name);
fprintf(stderr,
" could not be found. File execution may fail.\n");
}
}
}
}
}
} /* end downloadResources() */
/*
** The types of resource comments understood by this app.
*/
typedef enum {fonts, neededFonts, suppliedFonts,
procSet, neededProcSet, suppliedProcSet, other} CommentType;
typedef struct {
char *comment; /* Comment string */
int len; /* Length of comment string */
CommentType type; /* What this comment string is conveying */
char *resourceName; /* The PSres name for this type of resource */
Boolean supplied; /* Does the comment imply the resource is included? */
} ResourceComment;
ResourceComment commentTable[] = {
{"%%DocumentFonts:", 0, fonts, "FontOutline", False},
{"%%DocumentNeededFonts:", 0, neededFonts, "FontOutline", False},
{"%%DocumentSuppliedFonts:", 0, suppliedFonts, "FontOutline", True},
{"%%DocumentProcSets:", 0, procSet, "ProcSet", False},
{"%%DocumentNeededProcSets:", 0, neededProcSet, "ProcSet", False},
{"%%DocumentSuppliedProcSets:", 0, suppliedProcSet, "ProcSet", True},
{NULL, 0, other, NULL, False}
};
/*************************************************************
**
** FUNCTION: parseFileHeader
**
** DESCRIPTION: Parse the header of an EPS file for BoundingBox
** and resource comments
**
** PARAMETERS: e Element describing EPS file
**
** RETURN: Whether a bounding box comment was found
**
*************************************************************/
Boolean parseFileHeader(e)
Element *e;
{
#define BBOXLEN 14 /* Length of "%%BoundingBox:" */
#define BEGINDOCUMENTLEN 15 /* Length of "%%BeginDocument" */
#define BEGINBINARYLEN 14 /* Length of "%%BeginBinary:" */
#define BUFLEN 257
char buf[BUFLEN];
char buf2[BUFLEN];
Boolean atend = False; /* Found an (atend) comment */
Boolean foundBBox = False;
CommentType lastLine = other;
float llx, lly, urx, ury;
int n;
int nestingLevel = 0;
unsigned long binaryCount = 0;
int len;
ResourceComment *res;
/*
** If this is the first time through, fill in the length fields
** in the comment table.
*/
if (commentTable[0].len == 0) {
for (res = commentTable; res->comment != NULL; res++) {
res->len = strlen(res->comment);
}
}
while (1) {
/*
** If EOF, we're done
*/
if (fgets(buf, BUFLEN, e->f) == NULL) {
goto SUCCESS;
}
len = strlen(buf);
/*
** If in binary data ignore line and decrement binary count
*/
if (binaryCount != 0) {
if (len > binaryCount) binaryCount = 0;
else binaryCount -= len;
continue;
}
/*
** Line too long? Give error message and abort
*/
if (len == BUFLEN-1 && buf[BUFLEN-1] != '\n') {
fprintf(stderr, "Line too long reading file %s\n", e->filename);
buf[79] = '\0';
fprintf(stderr, "Offending line begins\n%s\n", buf);
goto FAILURE;
}
/*
** See if we're beginning binary data
*/
if (strncmp(buf, "%%BeginBinary:", BEGINBINARYLEN) == 0) {
n = sscanf(buf, "%%%%BeginBinary: %lu", &binaryCount);
if (n != 1) binaryCount = 0; /* Malformed comment */
/*
** Check for begin/end document comments. We ignore anything in
** nested documents
*/
} else if (strncmp(buf, "%%BeginDocument", BEGINDOCUMENTLEN) == 0) {
nestingLevel++;
} else if (strcmp(buf, "%%EndDocument\n") == 0) {
nestingLevel--;
/*
** If nesting level is 0, look for more comments
*/
} else if (nestingLevel == 0) {
/*
** If we haven't already hit an (atend), the end of the
** comments is a good place to stop looking
*/
if (!atend && (strcmp(buf, "%%EndComments\n") == 0)) {
goto SUCCESS;
}
/*
** If this is a continued line, and the previous comment
** was a resource line, add more resources
*/
if (strncmp(buf, "%%+", 3) == 0) {
if (lastLine != other) {
if (buf[3] != '\0' && buf[3] != '\n') {
for (res = commentTable; res->type != lastLine;
res++) {}
addResources(e, res->resourceName,
buf+3, res->supplied);
}
}
continue;
}
/*
** See if this is a resource comment. If it's (atend), set flag
** to indicate that we have to keep going to the end of the file
*/
for (res = commentTable; res->comment != NULL; res++) {
if (strncmp(buf, res->comment, res->len) == 0) {
/*
** Success; add resources
*/
lastLine = res->type;
n = sscanf(buf + res->len, "%s", buf2);
if (n == 1 && strcmp(buf2, "(atend)") == 0) {
atend = True;
} else if (n > 0) {
addResources(e, res->resourceName,
buf + res->len, res->supplied);
}
goto LOOPEND;
}
}
/*
** Current line was not a resource comment. If the next line is
** a continuation, we need to know to ignore it
*/
lastLine = other;
/*
** Check for a bounding box comment
*/
if (strncmp(buf, "%%BoundingBox:", BBOXLEN) == 0) {
n = sscanf(buf, "%%%%BoundingBox: %f %f %f %f",
&llx, &lly, &urx, &ury);
/*
** If we didn't find four numbers, check for (atend)
*/
if (n != 4) {
n = sscanf(buf, "%%%%BoundingBox: %7s", buf2);
if (n == 1 && strcmp(buf2, "(atend)") == 0) {
atend = True;
} else {
fprintf(stderr, "Malformed %%%%BoundingBox comment\
in file %s:\n%s\n", e->filename, buf);
goto FAILURE;
}
} else {
foundBBox = True;
/*
** Convert bounding box to integers, which they should
** be but sometimes aren't
*/
e->origBBox.ll.x = floor(llx);
e->origBBox.ll.y = floor(lly);
e->origBBox.ur.x = ceil(urx);
e->origBBox.ur.y = ceil(ury);
}
}
}
LOOPEND: ;
}
SUCCESS:
/*
** Seem to be successful, but make sure we found a bounding box comment.
** Download any resources required by the file
*/
if (foundBBox) {
downloadResources(e->resources);
return True;
} else fprintf(stderr,
"Missing bounding box comment in file %s\n", e->filename);
FAILURE:
freeResourceList(e->resources);
return False;
#undef BUFLEN
#undef BBOXLEN
#undef BEGINDOCUMENTLEN
#undef BEGINBINARYLEN
} /* end parseFileHeader() */
/*************************************************************
**
** FUNCTION: imageFile
**
** DESCRIPTION: Execute an EPS file into the imaging context
**
** PARAMETERS: e Element to execute
**
** RETURN: None
**
*************************************************************/
Boolean imageFile(e)
Element *e;
{
#define BUFSIZE 256
#define EXECLEN 6 /* Length of "\nexec\n" */
char buf[BUFSIZE];
static char eobuf[] = "/execSuccess true def\n\
stop\n\
Magic end of data line )))))))))) 99#2 2#99 <xyz> // 7gsad,32h4ghNmndFgj2\n";
static char restorebuf[] =
"\nEPSFsave restore\n";
int err;
/*
** Reset to beginning of file
*/
rewind(e->f);
/*
** Prepare to execute PostScript code
*/
PSWBeginEPSF(AppData.imageCtxt);
DPSWritePostScript(AppData.imageCtxt, "\nexec\n", EXECLEN);
/*
** Copy file to context
*/
while (fgets(buf, BUFSIZE, e->f) != NULL) {
DPSWritePostScript(AppData.imageCtxt, buf, strlen(buf));
}
/*
** Mark the end of the data stream
*/
DPSWritePostScript(AppData.imageCtxt, eobuf, strlen(eobuf));
/*
** Check the results of the imaging: Get the error status and restore the
** context
*/
PSWEndEPSF(AppData.imageCtxt, &err);
/*
** Can't do this is a wrap because of restore semantics
*/
DPSWritePostScript(AppData.imageCtxt, restorebuf, strlen(restorebuf));
return err;
#undef EXECLEN
#undef BUFSIZE
} /* end imageFile() */
/*************************************************************
**
** FUNCTION: computeBBox
**
** DESCRIPTION: Compute the bounding box for an element taking current
** scale and translation into account
**
** PARAMETERS: e Element
**
** RETURN: llx lower-left x coordinate
** lly lower-left y coordinate
** urx upper-right x coordinate
** ury upper-right y coordinate
**
*************************************************************/
void computeBBox(e, llx, lly, urx, ury)
Element *e;
int *llx, *lly, *urx, *ury;
{
BBox b;
Point ll, lr, ul, ur;
float r, theta;
/*
** Create a bounding box scaled like the element
*/
b.ll.x = 0;
b.ll.y = 0;
b.ur.x = (e->origBBox.ur.x - e->origBBox.ll.x) * e->sx;
b.ur.y = (e->origBBox.ur.y - e->origBBox.ll.y) * e->sy;
/*
** For each corner of the box, rotate and translate
*/
ll.x = e->tx;
ll.y = e->ty;
lr.x = (b.ur.x) * cos(DTOR(e->rotation)) + e->tx;
lr.y = (b.ur.x) * sin(DTOR(e->rotation)) + e->ty;
ul.x = (b.ur.y) * cos(DTOR(e->rotation + 90.0)) + e->tx;
ul.y = (b.ur.y) * sin(DTOR(e->rotation + 90.0)) + e->ty;
if (b.ur.x == 0.0 && b.ur.y == 0.0) {
ur.x = e->tx;
ur.y = e->ty;
} else {
r = sqrt((b.ur.x) * (b.ur.x) + (b.ur.y) * (b.ur.y));
theta = atan2((b.ur.y), (b.ur.x));
ur.x = r * cos(theta + DTOR(e->rotation)) + e->tx;
ur.y = r * sin(theta + DTOR(e->rotation)) + e->ty;
}
/*
** Return values are the extremes of the four points
*/
*llx = floor(ll.x);
*llx = MIN(*llx, floor(lr.x));
*llx = MIN(*llx, floor(ul.x));
*llx = MIN(*llx, floor(ur.x));
*lly = floor(ll.y);
*lly = MIN(*lly, floor(lr.y));
*lly = MIN(*lly, floor(ul.y));
*lly = MIN(*lly, floor(ur.y));
*urx = ceil(ll.x);
*urx = MAX(*urx, ceil(lr.x));
*urx = MAX(*urx, ceil(ul.x));
*urx = MAX(*urx, ceil(ur.x));
*ury = ceil(ll.y);
*ury = MAX(*ury, ceil(lr.y));
*ury = MAX(*ury, ceil(ul.y));
*ury = MAX(*ury, ceil(ur.y));
} /* end computeBBox() */
/*
** Data needed to write an output file into a buffer
*/
typedef struct {
char *buf; /* Current output buffer */
char *currentChar; /* Where to add more data */
int bufLen; /* The length of the buffer so far */
int bufSize; /* The allocated size */
} CopyData;
/*************************************************************
**
** FUNCTION: copyFunc
**
** DESCRIPTION: Function to copy its data to a buffer. When
** passed to writePictureToFile, this makes the output
** go into the buffer
**
** PARAMETERS: buf Null-terminated string to write
** clientData Pointer to CopyData structure
**
** RETURN: None
**
*************************************************************/
static void copyFunc(buf, clientData)
char *buf;
char *clientData;
{
CopyData *d = (CopyData *) clientData;
int len = strlen(buf);
len = strlen(buf);
if (len + d->bufLen >= d->bufSize) {
d->bufSize += 1000;
d->buf = XtRealloc(d->buf, d->bufSize);
}
strcpy(d->currentChar, buf);
d->currentChar += len;
d->bufLen += len;
} /* end copyFunc() */
/*************************************************************
**
** FUNCTION: convertToEPS
**
** DESCRIPTION: Convert the element to an EPS format buffer
**
** PARAMETERS: e Element to write
** doPreview Whether to write a preview bitmap
**
** RETURN: EPS buffer
**
*************************************************************/
char *convertToEPS(e, doPreview)
Element *e;
Boolean doPreview;
{
int llx, lly, urx, ury;
int length, width, height, size, lines;
CopyData d;
/*
** Find the bounding box of the element
*/
computeBBox(e, &llx, &lly, &urx, &ury);
/*
** Figure out how large to make the buffer
*/
length = e->length + 1000;
if (doPreview) {
width = urx - llx;
height = ury - lly;
if (AppData.deepPreview) size = width * 2;
else size = (width + 7) / 8 * 2;
lines = size + 249 / 250;
length += height * lines * (size > 250 ? 253 : size + 3);
}
d.buf = (char *) XtMalloc(length);
d.currentChar = d.buf;
d.bufLen = 0;
d.bufSize = length;
writePictureToFile(copyFunc, (char *) &d, e, doPreview);
return d.buf;
} /* end convertToEPS() */
/*************************************************************
**
** FUNCTION: findPictureBBox
**
** DESCRIPTION: Find the bounding box for the picture. If single
** is non-null, just do that one element
**
** PARAMETERS: single If non-null, just do this element
**
** RETURN: llx lower-left x coordinate
** lly lower-left y coordinate
** urx upper-right x coordinate
** ury upper-right y coordinate
**
*************************************************************/
static void findPictureBBox(llx, lly, urx, ury, single)
int *llx, *lly, *urx, *ury;
Element *single;
{
Element *e;
int a, b, c, d;
if (single) computeBBox(single, llx, lly, urx, ury);
else {
/*
** Find bbox for first element
*/
computeBBox(AppData.elements, llx, lly, urx, ury);
/*
** Update with bboxes of additional elements
*/
for (e = AppData.elements->next; e != NULL; e = e->next) {
computeBBox(e, &a, &b, &c, &d);
if (a < *llx) *llx = a;
if (b < *lly) *lly = b;
if (c > *urx) *urx = c;
if (d > *ury) *ury = d;
}
}
} /* end findPictureBBox() */
/*************************************************************
**
** FUNCTION: executeElement
**
** DESCRIPTION: Execute an element
**
** PARAMETERS: e element to execute
** llx x coords of lower left corner of bbox
** llx y coords of lower left corner of bbox
**
** RETURN: None
**
*************************************************************/
static void executeElement(e, llx, lly)
Element *e;
int llx, lly;
{
PSWTransformBeforeEPSF(AppData.imageCtxt, e->tx - llx, e->ty - lly,
e->sx, e->sy, e->rotation,
-e->origBBox.ll.x, -e->origBBox.ll.y);
(void) imageFile(e);
} /* end executeElement() */
/*************************************************************
**
** FUNCTION: addResourcesToList
**
** DESCRIPTION: Merge an element's resources into a resource list
**
** PARAMETERS: e Element to add
** base List of resources so far
**
** RETURN: None
**
*************************************************************/
static void addResourcesToList(e, base)
Element *e;
ResourceType **base;
{
ResourceType *t, *t1;
Resource *r, *r1;
/*
** Go through element's resources and add each one to the combined
** list if it's not there already
*/
for (t = e->resources; t != NULL; t = t->next) {
for (t1 = *base; t1 != NULL; t1 = t1->next) {
if (strcmp(t->name, t1->name) == 0) break;
}
if (t1 == NULL) {
t1 = XtNew(ResourceType);
t1->name = XtNewString(t->name);
t1->list = NULL;
t1->next = *base;
*base = t1;
}
for (r = t->list; r != NULL; r = r->next) {
if (r->included) continue;
for (r1 = t1->list; r1 != NULL; r1 = r1->next) {
if (strcmp(r->name, r1->name) == 0) break;
}
if (r1 == NULL) {
r1 = XtNew(Resource);
r1->name = XtNewString(r->name);
r->version = r->revision = NULL;
r1->included = False;
r1->next = t1->list;
t1->list = r1;
}
}
}
} /* end addResourcesToList() */
/*************************************************************
**
** FUNCTION: writeResources
**
** DESCRIPTION: Write comments describing resource requirements
**
** PARAMETERS: writeFunc Function to output data
** data Client data for writeFunc
** single If non-null, just write resources
** for this element
**
** RETURN: None
**
*************************************************************/
static void writeResources(writeFunc, data, single)
void (*writeFunc)();
char *data;
Element *single;
{
ResourceType *t = NULL;
Resource *r;
Element *e;
Boolean first, procSet;
char *str;
int i;
/*
** Create resource list. If single, just use element's list;
** otherwise create a merged list
*/
if (single) t = single->resources;
else {
for (e = AppData.elements; e != NULL; e = e->next) {
addResourcesToList(e, &t);
}
}
/*
** Go through list and write comments
*/
while (t != NULL) {
for (i = 0; i < 2; i++) {
first = True;
/*
** Figure out which string to write to introduce comments
*/
if (strcmp(t->name, "FontOutline") == 0) {
procSet = False;
if (i == 0) str = "%%DocumentFonts: ";
else str = "%%DocumentNeededFonts: ";
} else {
procSet = True;
if (i == 0) str = "%%DocumentProcSets: ";
else str = "%%DocumentNeededProcSets: ";
}
/*
** Write the comments for this resource type
*/
for (r = t->list; r != NULL; r = r->next) {
if (r->included) continue;
if (first) (*writeFunc)(str, data);
else (*writeFunc)("%%+ ", data);
(*writeFunc)(r->name, data);
if (procSet) {
(*writeFunc)(" ", data);
(*writeFunc)(r->version, data);
(*writeFunc)(" ", data);
(*writeFunc)(r->revision, data);
}
(*writeFunc)("\n", data);
first = False;
}
}
t = t->next;
}
/*
** If we created a merged list, free it
*/
if (single == NULL) freeResourceList(t);
} /* end writeResources() */
/*************************************************************
**
** FUNCTION: writePreview
**
** DESCRIPTION: Write preview comments from X image data
**
** PARAMETERS: im X image data
** writeFunc Function to output data
** data Client data for writeFunc
**
** RETURN: None
**
*************************************************************/
static void writePreview(im, writeFunc, data)
XImage *im;
void (*writeFunc)();
char *data;
{
int size;
int lines = 1;
register int i, j;
int chars;
int pixel;
int accum;
char buf[257];
/*
** Compute characters per line of preview and number of lines
*/
if (im->depth == 1) size = (im->width + 7) / 8 * 2;
else size = im->width * 2;
lines = (size + 249) / 250;
/*
** Write BeginPreview comment
*/
sprintf(buf, "%%%%BeginPreview: %d %d %d %d", im->width, im->height,
im->depth, lines * im->height);
(*writeFunc)(buf, data);
/*
** If depth is 8, write out two hex digits for each pixel
*/
if (im->depth == 8) {
/*
** Go through lines of image
*/
for (i = 0; i < im->height; i++) {
(*writeFunc)("\n%", data);
chars = 0;
/*
** For each line, go through pixels. Make sure lines don't
** get too long
*/
for (j = 0; j < im->width; j++) {
if (chars > 250) {
(*writeFunc)("\n%", data);
chars = 0;
}
pixel = XGetPixel(im, j, i);
sprintf(buf, "%02x", pixel);
(*writeFunc)(buf, data);
chars += 2;
}
}
/*
** If depth is 8, combine sets of 8 pixels into an integer and write as
** two hex digits
*/
} else {
/*
** Go through lines of image
*/
for (i = 0; i < im->height; i++) {
(*writeFunc)("\n%", data);
chars = 0;
accum = 0;
/*
** For each line, go through pixels. Make sure lines don't
** get too long
*/
for (j = 0; j < im->width; j++) {
if (chars > 250) {
(*writeFunc)("\n%", data);
chars = 0;
}
pixel = XGetPixel(im, j, i);
accum = (accum << 1) + pixel;
if (((j + 1) % 8) == 0) {
sprintf(buf, "%02x", accum);
(*writeFunc)(buf, data);
chars += 2;
accum = 0;
}
}
/*
** If there are leftover pixels, shift left and write
*/
if ((im->width % 8) != 0) {
accum = accum << 8 - (im->width % 8);
if (chars > 250) (*writeFunc)("\n", data);
sprintf(buf, "%02x", accum);
(*writeFunc)(buf, data);
}
}
}
(*writeFunc)("\n%%EndPreview\n", data);
XDestroyImage(im);
} /* end writePreview() */
/*************************************************************
**
** FUNCTION: writeElement
**
** DESCRIPTION: Copy an element to the output file
**
** PARAMETERS: writeFunc Function to output data
** data Client data for writeFunc
** e Element to write
**
** RETURN: None
**
*************************************************************/
static void writeElement(writeFunc, data, e)
void (*writeFunc)();
char *data;
Element *e;
{
#define BUFSIZE 257
char linebuf[BUFSIZE];
BBox *b = &e->origBBox;
/*
** Write the comments to prepare for an EPS file and transform the
** coordinate system
*/
(*writeFunc)("BeginEPSF\n", data);
sprintf(linebuf, "%g %g translate %g rotate %g %g scale %g %g translate\n",
e->tx, e->ty, e->rotation, e->sx, e->sy, -b->ll.x, -b->ll.y);
(*writeFunc)(linebuf, data);
sprintf(linebuf, "%g %g moveto %g %g lineto %g %g lineto %g %g lineto\n",
b->ll.x, b->ll.y, b->ur.x, b->ll.y,
b->ur.x, b->ur.y, b->ll.x, b->ur.y);
(*writeFunc)(linebuf, data);
(*writeFunc)("closepath clip newpath\n", data);
sprintf(linebuf, "%%%%BeginDocument: %s\n", e->filename);
(*writeFunc)(linebuf, data);
/*
** Copy the file to the output
*/
rewind(e->f);
while (fgets(linebuf, BUFSIZE, e->f) != NULL) {
(*writeFunc)(linebuf, data);
}
/*
** End the document
*/
(*writeFunc)("\n%%EndDocument\nEndEPSF\n", data);
#undef BUFSIZE
} /* end writeElement() */
/*
** Document prolog for inclusion in output
*/
static char prolog[] = "\
%%BeginProlog\n\
/BeginEPSF {\n\
/b4_Inc_state save def\n\
/dict_count countdictstack def\n\
/op_count count 1 sub def\n\
userdict begin\n\
/showpage {} def\n\
0 setgray 0 setlinecap\n\
1 setlinewidth 0 setlinejoin\n\
10 setmiterlimit [] 0 setdash newpath\n\
/languagelevel where\n\
{pop languagelevel\n\
1 ne\n\
{false setstrokeadjust false setoverprint\n\
} if\n\
} if\n\
} bind def\n\
\n\
/EndEPSF {\n\
count op_count sub {pop} repeat\n\
countdictstack dict_count sub {end} repeat\n\
b4_Inc_state restore\n\
} bind def\n\
%%EndProlog\n\
%%Page: 1 1\n\
/pagesave save def\n";
/*************************************************************
**
** FUNCTION: writeFile
**
** DESCRIPTION: Write an output file
**
** PARAMETERS: im Preview image, if a preview is needed
** writeFunc Function to output data
** data Client data for writeFunc
** single If non-NULL, just write this element
** llx lly urx ury Bounding box of output
** doPreview Whether to include a preview bitmap
**
** RETURN: None
**
*************************************************************/
static void writeFile(im, writeFunc, data, single,
llx, lly, urx, ury, doPreview)
XImage *im;
void (*writeFunc)();
char *data;
Element *single;
int llx, lly, urx, ury;
Boolean doPreview;
{
Element *e;
char buf[257];
/*
** Write file header including bounding box
*/
(*writeFunc)("%!PS-Adobe-3.0\n%%BoundingBox: ", data);
sprintf(buf, "%d %d %d %d\n", llx, lly, urx, ury);
(*writeFunc)(buf, data);
/*
** Write resource requirement to output
*/
writeResources(writeFunc, data, single);
(*writeFunc)("%%Pages: 1\n%%EndComments\n", data);
/*
** If doing a preview, write it
*/
if (doPreview) writePreview(im, writeFunc, data);
/*
** Write the document prolog
*/
(*writeFunc)(prolog, data);
/*
** Write the element(s) out
*/
if (single) writeElement(writeFunc, data, single);
else {
for (e = AppData.lastElement; e != NULL; e = e->prev) {
writeElement(writeFunc, data, e);
}
}
/*
** Finish the document
*/
(*writeFunc)("pagesave restore showpage\n%%EOF\n", data);
} /* end writeFile() */
/*************************************************************
**
** FUNCTION: writePictureToFile
**
** DESCRIPTION: Write an output file
**
** PARAMETERS: writeFunc Function to output data
** data Client data for writeFunc
** single If non-NULL, just write this element
** doPreview Whether to include a preview bitmap
**
** RETURN: None
**
*************************************************************/
void writePictureToFile(writeFunc, data, single, doPreview)
void (*writeFunc)();
char *data;
Element *single;
Boolean doPreview;
{
int llx, lly, urx, ury;
Point pt;
XPoint xpt1, xpt2;
int width, height;
Pixmap p;
Element *e;
XImage *im;
Display *dpy = XtDisplay(AppData.drawingArea);
XDefineCursor(XtDisplay(AppData.drawingArea),
XtWindow(AppData.drawingArea), AppData.busyCursor);
/*
** Find the bounding box of the output
*/
findPictureBBox(&llx, &lly, &urx, &ury, single);
/*
** If doing a preview, compute preview image size
*/
if (doPreview) {
pt.x = llx;
pt.y = lly;
convertToX(&xpt1, &pt);
pt.x = urx;
pt.y = ury;
convertToX(&xpt2, &pt);
width = xpt2.x - xpt1.x + 1;
height = xpt1.y - xpt2.y + 1;
/*
** Allocate a pixmap or bitmap for the preview and set it
** to be the rendering destination
*/
if (AppData.deepPreview && AppData.depth == 8) {
p = allocPixmap(dpy, XtWindow(AppData.drawingArea),
width, height, 8);
XFillRectangle(XtDisplay(AppData.drawingArea), p, AppData.gc,
0, 0, width, height);
setEPSIPixmapParameters(p, height);
} else {
p = allocPixmap(dpy, XtWindow(AppData.drawingArea),
width, height, 1);
XFillRectangle(XtDisplay(AppData.drawingArea), p, AppData.bitmapgc,
0, 0, width, height);
setEPSIBitmapParameters(p, height);
}
/*
** Execute the element(s) to generate preview
*/
if (single) executeElement(single, llx, lly);
else {
for (e = AppData.lastElement; e != NULL; e = e->prev) {
executeElement(e, llx, lly);
}
}
/*
** Get the image back from the pixmap
*/
im = XGetImage(dpy, p, 0, 0, width, height, -1, ZPixmap);
XFreePixmap(dpy, p);
}
/*
** Write the output
*/
writeFile(im, writeFunc, data, single, llx, lly, urx, ury, doPreview);
XDefineCursor(XtDisplay(AppData.drawingArea),
XtWindow(AppData.drawingArea), None);
} /* end writePictureToFile() */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.