DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T p

⟦951fbcd0b⟧ TextFile

    Length: 17958 (0x4626)
    Types: TextFile
    Names: »pxl.c«

Derivation

└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦c319c2751⟧ »unix3.0/TeX3.0.tar.Z« 
        └─⟦036c765ac⟧ 
            └─⟦this⟧ »TeX3.0/MFcontrib/fonttool/pxl.c« 
└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
    └─⟦this⟧ »./tex82/MFcontrib/fonttool/pxl.c« 
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦63303ae94⟧ »unix3.14/TeX3.14.tar.Z« 
        └─⟦c58930e5c⟧ 
            └─⟦this⟧ »TeX3.14/MFcontrib/fonttool/pxl.c« 

TextFile

/*
 * File:
 *
 *	pxl.c
 *
 * Author:
 *	Brad Rullman
 *	Department of Computer Science  FR-35
 *	University of Washington
 *	Seattle, Washington  98155
 *	email: ecola@cs.washington.edu
 *
 *	Copyright @ March, 1987 - This program, or any subset of the functions
 *	herein, is not to be redistributed, or used for personal or commercial
 *	gain in the form of fame, fortune, or shorter working hours, without
 *	the consent of the author.
 *
 * Function:
 *
 *	A file of functions used to read/write a pxl description
 *	to/from a pixrect structure.
 *	(For a complete discussion of pxl files for TeX, I refer the
 *	reader to "The Format of PXL Files" by David Fuchs, which
 *	is probably included in the TeX distribution somewhere.)
 *
 * Contents:
 *
 *   Public:
 *
 *	OpenPxlFile		Opens a pxl file. Only 1 open at a time.
 *	ClosePxlFile		Closes a pxl file.
 *	ReadCharacter		Reads a character into ViewSW and PaintSW.
 *	WriteCharacter		Writes a character into a pxl file.
 * 
 *   Private Internal:
 *
 *	copyFile		Copies one file to another.
 *	getPXLData		Returns the pxl directory data of a character.
 *	setPXLData		Sets the pxl directory data of a character.
 *	readRaster		Loads a pixrect with raster image of a char.
 *	writeRaster		Writes a char's raster image from a pixrect.
 */

#include "global.h"
#include "pxl.h"
#include <sys/param.h>

static char	inputFileName[MAXFILENAMLEN];
static char	tempName[] = "/tmp/fonttool.XXXXXX";
static FILE	*inputFile = NULL;  /* stream pointer for font to be read */
static FILE	*outputFile; 	    /* stream pointer for the modified font */



/*
 * copyFile
 *
 * Input:
 *	file1: source file.
 *	file2: destination file.
 * Output:
 *	none.
 * Action:
 *	Reads from file1 starting at its current seek pointer position,
 *	and writes to file2's current seek pointer position.  Does not
 *	reset pointers.
 */
static void
copyFile(file1, file2)
int file1, file2;
{
    char buf[MAXBSIZE];
    int n;

    for (;;) {
	n = fread(buf, sizeof(*buf), sizeof(buf), file1);
	if (n == 0) {
	    break;
	}
	if (n < 0) {
	    AbortWithError("copyFile: Failed read\n.");
	}
	if (fwrite(buf, sizeof(*buf), n, file2) != n) {
	    AbortWithError("copyFile: Failed write\n.");
	}
    }
}



/*
 * OpenPxlFile
 *
 * Input:
 *	fileName: path of file to open.
 * Output:
 *	An int. 1 = no errors. 0 = not a pxl file. -1 = couldn't open.
 * Action:
 *	Trys to open the file passed in. The returned file descriptor is
 *	saved in inputFile.  Should only be called when the user selects
 *	"Open Font" from the OptionSW.
 *
 */
int
OpenPxlFile(fileName)
char *fileName;
{
    int firstWord;
    void ClosePxlFile();

    if (inputFile != NULL) {
	ClosePxlFile();
    }
    if ((inputFile = fopen(fileName, "r")) == NULL) {
	return(-1);
    }

    fread((int *)(&firstWord), sizeof(int), 1, inputFile);
    if (firstWord != PXLID) {
	ClosePxlFile();
	return(0);
    }

    strcpy(inputFileName, fileName);
    outputFile = NULL;
    return(1);
}



/*
 * ClosePxlFile
 *
 * Input:
 *	none.
 * Output:
 *	none.
 * Action:
 *	Closes the current pxl file.
 */
