RasterFontWriterImpl.mesa
Michael Plass, February 16, 1984 1:25:36 pm PST
Last changed by Pavel on October 12, 1984 6:21:43 pm PDT
Removed some dependencies upon glyphs being small enough for 16-bit numbers.
DIRECTORY
Basics,
Font,
FS,
ImagerBasic,
ImagerMasks,
ImagerPixelMaps,
ImagerTransform,
IO,
RasterFontWriter,
Real,
Rope,
UFFileManager,
UFPressFontFormat,
UFPressFontReader,
UFStrikeFormat,
VM;
RasterFontWriterImpl: CEDAR PROGRAM
IMPORTS FS, ImagerMasks, ImagerPixelMaps, ImagerTransform, IO, Real, Rope, UFFileManager, UFPressFontFormat, UFPressFontReader
EXPORTS RasterFontWriter ~
BEGIN
OPEN RasterFontWriter;
FormatError: PUBLIC ERROR [byteIndex: INT] ~ CODE;
Create: PUBLIC PROC [defaultBoxBounds: ImagerPixelMaps.DeviceRectangle, defaultWidth: INTEGER] RETURNS [internalFont: InternalFont] ~ {
defaultPixels: ImagerPixelMaps.PixelMap ← ImagerPixelMaps.Create[0, defaultBoxBounds];
defaultPixels.Clear;
defaultPixels.Fill[defaultBoxBounds, 1];
internalFont ← NEW [InternalFontRep];
internalFont.defaultChar ← [fWidth: defaultWidth, sWidth: 0, pixels: defaultPixels];
FOR char: CHAR IN CHAR DO
internalFont.charRep[char] ← internalFont.defaultChar;
ENDLOOP;
};
LoadAC: PROC [fileName: Rope.ROPE] RETURNS [internalFont: InternalFont] ~ TRUSTED {
fileKey: Font.Key ← UFFileManager.KeyOf[fileName];
sizeInMeters: REAL ← UFPressFontReader.Size[[fileKey, 0]];
bc, ec: CHAR;
[bc, ec] ← UFPressFontReader.Range[[fileKey, 0]];
internalFont ← Create[[-8, 1, 8, 8], 10];
internalFont.family ← UFPressFontReader.Family[[fileKey, 0]];
internalFont.face ← UFPressFontReader.Face[[fileKey, 0]];
internalFont.bitsPerEmQuad ← sizeInMeters*UFPressFontReader.Resolution[[fileKey, 0]].xRes/0.0254;
FOR char: CHAR IN [bc..ec] DO
info: UFPressFontReader.CharInfo ← UFPressFontReader.GetCharInfo[[fileKey, 0], char];
pixelArray: ImagerBasic.PixelArray ← UFPressFontReader.GetCharRaster[[fileKey, 0], char];
IF pixelArray # NIL THEN {
mask: ImagerMasks.Mask ← ImagerMasks.FromPixelArray[pixelArray, pixelArray.m.Concat[ImagerTransform.Rotate[90]]];
bb: ImagerMasks.Mask ← ImagerMasks.FromRectangle[ImagerMasks.BoundingBox[mask]];
pixelMap: ImagerPixelMaps.PixelMap ← ImagerMasks.ToPixelMap[mask, bb];
internalFont.charRep[char] ← [
fWidth: info.widthX*internalFont.bitsPerEmQuad,
sWidth: -info.widthY*internalFont.bitsPerEmQuad,
pixels: pixelMap
];
};
ENDLOOP;
};
Load: PUBLIC PROC [fileName: Rope.ROPE] RETURNS [internalFont: InternalFont] ~ TRUSTED {
file: IO.STREAM ← FS.StreamOpen[fileName];
ReadBlock: UNSAFE PROC [dest: LONG POINTER, words: CARDINAL, wordOffset: INT ← -1] ~ UNCHECKED {
IF wordOffset >= 0 THEN file.SetIndex[wordOffset*Basics.bytesPerWord];
[] ← file.UnsafeGetBlock[[dest, 0, words*Basics.bytesPerWord]];
};
CurWordOffset: PROC RETURNS [wordOffset: INT] ~ CHECKED {
wordOffset ← file.GetIndex/Basics.bytesPerWord;
};
strike: ImagerPixelMaps.PixelMap;
header: UFStrikeFormat.Header;
internalFont ← NEW[InternalFontRep];
ReadBlock[@header, SIZE[UFStrikeFormat.Header], 0];
IF header.format.oneBit # T AND header.format.unused # 0 THEN {
IO.Close[file];
RETURN [LoadAC[fileName]];
};
IF header.format.oneBit # T THEN ERROR FormatError[0];
IF header.format.index # F THEN ERROR FormatError[0];
IF header.format.unused # 0 THEN ERROR FormatError[1];
IF header.format.kerned = T THEN {
boundingBox: UFStrikeFormat.BoundingBox;
body: UFStrikeFormat.Body;
xInSegment, prevXInSegment: CARDINAL;
xInSegmentOffset: INT;
widthEntryOffset: INT;
widthEntry: UFStrikeFormat.WidthEntry;
bodyOffset: INT;
ReadBlock[@boundingBox, SIZE[UFStrikeFormat.BoundingBox]];
bodyOffset ← CurWordOffset[];
ReadBlock[@body, SIZE[UFStrikeFormat.Body]];
strike ← ImagerPixelMaps.Create[0, [-body.ascent, 0, body.ascent+body.descent, body.raster*Basics.bitsPerWord]];
ReadBlock[strike.refRep.pointer, strike.refRep.words];
widthEntryOffset ← CurWordOffset[] + (header.max-header.min+3)*SIZE[CARDINAL];
IF widthEntryOffset # bodyOffset + body.length THEN ERROR FormatError[bodyOffset*SIZE[CARDINAL]];
ReadBlock[@prevXInSegment, SIZE[CARDINAL]];
xInSegmentOffset ← CurWordOffset[];
FOR char: CHAR IN [header.min..header.max] DO
charPixels: ImagerPixelMaps.PixelMap ← strike;
ReadBlock[@xInSegment, SIZE[CARDINAL], xInSegmentOffset];
xInSegmentOffset ← xInSegmentOffset + SIZE[CARDINAL];
ReadBlock[@widthEntry, SIZE[UFStrikeFormat.WidthEntry], widthEntryOffset];
widthEntryOffset ← widthEntryOffset + SIZE[UFStrikeFormat.WidthEntry];
IF widthEntry # UFStrikeFormat.nullWidthEntry THEN {
IF widthEntry.width > header.maxwidth THEN ERROR FormatError[(widthEntryOffset-SIZE[UFStrikeFormat.WidthEntry])*Basics.bytesPerWord];
charPixels.fOrigin ← widthEntry.offset+boundingBox.fbbox-prevXInSegment;
charPixels.fMin ← prevXInSegment;
charPixels.fSize ← xInSegment-prevXInSegment;
internalFont.charRep[char] ← [
sWidth: 0,
fWidth: widthEntry.width,
pixels: charPixels
];
};
prevXInSegment ← xInSegment;
ENDLOOP;
ReadBlock[@xInSegment, SIZE[CARDINAL], xInSegmentOffset];
xInSegmentOffset ← xInSegmentOffset + SIZE[CARDINAL];
ReadBlock[@widthEntry, SIZE[UFStrikeFormat.WidthEntry], widthEntryOffset];
widthEntryOffset ← widthEntryOffset + SIZE[UFStrikeFormat.WidthEntry];
IF widthEntry # UFStrikeFormat.nullWidthEntry THEN {
strike.fOrigin ← widthEntry.offset+boundingBox.fbbox-prevXInSegment;
strike.fMin ← prevXInSegment;
strike.fSize ← xInSegment-prevXInSegment;
internalFont.defaultChar ← [
sWidth: 0,
fWidth: widthEntry.width,
pixels: strike
];
}
ELSE ERROR FormatError[file.GetIndex];
}
ELSE {
body: UFStrikeFormat.Body;
xInSegment, prevXInSegment: CARDINAL;
ReadBlock[@body, SIZE[UFStrikeFormat.Body]];
strike ← ImagerPixelMaps.Create[0, [-body.ascent, 0, body.ascent+body.descent, body.raster*Basics.bitsPerWord]];
ReadBlock[strike.refRep.pointer, strike.refRep.words];
ReadBlock[@prevXInSegment, SIZE[CARDINAL]];
FOR char: CHAR IN [header.min..header.max] DO
charPixels: ImagerPixelMaps.PixelMap ← strike;
ReadBlock[@xInSegment, SIZE[CARDINAL]];
IF xInSegment>prevXInSegment THEN {
charPixels.fOrigin ← -prevXInSegment;
charPixels.fMin ← prevXInSegment;
charPixels.fSize ← xInSegment-prevXInSegment;
IF charPixels.fSize > header.maxwidth THEN ERROR FormatError[file.GetIndex-2];
internalFont.charRep[char] ← [
sWidth: 0,
fWidth: charPixels.fSize,
pixels: charPixels
];
};
prevXInSegment ← xInSegment;
ENDLOOP;
ReadBlock[@xInSegment, SIZE[CARDINAL]];
strike.fOrigin ← -prevXInSegment;
strike.fMin ← prevXInSegment;
strike.fSize ← xInSegment-prevXInSegment;
internalFont.defaultChar ← [
sWidth: 0,
fWidth: strike.fSize,
pixels: strike
];
};
FOR char: CHAR IN CHAR DO
IF internalFont.charRep[char].pixels.refRep = NIL THEN {
internalFont.charRep[char] ← internalFont.defaultChar;
};
ENDLOOP;
IF file.GetIndex # file.GetLength THEN ERROR FormatError[file.GetIndex];
file.Close;
};
ComputeFontMetrics: PUBLIC PROC [internalFont: InternalFont] RETURNS [bc, ec: CHAR, sMin, fMin, sMax, fMax: INTEGER, maxWidth, totalWidth, fSizeStrike: CARDINAL] ~ {
ProcessChar: PROC [charRep: InternalCharRep] ~ {
bb: ImagerPixelMaps.DeviceRectangle ← charRep.pixels.Window;
fWidth: INT ← Real.RoundLI[charRep.fWidth];
IF bb.sSize > 0 AND bb.fSize > 0 THEN {
sMin ← MIN[sMin, bb.sMin];
fMin ← MIN[fMin, bb.fMin];
sMax ← MAX[sMax, bb.sMin+bb.sSize];
fMax ← MAX[fMax, bb.fMin+bb.fSize];
fSizeStrike ← fSizeStrike + bb.fSize;
};
totalWidth ← totalWidth + fWidth;
maxWidth ← MAX[fWidth, maxWidth];
};
bc ← '\000;
ec ← '\377;
WHILE bc < '\377 AND internalFont.charRep[bc] = internalFont.defaultChar DO bc ← bc + 1 ENDLOOP;
WHILE ec > '\000 AND internalFont.charRep[ec] = internalFont.defaultChar DO ec ← ec - 1 ENDLOOP;
maxWidth ← totalWidth← fSizeStrike ← 0;
sMin ← fMin ← sMax ← fMax ← 0;
FOR char: CHAR IN [bc..ec] DO
IF internalFont.charRep[char] # internalFont.defaultChar THEN ProcessChar[internalFont.charRep[char]];
ENDLOOP;
ProcessChar[internalFont.defaultChar];
};
ComputeWidthEntry: PROC [charRep: InternalCharRep, fMinFont: INTEGER] RETURNS [widthEntry: UFStrikeFormat.WidthEntry] ~ {
window: ImagerPixelMaps.DeviceRectangle ← charRep.pixels.Window;
IF window.sSize = 0 OR window.fSize = 0 THEN window.fMin ← 0;
IF window.fMin-fMinFont < 0 THEN ERROR;
widthEntry.offset ← window.fMin-fMinFont;
widthEntry.width ← Real.RoundLI[charRep.fWidth];
};
WriteKernedStrike: PUBLIC PROC [internalFont: InternalFont, fileName: Rope.ROPE] ~ TRUSTED {
file: IO.STREAM ← FS.StreamOpen[fileName, $create];
WriteBlock: UNSAFE PROC [source: LONG POINTER, words: CARDINAL] ~ UNCHECKED {
file.UnsafePutBlock[[source, 0, words*Basics.bytesPerWord]];
};
min, max: CHAR;
sMin, fMin, sMax, fMax: INTEGER;
maxwidth, strikeWidth: CARDINAL;
[min, max, sMin, fMin, sMax, fMax, maxwidth, ----, strikeWidth] ← ComputeFontMetrics[internalFont];
IF max>=min THEN {
ascent: NAT ← -sMin;
descent: NAT ← sMax;
bodyStart: INT;
header: UFStrikeFormat.Header;
boundingBox: UFStrikeFormat.BoundingBox ← [fbbox: fMin, fbboy: -sMax, fbbdx: fMax-fMin, fbbdy: sMax-sMin];
body: UFStrikeFormat.Body;
strike: ImagerPixelMaps.PixelMap;
widthEntry: UFStrikeFormat.WidthEntry;
f: INTEGER;
strike ← ImagerPixelMaps.Create[0, [-ascent, 0, ascent+descent, strikeWidth]];
strike.Clear;
f ← 0;
FOR c: CHAR IN [min..max] DO
IF internalFont.charRep[c] # internalFont.defaultChar THEN {
pixels: ImagerPixelMaps.PixelMap ← internalFont.charRep[c].pixels;
pixels ← pixels.ShiftMap[0, f-pixels.Window.fMin];
strike.Transfer[pixels];
IF pixels.sSize # 0 THEN f ← f + pixels.fSize;
};
ENDLOOP;
strike.Transfer[internalFont.defaultChar.pixels.ShiftMap[0, f-internalFont.defaultChar.pixels.Window.fMin]];
header.format ← [oneBit: T, index: F, fixed: F, kerned: T, unused: 0];
header.min ← min;
header.max ← max;
header.maxwidth ← maxwidth;
body.length ← strike.refRep.words+SIZE[UFStrikeFormat.Body]+(max-min+3)*SIZE[CARDINAL];
body.ascent ← ascent;
body.descent ← descent;
body.xoffset ← 0;
body.raster ← strike.refRep.rast;
WriteBlock[@header, SIZE[UFStrikeFormat.Header]];
WriteBlock[@boundingBox, SIZE[UFStrikeFormat.BoundingBox]];
bodyStart ← file.GetIndex;
WriteBlock[@body, SIZE[UFStrikeFormat.Body]];
WriteBlock[strike.refRep.pointer, strike.refRep.words];
strikeWidth ← 0;
WriteBlock[@strikeWidth, SIZE[CARDINAL]];
FOR c: CHAR IN [min..max] DO
charRep: InternalCharRep ← internalFont.charRep[c];
IF charRep # internalFont.defaultChar THEN {
IF charRep.pixels.sSize # 0 THEN
strikeWidth ← strikeWidth + charRep.pixels.fSize;
};
WriteBlock[@strikeWidth, SIZE[CARDINAL]];
ENDLOOP;
IF internalFont.defaultChar.pixels.sSize # 0 THEN
strikeWidth ← strikeWidth + internalFont.defaultChar.pixels.fSize;
WriteBlock[@strikeWidth, SIZE[CARDINAL]];
IF file.GetIndex-bodyStart # body.length*Basics.bytesPerWord THEN ERROR;
FOR c: CHAR IN [min..max] DO
widthEntry ← IF internalFont.charRep[c] = internalFont.defaultChar
THEN widthEntry ← UFStrikeFormat.nullWidthEntry
ELSE ComputeWidthEntry[internalFont.charRep[c], fMin];
WriteBlock[@widthEntry, SIZE[UFStrikeFormat.WidthEntry]];
ENDLOOP;
widthEntry ← ComputeWidthEntry[internalFont.defaultChar, fMin];
WriteBlock[@widthEntry, SIZE[UFStrikeFormat.WidthEntry]];
};
file.Close;
};
WriteStrike: PUBLIC PROC [internalFont: InternalFont, fileName: Rope.ROPE] ~ TRUSTED {
file: IO.STREAM ← FS.StreamOpen[fileName, $create];
WriteBlock: UNSAFE PROC [source: LONG POINTER, words: CARDINAL] ~ UNCHECKED {
file.UnsafePutBlock[[source, 0, words*Basics.bytesPerWord]];
};
header: UFStrikeFormat.Header;
strike: ImagerPixelMaps.PixelMap;
body: UFStrikeFormat.Body;
min, max: CHAR;
sMin, fMin, sMax, fMax: INTEGER;
maxwidth, strikeWidth: CARDINAL;
[min, max, sMin, fMin, sMax, fMax, maxwidth, strikeWidth, ----] ← ComputeFontMetrics[internalFont];
IF max>=min THEN {
ascent: NAT ← -sMin;
descent: NAT ← sMax;
bodyStart: INT;
strike ← ImagerPixelMaps.Create[0, [-ascent, 0, ascent+descent, strikeWidth]];
strike.Clear;
strikeWidth ← 0;
FOR c: CHAR IN [min..max] DO
IF internalFont.charRep[c] # internalFont.defaultChar THEN {
strike.Transfer[internalFont.charRep[c].pixels.ShiftMap[0, strikeWidth]];
strikeWidth ← strikeWidth + Real.RoundLI[internalFont.charRep[c].fWidth];
};
ENDLOOP;
strike.Transfer[internalFont.defaultChar.pixels.ShiftMap[0, strikeWidth]];
header.format ← [oneBit: T, index: F, fixed: F, kerned: F, unused: 0];
header.min ← min;
header.max ← max;
header.maxwidth ← maxwidth;
body.length ← strike.refRep.words+SIZE[UFStrikeFormat.Body]+(max-min+1+2)*SIZE[CARDINAL];
body.ascent ← ascent;
body.descent ← descent;
body.xoffset ← 0;
body.raster ← strike.refRep.rast;
WriteBlock[@header, SIZE[UFStrikeFormat.Header]];
bodyStart ← file.GetIndex;
WriteBlock[@body, SIZE[UFStrikeFormat.Body]];
WriteBlock[strike.refRep.pointer, strike.refRep.words];
strikeWidth ← 0;
WriteBlock[@strikeWidth, SIZE[CARDINAL]];
FOR c: CHAR IN [min..max] DO
IF internalFont.charRep[c] # internalFont.defaultChar THEN {
strikeWidth ← strikeWidth + Real.RoundLI[internalFont.charRep[c].fWidth];
};
WriteBlock[@strikeWidth, SIZE[CARDINAL]];
ENDLOOP;
strikeWidth ← strikeWidth + Real.RoundLI[internalFont.defaultChar.fWidth];
WriteBlock[@strikeWidth, SIZE[CARDINAL]];
IF file.GetIndex-bodyStart # body.length*Basics.bytesPerWord THEN ERROR;
};
file.Close;
};
WriteNameEntry: PROC [file: IO.STREAM, code: UFPressFontFormat.FontCode, name: Rope.ROPE] ~ TRUSTED {
WriteBlock: UNSAFE PROC [source: LONG POINTER, words: CARDINAL] ~ UNCHECKED {
file.UnsafePutBlock[[source, 0, words*Basics.bytesPerWord]];
};
shortenedName: Rope.ROPE ← name.Substr[len: 19];
length: NAT ← shortenedName.Length;
hdr: UFPressFontFormat.IndexHeader ← [type: name, length: 12];
WriteBlock[@hdr, SIZE[UFPressFontFormat.IndexHeader]];
file.PutChar['\000];
file.PutChar['\000+code];
file.PutChar['\000+length];
file.PutRope[shortenedName];
WHILE length < 19 DO file.PutChar['\000]; length ← length + 1 ENDLOOP;
};
WriteAC: PUBLIC PROC [internalFont: InternalFont, fileName: Rope.ROPE, bitsPerInch: REAL ← 384.0] ~ TRUSTED {
micaSize: REAL ← internalFont.bitsPerEmQuad/bitsPerInch*2540.0;
bitsPerInchX: REAL ← bitsPerInch;
bitsPerInchY: REAL ← bitsPerInch;
file: IO.STREAM ← FS.StreamOpen[fileName, $create];
WriteBlock: UNSAFE PROC [source: LONG POINTER, words: INT] ~ UNCHECKED {
file.UnsafePutBlock[[source, 0, words*Basics.bytesPerWord]];
};
CurWordOffset: PROC RETURNS [wordOffset: INT] ~ CHECKED {
wordOffset ← file.GetIndex/Basics.bytesPerWord;
};
min, max: CHAR;
endIndexEntry: UFPressFontFormat.IndexHeader ← [type: end, length: SIZE[UFPressFontFormat.IndexHeader]];
charsIndexEntryByteLoc: INT;
charsIndexEntry: UFPressFontFormat.RawIndex.chars;
pixelMap: ImagerPixelMaps.PixelMap ← ImagerPixelMaps.Create[0, [0,0,16,16]];
pixelMap.Clear;
[min, max, ----, ----, ----, ----, ----, ----, ----] ← ComputeFontMetrics[internalFont];
charsIndexEntry ← [
hdr: [type: chars, length: SIZE[UFPressFontFormat.RawIndex.chars]],
variantPart: chars[
family: 0,
face: internalFont.face,
bc: min,
ec: max,
size: Real.RoundLI[micaSize],
rotation: 0,
startaddress: [0,0],
length: [0,0],
resolutionx: Real.RoundLI[bitsPerInchX*10],
resolutiony: Real.RoundLI[bitsPerInchY*10]
]
];
WriteNameEntry[file, 0, internalFont.family];
charsIndexEntryByteLoc ← file.GetIndex;
IF max>=min THEN {
WriteBlock[@charsIndexEntry, charsIndexEntry.hdr.length];
};
WriteBlock[@endIndexEntry, SIZE[UFPressFontFormat.IndexHeader]];
IF max>=min THEN {
startaddress: INT ← CurWordOffset[];
directoryStart, filePos: INT;
missingCharData: UFPressFontFormat.BoundingBox ← [xwidth: [0, 0], ywidth: [0, 0], BBox: 0, BBoy: 0, BBdx: 0, BBdy: LAST[CARDINAL]];
missingCharDirectoryMarker: UFPressFontFormat.bcplLONGCARDINAL ← [LAST[CARDINAL], LAST[CARDINAL]];
FOR c: CHAR IN [min..max] DO
IF internalFont.charRep[c] = internalFont.defaultChar THEN {
WriteBlock[@missingCharData, SIZE[UFPressFontFormat.BoundingBox]];
}
ELSE {
charRep: InternalCharRep ~ internalFont.charRep[c];
window: ImagerPixelMaps.DeviceRectangle ← charRep.pixels.Window;
xwidth: UFPressFontFormat.Fraction ~ Real.RoundLI[charRep.fWidth * 65536];
ywidth: UFPressFontFormat.Fraction ~ Real.RoundLI[-charRep.sWidth * 65536];
charData: UFPressFontFormat.BoundingBox ← [
xwidth: UFPressFontFormat.MesaToBcplFraction[xwidth],
ywidth: UFPressFontFormat.MesaToBcplFraction[ywidth],
BBox: window.fMin,
BBoy: -window.sSize-window.sMin,
BBdx: window.fSize,
BBdy: window.sSize
];
WriteBlock[@charData, SIZE[UFPressFontFormat.BoundingBox]];
};
ENDLOOP;
directoryStart ← CurWordOffset[];
filePos ← directoryStart + (max-min+1)*SIZE[UFPressFontFormat.bcplLONGCARDINAL];
FOR c: CHAR IN [min..max] DO
charRep: InternalCharRep ~ internalFont.charRep[c];
IF charRep = internalFont.defaultChar THEN {
WriteBlock[@missingCharDirectoryMarker, SIZE[UFPressFontFormat.bcplLONGCARDINAL]];
}
ELSE {
relFilePos: UFPressFontFormat.bcplLONGCARDINAL ← UFPressFontFormat.MesaToBcplLongCardinal[filePos-directoryStart];
bbdx: NAT ~ charRep.pixels.fSize;
bbdy: NAT ~ charRep.pixels.sSize;
bbdyW: NAT ~ (bbdy+Basics.bitsPerWord-1)/Basics.bitsPerWord;
WriteBlock[@relFilePos, SIZE[UFPressFontFormat.bcplLONGCARDINAL]];
filePos ← filePos + 1 + INT[bbdyW]*bbdx;
};
ENDLOOP;
IF CurWordOffset[] # directoryStart + (max-min+1)*SIZE[UFPressFontFormat.bcplLONGCARDINAL] THEN ERROR;
FOR c: CHAR IN [min..max] DO
charRep: InternalCharRep ~ internalFont.charRep[c];
IF charRep # internalFont.defaultChar THEN {
bbdx: NAT ~ charRep.pixels.fSize;
bbdy: NAT ~ charRep.pixels.sSize;
bbdyW: NAT ~ (bbdy+Basics.bitsPerWord-1)/Basics.bitsPerWord;
rasterDef: MACHINE DEPENDENT RECORD [bbdyW: [0..64), bbdy: [0..1024)] ← [bbdyW, bbdx];
WriteBlock[@rasterDef, 1];
pixelMap ← ImagerPixelMaps.Rotate[charRep.pixels, pixelMap.refRep];
IF pixelMap.refRep.lines # bbdx THEN ERROR;
IF pixelMap.refRep.rast # bbdyW THEN ERROR;
WriteBlock[pixelMap.refRep.pointer, INT[bbdyW]*bbdx];
};
ENDLOOP;
IF filePos # CurWordOffset[] THEN ERROR;
charsIndexEntry.startaddress ← LOOPHOLE[UFPressFontFormat.MesaToBcplLongCardinal[startaddress]];
charsIndexEntry.length ← UFPressFontFormat.MesaToBcplLongCardinal[CurWordOffset[] - startaddress];
file.SetIndex[charsIndexEntryByteLoc];
WriteBlock[@charsIndexEntry, charsIndexEntry.hdr.length];
};
file.Close;
};
Trim: PUBLIC PROC [internalFont: InternalFont] ~ {
oldDefault: InternalCharRep ← internalFont.defaultChar;
internalFont.defaultChar.pixels ← internalFont.defaultChar.pixels.Trim[0];
FOR c: CHAR IN CHAR DO
IF internalFont.charRep[c] = oldDefault THEN internalFont.charRep[c] ← internalFont.defaultChar
ELSE internalFont.charRep[c].pixels ← internalFont.charRep[c].pixels.Trim[0];
ENDLOOP;
};
END.