// C O N V E R T -- read SD, create CD (PREPRESS,PRESS) // catalog number ??? //ConvertAWidth(ps,pc,p) // Convert the widths of a single character. // ps -> SplineWidth. Fills up pc -> CharWidth. // p -> Convert structure. //ConvertAChar(w,wo,pc,p,FSGet,FSPut) // Converts a single character. p -> Convert structure, // which describes some parameters. // w is window to read splines from; wo window to put // scan-converted characters into. // pc -> CharWidth structure to return goodies. // Returns an error code: // 0 = All OK // 1= not enough core in SCV // 2,3 = SCV errors in splines // 10= Spline description file illegal // 11= Illegal Press font object // 12= Scan convert screwed up -- not even # intersections // 13= Bit intersection out of range // 14= Conversion did not terminate properly. // FSGet,FSPut are routines for getting, releasing storage. //SetSCVTransform(siz,rotation,incline,resolutionx,resolutiony) // Set up SCV transformation matrix. //Cos(theta,lvsign,lvmag) // Computes the cosine of the angle "theta" (in minutes) and // returns sign (0 if positive, -1 if negative) and magnitude // (0 to #177777) get "ix.dfs" get "scv.dfs" // outgoing procedures external [ ConvertAChar ConvertAWidth SetSCVTransform Cos ] // outgoing statics external [ convertThicken ] static [ convertThicken=false ] // incoming procedures external [ //In SCV package SCVInit SCVBeginObject SCVEndObject SCVMoveToF SCVDrawToF SCVDrawCurve SCVMatrix SCVReadRuns SCVTransformF SCVFlush Floor //Window package WindowSetPosition WindowGetPosition WindowReadBlock WindowWriteBlock WindowRead WindowWrite WindowCopy //Block move, store Zero; SetBlock; MoveBlock //Misc MulDiv //Floating point FLD;FST;FTR;FLDI;FNEG;FAD;FSB;FML;FDV;FCM;FSN FLDV;FSTV;FLDDP;FSTDP;DPAD;DPSB ] // incoming statics //external // [ // ] // internal statics //static // [ // ] // File-wide structure and manifest declarations. // Procedures let ConvertAWidth(s,c,p) = valof [ // s -> SplineWidth structure of char to compute widths. // c -> CharWidth structure to receive results. // p -> Convert structure that governs how things are done. // Returns true if spline will be needed. let spline=false let pw=lv s>>SplineWidth.WX test pw!0 eq 0 & pw!1 eq -1 then [ //Non existent char c>>CharWidth.H=HNonExCode ] or [ //Transform widths SCVTransformF(lv s>>SplineWidth.WX,lv s>>SplineWidth.WY) FSTDP(8,lv c>>CharWidth.WX) //and save for CD file FSTDP(9,lv c>>CharWidth.WY) //as double-precision //Calculate bounding box. //Warning: the calculation for the bounding box is really not good enough. // This is because the bounding box kept with the SD description is calculated // a little differently than will be the endpoints of the splines when passed // to SCV during conversion. As a result, small round-off errors will occur // (partly because SCVDrawCurve uses ->relative<- numbers!). This can change // 2E-9 into -2E-9, which will cause a different bounding box to be calculated. if p>>Convert.BBGood then [ //Transform bounding box SCVTransformF(lv s>>SplineWidth.XL,lv s>>SplineWidth.YB) FLD(1,8) //Save left edge let yb=Floor(9) //Y bottom SCVTransformF(lv s>>SplineWidth.XR,lv s>>SplineWidth.YT) let yh=Floor(9) //Now swap ybottom and yheight if inverted (will happen if character is rotated). if yb gr yh then [ let t=yb; yb=yh; yh=t ] yh=yh-yb+1 //And same for x, but (1) check for empty character, and (2) // in scan direction, things are assymetric, because of the kind of // scan conversion we are doing. let xl,xw=nil,nil let sg=FCM(1,8) switchon sg into [ case 0: xl=0; xw=0; yb=0; yh=0 //Character is empty endcase case 1: FLD(2,1);FLD(1,8);FLD(8,2) //Swap -- ac 1 < ac 8 case -1: xl=Floor(1)+1 //Assymetry xw=Floor(8)-xl+1 endcase ] c>>CharWidth.XL=xl c>>CharWidth.YB=yb c>>CharWidth.H=yh c>>CharWidth.W=xw if p>>Convert.SplineOk & SplineNeeded(c) then [ c>>CharWidth.H=HSplineCode spline=true ] ] ] resultis spline ] and ConvertAChar(w,wo,pc,p,FSGet,FSPut) = valof [ //Assume w positioned at spline, wo positioned to receive it. // pc -> CharWidth structure to receive results (bounding box only) // p -> Convert structure that governs how things are done. let originallen=32000 //Generous estimate! if p>>Convert.PressFontPart then originallen=p>>Convert.Len SCVInit(FSGet,FSPut) SCVBeginObject(not p>>Convert.Monotone,p>>Convert.Monotone) let opos=vec 3 //Remember old pos for spline WindowGetPosition(w,opos) WindowGetPosition(wo,opos+2) let stuff=vec 12 let len=originallen [ if len le 0 then break let op=WindowRead(w) switchon op into [ case DSplineFontMoveTo: //MoveTo WindowReadBlock(w,stuff,4) SCVMoveToF(stuff,stuff+2) len=len-5 endcase; case DSplineFontDrawTo: //DrawTo WindowReadBlock(w,stuff,4) SCVDrawToF(stuff,stuff+2) len=len-5 endcase; case DSplineFontDrawCurve: //DrawCurve WindowReadBlock(w,stuff,12) SCVDrawCurve(stuff,stuff+2,stuff+4,stuff+6, stuff+8,stuff+10) len=len-13 endcase; case DSplineFontEndObjects: //End break endcase default: resultis 10 //Illegal file format ] ] repeat let v=vec (size SCV/16) SCVEndObject(v) //Finish off if v>>SCV.Error then [ //Error -- return code SCVFlush(v) resultis v>>SCV.Error ] //Compute offsets (ox,oy), width (ns) and height (nb) let ns,nb=nil,nil let ox=v>>SCV.Smin test ox gr v>>SCV.Smax then [ ox=0;ns=0 ] or ns=v>>SCV.Smax-ox+1 let oy=v>>SCV.Rmin test oy gr v>>SCV.Rmax then [ oy=0;nb=0 ] or nb=v>>SCV.Rmax-oy+1 if p>>Convert.PressFontPart then [ if len ne 0 then [ SCVFlush(v) resultis 11 ] SCVTransformF(stuff,stuff+2) //Use last MOVETO FSTDP(8,lv pc>>CharWidth.WX) // to compute widths FSTDP(9,lv pc>>CharWidth.WY) ] //Salt away goodies in the structure pc>>CharWidth.XL=ox pc>>CharWidth.YB=oy pc>>CharWidth.W=ns pc>>CharWidth.H=nb let nbw=(nb+15) rshift 4 //Number of "words" high //Now decide if splines needed. test p>>Convert.SplineOk & SplineNeeded(pc) then [ //The character will occupy too much space if scan-converted and // saved in a character file as bits. So, we simply scale the // spline definition, and place it in the character file. In addition, // the CharWidth.H entry is changed to have a special code that // indicates this character is described by splines, and XL and YB // have in them the file position of the spline encoding. WindowSetPosition(w,opos) //Restart WindowGetPosition(wo,opos+2) pc>>CharWidth.H=HSplineCode pc>>CharWidth.XL=opos!2 //Save position pc>>CharWidth.YB=opos!3 len=originallen [ if len eq 0 then break //Copy splines to wo let op=WindowRead(w) stuff!0=op let l = selecton op into [ case DSplineFontMoveTo: case DSplineFontDrawTo: 4 case DSplineFontDrawCurve: 12 case DSplineFontNewObject: case DSplineFontEndObjects: 0 ] WindowReadBlock(w,stuff+1,l) for p=1 to l by 4 do //Splines must be scaled, rot'd [ SCVTransformF(stuff+p,stuff+p+2) FST(8,stuff+p) FST(9,stuff+p+2) ] WindowWriteBlock(wo,stuff,l+1) if l eq 0 then break //End ] repeat SCVFlush(v) //Release any storage ] or [ //Can convert OK //The character can be converted into a bit matrix, and stored in // the character definition file as such. let sl=nil sl<<FHEAD.hw=nbw sl<<FHEAD.ns=ns //Make up font header WindowWrite(wo,sl) if sl eq 0 then resultis 0 //(Only if space) let Masks= table [ #177777; #077777; #037777; #017777; #007777; #003777; #001777; #000777; #000377; #000177; #000077; #000037; #000017; #000007; #000003; #000001; #000000 ] let slbuf=vec 100 //For making up scan lines Zero(slbuf,100) //Prepare to call SCVReadRuns to obtain all runs until the character // exhausts. let buf=vec 1000 let sl=v>>SCV.Smin v>>SCV.Send=sl-1 [ v>>SCV.Sbegin=v>>SCV.Send+1 //Move right v>>SCV.Send=v>>SCV.Smax //Optimistic SCVReadRuns(v,buf,1000) let n=v>>SCV.IntCnt if n eq 0 then break //No more intersections let p=v>>SCV.IntPtr for i=1 to n by 2 do [ while sl ne p!0 do //Going to new scan line. [ WindowWriteBlock(wo,slbuf,nbw) Zero(slbuf,nbw) sl=sl+1 ] if p!2 ne sl then resultis 12 let yb=p!1-oy //Bottom y let yt=p!3-oy+(convertThicken? 1,0) //Top y+1 p=p+4 //Bump to next intersection // Turn on bits from yb to yt-1 (inclusive) if yb ls 0 % yt gr nb then resultis 13 if yt ge yb then //Only show non-zero runs [ let LeftMask=(Masks!(yb)) let RightMask= not (Masks!(yt)) yb=yb rshift 4 let wc=(yt rshift 4)-yb //Word count let w=slbuf+yb //Word address let bw=(@w & (not LeftMask))%(-1 & LeftMask) for i=0 to wc-1 do [ w!i=bw; bw=-1 ] w!wc=(w!wc & (not RightMask))%(bw & RightMask) ] ] ] repeat WindowWriteBlock(wo,slbuf,nbw) //Last line.... if sl ne v>>SCV.Smax then resultis 14 ] resultis 0 ] and //Set up the SCV transformation matrix from parameters that are // supplied for converting a font: // siz Size of the font in micas // rotation Rotation of the font in minutes // incline Incline of the font in percent // resx,resy Resolution of the output device // (if not supplied, FPAC's 3&4 assumed set up) SetSCVTransform(siz,rotation,incline,resx,resy; numargs n) be [ FLDI(5,25400) FLDI(1,siz); FLDI(2,siz) if n gr 3 then [ FLDI(3,resx); FLDI(4,resy) ] FML(1,3); FML(2,4) FDV(1,5); FDV(2,5) //x and y scales. test rotation ne 0 then [ //Get sine and cosine GetFloatingCos(rotation,3) GetFloatingCos(rotation-90*60,4) ] or [ FLDI(3,1); FLDI(4,0) ] FLD(5,3); FML(5,1) //m[1,1] FLD(6,4); FML(6,1) //m[1,2] FNEG(4) FLDI(7,incline);FLDI(0,100);FDV(7,0) FML(7,3);FAD(4,7);FML(4,2) //m[2,1] FML(3,2) //m[2,2] SCVMatrix(5,6,4,3) ] and //Return floating cosine in ac. Argument is minutes of arc. GetFloatingCos(min,ac) be [ let v=vec 4 v!1=0 //Exponent v!3=0 //Low mantissa let one=table [ 0;0;#177777;0 ] //Normalization constant Cos(min,v,v+2) // Now normalize the number if v!2 then while ((v!2)𘚠) eq 0 do [ v!2=v!2 lshift 1; v!1=v!1-1 ] FLDV(ac,v) FLDV(0,one) FDV(ac,0) ] and Cos(theta,lvsign,lvmag) be [ //Calculate the cosine of the given angle, and return the // magnitude as a fraction of #177777 (largest number) // Also return sign (0 if positive, -1 if negative) if theta ls 0 then theta=-theta @lvsign=-(((theta+90*60)/(180*60))&1) let d=theta rem 90*60 if ((theta/(90*60))&1) ne 0 then d=90*60-d let min=d rem 60 //Minutes part d=d/60 //Degrees part //Now d in range 0-90 degrees let retrievecos(d,min) =valof [ //0 le d le 45 let cosar=table [ #177777; #177765; #177727; #177645; #177537; #177405; #177227; #177026; #176601; #176330; #176033; #175512; #175146; #174557; #174144; #173505; #173024; #172317; #171567; #171014; #170216; #167376; #166532; #165645; #164735; #164002; #163026; #162030; #161007; #157746; #156662; #155556; #154430; #153262; #152072; #150663; #147432; #146162; #144672; #143362; #142032; #140463; #137075; #135471; #134045; #132405; #130743; //46 degrees because of interpolation ] let a=cosar!d //First answer if min ne 0 then //Must interpolate [ let b=cosar!(d+1) a=a-MulDiv(a-b,min,60) //Careful about signs ] resultis a ] test d gr 45 then [ //Use half-angle formulae if (d&1) ne 0 then min=min+60 //Divide angle by 2 let a=retrievecos(d rshift 1,min rshift 1) a=MulDiv(a,a,#177777) // cos↑2(theta/2) a=a-#100000 // cos↑2 -1/2 @lvmag=a lshift 1 //2 cos↑2 -1 ] or @lvmag=retrievecos(d,min) ] and //Return true if character described by pc>>CharWidth... // will be too big for a scan-converted form. SplineNeeded(pc) = valof [ let nbw=(pc>>CharWidth.H+15)/16 resultis (nbw gr 100) % (nbw*pc>>CharWidth.W gr 2000) ]