void
ClosePxlFile()
{
    fclose(inputFile);
    inputFile = NULL;		/* Indicate no pxl file open */
}



/*
 * getPXLData
 *
 * Input:
 *	c      : the ascii value of a character whose pxl data is required.
 *	pxlData: a pointer to a PXLData structure.
 * Output:
 *	none.
 * Action:
 *	Reads the pxl file, filling in the data fields of the passed
 *	PXLData structure.
 */
static void
getPXLData(c, pxlData)
int c;
PXLDataPtr pxlData;
{
    if ((c < 0) || (c > 127)) {
	AbortWithError("getPxlData: Bad ascii character.\n");
    }

    /*
     * Seek to (-517 * 4) + (4*c * 4) from the end of the file, which is
     * start of font directory + 4 words * c * 4 bytesperword,
     * i.e. the start of the directory entry for character c.
     */
    if (fseek(inputFile, ((-517 * 4) + (16 * c)), 2) == -1) {
	AbortWithError("getPxlData: Failed seek.\n");
    }

    fread((short *)(&pxlData->width), sizeof(short), 1, inputFile);
    fread((short *)(&pxlData->height), sizeof(short), 1, inputFile);
    fread((short *)(&pxlData->xOffset), sizeof(short), 1, inputFile);
    fread((short *)(&pxlData->yOffset), sizeof(short), 1, inputFile);
    fread((int *)(&pxlData->rasterPtr), sizeof(int), 1, inputFile);
    pxlData->rasterPtr = pxlData->rasterPtr * sizeof(int);
}



/*
 * setPXLData
 *
 * Input:
 *	c      : the ascii value of a character.
 *	pxlData: a pointer to a PXLData structure.
 * Output:
 *	none.
 * Action:
 *	Modifies outputFile file so that the font directory entry for
 *	c is replaced by pxlData.
 */
static void
setPXLData(c, pxlData)
int c;
PXLDataPtr pxlData;
{
    if ((c < 0) || (c > 127)) {
	AbortWithError("setPxlData: Bad ascii character.\n");
    }

    /*
     * Seek to (-517 * 4) + (4*c * 4) from the end of the file, which is
     * start of font directory + 4 words * c * 4 bytesperword,
     * i.e. the start of the directory entry for character c.
     */
    if (fseek(outputFile, ((-517 * 4) + (16 * c)), 2) == -1) {
	AbortWithError("setPxlData: Failed seek.\n");
    }

#ifndef SUN
    AbortWithError("setPxlData: Error: Machine dependent code.\n");
#endif

    fwrite((short *)(&pxlData->width), sizeof(short), 1, outputFile);
    fwrite((short *)(&pxlData->height), sizeof(short), 1, outputFile);
    fwrite((short *)(&pxlData->xOffset), sizeof(short), 1, outputFile);
    fwrite((short *)(&pxlData->yOffset), sizeof(short), 1, outputFile);
    pxlData->rasterPtr = pxlData->rasterPtr / sizeof(int);
    fwrite((int *)(&pxlData->rasterPtr), sizeof(int), 1, outputFile);
}



/*
 * readRaster
 *
 * Input:
 *	srcPR 	: pointer to the pixrect to load the character in.
 *	x, y	: pixrect coordinates at which to load the character.
 *	pxlData	: pointer to a structure containing pxl data for the character
 *		  in question.
 * Output:
 *	none.
 * Action:
 *	Reads the region defined by the character's bounding box into
 *	the given pixrect at the given coordinates.  Assumes that the
 *	given pixrect is large enough to hold the character, otherwise 
 *	clipping takes place.
 *	Notice that the raster image file is assumed to be big-endian,
 *	that is for the 4 byte word starting at position 600, the most
 *	significant 8 bits come at location 600, the next significant
 *	8 bits come at location 601, etc.
 */
