|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 17958 (0x4626)
Types: TextFile
Names: »pxl.c«
└─⟦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«
/*
* 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;
}