static void
readRaster(srcPR, x, y, pxlData)
struct pixrect *srcPR;
int x, y;
PXLDataPtr pxlData;
{
    int wordWidth;		/* width of character raster, in words */
    int rasterLen;		/* length of char raster, in bytes */
    struct pixrect *paddedPR;	/* temporary pixrect */
    struct mpr_data *memoryData;/* ptr to a pixrect's memory data */

    wordWidth = ((int) (pxlData->width/32)) + ((pxlData->width % 32) != 0);
    paddedPR = mem_create((wordWidth*32), pxlData->height, (int) 1);

    /* 
     * Read in the raster image. The raster image will require wordWidth *
     * height words of memory, where a word is 32 bits. This raster image
     * is flushed out with 0's so that each row is some multiple of 32 bits
     * long.
     */
    fseek(inputFile, pxlData->rasterPtr, 0);
    rasterLen = wordWidth * pxlData->height * sizeof(int);
    memoryData = (struct mpr_data *) paddedPR->pr_data;
    if (fread((char *) memoryData->md_image, sizeof(char), rasterLen, 
	       inputFile) != rasterLen) {
	perror("readRaster");
	AbortWithError("readRaster: Failed read.\n");
    }

    /*
     * The pixrect is now loaded with the padded image of the character.
     * The final step is to cut this pixrect down to exact true size
     * and load it into the desired pixrect.
     */
    pr_rop(srcPR, x, y, pxlData->width, pxlData->height, 
	   PIX_SRC, paddedPR, 0, 0);
    pr_destroy(paddedPR);			/* No longer needed */
}



/*
 * ReadCharacter
 *
 * Input:
 *	c: a character to read.
 * Output: 
 *	none.
 * Action:
 *	Reads the given character into the View and Paint subwindows.
 */
void
ReadCharacter(c)
int c;
{
    PXLData charPxlData;
    int boxWithRefWidth, boxWithRefHeight;
    int neededViewSWWidth, neededViewSWHeight;
    int xLoad, yLoad;

    if (inputFile == NULL) {
	ShowMsg("***** Open a PXL file before loading a character. *****");
	return;
    }
    if (RasterChanged) {
	ShowMsg("***** Load over existing raster?  (Left \
		confirms, right cancels.) *****");
	if (!Confirm()) {
	    return;
	}
    }
    ClearMsg();
    RasterChanged = 0;

    SETCURSORWATCH;
    getPXLData(c, &charPxlData);

    /*
     * Find the bounding box that contains both the character and 
     * its reference point, then adjust the size of the view subwindow
     * and related structures.
     */
    boxWithRefWidth = MAX(charPxlData.width - charPxlData.xOffset,
			  MAX(charPxlData.xOffset,
			      charPxlData.width));
    boxWithRefHeight = MAX(charPxlData.height - charPxlData.yOffset,
			   MAX(charPxlData.yOffset,
			       charPxlData.height));
    neededViewSWWidth = MIN(MAXVIEWSWWIDTH,
			    MAX(MINVIEWSWWIDTH,
				boxWithRefWidth + 2*MINVIEWSWMARGIN));
    neededViewSWHeight = MIN(MAXVIEWSWHEIGHT,
			     MAX(MINVIEWSWHEIGHT, 
				 boxWithRefHeight + 2*MINVIEWSWMARGIN));
    if ( (ViewPR->pr_size.x != neededViewSWWidth) || 
	 (ViewPR->pr_size.y != neededViewSWHeight) ) {
	ResizePRs(neededViewSWWidth, neededViewSWHeight, 0);
    }

    /*
     * Find the ViewPR coordinates (xLoad, yLoad) that will correspond
     * to the origin of the character's bounding box when it is loaded.
     * We want the bounding box formed by the union of the character and
     * its reference point to be centered in the ViewPR.
     */
    xLoad = MAX( (ViewPR->pr_size.x-boxWithRefWidth)/2 - charPxlData.xOffset,
		 (ViewPR->pr_size.x-boxWithRefWidth)/2 );
    yLoad = MAX( (ViewPR->pr_size.y-boxWithRefHeight)/2 - charPxlData.yOffset,
		 (ViewPR->pr_size.y-boxWithRefHeight)/2 );

    ReferenceXY.x = SCALEUP(xLoad + charPxlData.xOffset);
    ReferenceXY.y = SCALEUP(yLoad + charPxlData.yOffset);

    /*
     * Load the character into the ViewPR and display it.  Note that if the
     * char's width and height are zero, then it is either not currently
     * present in the font or is "totally white";  in either case it has
     * no raster.
     */
    CLEARPR(ViewPR);
    if ( (charPxlData.width > 0) && (charPxlData.height > 0) ) {
	readRaster(ViewPR, xLoad, yLoad, &charPxlData);
    }
    CLEARPR(PaintPR);
    DisplayPR(0, 0, ViewPR->pr_size.x, ViewPR->pr_size.y);
    COPYPR(ViewPR, UndoPR);

    SETCURSORNORMAL;
}






/*
 * writeRaster
 *
 * Input:
 *	srcPR 	: pointer to the pixrect containing the character.
 *	x, y	: pixrect coordinates specifying the origin of
 *		  the character's bounding box.
 *	oldPxlData: pointer to a structure containing pxl data for
 *		    the original character.
 *	newPxlData: pointer to a structure containing pxl data for
 *		    the new character.
 * Output:
 *	none.
 * Action:
 *	Copies the current input file to the current output file, inserting
 *	a raster description for the image in srcPR into the output file and
 *	excluding the old raster for that character.
 *	Notice that the raster image file is assumed to be big-endian,
 *	that is for the 4 byte word starting at position 600, the most
 *	significant 8 bits come at location 600, the next significant
 *	8 bits come at location 601, etc.
 */
static void
writeRaster(srcPR, x, y, oldPxlData, newPxlData)
struct pixrect *srcPR;
int x, y;
PXLDataPtr oldPxlData, newPxlData;
{
    char copyBuf[MAXBSIZE];
    int oldWordWidth, newWordWidth;
    int oldRasterLen, newRasterLen;
    int changeInByteLen;
    int numBufsToCopy, n;
    struct pixrect *paddedPR;
    register int c;
    int fontDirPtr;			/* offset to font directory */
    PXLData tempPxlData;
    struct mpr_data *memoryData;	/* ptr to a pixrect's memory data */

    /*
     * Initialize.
     */
    oldWordWidth = ((int) (oldPxlData->width/32)) 
		   + ((oldPxlData->width % 32) != 0);
    oldRasterLen = oldWordWidth * oldPxlData->height * sizeof(int);
    newWordWidth = ((int) (newPxlData->width/32)) 
		   + ((newPxlData->width % 32) != 0);
    newRasterLen = newWordWidth * newPxlData->height * sizeof(int);

    /*
     * Write the raster image into a pixrect that is an integer number
     * of words wide.
     */
    paddedPR = mem_create((newWordWidth * 32), newPxlData->height, 1);
    pr_rop(paddedPR, 0, 0, newPxlData->width, newPxlData->height,
	   PIX_SRC, srcPR, x, y);

    /*
     * Copy the old file into the new file up to the point where a raster 
     * is to be replaced.
     */
    rewind(inputFile);
    rewind(outputFile);
    numBufsToCopy = oldPxlData->rasterPtr/sizeof(copyBuf) + 1;
    for (c = 0; c < numBufsToCopy; c++) {
	n = fread(copyBuf, sizeof(*copyBuf), sizeof(copyBuf), inputFile);
	if (n == 0) {
	    AbortWithError("writeRaster: Failed read in file copy\n.");
	}
	if (fwrite(copyBuf, sizeof(*copyBuf), n, outputFile) != n) {
	    AbortWithError("writeRaster: Failed write in file copy\n.");
	}
    }
    if (truncate(tempName, oldPxlData->rasterPtr) == -1) {
	AbortWithError("writeRaster: truncate failed.\n");
    }

    /*
     * Write new raster info from the padded pixrect to the output file
     * at the old raster's position.
     */
#ifndef SUN
    AbortWithError("writeRaster: Error: Machine dependent code.\n");
#endif
    memoryData = (struct mpr_data *) paddedPR->pr_data;
    fseek(outputFile, oldPxlData->rasterPtr, 0);
    if (fwrite((char *) memoryData->md_image, sizeof(char), newRasterLen, 
	       outputFile) != newRasterLen) {
	AbortWithError("writeRaster: Failed write.\n");
    }
    pr_destroy(paddedPR);

    /*
     * Copy the rest of the old file into the new file, omitting the
     * old raster.
     */
    fseek(inputFile, oldPxlData->rasterPtr + oldRasterLen, 0);
    copyFile(inputFile, outputFile);

    /*
     * Fix-up the pointer to the start of the font directory by reading the
     * old one, adding the number of additional words that have been written,
     * and writing the new one back.
     */
    fseek(outputFile, (int) (-FONTDIRPTR), 2);
    fread((int *)(&fontDirPtr), sizeof(int), 1, outputFile);
    changeInByteLen = newRasterLen - oldRasterLen;
    fontDirPtr += changeInByteLen/sizeof(int);
    fseek(outputFile, (int) (-FONTDIRPTR), 2);
    fwrite((int *)(&fontDirPtr), sizeof(int), 1, outputFile);

    /*
     * Fix-up all the affected character raster pointers in the font directory
     * by adding the change in the file's byte length.
     */
    for (c = 0; c < 128; c++) {
	getPXLData(c, &tempPxlData);
	if (tempPxlData.rasterPtr > oldPxlData->rasterPtr) {
	    tempPxlData.rasterPtr += changeInByteLen;
	    setPXLData(c, &tempPxlData);
	}
    }
}



/*
 * WriteCharacter
 *
 * Input:
 *	c: a character to read.
 * Output: 
 *	none.
 * Action:
 *	Tries to write the raster image in the ViewPR out to the current
 *	font's pxl file, replacing the existing one.
 */
void
WriteCharacter(c)
int c;
{
    /*
     * (mindx,mindy) (maxdx, maxdy) define the bounding box of the "set"
     * pixels in the ViewPR.
     */
    register int mindx, maxdx, mindy, maxdy;
    register int dx, dy;
    PXLData oldPxlData, newPxlData;
    char bakupFileName[MAXFILENAMLEN+4];

    if (inputFile == NULL) {
	ShowMsg("***** Open a PXL file before saving a character. *****");
	return;
    }
    ClearMsg();
    RasterChanged = 0;

    SETCURSORWATCH;

    /*
     * If this is the first character written to this pxl file during this 
     * session, rename the original input file to a ".bak" file and copy it
     * to a new file of the same name as the original.
     */
    if (outputFile == NULL) {
	strcpy(bakupFileName, inputFileName);
	strcat(bakupFileName, ".bak");
	rename(inputFileName, bakupFileName);
	outputFile = fopen(inputFileName, "w+");
	if (outputFile == NULL) {
	     AbortWithError("WriteCharacter: Couldn't create output file.\n");
	}
	rewind(inputFile);
	copyFile(inputFile, outputFile);
	fclose(inputFile);
	inputFile = outputFile;
    }

    /*
     * Create a temporary file to write changes to.
     */
    mktemp(tempName);
    outputFile = fopen(tempName, "w+");
    if (outputFile == NULL) {
	AbortWithError("WriteCharacter: Couldn't create temporary file.\n");
    }

    /*
     * Find the character's bounding box.
     */
    mindx = ViewPR->pr_size.x;
    mindy = ViewPR->pr_size.y;
    maxdx = 0;
    maxdy = 0;
    for (dx = 0; dx < ViewPR->pr_size.x; dx++) {
	for (dy = 0; dy < ViewPR->pr_size.y; dy++) {
	    if (pr_get(ViewPR, dx, dy)) {
		mindx = MIN(mindx, dx);
		maxdx = MAX(maxdx, dx);
		mindy = MIN(mindy, dy);
		maxdy = MAX(maxdy, dy);
	    }
	}
    }

    /*
     * Initialize the character's new pxl data: the size of its bounding
     * box, the placement of the reference point (relative to the
     * top left corner of the bounding box), and the pointer to its raster.
     */
    getPXLData(c, &oldPxlData);
    if ( (mindx == ViewPR->pr_size.x) && (mindy == ViewPR->pr_size.y) &&
	 (maxdx == 0) && (maxdy == 0) ) {  /* new char is totally white */
	newPxlData.width = 0;
	newPxlData.height = 0;
	newPxlData.xOffset = 0;
	newPxlData.yOffset = 0;
	newPxlData.rasterPtr = 0;
    }
    else {
	newPxlData.width = maxdx - mindx + 1;
	newPxlData.height = maxdy - mindy + 1;
	newPxlData.xOffset = SCALEDOWN(ReferenceXY.x) - mindx;
	newPxlData.yOffset = SCALEDOWN(ReferenceXY.y) - mindy;
 	if (oldPxlData.rasterPtr != 0) {
	    newPxlData.rasterPtr = oldPxlData.rasterPtr;
	}
	else {  /* old char is totally white; make new raster first in file */
	    newPxlData.rasterPtr = oldPxlData.rasterPtr = sizeof(int);
	}
    }

    /*
     * Write out the character raster and its new pxl data.
     */
    writeRaster(ViewPR, mindx, mindy, &oldPxlData, &newPxlData);
    setPXLData(c, &newPxlData);

    fclose(inputFile);
    if (rename(tempName, inputFileName) == -1) {
	AbortWithError("WriteCharacter: File rename failed\n");
    }
    inputFile = outputFile;

    SETCURSORNORMAL;
}