Skip to content

Instantly share code, notes, and snippets.

@avonwyss
Last active October 17, 2023 04:32
Show Gist options
  • Save avonwyss/570e394a83ed21a75fe0ff5ace989abf to your computer and use it in GitHub Desktop.
Save avonwyss/570e394a83ed21a75fe0ff5ace989abf to your computer and use it in GitHub Desktop.

UDOC.js

!!! Live Demo !!! UDOC.js is a robust document parser and converter with a very simple interface. It is used in Photopea to load and save PS, EPS, PDF, WMF and EMF files.

If you want to render a PDF file, use pdf.js. For all other PDF-related operations, use UDOC.js.

Parsing

FromXYZ.Parse(b, w)

  • b: ArrayBuffer - a binary data of a document
  • w: Writer object (e.g. an instance of ToPDF.js)

A Parser takes a binary file and parses it. During that process, it calls methods of the writer (like w.StartPage(...), w.Fill(...), w.Stroke(...), w.PutText(...), w.PutImage(...), w.ShowPage() ...). The data of the document flow from the Parser to the Writer by calling these methods.

Documents consist of pages. The parser calls w.StartPage(...) at the beginning of each page, and w.ShowPage() at the end of each page. Fill, Stroke, PutText and PutImage calls can occur in between. The parsing is finished by calling w.Done().

w.StartPage(x0,y0,x1,y1)

  • x0,y0,x1,y1 - the bounding box of the page

w.ShowPage(), w.Done()

w.Fill(gst, evenOdd)

  • gst - Graphic State
  • evenOdd - Boolean - filling rule (true: even-odd, false: non-zero)

w.Stroke(gst)

  • gst: Graphic State

w.PutText(gst, str, stw)

  • gst - Graphic State
  • str - a string to render
  • stw - string width (you can ignore it)

w.PutImage(gst, img, w, h, msk)

  • gst - Graphic State
  • img - Image
  • w, h - image size
  • msk - Image for the mask (can be null)

The Image is a Uint8Array with binary data. If its size is w * h * 4, it contains the raw RGBA image. Otherwise, it contains a compressed image (like JPEG, JBIG2, CCITT etc.). If the mask image is present, its color data should be used as the transparency for the main image.

Graphic State

The Graphic State is an object, containing the current graphic parameters (current path, current fill color, current stroke thickness). The Writer can read these parameters, but it shall not rewrite them.

ctm   : [1,0,0,1,0,0],// current transformation matrix
font  : Font,         // current text parameters
ca    : 1,            // fill transparency
colr  : [0,0,0],      // fill color
CA    : 1,            // stroke transparency
COLR  : [0,0,0],      // stroke color
bmode : "/Normal",    // blend mode
lwidth:  1,           // line width
lcap  :  0,           // line cap
ljoin :  0,           // line join
mlimit: 10,           // miter limit
doff: 0, dash: [],    // dashing offset and a pattern
pth : Path,           // current path (absolute coordinates)
cpth: Path            // current clipping path (absolute coordinates)

Font object

Tc   :   0,           // character spacing
Th   : 100,           // horizontal scale
Tl   :   0,           // leading
Tfs  :   1,           // font size
Tf   : "Helvetica-Bold",   // PostScriptName of the current font 
Tm   : [1,0,0,1,0,0]       // text transformation matrix

Path object

cmds : ["M", "L", "C", "Z"],         // drawing commands (moveTo, lineTo, curveTo, closePath)
crds : [0,0,  1,1,  2,2,3,0,2,1  ]   // coordinates for drawing commands (2 for M and L, 6 for C, 0 for Z)

By making a single Writer (into your internal format), you will let your software load PS, PDF, EMF, WMF and possibly other formats (for which Parsers exist). By making a single Parser (from your internal format), you will let your software export documents into PDF, EMF and other formats (for which Writers exist). Here is a simple writer, that counts pages and stores all strings.

var numPages = 0, strings = [], ef = function(){};
var W = {  // our writer
    StartPage:ef, Fill:ef, Stroke:ef, PutImage:ef, Done:ef,
    PutText : function(gst, str, stw) {  strings.push(str);  },
    ShowPage: function() {  numPages++;  }
};  
FromPDF.Parse(pdfFile, W);
console.log(numPages, strings);

UDOC.js file

UDOC.js contains various utilities, that can be used by Parsers or Writers. E.g. UDOC.getState() returns a default Graphic State. UDOC.M contains utilities for working with 2D matrices, and UDOC.G contains utilities for working with vector paths.

Generating documents

This repository contains the ToPDF and ToEMF Writers. You can use ToPDF with FromPS to convert PostScript to PDF (or even with FromPDF to convert PDF to PDF), but you can also use it to generate PDFs from your own format.

Here is an example of drawing a simple square and the result.

var gst = UDOC.getState();  // Graphics State with default parameters;
gst.colr= [0.8,0,0.8];      // purple fill color
gst.pth = {  cmds:["M","L","L","L","Z"], crds:[20,20,80,20,80,80,20,80]  };  // a square
var pdf = new ToPDF();  // or new ToEMF(); to make an EMF file
pdf.StartPage(0,0,100,100);  pdf.Fill(gst);  pdf.ShowPage();  pdf.Done();
console.log(pdf.buffer);  // ArrayBuffer of the PDF file

The Writer ToContext2D (ToContext2D.js) can be used as a simple renderer of PS, PDF, WMF or EMF files.

var pNum  = 0;  // number of the page, that you want to render
var scale = 1;  // the scale of the document
var wrt = new ToContext2D(pNum, scale);
FromPDF.Parse(myFile, wrt);
document.body.appendChild(wrt.canvas);

But you can use it as a guide for writing your own Writers.

FromPDF and ToPDF use pako.js for the Deflate compression.

function FromEMF ()
{
}
FromEMF.Parse = function(buff, genv)
{
buff = new Uint8Array(buff); var off=0;
//console.log(buff.slice(0,32));
var prms = {fill:false, strk:false, bb:[0,0,1,1], wbb:[0,0,1,1], fnt:{nam:"Arial",hgh:25,und:false,orn:0}, tclr:[0,0,0], talg:0}, gst, tab = [], sts=[];
var rI = FromEMF.B.readShort, rU = FromEMF.B.readUshort, rI32 = FromEMF.B.readInt, rU32 = FromEMF.B.readUint, rF32 = FromEMF.B.readFloat;
var opn=0;
while(true) {
var fnc = rU32(buff, off); off+=4;
var fnm = FromEMF.K[fnc];
var siz = rU32(buff, off); off+=4;
//if(gst && isNaN(gst.ctm[0])) throw "e";
//console.log(fnc,fnm,siz);
var loff = off;
//if(opn++==253) break;
var obj = null, oid = 0;
//console.log(fnm, siz);
if(false) {}
else if(fnm=="EOF") { break; }
else if(fnm=="HEADER") {
prms.bb = FromEMF._readBox(buff,loff); loff+=16; //console.log(fnm, prms.bb);
genv.StartPage(prms.bb[0],prms.bb[1],prms.bb[2],prms.bb[3]);
gst = UDOC.getState(prms.bb);
}
else if(fnm=="SAVEDC") sts.push(JSON.stringify(gst), JSON.stringify(prms));
else if(fnm=="RESTOREDC") {
var dif = rI32(buff, loff); loff+=4;
while(dif<-1) { sts.pop(); sts.pop(); }
prms = JSON.parse(sts.pop()); gst = JSON.parse(sts.pop());
}
else if(fnm=="SELECTCLIPPATH") { gst.cpth = JSON.parse(JSON.stringify(gst.pth)); }
else if(["SETMAPMODE","SETPOLYFILLMODE","SETBKMODE"/*,"SETVIEWPORTEXTEX"*/,"SETICMMODE","SETROP2","EXTSELECTCLIPRGN"].indexOf(fnm)!=-1) {}
//else if(fnm=="INTERSECTCLIPRECT") { var r=prms.crct=FromEMF._readBox(buff, loff); /*var y0=r[1],y1=r[3]; if(y0>y1){r[1]=y1; r[3]=y0;}*/ console.log(prms.crct); }
else if(fnm=="SETMITERLIMIT") gst.mlimit = rU32(buff, loff);
else if(fnm=="SETTEXTCOLOR") prms.tclr = [buff[loff]/255, buff[loff+1]/255, buff[loff+2]/255];
else if(fnm=="SETTEXTALIGN") prms.talg = rU32(buff, loff);
else if(fnm=="SETVIEWPORTEXTEX" || fnm=="SETVIEWPORTORGEX") {
if(prms.vbb==null) prms.vbb=[];
var coff = fnm=="SETVIEWPORTORGEX" ? 0 : 2;
prms.vbb[coff ] = rI32(buff, loff); loff+=4;
prms.vbb[coff+1] = rI32(buff, loff); loff+=4;
//console.log(prms.vbb);
if(fnm=="SETVIEWPORTEXTEX") FromEMF._updateCtm(prms, gst);
}
else if(fnm=="SETWINDOWEXTEX" || fnm=="SETWINDOWORGEX") {
var coff = fnm=="SETWINDOWORGEX" ? 0 : 2;
prms.wbb[coff ] = rI32(buff, loff); loff+=4;
prms.wbb[coff+1] = rI32(buff, loff); loff+=4;
if(fnm=="SETWINDOWEXTEX") FromEMF._updateCtm(prms, gst);
}
//else if(fnm=="SETMETARGN") {}
else if(fnm=="COMMENT") { var ds = rU32(buff, loff); loff+=4; }
else if(fnm=="SELECTOBJECT") {
var ind = rU32(buff, loff); loff+=4;
//console.log(ind.toString(16), tab, tab[ind]);
if (ind==0x80000000) { prms.fill=true ; gst.colr=[1,1,1]; } // white brush
else if(ind==0x80000005) { prms.fill=false; } // null brush
else if(ind==0x80000007) { prms.strk=true ; prms.lwidth=1; gst.COLR=[0,0,0]; } // black pen
else if(ind==0x80000008) { prms.strk=false; } // null pen
else if(ind==0x8000000d) {} // system font
else if(ind==0x8000000e) {} // device default font
else {
var co = tab[ind]; //console.log(ind, co);
if(co.t=="b") {
prms.fill=co.stl!=1;
if (co.stl==0) {}
else if(co.stl==1) {}
else throw co.stl+" e";
gst.colr=co.clr;
}
else if(co.t=="p") {
prms.strk=co.stl!=5;
gst.lwidth = co.wid;
gst.COLR=co.clr;
}
else if(co.t=="f") {
prms.fnt = co;
gst.font.Tf = co.nam;
gst.font.Tfs = Math.abs(co.hgh);
gst.font.Tun = co.und;
}
else throw "e";
}
}
else if(fnm=="DELETEOBJECT") {
var ind = rU32(buff, loff); loff+=4;
if(tab[ind]!=null) tab[ind]=null;
else throw "e";
}
else if(fnm=="CREATEBRUSHINDIRECT") {
oid = rU32(buff, loff); loff+=4;
obj = {t:"b"};
obj.stl = rU32(buff, loff); loff+=4;
obj.clr = [buff[loff]/255, buff[loff+1]/255, buff[loff+2]/255]; loff+=4;
obj.htc = rU32(buff, loff); loff+=4;
//console.log(oid, obj);
}
else if(fnm=="CREATEPEN" || fnm=="EXTCREATEPEN") {
oid = rU32(buff, loff); loff+=4;
obj = {t:"p"};
if(fnm=="EXTCREATEPEN") {
loff+=16;
obj.stl = rU32(buff, loff); loff+=4;
obj.wid = rU32(buff, loff); loff+=4;
//obj.stl = rU32(buff, loff);
loff+=4;
} else {
obj.stl = rU32(buff, loff); loff+=4;
obj.wid = rU32(buff, loff); loff+=4; loff+=4;
}
obj.clr = [buff[loff]/255, buff[loff+1]/255, buff[loff+2]/255]; loff+=4;
}
else if(fnm=="EXTCREATEFONTINDIRECTW") {
oid = rU32(buff, loff); loff+=4;
obj = {t:"f", nam:""};
obj.hgh = rI32(buff, loff); loff += 4;
loff += 4*2;
obj.orn = rI32(buff, loff)/10; loff+=4;
var wgh = rU32(buff, loff); loff+=4; //console.log(fnm, obj.orn, wgh);
//console.log(rU32(buff,loff), rU32(buff,loff+4), buff.slice(loff,loff+8));
obj.und = buff[loff+1]; obj.stk = buff[loff+2]; loff += 4*2;
while(rU(buff,loff)!=0) { obj.nam+=String.fromCharCode(rU(buff,loff)); loff+=2; }
if(wgh>500) obj.nam+="-Bold";
//console.log(wgh, obj.nam);
}
else if(fnm=="EXTTEXTOUTW") {
//console.log(buff.slice(loff-8, loff-8+siz));
loff+=16;
var mod = rU32(buff, loff); loff+=4; //console.log(mod);
var scx = rF32(buff, loff); loff+=4;
var scy = rF32(buff, loff); loff+=4;
var rfx = rI32(buff, loff); loff+=4;
var rfy = rI32(buff, loff); loff+=4;
//console.log(mod, scx, scy,rfx,rfy);
gst.font.Tm = [1,0,0,-1,0,0];
UDOC.M.rotate(gst.font.Tm, prms.fnt.orn*Math.PI/180);
UDOC.M.translate(gst.font.Tm, rfx, rfy);
var alg = prms.talg; //console.log(alg.toString(2));
if ((alg&6)==6) gst.font.Tal = 2;
else if((alg&7)==0) gst.font.Tal = 0;
else throw alg+" e";
if((alg&24)==24) {} // baseline
else if((alg&24)==0) UDOC.M.translate(gst.font.Tm, 0, gst.font.Tfs);
else throw "e";
var crs = rU32(buff, loff); loff+=4;
var ofs = rU32(buff, loff); loff+=4;
var ops = rU32(buff, loff); loff+=4; //if(ops!=0) throw "e";
//console.log(ofs,ops,crs);
loff+=16;
var ofD = rU32(buff, loff); loff+=4; //console.log(ops, ofD, loff, ofs+off-8);
ofs += off-8; //console.log(crs, ops);
var str = "";
for(var i=0; i<crs; i++) { var cc=rU(buff,ofs+i*2); str+=String.fromCharCode(cc); };
var oclr = gst.colr; gst.colr = prms.tclr;
//console.log(str, gst.colr, gst.font.Tm);
//var otfs = gst.font.Tfs; gst.font.Tfs *= 1/gst.ctm[0];
genv.PutText(gst, str, str.length*gst.font.Tfs*0.5); gst.colr=oclr;
//gst.font.Tfs = otfs;
//console.log(rfx, rfy, scx, ops, rcX, rcY, rcW, rcH, offDx, str);
}
else if(fnm=="BEGINPATH") { UDOC.G.newPath(gst); }
else if(fnm=="ENDPATH" ) { }
else if(fnm=="CLOSEFIGURE") UDOC.G.closePath(gst);
else if(fnm=="MOVETOEX" ) { UDOC.G.moveTo(gst, rI32(buff,loff), rI32(buff,loff+4)); }
else if(fnm=="LINETO" ) {
if(gst.pth.cmds.length==0) { var im=gst.ctm.slice(0); UDOC.M.invert(im); var p = UDOC.M.multPoint(im, gst.cpos); UDOC.G.moveTo(gst, p[0], p[1]); }
UDOC.G.lineTo(gst, rI32(buff,loff), rI32(buff,loff+4)); }
else if(fnm=="POLYGON" || fnm=="POLYGON16" || fnm=="POLYLINE" || fnm=="POLYLINE16" || fnm=="POLYLINETO" || fnm=="POLYLINETO16") {
loff+=16;
var ndf = fnm.startsWith("POLYGON"), isTo = fnm.indexOf("TO")!=-1;
var cnt = rU32(buff, loff); loff+=4;
if(!isTo) UDOC.G.newPath(gst);
loff = FromEMF._drawPoly(buff,loff,cnt,gst, fnm.endsWith("16")?2:4, ndf, isTo);
if(!isTo) FromEMF._draw(genv,gst,prms, ndf);
//console.log(prms, gst.lwidth);
//console.log(JSON.parse(JSON.stringify(gst.pth)));
}
else if(fnm=="POLYPOLYGON16") {
loff+=16;
var ndf = fnm.startsWith("POLYPOLYGON"), isTo = fnm.indexOf("TO")!=-1;
var nop = rU32(buff, loff); loff+=4; loff+=4;
var pi = loff; loff+= nop*4;
if(!isTo) UDOC.G.newPath(gst);
for(var i=0; i<nop; i++) {
var ppp = rU(buff, pi+i*4);
loff = FromEMF._drawPoly(buff,loff,ppp,gst, fnm.endsWith("16")?2:4, ndf, isTo);
}
if(!isTo) FromEMF._draw(genv,gst,prms, ndf);
}
else if(fnm=="POLYBEZIER" || fnm=="POLYBEZIER16" || fnm=="POLYBEZIERTO" || fnm=="POLYBEZIERTO16") {
loff+=16;
var is16 = fnm.endsWith("16"), rC = is16?rI:rI32, nl = is16?2:4;
var cnt = rU32(buff, loff); loff+=4;
if(fnm.indexOf("TO")==-1) {
UDOC.G.moveTo(gst, rC(buff,loff), rC(buff,loff+nl)); loff+=2*nl; cnt--;
}
while(cnt>0) {
UDOC.G.curveTo(gst, rC(buff,loff), rC(buff,loff+nl), rC(buff,loff+2*nl), rC(buff,loff+3*nl), rC(buff,loff+4*nl), rC(buff,loff+5*nl) );
loff+=6*nl;
cnt-=3;
}
//console.log(JSON.parse(JSON.stringify(gst.pth)));
}
else if(fnm=="RECTANGLE" || fnm=="ELLIPSE") {
UDOC.G.newPath(gst);
var bx = FromEMF._readBox(buff, loff);
if(fnm=="RECTANGLE") {
UDOC.G.moveTo(gst, bx[0],bx[1]);
UDOC.G.lineTo(gst, bx[2],bx[1]);
UDOC.G.lineTo(gst, bx[2],bx[3]);
UDOC.G.lineTo(gst, bx[0],bx[3]);
}
else {
var x = (bx[0]+bx[2])/2, y = (bx[1]+bx[3])/2;
UDOC.G.arc(gst,x,y,(bx[2]-bx[0])/2,0,2*Math.PI, false);
}
UDOC.G.closePath(gst);
FromEMF._draw(genv,gst,prms, true);
//console.log(prms, gst.lwidth);
}
else if(fnm=="FILLPATH" ) genv.Fill(gst, false);
else if(fnm=="STROKEPATH") genv.Stroke(gst);
else if(fnm=="STROKEANDFILLPATH") { genv.Fill(gst, false); genv.Stroke(gst); }
else if(fnm=="SETWORLDTRANSFORM" || fnm=="MODIFYWORLDTRANSFORM") {
var mat = [];
for(var i=0; i<6; i++) mat.push(rF32(buff,loff+i*4)); loff+=24;
//console.log(fnm, gst.ctm.slice(0), mat);
if(fnm=="SETWORLDTRANSFORM") gst.ctm=mat;
else {
var mod = rU32(buff,loff); loff+=4;
if(mod==2) { var om=gst.ctm; gst.ctm=mat; UDOC.M.concat(gst.ctm, om); }
else throw "e";
}
}
else if(fnm=="SETSTRETCHBLTMODE") { var sm = rU32(buff, loff); loff+=4; }
else if(fnm=="STRETCHDIBITS") {
var bx = FromEMF._readBox(buff, loff); loff+=16;
var xD = rI32(buff, loff); loff+=4;
var yD = rI32(buff, loff); loff+=4;
var xS = rI32(buff, loff); loff+=4;
var yS = rI32(buff, loff); loff+=4;
var wS = rI32(buff, loff); loff+=4;
var hS = rI32(buff, loff); loff+=4;
var ofH = rU32(buff, loff)+off-8; loff+=4;
var szH = rU32(buff, loff); loff+=4;
var ofB = rU32(buff, loff)+off-8; loff+=4;
var szB = rU32(buff, loff); loff+=4;
var usg = rU32(buff, loff); loff+=4; if(usg!=0) throw "e";
var bop = rU32(buff, loff); loff+=4;
var wD = rI32(buff, loff); loff+=4;
var hD = rI32(buff, loff); loff+=4; //console.log(bop, wD, hD);
//console.log(ofH, szH, ofB, szB, ofH+40);
//console.log(bx, xD,yD,wD,hD);
//console.log(xS,yS,wS,hS);
//console.log(ofH,szH,ofB,szB,usg,bop);
var hl = rU32(buff, ofH); ofH+=4;
var w = rU32(buff, ofH); ofH+=4;
var h = rU32(buff, ofH); ofH+=4; if(w!=wS || h!=hS) throw "e";
var ps = rU (buff, ofH); ofH+=2;
var bc = rU (buff, ofH); ofH+=2; if(bc!=8 && bc!=24 && bc!=32) throw bc+" e";
var cpr= rU32(buff, ofH); ofH+=4; if(cpr!=0) throw cpr+" e";
var sz = rU32(buff, ofH); ofH+=4;
var xpm= rU32(buff, ofH); ofH+=4;
var ypm= rU32(buff, ofH); ofH+=4;
var cu = rU32(buff, ofH); ofH+=4;
var ci = rU32(buff, ofH); ofH+=4; //console.log(hl, w, h, ps, bc, cpr, sz, xpm, ypm, cu, ci);
//console.log(hl,w,h,",",xS,yS,wS,hS,",",xD,yD,wD,hD,",",xpm,ypm);
var rl = Math.floor(((w * ps * bc + 31) & ~31) / 8);
var img = new Uint8Array(w*h*4);
if(bc==8) {
for(var y=0; y<h; y++)
for(var x=0; x<w; x++) {
var qi = (y*w+x)<<2, ind = buff[ofB+(h-1-y)*rl+x]<<2;
img[qi ] = buff[ofH+ind+2];
img[qi+1] = buff[ofH+ind+1];
img[qi+2] = buff[ofH+ind+0];
img[qi+3] = 255;
}
}
if(bc==24) {
for(var y=0; y<h; y++)
for(var x=0; x<w; x++) {
var qi = (y*w+x)<<2, ti=ofB+(h-1-y)*rl+x*3;
img[qi ] = buff[ti+2];
img[qi+1] = buff[ti+1];
img[qi+2] = buff[ti+0];
img[qi+3] = 255;
}
}
if(bc==32) {
for(var y=0; y<h; y++)
for(var x=0; x<w; x++) {
var qi = (y*w+x)<<2, ti=ofB+(h-1-y)*rl+x*4;
img[qi ] = buff[ti+2];
img[qi+1] = buff[ti+1];
img[qi+2] = buff[ti+0];
img[qi+3] = buff[ti+3];
}
}
var ctm = gst.ctm.slice(0);
gst.ctm = [1,0,0,1,0,0];
UDOC.M.scale(gst.ctm, wD, -hD);
UDOC.M.translate(gst.ctm, xD, yD+hD);
UDOC.M.concat(gst.ctm, ctm);
genv.PutImage(gst, img, w, h);
gst.ctm = ctm;
}
else {
console.log(fnm, siz);
}
if(obj!=null) tab[oid]=obj;
off+=siz-8;
}
//genv.Stroke(gst);
genv.ShowPage(); genv.Done();
}
FromEMF._readBox = function(buff, off) { var b=[]; for(var i=0; i<4; i++) b[i] = FromEMF.B.readInt(buff,off+i*4); return b; }
FromEMF._updateCtm = function(prms, gst) {
var mat = [1,0,0,1,0,0];
var wbb = prms.wbb, bb = prms.bb, vbb=(prms.vbb && prms.vbb.length==4) ? prms.vbb:prms.bb;
//var y0 = bb[1], y1 = bb[3]; bb[1]=Math.min(y0,y1); bb[3]=Math.max(y0,y1);
UDOC.M.translate(mat, -wbb[0],-wbb[1]);
UDOC.M.scale(mat, 1/wbb[2], 1/wbb[3]);
UDOC.M.scale(mat, vbb[2], vbb[3]);
//UDOC.M.scale(mat, vbb[2]/(bb[2]-bb[0]), vbb[3]/(bb[3]-bb[1]));
//UDOC.M.scale(mat, bb[2]-bb[0],bb[3]-bb[1]);
gst.ctm = mat;
}
FromEMF._draw = function(genv, gst, prms, needFill) {
if(prms.fill && needFill ) genv.Fill (gst, false);
if(prms.strk && gst.lwidth!=0) genv.Stroke(gst);
}
FromEMF._drawPoly = function(buff, off, ppp, gst, nl, clos, justLine) {
var rS = nl==2 ? FromEMF.B.readShort : FromEMF.B.readInt;
for(var j=0; j<ppp; j++) {
var px = rS(buff, off); off+=nl;
var py = rS(buff, off); off+=nl;
if(j==0 && !justLine) UDOC.G.moveTo(gst,px,py); else UDOC.G.lineTo(gst,px,py);
}
if(clos) UDOC.G.closePath(gst);
return off;
}
FromEMF.B = {
uint8 : new Uint8Array(4),
readShort : function(buff,p) { var u8=FromEMF.B.uint8; u8[0]=buff[p]; u8[1]=buff[p+1]; return FromEMF.B.int16 [0]; },
readUshort : function(buff,p) { var u8=FromEMF.B.uint8; u8[0]=buff[p]; u8[1]=buff[p+1]; return FromEMF.B.uint16[0]; },
readInt : function(buff,p) { var u8=FromEMF.B.uint8; u8[0]=buff[p]; u8[1]=buff[p+1]; u8[2]=buff[p+2]; u8[3]=buff[p+3]; return FromEMF.B.int32 [0]; },
readUint : function(buff,p) { var u8=FromEMF.B.uint8; u8[0]=buff[p]; u8[1]=buff[p+1]; u8[2]=buff[p+2]; u8[3]=buff[p+3]; return FromEMF.B.uint32[0]; },
readFloat : function(buff,p) { var u8=FromEMF.B.uint8; u8[0]=buff[p]; u8[1]=buff[p+1]; u8[2]=buff[p+2]; u8[3]=buff[p+3]; return FromEMF.B.flot32[0]; },
readASCII : function(buff,p,l){ var s = ""; for(var i=0; i<l; i++) s += String.fromCharCode(buff[p+i]); return s; }
}
FromEMF.B.int16 = new Int16Array (FromEMF.B.uint8.buffer);
FromEMF.B.uint16 = new Uint16Array(FromEMF.B.uint8.buffer);
FromEMF.B.int32 = new Int32Array (FromEMF.B.uint8.buffer);
FromEMF.B.uint32 = new Uint32Array(FromEMF.B.uint8.buffer);
FromEMF.B.flot32 = new Float32Array(FromEMF.B.uint8.buffer);
FromEMF.C = {
EMR_HEADER : 0x00000001,
EMR_POLYBEZIER : 0x00000002,
EMR_POLYGON : 0x00000003,
EMR_POLYLINE : 0x00000004,
EMR_POLYBEZIERTO : 0x00000005,
EMR_POLYLINETO : 0x00000006,
EMR_POLYPOLYLINE : 0x00000007,
EMR_POLYPOLYGON : 0x00000008,
EMR_SETWINDOWEXTEX : 0x00000009,
EMR_SETWINDOWORGEX : 0x0000000A,
EMR_SETVIEWPORTEXTEX : 0x0000000B,
EMR_SETVIEWPORTORGEX : 0x0000000C,
EMR_SETBRUSHORGEX : 0x0000000D,
EMR_EOF : 0x0000000E,
EMR_SETPIXELV : 0x0000000F,
EMR_SETMAPPERFLAGS : 0x00000010,
EMR_SETMAPMODE : 0x00000011,
EMR_SETBKMODE : 0x00000012,
EMR_SETPOLYFILLMODE : 0x00000013,
EMR_SETROP2 : 0x00000014,
EMR_SETSTRETCHBLTMODE : 0x00000015,
EMR_SETTEXTALIGN : 0x00000016,
EMR_SETCOLORADJUSTMENT : 0x00000017,
EMR_SETTEXTCOLOR : 0x00000018,
EMR_SETBKCOLOR : 0x00000019,
EMR_OFFSETCLIPRGN : 0x0000001A,
EMR_MOVETOEX : 0x0000001B,
EMR_SETMETARGN : 0x0000001C,
EMR_EXCLUDECLIPRECT : 0x0000001D,
EMR_INTERSECTCLIPRECT : 0x0000001E,
EMR_SCALEVIEWPORTEXTEX : 0x0000001F,
EMR_SCALEWINDOWEXTEX : 0x00000020,
EMR_SAVEDC : 0x00000021,
EMR_RESTOREDC : 0x00000022,
EMR_SETWORLDTRANSFORM : 0x00000023,
EMR_MODIFYWORLDTRANSFORM : 0x00000024,
EMR_SELECTOBJECT : 0x00000025,
EMR_CREATEPEN : 0x00000026,
EMR_CREATEBRUSHINDIRECT : 0x00000027,
EMR_DELETEOBJECT : 0x00000028,
EMR_ANGLEARC : 0x00000029,
EMR_ELLIPSE : 0x0000002A,
EMR_RECTANGLE : 0x0000002B,
EMR_ROUNDRECT : 0x0000002C,
EMR_ARC : 0x0000002D,
EMR_CHORD : 0x0000002E,
EMR_PIE : 0x0000002F,
EMR_SELECTPALETTE : 0x00000030,
EMR_CREATEPALETTE : 0x00000031,
EMR_SETPALETTEENTRIES : 0x00000032,
EMR_RESIZEPALETTE : 0x00000033,
EMR_REALIZEPALETTE : 0x00000034,
EMR_EXTFLOODFILL : 0x00000035,
EMR_LINETO : 0x00000036,
EMR_ARCTO : 0x00000037,
EMR_POLYDRAW : 0x00000038,
EMR_SETARCDIRECTION : 0x00000039,
EMR_SETMITERLIMIT : 0x0000003A,
EMR_BEGINPATH : 0x0000003B,
EMR_ENDPATH : 0x0000003C,
EMR_CLOSEFIGURE : 0x0000003D,
EMR_FILLPATH : 0x0000003E,
EMR_STROKEANDFILLPATH : 0x0000003F,
EMR_STROKEPATH : 0x00000040,
EMR_FLATTENPATH : 0x00000041,
EMR_WIDENPATH : 0x00000042,
EMR_SELECTCLIPPATH : 0x00000043,
EMR_ABORTPATH : 0x00000044,
EMR_COMMENT : 0x00000046,
EMR_FILLRGN : 0x00000047,
EMR_FRAMERGN : 0x00000048,
EMR_INVERTRGN : 0x00000049,
EMR_PAINTRGN : 0x0000004A,
EMR_EXTSELECTCLIPRGN : 0x0000004B,
EMR_BITBLT : 0x0000004C,
EMR_STRETCHBLT : 0x0000004D,
EMR_MASKBLT : 0x0000004E,
EMR_PLGBLT : 0x0000004F,
EMR_SETDIBITSTODEVICE : 0x00000050,
EMR_STRETCHDIBITS : 0x00000051,
EMR_EXTCREATEFONTINDIRECTW : 0x00000052,
EMR_EXTTEXTOUTA : 0x00000053,
EMR_EXTTEXTOUTW : 0x00000054,
EMR_POLYBEZIER16 : 0x00000055,
EMR_POLYGON16 : 0x00000056,
EMR_POLYLINE16 : 0x00000057,
EMR_POLYBEZIERTO16 : 0x00000058,
EMR_POLYLINETO16 : 0x00000059,
EMR_POLYPOLYLINE16 : 0x0000005A,
EMR_POLYPOLYGON16 : 0x0000005B,
EMR_POLYDRAW16 : 0x0000005C,
EMR_CREATEMONOBRUSH : 0x0000005D,
EMR_CREATEDIBPATTERNBRUSHPT : 0x0000005E,
EMR_EXTCREATEPEN : 0x0000005F,
EMR_POLYTEXTOUTA : 0x00000060,
EMR_POLYTEXTOUTW : 0x00000061,
EMR_SETICMMODE : 0x00000062,
EMR_CREATECOLORSPACE : 0x00000063,
EMR_SETCOLORSPACE : 0x00000064,
EMR_DELETECOLORSPACE : 0x00000065,
EMR_GLSRECORD : 0x00000066,
EMR_GLSBOUNDEDRECORD : 0x00000067,
EMR_PIXELFORMAT : 0x00000068,
EMR_DRAWESCAPE : 0x00000069,
EMR_EXTESCAPE : 0x0000006A,
EMR_SMALLTEXTOUT : 0x0000006C,
EMR_FORCEUFIMAPPING : 0x0000006D,
EMR_NAMEDESCAPE : 0x0000006E,
EMR_COLORCORRECTPALETTE : 0x0000006F,
EMR_SETICMPROFILEA : 0x00000070,
EMR_SETICMPROFILEW : 0x00000071,
EMR_ALPHABLEND : 0x00000072,
EMR_SETLAYOUT : 0x00000073,
EMR_TRANSPARENTBLT : 0x00000074,
EMR_GRADIENTFILL : 0x00000076,
EMR_SETLINKEDUFIS : 0x00000077,
EMR_SETTEXTJUSTIFICATION : 0x00000078,
EMR_COLORMATCHTOTARGETW : 0x00000079,
EMR_CREATECOLORSPACEW : 0x0000007A
};
FromEMF.K = [];
(function() {
var inp, out, stt;
inp = FromEMF.C; out = FromEMF.K; stt=4;
for(var p in inp) out[inp[p]] = p.slice(stt);
} )();
function FromPDF ()
{
}
FromPDF.Parse = function(buff, genv)
{
buff = new Uint8Array(buff);
var off = 0;
while(buff[off]==32) off++;
if(off!=0) buff = new Uint8Array(buff.buffer, off, buff.length-off);
var offset = buff.length-3;
while(FromPS.B.readASCII(buff,offset,3) != "%%E") offset--;
var eoff = offset;
offset--;
while( FromPS.isEOL(buff[offset])) offset--;
while(!FromPS.isEOL(buff[offset])) offset--;
var xref = parseInt(FromPS.B.readASCII(buff, offset+1, eoff-offset-1));
if(isNaN(xref)) throw "no xref";
var xr = [];
var tr = FromPDF.readXrefTrail(buff, xref, xr);
//console.log(xr);
var file = {buff:buff, off:0}, rt = tr["/Root"];
if(rt.typ=="ref") tr["/Root"] = FromPDF.getIndirect(rt.ind,rt.gen,file,xr)
var ps = tr["/Root"]["/Pages"];
if(ps.typ=="ref") tr["/Root"]["/Pages"] = FromPDF.getIndirect(ps.ind,ps.gen,file,xr)
var stk = [tr["/Root"]["/Pages"]];
while(stk.length!=0) {
var pg = stk.pop();
if(pg["/Type"]=="/Pages") {
var ks = pg["/Kids"];
for(var i=0; i<ks.length; i++) {
if(ks[i].typ=="ref") ks[i] = FromPDF.getIndirect(ks[i].ind,ks[i].gen,file,xr)
stk.push(ks[i]);
}
}
}
var time = Date.now();
FromPDF.render(tr["/Root"], genv, tr);
genv.Done();
//console.log(Date.now()-time);
}
FromPDF.render = function(root, genv, tr)
{
var ops = [
"CS","cs","SCN","scn","SC","sc","sh",
"Do", "gs", "ID","EI", "re","cm","y","v","B","B*", "BT","ET",
"Tj","TJ","Tf","Tm","Td","T*",
"Tc","Tw","Tz","TL","Tr","Ts",
"MP","DP","BMC","BDC","EMC","BX","EX", "ri"
];
var prcs = {
"J":"setlinecap",
"j":"setlinejoin",
"w":"setlinewidth",
"d":"setdash",
"M":"setmiterlimit",
"i":"setflat",
"q":"gsave", "Q":"grestore",
"m":"moveto", "l":"lineto", "c":"curveto", "h":"closepath",
"W":"clip", "W*":"eoclip",
"f":"fill","F":"fill","f*":"eofill", "S":"stroke", "b":"h B", "b*":"h B*",
"n":"newpath",
"RG" : "/DeviceRGB CS SCN",
"rg" : "/DeviceRGB cs scn",
"G" : "/DeviceGray CS SCN",
"g" : "/DeviceGray cs scn",
"K" : "/DeviceCMYK CS SCN",
"k" : "/DeviceCMYK cs scn",
"TD" : "dup neg TL Td",
"\"" : "exch Tc exch Tw '",
"'" : "T* Tj",
"s" : "h S",
"BI" : "/BI"
}
prcs = FromPS.makeProcs(prcs);
var stk = [root["/Pages"]], pi=0;
while(stk.length!=0) {
var pg = stk.pop();
if(pg["/Type"]=="/Pages") {
var ks = pg["/Kids"];
for(var i=ks.length-1; i>=0; i--) stk.push(ks[i]);
continue;
}
pi++; //if(pi!=1) continue;
var cts = pg["/Contents"]; //console.log(pg);
if(cts.length==null) cts = [cts];
//var uu = pg["/UserUnit"]; if(uu) console.log(uu);
var bb = pg["/MediaBox"]; if(bb==null) bb = root["/Pages"]["/MediaBox"];
var env = FromPS._getEnv(bb); env.pgOpen = true;
var gs = [];
var os = []; // operand stack
var ds = FromPS._getDictStack(ops, prcs);
var es = [];
genv.StartPage(bb[0],bb[1],bb[2],bb[3]);
if(tr["/Encrypt"]) { if(stk.length==0) alert("Encrypted PDF is not supported yet."); }
else
for(var j=0; j<cts.length; j++)
{
var cnt = FromPDF.GS(cts[j]); var end=cnt.length-1; while(cnt[end]==0) end--;
cnt = new Uint8Array(cnt.buffer, 0, end+1);
//console.log(FromPS.B.readASCII(cnt,0,cnt.length));
es.push({ typ:"file", val: { buff:cnt, off:0, extra:pg } }); // execution stack
var repeat = true;
while(repeat) { repeat = FromPS.step(os, ds, es, gs, env, genv, FromPDF.operator); }
}
genv.ShowPage(); //if(pi>23) break;
}
}
FromPDF.operator = function(op, os, ds, es, gs, env, genv)
{
var gst = env.gst;
var lfi = es.length-1; while(es[lfi].typ!="file") lfi--;
var fle = es[lfi].val;
var res = fle.extra["/Resources"];
if(op=="Do") {
var nam = os.pop().val, xo = res["/XObject"][nam];
//console.log(xo);
var st=xo["/Subtype"], stm = FromPDF.GS(xo);
if(st=="/Form") {
//console.log(FromPS.B.readASCII(stm,0,stm.length));
es.push( {typ:"file", val: { buff:stm, off:0, extra:xo }} );
}
else if(st=="/Image") {
var sms = null; //console.log(xo);
if(xo["/SMask"]) sms = FromPDF.getImage(xo["/SMask"], gst);
var w=xo["/Width"], h=xo["/Height"], cs=xo["/ColorSpace"];
var img = FromPDF.getImage(xo, gst);
if(xo["/ImageMask"]==true) {
sms = img;
img = new Uint8Array(w*h*4);
var r0 = gst.colr[0]*255, g0 = gst.colr[1]*255, b0 = gst.colr[2]*255;
for(var i=0; i<w*h*4; i+=4) { img[i]=r0; img[i+1]=g0; img[i+2]=b0; img[i+3]=255; }
}
genv.PutImage(gst, img, w,h, sms);
}
else console.log("Unknown XObject",st);
}
else if(op=="gs") {
var nm = os.pop().val;
var egs = res["/ExtGState"][nm];
for(var p in egs) {
var v = egs[p];
if(p=="/Type") continue;
else if(p=="/CA") gst.CA=v;
else if(p=="/ca") gst.ca=v;
else if(p=="/BM") gst.bmode = v;
else if(p=="/LC") gst.lcap = v;
else if(p=="/LJ") gst.ljoin = v;
else if(p=="/LW") gst.lwidth = v;
else if(p=="/ML") gst.mlimit = v;
else if(p=="/SA") gst.SA = v;
else if(p=="/OPM")gst.OPM = v;
else if(p=="/AIS")gst.AIS = v;
else if(p=="/OP") gst.OP = v;
else if(p=="/op") gst.op = v;
else if(p=="/SMask") { gst.SMask = ""; }
else if(p=="/SM") gst.SM = v;
else if(p=="/HT" || p=="/TR") {}
else console.log("Unknown gstate property: ", p, v);
}
}
else if(op=="ID") {
var dic = {};
while(true) { var v = os.pop().val; if(v=="/BI") break; dic[os.pop().val] = v; } fle.off++;
var w=dic["/W"], h=dic["/H"], ar=w*h, img = new Uint8Array(ar*4), cs = dic["/CS"], bpc = dic["/BPC"];
var end = fle.off;
while(!FromPS.isWhite(fle.buff[end]) || fle.buff[end+1]!=69 || fle.buff[end+2]!=73) end++;
var stm = fle.buff.slice(fle.off, end); fle.off+=stm.length;
if(dic["/F"]=="/Fl") { stm = FromPS.F.FlateDecode({buff:stm, off:0}); delete dic["/F"]; }
if(cs=="/G" && dic["/F"]==null) {
FromPDF.plteImage(stm, 0, img, null, w, h, bpc);
}
else if(cs[0].typ!=null) {
FromPDF.plteImage(stm, 0, img, cs[3].val, w, h, bpc);
}
else img = stm;
genv.PutImage(gst, img, w,h);
}
else if(op=="n" || op=="BT" || op=="EI") {}
else if(op=="ET") { gst.font.Tm = [1,0,0,1,0,0]; gst.font.Tlm=gst.font.Tm.slice(0); }
else if(op=="re") {
var h=os.pop().val, w=os.pop().val, y=os.pop().val, x=os.pop().val;
UDOC.G.moveTo(gst,x,y); UDOC.G.lineTo(gst,x+w,y); UDOC.G.lineTo(gst,x+w,y+h); UDOC.G.lineTo(gst,x,y+h); UDOC.G.closePath(gst);
}
else if(op=="y" || op=="v") {
var im=gst.ctm.slice(0); UDOC.M.invert(im); var p=UDOC.M.multPoint(im,gst.cpos);
var y3=os.pop().val, x3=os.pop().val, y1=os.pop().val, x1=os.pop().val;
if(op=="y") UDOC.G.curveTo(gst,x1,y1,x3,y3,x3,y3);
else UDOC.G.curveTo(gst,p[0],p[1],x1,y1,x3,y3);
}
else if(op=="B" || op=="B*") {
genv.Fill(gst, op=="B*"); //UDOC.G.newPath(gst);
genv.Stroke(gst); UDOC.G.newPath(gst);
}
else if(op=="cm" || op=="Tm") {
var m = []; for(var i=0; i<6; i++) m.push(os.pop().val); m.reverse();
if(op=="cm") { UDOC.M.concat(m, gst.ctm); gst.ctm = m; }
else { gst.font.Tm = m; gst.font.Tlm = m.slice(0); }
}
else if(op=="Td" || op=="T*") {
var x=0, y=0;
if(op=="T*") { x=0; y=-gst.font.Tl; }
else { y=os.pop().val; x=os.pop().val; }
var tm = [1,0,0,1,x,y]; UDOC.M.concat(tm,gst.font.Tlm);
gst.font.Tm = tm; gst.font.Tlm = tm.slice(0);
}
else if(op=="Tf") {
var sc = os.pop().val, fnt = os.pop().val;
gst.font.Tf=fnt;//rfnt["/BaseFont"].slice(1);
gst.font.Tfs=sc; //os.push(fnt);
}
else if(op=="Tj" || op=="TJ") {
var sar = os.pop();
if(sar.typ=="string") sar = [sar];
else sar = sar.val;
var rfnt = res["/Font"][fnt];
var tf = gst.font.Tf;
var fnt = res["/Font"][tf];
var scl = UDOC.M.getScale(gst.font.Tm)*gst.font.Tfs/1000;
for(var i=0; i<sar.length; i++) {
//if(sar[i].typ!="string") { gst.font.Tm[4] += -scl*sar[i].val; continue; }
if(sar[i].typ!="string") { if(i==0) gst.font.Tm[4] += -scl*sar[i].val; continue; }
var str = FromPDF.getString(sar[i].val, fnt);
if(sar[i+1] && sar[i+1].typ!="string") { var sv = sar[i+1].val; str[1] += -sv; if(-900<sv && sv<-100) str[0]+=" "; }
gst.font.Tf = str[2];
genv.PutText(gst, str[0], str[1]/1000); //gst.cpos[0] += str.length*gst.font.mat[0]*0.5;
gst.font.Tf = tf;
gst.font.Tm[4] += scl*str[1];
}
}
else if(op=="Tc") gst.font.Tc = os.pop().val;
else if(op=="Tw") gst.font.Tw = os.pop().val;
else if(op=="Tz") gst.font.Th = os.pop().val;
else if(op=="TL") gst.font.Tl = os.pop().val;
else if(op=="Tr") gst.font.Tmode = os.pop().val;
else if(op=="Ts") gst.font.Trise = os.pop().val;
else if(op=="CS" || op=="cs" ) { var cs = os.pop().val; if(op=="CS") gst.sspace=cs; else gst.space=cs; }
else if(op=="SCN" || op=="scn" || op=="SC" || op=="sc") {
var stk = (op=="SCN" || op=="SC");
var csi = stk ? gst.sspace : gst.space, cs, c = null;
//console.log(op, cs, os); throw "e";
var sps = res ? res["/ColorSpace"] : null; //if(sps!=null) console.log(sps[csi]);
if(sps!=null && sps[csi]!=null) {
if(sps[csi][1] && sps[csi][1]["/Alternate"]) cs = sps[csi][1]["/Alternate"]; //cs = sps[csi][0];
else cs = (typeof sps[csi] == "string") ? sps[csi] : sps[csi][0];
}
else cs = csi;
//console.log(sps, cs, os.slice(0));
if(cs=="/Lab" || cs=="/DeviceRGB" || cs=="/DeviceN" || (cs=="/ICCBased" && sps[csi][1]["/N"]==3)) {
c=[os.pop().val, os.pop().val, os.pop().val]; c.reverse(); }
else if(cs=="/DeviceCMYK" || (cs=="/ICCBased" && sps[csi][1]["/N"]==4)) {
var cmyk=[os.pop().val,os.pop().val,os.pop().val,os.pop().val]; cmyk.reverse(); c = UDOC.C.cmykToRgb(cmyk); }
else if(cs=="/DeviceGray" || cs=="/CalGray") { var gv=FromPS.nrm(os.pop().val); c=[gv,gv,gv]; }
else if(cs=="/Separation") {
var cval = FromPDF.Func(sps[csi][3], [os.pop().val]);
if(sps && sps[csi] && sps[csi][2]=="/DeviceCMYK") c = UDOC.C.cmykToRgb(cval);
else c = UDOC.C.labToRgb(cval);
}
else if(cs=="/Pattern") {
//*
var pt = res["/Pattern"][os.pop().val]; //console.log(pt);
var ptyp = pt["/PatternType"];
if(ptyp==1) { console.log("tile pattern"); return; }
FromPDF.setShadingFill(pt["/Shading"], pt["/Matrix"], stk, gst);
return;//*/ os.pop(); c=[1,0.5,0];
}
else { console.log(csi, cs, os, sps, res); throw("e"); }
//console.log(c);
if(stk) gst.COLR = c; else gst.colr=c;
}
else if(op=="sh") { //os.pop(); return;
//if(window.asdf==null) window.asdf=0;
//window.asdf++; if(window.asdf!=6) return;
var sh = res["/Shading"][os.pop().val]; //console.log(sh);
var ocolr = gst.colr, opth = gst.pth;
gst.pth = gst.cpth; gst.cpth = UDOC.G.rectToPath(env.bb);
FromPDF.setShadingFill(sh, gst.ctm.slice(0), false, gst);
//console.log(gst);
genv.Fill(gst);
gst.colr = ocolr; gst.pth = opth;
}
else if(op=="MP" || op=="BMC" || op=="ri") { os.pop(); }
else if(op=="DP" || op=="BDC") { os.pop(); os.pop(); }
else if(op=="EMC"|| op=="BX" || op=="EX") { }
else
throw ("Unknown operator", op);
}
FromPDF.setShadingFill = function(sh, mat, stk, gst)
{
var styp = sh["/ShadingType"], cs = sh["/ColorSpace"];
//console.log(cs);
//if(cs!="/DeviceRGB") throw "unknown shading space " + cs;
var ftyp = "";
if(styp==2) {
ftyp="lin";
}
else if(styp==3) {
ftyp="rad";
}
else { console.log("Unknown shading type", styp); return; }
//console.log(gst); console.log(sh);
var fill = {typ:ftyp, mat:mat, grad:FromPDF.getGrad(sh["/Function"], cs), crds:sh["/Coords"]}
if(stk) gst.COLR = fill; else gst.colr=fill;
}
FromPDF.getGrad = function(fn, cs) {
//console.log(fn,cs);
var F = FromPDF._normColor;
var fs = fn["/Functions"], ft = fn["/FunctionType"], bs = fn["/Bounds"], enc = fn["/Encode"];
//console.log(fn);
if(ft==0 || ft==2) return [ [0,F(fn,[0], cs)], [1,F(fn,[1], cs)] ];
var zero = enc[0];
var grd = [];
if(bs.length==0 || bs[0]>0) grd.push([0, F(fs[0], [zero], cs)] );
for(var i=0; i<bs.length; i++) grd.push([bs[i], F(fs[i],[zero], cs)]);
if(bs.length==0 || bs[bs.length-1]<1) grd.push([1, F(fs[fs.length-1], [1-zero], cs)]);
//console.log(fn, grd);
return grd;
}
FromPDF._clrSamp = function(stm, i) { return [stm[i]/255, stm[i+1]/255, stm[i+2]/255]; }
FromPDF._normColor = function(fn, vls, cs) {
//console.log(fn, vls, cs);
var clr = FromPDF.Func(fn, vls);
if(cs[3] && cs[3]["/Length"]) {
clr = FromPDF.Func(cs[3], clr);
//console.log(clr);
if(cs[2]=="/DeviceCMYK" || clr.length==4) { clr = UDOC.C.cmykToRgb(clr); }
else { console.log(clr, cs); throw "unknown color profile"; }
//console.log(clr);
}
else if((cs[1] && cs[1]["/N"]==4)
|| cs=="/DeviceCMYK") clr = UDOC.C.cmykToRgb(clr);
//if(clr.length<3) { console.log(clr.slice(0)); throw "e"; clr.push(1); }
return clr;
}
FromPDF.getImage = function(xo, gst) {
var w=xo["/Width"], h=xo["/Height"], ar = w*h, stm=FromPDF.GS(xo), ft=xo["/Filter"], cs=xo["/ColorSpace"], bpc=xo["/BitsPerComponent"], mte=xo["/Matte"];
//if(w==295 && h==98) console.log(xo);
//if(w=="327" && h==9) console.log(xo);
var img = xo["image"]; //console.log(xo);
if(img==null) {
//console.log(xo);
var msk = xo["/Mask"];
if(cs && cs[0]=="/Indexed") {
var pte;
if(cs[3].length!=null) { // palette in a string
var str = cs[3]; pte = new Uint8Array(256*3);
for(var i=0; i<str.length; i++) pte[i] = str.charCodeAt(i);
}
else pte = FromPDF.GS(cs[3]);
if(cs[1]=="/DeviceCMYK" || (cs[1] && cs[1][1] && cs[1][1]["/N"]==4)) {
var opte = pte, pte = new Uint8Array(256*3);
for(var i=0; i<256; i++) { var qi=(i<<2), ti=qi-i, rgb = UDOC.C.cmykToRgb([opte[qi]/255, opte[qi+1]/255, opte[qi+2]/255, opte[qi+3]/255]);
pte[ti]=rgb[0]*255; pte[ti+1]=rgb[1]*255; pte[ti+2]=rgb[2]*255;
//var ib = 1-(opte[qi+3]/255); pte[ti]=(255-opte[qi])*ib; pte[ti+1]=(255-opte[qi+1])*ib; pte[ti+2]=(255-opte[qi+2])*ib;
}
}
var nc = new Uint8Array(ar*4);
FromPDF.plteImage(stm, 0, nc, pte, w, h, bpc, msk);
img=nc;
}
else if(ft==null && cs && cs=="/DeviceGray") {
var pte = [0,0,0,255,255,255], nc = new Uint8Array(ar*4);
if(xo["/Decode"] && xo["/Decode"][0]==1) { pte.reverse(); }
if(xo["/ImageMask"]==true) pte.reverse();
FromPDF.plteImage(stm, 0, nc, bpc==1?pte:null, w, h, bpc, msk);
img=nc;
}
else if(ft==null && cs && cs[0]=="/ICCBased" && cs[1] && cs[1]["/N"]==4) { // CMYK
var nc = new Uint8Array(ar*4), cmy=[0,0,0,0];
for(var i=0; i<ar; i++) {
var qi = i*4; cmy[0]=stm[qi]*(1/255); cmy[1]=stm[qi+1]*(1/255); cmy[2]=stm[qi+2]*(1/255); cmy[3]=stm[qi+3]*(1/255);
var rgb = UDOC.C.cmykToRgb(cmy);
nc[qi ]=~~(rgb[0]*255+0.5);
nc[qi+1]=~~(rgb[1]*255+0.5);
nc[qi+2]=~~(rgb[2]*255+0.5);
nc[qi+3]=255;
}
img = nc;
}
else if(w*h*3<=stm.length) {
var mlt = Math.round(255/((1<<bpc)-1));
var bpl = Math.ceil(w*3*bpc/8);
var nc = new Uint8Array(ar*4);
for(var y=0; y<h; y++) {
var so = bpl * y;
for(var x=0; x<w; x++)
{
var qi=(y*w+x)*4, tx=3*x;
nc[qi ]=FromPDF.getBitNum(stm, so, tx , bpc);
nc[qi+1]=FromPDF.getBitNum(stm, so, tx+1, bpc);
nc[qi+2]=FromPDF.getBitNum(stm, so, tx+2, bpc);
nc[qi+3]=255;
}
}
img = nc;
}
else { img = stm; }
if(mte && mte.join("")!="000") {
var r = Math.round(mte[0]*255), g=Math.round(mte[1]*255), b=Math.round(mte[2]*255);
for(var i=0; i<img.length; i+=4) {
img[i ]=Math.max(img[i ],r);
img[i+1]=Math.max(img[i+1],g);
img[i+2]=Math.max(img[i+2],b);
}
}
xo["image"] = img;
}
return img;
}
FromPDF.plteImage = function(buff, off, img, plt, w, h, bpc, msk)
{
var mlt = Math.round(255/((1<<bpc)-1));
var bpl = Math.ceil(w*bpc/8);
for(var y=0; y<h; y++) {
var so = off + bpl * y;
for(var x=0; x<w; x++) {
var ci = FromPDF.getBitNum(buff, so, x, bpc);
var qi = (y*w+x)<<2;
if(plt) { var c =ci*3; img[qi]=plt[c]; img[qi+1]=plt[c+1]; img[qi+2]=plt[c+2]; }
else { var nc=ci*mlt; img[qi]=nc; img[qi+1]=nc; img[qi+2]=nc; }
img[qi+3]=255;
if(msk && msk[0]<=ci && ci<=msk[1]) img[qi+3]=0;
}
}
}
FromPDF.getBitNum = function(buff, so, x, bpc) {
var ci = 0;
if (bpc==8) ci = buff[so+x];
else if(bpc==4) ci=(buff[so+(x>>1)]>>((1-(x&1))<<2))&15;
else if(bpc==2) ci=(buff[so+(x>>2)]>>((3-(x&3))<<1))&3;
else if(bpc==1) ci=(buff[so+(x>>3)]>>((7-(x&7))<<0))&1;
return ci;
}
FromPDF.Func = function(f, vls)
{
//console.log(f, vls);
var dom = f["/Domain"], rng = f["/Range"], typ = f["/FunctionType"], out = [];
for(var i=0; i<vls.length; i++) vls[i]=Math.max(dom[2*i], Math.min(dom[2*i+1], vls[i]));
if(typ==0) {
var enc = f["/Encode"], sz = f["/Size"], dec = f["/Decode"], n = rng.length/2;
if(enc==null) enc=[0,sz[0]-1];
if(dec==null) dec=rng;//[0,sz[0]-1,0,sz[0]-1,0,sz[0]-1];
for(var i=0; i<vls.length; i++) {
var ei = FromPDF.intp(vls[i],dom[2*i],dom[2*i+1],enc[2*i],enc[2*i+1]);
vls[i] = Math.max(0, Math.min(sz[i]-1, ei));
}
for(var j=0; j<n; j++) {
var x = Math.round(vls[0]), rj = FromPDF.GS(f)[n*x+j];
rj = FromPDF.intp(rj, 0,255, dec[2*j],dec[2*j+1]);
out.push(rj);
}
}
else if(typ==2) {
var c0=f["/C0"],c1=f["/C1"],N=f["/N"]
var x = vls[0];
for(var i=0; i<c0.length; i++) out[i] = c0[i] + Math.pow(x,N) * (c1[i]-c0[i]);
}
else if(typ==4) {
var env = FromPS._getEnv([0,0,0,0]); env.pgOpen = true;
var gs = [];
var os = []; // operand stack
var ds = FromPS._getDictStack([], {});
var es = [];
//console.log(FromPS.B.readASCII(FromPDF.GS(f),0,FromPDF.GS(f).length));
es.push({ typ:"file", val: { buff:FromPDF.GS(f), off:0 } }); // execution stack
var repeat = true;
while(repeat) repeat = FromPS.step(os, ds, es, gs, env, {}, FromPDF.operator);
var proc = os.pop(); proc.off=0;
es.push(proc);
for(var i=0; i<vls.length; i++) os.push({typ:"real",val:vls[i]});
repeat = true;
while(repeat) repeat = FromPS.step(os, ds, es, gs, env, {}, FromPDF.operator);
for(var i=0; i<os.length; i++) out.push(os[i].val);
}
if(rng) for(var i=0; i<out.length; i++) out[i]=Math.max(rng[2*i], Math.min(rng[2*i+1], out[i]));
return out;
}
FromPDF.intp = function(x,xmin,xmax,ymin,ymax) { return ymin + (x-xmin) * (ymax-ymin)/(xmax-xmin); }
FromPDF.getString = function(sv, fnt)
{
//console.log(sv, fnt); //throw "e";
var st = fnt["/Subtype"], s="", m=0, psn=null;
var tou = fnt["/ToUnicode"], enc = fnt["/Encoding"], sfnt=fnt; // font with a stream
if(st=="/Type0") sfnt = fnt["/DescendantFonts"][0]; // // only in type 0
if(tou!=null) s = FromPDF.toUnicode(sv, tou);
else if(enc=="/WinAnsiEncoding" ) s = FromPDF.encFromMap(sv, FromPDF._win1252);
else if(enc=="/MacRomanEncoding") s = FromPDF.encFromMap(sv, FromPDF._macRoman);
else if(st=="/Type0") {
var off=0;
if(enc=="/Identity-H") off=31;
for(var j=0; j<sv.length; j+=2) {
var gid = (sv[j]<<8)|sv[j+1]; //console.log(gid, stm);
s += String.fromCharCode(gid+off); // don't know why 31
}
}
else if(enc!=null && enc["/Type"]=="/Encoding") {
var dfs = enc["/Differences"];
var benc = enc["/BaseEncoding"], map = null;
if(benc=="/WinAnsiEncoding" ) map = FromPDF._win1252;
if(benc=="/MacRomanEncoding") map = FromPDF._macRoman;
if(dfs) {
//console.log(sv,dfs);
var s = "";
for(var i=0; i<sv.length; i++) {
var ci = sv[i], coff=-5, found = false;
for(var j=0; j<dfs.length; j++)
{
if(typeof dfs[j] == "string") { if(ci==coff) { s+=FromPDF.fromCName(dfs[j].slice(1)); found=true; break; } coff++; }
else coff=dfs[j];
}
if(!found && map!=null) {
var cin = map.indexOf(ci);
if(cin!=-1) ci = String.fromCharCode(map[cin+1]);
s += String.fromCharCode(ci);
}
}
//console.log(s);
}
//console.log(enc, sv); throw "e";
//s = FromPDF.fromWin(sv);
}
else { /*console.log("reading simple string", sv, fnt);*/ s = FromPS.readStr(sv); }
//console.log(sv, fnt);
if(st=="/Type0") {
//console.log(fnt); //throw "e";
var ws = sfnt["/W"];
if(ws==null) m = s.length*1000*0.4;
else
for(var i=0; i<sv.length; i+=2) {
var cc = (sv[i]<<8)|sv[i+1], gotW = false;
for(var j=0; j<ws.length; j+=2) {
var i0=ws[j], i1 = ws[j+1];
if(i1.length) { if(0<=cc-i0 && cc-i0<i1.length) { m += i1[cc-i0]; gotW=true; } }
else { if(i0<=cc && cc<=i1) { m += ws[j+2]; gotW = true; } j++; }
}
if(!gotW) m += ws[1][0];
}
}
else if(st=="/Type1" || st=="/Type3" || st=="/TrueType") {
var fc=fnt["/FirstChar"], ws = fnt["/Widths"];
if(ws) for(var i=0; i<sv.length; i++) m += ws[sv[i]-fc];
else { m = s.length*1000*0.4; console.log("approximating word width"); }
}
else throw "unknown font type";
//console.log(fnt);// throw "e";
//console.log(sfnt);
var fd = sfnt["/FontDescriptor"];
if(fd) {
if(fd["psName"]) psn=fd["psName"];
else {
var pp, ps = ["","2","3"];
for(var i=0; i<3; i++) if(fd["/FontFile"+ps[i]]) pp = "/FontFile"+ps[i];
if(pp) {
var fle = FromPDF.GS(fd[pp]);
if(pp!=null && fle && FromPS.B.readUint(fle,0)==65536) psn = fd["psName"] = FromPDF._psName(fle);
}
}
}
if(psn==null && fnt["/BaseFont"]) psn = fnt["/BaseFont"].slice(1);
if(psn==null) psn = "DejaVuSans";
//if(sv.length==9) console.log(s);
return [s, m, psn.split("+").pop()];
}
FromPDF._psName = function(fle) {
var rus = FromPS.B.readUshort;
var num = rus(fle, 4);
var noff = 0;
for(var i=0; i<num; i++) {
var tn = FromPS.B.readASCII(fle,12+i*16,4), to = FromPS.B.readUint(fle, 12+i*16+8);
if(tn=="name") { noff=to; break; }
}
if(noff==0) return null;
var cnt=rus(fle, noff+2);
var offset0=noff+6, offset=noff+6;
for(var i=0; i<cnt; i++) {
var platformID = rus(fle, offset );
var eID = rus(fle, offset+ 2); // encoding ID
var languageID = rus(fle, offset+ 4);
var nameID = rus(fle, offset+ 6);
var length = rus(fle, offset+ 8);
var noffset = rus(fle, offset+10);
offset += 12;
var s;
var soff = offset0 + cnt*12 + noffset;
if(eID==1 || eID==10 || eID==3) { s=""; for(var j=1; j<length; j+=2) s += String.fromCharCode(fle[soff+j]); }
if(eID==0 || eID== 2) s = FromPS.B.readASCII(fle, soff, length);
if(nameID==6 && s!=null && s.slice(0,3)!="OTS") return s.replace(/\s/g, "");
}
return null;
}
FromPDF.encFromMap = function(sv, map)
{
var s="";
for(var j=0; j<sv.length; j++) {
var cc = sv[j], ci = map.indexOf(cc);
if(ci!=-1) cc = map[ci+1];
s+=String.fromCharCode(cc);
}
return s;
}
FromPDF._win1252 = [ 0x80, 0x20AC, 0x82, 0x201A, 0x83, 0x0192, 0x84, 0x201E, 0x85, 0x2026, 0x86, 0x2020, 0x87, 0x2021, 0x88, 0x02C6, 0x89, 0x2030,
0x8A, 0x0160, 0x8B, 0x2039, 0x8C, 0x0152, 0x8E, 0x017D, 0x91, 0x2018, 0x92, 0x2019, 0x93, 0x201C, 0x94, 0x201D, 0x95, 0x2022, 0x96, 0x2013,
0x97, 0x2014, 0x98, 0x02DC, 0x99, 0x2122, 0x9A, 0x0161, 0x9B, 0x203A, 0x9C, 0x0153, 0x9E, 0x017E, 0x9F, 0x0178 ];
FromPDF._macRoman = [ 0x80,0xc4, 0x81,0xc5, 0x82,0xc7, 0x83,0xc9, 0x84,0xd1, 0x85,0xd6, 0x86,0xdc, 0x87,0xe1,
0x88,0xe0, 0x89,0xe2, 0x8a,0xe4, 0x8b,0xe3, 0x8c,0xe5, 0x8d,0xe7, 0x8e,0xe9, 0x8f,0xe8,
0x90,0xea, 0x91,0xeb, 0x92,0xed, 0x93,0xec, 0x94,0xee, 0x95,0xef, 0x96,0xf1, 0x97,0xf3,
0x98,0xf2, 0x99,0xf4, 0x9a,0xf6, 0x9b,0xf5, 0x9c,0xfa, 0x9d,0xf9, 0x9e,0xfb, 0x9f,0xfc,
0xa0,0x2020, 0xa1,0xb0, 0xa2,0xa2, 0xa3,0xa3, 0xa4,0xa7, 0xa5,0x2022, 0xa6,0xb6, 0xa7,0xdf,
0xa8,0xae, 0xa9,0xa9, 0xaa,0x2122, 0xab,0xb4, 0xac,0xa8, 0xad,0x2660, 0xae,0xc6, 0xaf,0xd8,
0xb0,0x221e, 0xb1,0xb1, 0xb2,0x2264, 0xb3,0x2265, 0xb4,0xa5, 0xb5,0xb5, 0xb6,0x2202, 0xb7,0x2211,
0xb8,0x220f, 0xb9,0x3c0, 0xba,0x222b, 0xbb,0xaa, 0xbc,0xba, 0xbd,0x3a9, 0xbe,0xe6, 0xbf,0xf8,
0xc0,0xbf, 0xc1,0xa1, 0xc2,0xac, 0xc3,0x221a, 0xc4,0x192, 0xc5,0x2248, 0xc6,0x2206, 0xc7,0xab,
0xc8,0xbb, 0xc9,0x2026, 0xca,0xa0, 0xcb,0xc0, 0xcc,0xc3, 0xcd,0xd5, 0xce,0x152, 0xcf,0x153,
0xd0,0x2013, 0xd1,0x2014, 0xd2,0x201c, 0xd3,0x201d, 0xd4,0x2018, 0xd5,0x2019, 0xd6,0xf7, 0xd7,0x25ca,
0xd8,0xff, 0xd9,0x178, 0xda,0x2044, 0xdb,0x20ac, 0xdc,0x2039, 0xdd,0x203a, 0xde,0xfb01, 0xdf,0xfb02,
0xe0,0x2021, 0xe1,0xb7, 0xe2,0x201a, 0xe3,0x201e, 0xe4,0x2030, 0xe5,0xc2, 0xe6,0xca, 0xe7,0xc1,
0xe8,0xcb, 0xe9,0xc8, 0xea,0xcd, 0xeb,0xce, 0xec,0xcf, 0xed,0xcc, 0xee,0xd3, 0xef,0xd4,
0xf0,0xf8ff, 0xf1,0xd2, 0xf2,0xda, 0xf3,0xdb, 0xf4,0xd9, 0xf5,0x131, 0xf6,0x2c6, 0xf7,0x2dc,
0xf8,0xaf, 0xf9,0x2d8, 0xfa,0x2d9, 0xfb,0x2da, 0xfc,0xb8, 0xfd,0x2dd, 0xfe,0x2db, 0xff,0x2c7 ];
FromPDF.fromCName = function(cn)
{
if(cn.length==1) return cn;
if(cn.slice(0,3)=="uni") return String.fromCharCode(parseInt(cn.slice(3),16));
//var gi = parseInt(cn.slice(1)); if(cn.charAt(0)=="g" && !isNaN(gi)) return String.fromCharCode(gi);
var map = {
"space":32,"exclam":33,"quotedbl":34,"numbersign":35,"dollar":36,"percent":37,"parenleft":40,
"parenright":41,"asterisk":42,"plus":43,"comma":44,"hyphen":45,"period":46,"slash":47,
"zero":48,"one":49,"two":50,"three":51,"four":52,"five":53,"six":54,"seven":55,"eight":56,"nine":57,
"colon":58,"semicolon":59,"less":60,"equal":61,"at":64,
"bracketleft":91,"bracketright":93,"underscore":95,"braceleft":123,"braceright":125,
"dieresis":168,"circlecopyrt":169,"Eacute":201,
"dotlessi":0x0131,"tcaron":0x165,
"alpha":0x03B1,"phi":0x03C6,
"endash":0x2013,"emdash":0x2014,"asteriskmath":0x2217,"quoteright":0x2019,"quotedblleft":0x201C,"quotedblright":0x201D,"bullet":0x2022,
"minus":0x2202,
"fi": 0xFB01,"fl":0xFB02 };
var mc = map[cn];
if(mc==null) { if(cn.charAt(0)!="g") console.log("unknown character "+cn);
return cn; }
return String.fromCharCode(mc);
}
FromPDF.toUnicode = function(sar, tou) {
var cmap = tou["cmap"], s = "";
if(cmap==null) {
var file = {buff:FromPDF.GS(tou), off:0};
//console.log(FromPS.B.readASCII(file.buff, 0, file.buff.length));
var os = []; // operand stack
var ds = FromPS._getDictStack({});
var es = [{ typ:"file", val: file }]; // execution stack
var gs = [];
var env = FromPS._getEnv([0,0,1,1]); env.pgOpen = true;
var time = Date.now();
var repeat = true;
while(repeat) repeat = FromPS.step(os, ds, es, gs, env, null, FromPDF.operator);
cmap = env.res["CMap"];
tou["cmap"] = cmap;
//console.log(cmap); throw "e";
}
//console.log(cmap);
//cmap = cmap["Adobe-Identity-UCS"];
for(var p in cmap) { cmap=cmap[p]; break; }
//console.log(cmap, sar); throw "e";
var bfr = cmap.bfrange, bfc = cmap.bfchar, bpc = cmap["bpc"];
for(var i=0; i<sar.length; i+=bpc) {
var cc = sar[i]; if(bpc==2) cc = (cc<<8) | sar[i+1];
var mpd = false;
if(!mpd && bfr) for(var j=0; j<bfr.length; j+=3) {
var v0=bfr[j], v1=bfr[j+1], v2=bfr[j+2];
if(v0<=cc && cc<=v1) {
if(v2.length==null) cc+=v2-v0;
else cc = v2[cc-v0];
mpd=true; break;
}
}
if(!mpd && bfc) for(var j=0; j<bfc.length; j+=2) if(bfc[j]==cc) { cc=bfc[j+1]; mpd=true; break; }
s += String.fromCharCode(cc);
}
return s;
}
FromPDF.readXrefTrail = function(buff, xref, out)
{
var kw = FromPS.B.readASCII(buff, xref, 4);
if(kw=="xref") {
var off = xref+4;
if(buff[off]==13) off++; if(buff[off]==10) off++;
while(true) { // start of the line with M, N
if(FromPS.B.readASCII(buff, off, 7)=="trailer") { off+=8; break; }
var of0 = off;
while(!FromPS.isEOL(buff[off])) off++;
var line = FromPS.B.readASCII(buff, of0, off-of0); //console.log(line);
line = line.split(" ");
var n = parseInt(line[1]);
if(buff[off]==13) off++; if(buff[off]==10) off++;
for(var i=0; i<n; i++)
{
var li = parseInt(line[0])+i;
if(out[li]==null) out[li] = {
off: parseInt(FromPS.B.readASCII(buff, off, 10)),
gen: parseInt(FromPS.B.readASCII(buff, off+11, 5)),
chr: FromPS.B.readASCII(buff, off+17, 1),
val: null,
opn: false
};
off+=20;
}
}
var file = {buff:buff, off:off};//, trw = FromPS.getFToken(file);
var trl = FromPDF.readObject(file, file, out);
if(trl["/Prev"]) FromPDF.readXrefTrail(buff, trl["/Prev"], out);
return trl;
}
else {
var off = xref;
while(!FromPS.isEOL(buff[off])) off++; off++;
var xr = FromPDF.readObject({buff:buff, off:off}, file, null); //console.log(xr);
var sof = 0, sb = FromPDF.GS(xr), w = xr["/W"], ind = (xr["/Index"] ? xr["/Index"][0] : 0);
while(sof<sb.length) {
var typ=FromPDF.getInt(sb,sof,w[0]); sof+=w[0];
var a =FromPDF.getInt(sb,sof,w[1]); sof+=w[1];
var b =FromPDF.getInt(sb,sof,w[2]); sof+=w[2];
var off=0, gen=0, chr="n";
if(typ==0) {off=a; gen=b; chr="f";}
if(typ==1) {off=a; gen=b; chr="n";}
if(typ==2) {off=a; gen=b; chr="s";}
out[ind] = { off: off, gen: gen, chr: chr, val: null, opn: false }; ind++;
}
if(xr["/Prev"]) FromPDF.readXrefTrail(buff, xr["/Prev"], out);
//*
var fl = {buff:buff, off:0};
var ps = ["/Root","/Info"];
for(var i=0; i<ps.length; i++) {
var p = ps[i], val = xr[p];
if(val && val.typ=="ref") xr[p] = FromPDF.getIndirect(val.ind, val.gen, fl, out);
}
//*/
return xr;
}
}
FromPDF.getInt = function(b,o,l) {
if(l==0) return 0;
if(l==1) return b[o];
if(l==2) return ((b[o]<< 8)|b[o+1]);
if(l==3) return ((b[o]<<16)|(b[o+1]<<8)|b[o+2]); throw "e";
}
FromPDF.getIndirect = function(i,g,file,xr)
{
var xv = xr[i];
if(xv.chr=="f") return null;
if(xv.val!=null) return xv.val;
if(xv.opn) return {typ:"ref",ind:i, gen:g};
xv.opn = true;
var ooff = file.off, nval;
if(xv.chr=="s") {
var os = FromPDF.getIndirect(xv.off, xv.gen, file, xr), fle = {buff:FromPDF.GS(os), off:0};
var idx=0, ofs=0;
while(idx!=i) { idx=FromPS.getFToken(fle).val; ofs=FromPS.getFToken(fle).val; }
fle.off = ofs+os["/First"];
nval = FromPDF.readObject(fle, file, xr);
}
else {
file.off = xv.off;
var a=FromPS.getFToken(file), b=FromPS.getFToken(file), c=FromPS.getFToken(file);
//console.log(a,b,c);
nval = FromPDF.readObject(file, file, xr);
}
xv.val = nval;
file.off = ooff; xv.opn = false;
return nval;
}
FromPDF.readObject = function(file, mfile, xr)
{
//console.log(file.off, file.buff);
var tok = FromPS.getFToken(file);
//console.log(tok);
if(tok.typ=="integer") {
var off = file.off;
var tok2 = FromPS.getFToken(file);
if(tok2.typ=="integer") {
FromPS.skipWhite(file);
if(file.buff[file.off]==82) {
file.off++;
if(xr && xr[tok.val]) return FromPDF.getIndirect(tok.val, tok2.val, mfile, xr);
else return {typ:"ref",ind:tok.val, gen:tok2.val};
}
}
file.off = off;
}
if(tok.val=="<<") return FromPDF.readDict(file, mfile, xr);
if(tok.val=="[" ) return FromPDF.readArra(file, mfile, xr);
if(tok.typ=="string") {
var s = ""; for(var i=0; i<tok.val.length; i++) s+=String.fromCharCode(tok.val[i]);
return s;
}
return tok.val;
}
FromPDF.readDict = function(file, mfile, xr) {
var o = {};
while(true) {
var off=file.off, tok = FromPS.getFToken(file);
if(tok.typ=="name" && tok.val==">>") break;
file.off= off;
var key = FromPDF.readObject(file, mfile, xr);
var val = FromPDF.readObject(file, mfile, xr);
o[key] = val;
}
if(o["/Length"]!=null) {
var l = o["/Length"];
var tk = FromPS.getFToken(file); if(file.buff[file.off]==13) file.off++; if(file.buff[file.off]==10) file.off++;
o["buff"] = file.buff.slice(file.off, file.off+l); file.off += l; FromPS.getFToken(file); // endstream
}
return o;
}
FromPDF.GS = function(o) {
if(o["stream"]==null) {
var buff = o["buff"]; delete o["buff"];
var flt = o["/Filter"], prm=o["/DecodeParms"];
if(flt!=null) {
var fla = (typeof flt == "string") ? [flt] : flt;
var keepFlt = false;
for(var i=0; i<fla.length; i++) {
var cf = fla[i], fl = {buff:buff, off:0};
if (cf=="/FlateDecode" ) { buff = FromPS.F.FlateDecode (fl); }
else if(cf=="/ASCIIHexDecode") { buff = FromPS.F.HexDecode (fl); }
else if(cf=="/ASCII85Decode" ) { buff = FromPS.F.ASCII85Decode(fl); }
else if(cf=="/DCTDecode" || cf=="/CCITTFaxDecode" || cf=="/JPXDecode" || cf=="/JBIG2Decode") { keepFlt = true; } // JPEG
else { console.log(cf, buff); throw "e"; }
}
if(!keepFlt) delete o["/Filter"];
}
if(prm!=null) {
if(prm instanceof Array) prm = prm[0];
if(prm["/Predictor"]!=null && prm["/Predictor"]!=1) {
var w = prm["/Columns"], bpp = prm["/Colors"] ? prm["/Colors"]: 1, bpl = (bpp*w), h = (buff.length/(bpl+1));
FromPDF._filterZero(buff, 0, w, h, bpp); buff = buff.slice(0, h*bpl);
}
}
o["stream"] = buff;
}
return o["stream"];
}
FromPDF.readArra = function(file, mfile, xr) {
var o = [];
while(true) {
var off=file.off, tok = FromPS.getFToken(file);
if(tok.typ=="name" && tok.val=="]") return o;
file.off = off;
var val = FromPDF.readObject(file, mfile, xr);
o.push(val);
}
}
FromPDF._filterZero = function(data, off, w, h, bpp) { // copied from UPNG.js
var bpl = bpp*w, paeth = FromPDF._paeth;
for(var y=0; y<h; y++) {
var i = off+y*bpl, di = i+y+1;
var type = data[di-1];
if (type==0) for(var x= 0; x<bpl; x++) data[i+x] = data[di+x];
else if(type==1) {
for(var x= 0; x<bpp; x++) data[i+x] = data[di+x];
for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + data[i+x-bpp])&255;
}
else if(y==0) {
for(var x= 0; x<bpp; x++) data[i+x] = data[di+x];
if(type==2) for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x])&255;
if(type==3) for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + (data[i+x-bpp]>>1) )&255;
if(type==4) for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + paeth(data[i+x-bpp], 0, 0) )&255;
}
else {
if(type==2) { for(var x= 0; x<bpl; x++) data[i+x] = (data[di+x] + data[i+x-bpl])&255; }
if(type==3) { for(var x= 0; x<bpp; x++) data[i+x] = (data[di+x] + (data[i+x-bpl]>>1))&255;
for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + ((data[i+x-bpl]+data[i+x-bpp])>>1) )&255; }
if(type==4) { for(var x= 0; x<bpp; x++) data[i+x] = (data[di+x] + paeth(0, data[i+x-bpl], 0))&255;
for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + paeth(data[i+x-bpp], data[i+x-bpl], data[i+x-bpp-bpl]) )&255; }
}
}
return data;
}
FromPDF._paeth = function(a,b,c) {
var p = a+b-c, pa = Math.abs(p-a), pb = Math.abs(p-b), pc = Math.abs(p-c);
if (pa <= pb && pa <= pc) return a;
else if (pb <= pc) return b;
return c;
}
function FromPS ()
{
}
FromPS.Parse = function(buff, genv)
{
buff = new Uint8Array(buff);
var off = 0; while(!(buff[off]==37 && buff[off+1]==33)) off++;
var str = FromPS.B.readASCII(buff, off, buff.length-off);
var lines = str.split(/[\n\r]+/);
var crds = null;
var epsv = null;
for(var li=0; li<lines.length; li++)
{
var line = lines[li].trim();
if(line.charAt(0)=="%") {
while(line.charAt(0)=="%") line = line.slice(1);
var pts = line.split(":");
if(pts[0]=="BoundingBox") crds = pts[1].trim().split(/[ ]+/).map(parseFloat);
if(line.indexOf("!PS-Adobe-3.0 EPSF-3.0")!=-1) epsv=line;
}
}
if(epsv==null || crds==null) crds = [0,0,595, 842];
var os = []; // operand stack
var ds = FromPS._getDictStack([],{});
var es = [{ typ:"file", val: { buff:buff, off:off } }]; // execution stack
var gs = [];
var env = FromPS._getEnv(crds);
var time = Date.now();
var repeat = true;
while(repeat) repeat = FromPS.step(os, ds, es, gs, env, genv);
if(env.pgOpen) genv.ShowPage();
genv.Done();
//FromPS.interpret(file, os, ds, es, [], gst, genv);
console.log(Date.now()-time);
}
FromPS._getDictStack = function(adefs, aprcs) {
var defs = [
"def","begin","end","currentfile","currentdict","known","version",
"currentpacking","setpacking","currentoverprint","setoverprint","currentglobal","setglobal",
"currentsystemparams","setsystemparams","currentuserparams","setuserparams","currentpagedevice","setpagedevice",
"currentflat",
"currentlinewidth","currentpoint","currentscreen","setscreen","currenthalftone",
"currentblackgeneration","currentundercolorremoval","currentcolortransfer",
"internaldict",
"dict","string","readstring","readhexstring","readline","getinterval","putinterval","token",
"array","aload","astore","length","maxlength","matrix","mark","counttomark","cleartomark","dictstack","countdictstack",
"makefont","scalefont","stringwidth",
"setfont", "setgray","currentgray", "setrgbcolor","currentrgbcolor","sethsbcolor", "setlinewidth", "setstrokeadjust","setflat","setlinecap",
"setlinejoin","setmiterlimit","setdash",
"clip","eoclip","clippath","pathbbox",
"newpath", "stroke", "fill", "eofill", "closepath","flattenpath","showpage","print",
"moveto", "lineto", "curveto", "arc","arcn",
"show","ashow","xshow","yshow","xyshow","widthshow","awidthshow","charpath",
"cshow",
"rmoveto","rlineto","rcurveto",
"translate","rotate","scale","concat","concatmatrix","invertmatrix","currentmatrix","defaultmatrix","setmatrix",
"save","restore","gsave", "grestore","grestoreall",
"usertime","readtime",
"save", "restore","flush","flushfile","readonly","executeonly",
"findresource","defineresource","undefineresource","image","imagemask","colorimage",
"xcheck","status","cachestatus","setcachelimit","type",
"if","ifelse","exec","stopped","dup","exch","copy","roll","index","pop","put","get","load","where","store","repeat","for","forall","loop","exit",
"bind",
"cvi","cvr","cvs","cvx","cvn","cvlit",
"add","sub","mul","div","idiv","bitshift","mod","exp","atan",
"neg","abs","floor","round","truncate","sqrt","ln","sin","cos",
"srand","rand","==","transform","itransform","dtransform","idtransform",
"eq","ge","gt","le","lt","ne",
"and","or","not",
"filter",
"begincmap","endcmap", "begincodespacerange","endcodespacerange", "beginbfrange","endbfrange","beginbfchar","endbfchar"
].concat(adefs);
var withCtx = ["image", "colorimage", "repeat", "for","forall","loop"];
for(var i=0; i<withCtx.length; i++) defs.push(withCtx[i]+"---");
var prcs = FromPS.makeProcs({
"findfont" : "/Font findresource",
"definefont" : "/Font defineresource",
"undefinefont": "/Font undefineresource"
});
for(var p in aprcs) prcs[p] = aprcs[p];
var systemdict = {}, globaldict = {}, userdict = {}, statusdict = {};
systemdict["systemdict"] = {typ:"dict", val:systemdict};
systemdict["globaldict"] = {typ:"dict", val:globaldict};
systemdict["userdict" ] = {typ:"dict", val:userdict };
systemdict["statusdict"] = {typ:"dict", val:statusdict};
systemdict["$error" ] = {typ:"dict", val:{}};
systemdict["errordict" ] = {typ:"dict", val:FromPS.makeProcs({"handleerror":""})};
systemdict["null"] = {typ:"null", val:null};
for(var i=0; i<defs.length; i++) systemdict[defs[i]] = { typ:"operator", val:defs[i] };
for(var p in prcs) systemdict[p] = prcs[p];
return [ systemdict, globaldict, userdict ]; // dictionary stack
}
FromPS._getEnv = function(crds) {
return {
bb:crds,
gst : UDOC.getState(crds),
packing:false, overprint:false, global:false, systemparams:{"MaxPatternCache":5000},userparams:{},pagedevice:{},
cmnum:0, fnt:null,
res:{},
pgOpen:false,
funs: FromPS.makeProcs({
"blackgeneration" : "",
"undercolorremoval" : "pop 0"
})
}
}
FromPS.makeProcs = function(prcs) {
var out = {};
for(var p in prcs) {
var pts = prcs[p].replace(/ +/g, " ").split(" ");
out[p] = {typ:"procedure", val:[]};
for(var i=0; i<pts.length; i++) out[p].val.push({typ:"name",val:pts[i]});
}
return out;
}
FromPS.addProc = function(obj, es) {
if(obj.val.length==0) return;
if(obj.off!=null && obj.off!=obj.val.length) es.push({typ:"procedure", val:obj.val, off:0});
else { obj.off=0; es.push( obj ); }
}
FromPS._f32 = new Float32Array(1);
FromPS.step = function(os, ds, es, gs, env, genv, Oprs)
{
var otime = Date.now(), f32 = FromPS._f32;
var getToken = FromPS.getToken;
var gst = env.gst;
var tok = getToken(es, ds); if(tok==null) return false;
var typ = tok.typ, val = tok.val;
//console.log(tok, os.slice(0));
//for(var i=0; i<os.length; i++) if(os[i].typ=="real" && isNaN(os[i].val)) throw "e";
/*ocnt++;
//if(ocnt>2*lcnt) { lcnt=ocnt; console.log(ocnt, os.length, file.stk.length); };
if(ocnt>8000000) {
for(var key in opoc) if(opoc[key][1]<1000) delete opoc[key];
console.log(Date.now()-otime, opoc); throw "e";
} */
if(["integer","real","dict","boolean","string","array","procedure","null"].indexOf(typ)!=-1) { os.push(tok); return true; }
if(typ!="name" && typ!="operator") throw "e";
//if(opoc[val]==null) opoc[val]=[0,0]; opoc[val][0]++; opoc[val][1]=ocnt;
if(val.charAt(0)=="/") {
if(val.charAt(1)=="/") throw "e";
else os.push(tok);
}
else if(val=="{") {
var ars = [], car = {typ:"procedure", val:[] };
var ltok=getToken(es,ds);
while(true) {
if (ltok.val=="{") { var ncr = {typ:"procedure", val:[]}; car.val.push(ncr); ars.push(car); car=ncr; }
else if(ltok.val=="}") { if(ars.length==0) break; car = ars.pop(); }
else car.val.push(ltok);
ltok=getToken(es,ds);
}
os.push( car );
}
else if(val=="[" || val=="<<") os.push( {typ:"mark"} );
else if(val=="]" || val==">>") {
var arr = []; while(os.length!=0) { var o=os.pop(); if(o.typ=="mark") break; arr.push(o); }
arr.reverse();
if(val=="]") os.push( {typ:"array", val:arr } );
else {
var ndct = {}; for(var i=0; i<arr.length; i+=2) ndct[arr[i].val.slice(1)] = arr[i+1];
os.push( {typ:"dict", val:ndct } );
}
}
else {
var obj = FromPS.getFromStacks(val, ds);
//if(val=="rl^") { console.log(val, os.slice(0)); }
if(obj==null) { console.log("unknown operator", val, os, ds); throw "e"; }
else if(obj.typ=="procedure") FromPS.addProc(obj, es); //{ obj.off=0; es.push(obj); }
/*
else if(op.typ=="string") {
var prc=[], sdta = {buff:op.val, off:0, stk:[]}, tk = getToken(sdta); while(tk!=null) { prc.push(tk); tk=getToken(sdta); }
FromPS.addProcedure(prc, file);
}*/
else if(["array","string","dict","null","integer","real","boolean","state","font","name"].indexOf(obj.typ)!=-1) os.push(obj);
else if(obj.typ=="operator")
{
var op = obj.val;
//console.log(op);
//if(omap[op]) op = omap[op];
if(op=="def") { var nv = os.pop(), nn = os.pop(); nn=nn.val.slice(1); ds[ds.length-1][nn] = nv; }
else if(op=="internaldict") { var l=os.pop().val; os.push({typ:"dict" , val:{}}); }
else if(op=="dict" ) { var l=os.pop().val; os.push({typ:"dict" , val:{}, maxl:l }); }
else if(op=="string" ) { var l=os.pop().val; os.push({typ:"string", val:new Array(l) }); }
else if(op=="readstring" || op=="readhexstring") {
var str = os.pop(), l=str.val.length, fl = os.pop().val; //console.log(op, str); throw "e";
if(op=="readstring") { for(var i=0; i<l; i++) str.val[i]=fl.buff[fl.off+i]; fl.off+=l; }
else {
var nv = FromPS.readHex(fl, l);
for(var i=0; i<nv.length; i++) str.val[i]=nv[i];
}
os.push(str, {typ:"boolean",val:true});
}
else if(op=="readline") {
var str = os.pop(), fl = os.pop().val, i=0;
if(FromPS.isEOL(fl.buff[fl.off])) fl.off++;
while(true) {
var cc = fl.buff[fl.off]; fl.off++;
if(FromPS.isEOL(cc)) break;
str.val[i]=cc; i++;
}
if(i<str.val.length && str.val[i]!=null) str.val[i]=null;
os.push(str, {typ:"boolean",val:true});
}
else if(op=="getinterval") {
var cnt = os.pop().val, idx = os.pop().val, src = os.pop(), out=[];
if(src.typ=="string") for(var i=0; i<cnt; i++) out.push(src.val[idx+i]);
else throw "e";
//console.log(idx,cnt,out.slice(0));
os.push({typ:src.typ, val:out});
}
else if(op=="putinterval") {
var src=os.pop(), idx=os.pop().val, tgt=os.pop(); //console.log(tgt,idx,src);
if(idx+src.val.length>=tgt.val.length) {} //throw "e";
else if(src.typ=="string") for(var i=0; i<src.val.length; i++) tgt.val[idx+i] = src.val[i];
else throw "e";
//console.log(src.val, tgt.val, idx); throw "e";
}
else if(op=="token") {
var src = os.pop(); if(src.typ!="string") throw "e";
var arr = [];
for(var i=0; i<src.val.length; i++) { var bv=src.val[i]; if(bv==null) break; arr.push(bv); }
var nfl = { buff:new Uint8Array(arr), off:0 }, tok = getToken([{typ:"file",val:nfl}], ds);
var ns = []; for(var i=nfl.off; i<arr.length; i++) ns.push(arr[i]);
os.push({typ:"string",val:ns}, tok, {typ:"boolean",val:true});
}
else if(op=="array" ) { var l=os.pop().val; os.push({typ:"array" , val:new Array(l) }); }
else if(op=="aload"){
var o = os.pop(), arr = o.val;
for(var i=0; i<arr.length; i++) os.push(arr[i]);
os.push(o);
}
else if(op=="astore") {
var o=os.pop(), arr = o.val; //console.log(arr.length); throw "e";
for(var i=0; i<arr.length; i++) arr[arr.length-1-i]=os.pop();
os.push(o);
}
else if(op=="length" ) {
var o = os.pop(), typ=o.typ, l=0;
if (typ=="array" ) l = o.val.length;
else if(typ=="procedure") l = o.val.length;
else if(typ=="dict" ) l = Object.keys(o.val).length;
else if(typ=="string" ) l = o.val.length;
else { console.log(o); throw "e"; }
os.push({typ:"integer",val:l});
}
else if(op=="maxlength") { var d=os.pop(); os.push({typ:"integer",val:d.maxl}); }
else if(op=="matrix" ) { os.push({typ:"array", val:FromPS.makeArr([1,0,0,1,0,0],"real") }); }
else if(op=="mark" ) { os.push({typ:"mark"}); }
else if(op=="counttomark" || op=="cleartomark") {
var mi = 0; while(mi<os.length && os[os.length-1-mi].typ!="mark")mi++;
if(op=="cleartomark") for(var i=0; i<mi+1; i++) os.pop();
else os.push({typ:"integer",val:mi});
}
else if(op=="dictstack") {
var arr = os.pop();
for(var i=0; i<ds.length; i++) arr.val[i] = {typ:"dict",val:ds[i]};
os.push(arr);
}
else if(op=="countdictstack") {
var n=0; for(var i=0; i<os.length; i++) if(os[i].typ=="dict") n++;
os.push({typ:"integer",val:n});
}
else if(op=="begin") { var o = os.pop(), dct=o.val; if(dct==null || o.typ!="dict") { console.log(o, ds); throw "e"; } ds.push(dct); }
else if(op=="end" ) { ds.pop(); }
else if(op=="currentfile") { var file; for(var i=es.length-1; i>=0; i--) if(es[i].typ=="file")file=es[i]; os.push(file); }
else if(op=="currentdict") { var dct=ds[ds.length-1]; os.push({typ:"dict", val:dct}); }
else if(op=="known") { var key=os.pop().val.slice(1), dct=os.pop().val; os.push({typ:"boolean",val:dct[key]!=null}); }
else if(op=="version") { os.push({typ:"string", val:[51]}); } // "3"
else if(["currentpacking","currentoverprint","currentglobal","currentsystemparams","currentuserparams","currentpagedevice"].indexOf(op)!=-1) { var nv = env[op.slice(7)];
os.push({typ:(typeof nv=="boolean")?"boolean":"dict",val:nv});
}
else if(["setpacking","setoverprint","setglobal","setsystemparams","setuserparams","setpagedevice"].indexOf(op)!=-1) { env[op.slice(3)] = os.pop().val; }
else if(op=="currentflat" ) { os.push({typ:"real",val:1}); }
else if(op=="currentlinewidth") { os.push({typ:"real",val:gst.lwidth}); }
else if(op=="currentpoint" ) { var im=gst.ctm.slice(0); UDOC.M.invert(im); var p=UDOC.M.multPoint(im,gst.cpos);
os.push({typ:"real",val:p[0]}, {typ:"real",val:p[1]}); }
else if(op=="currentscreen" ) { os.push({typ:"int",val:60}, {typ:"real",val:0},{typ:"real",val:0}); }
else if(op=="setscreen" ) { os.pop(); os.pop(); os.pop(); }
else if(op=="currenthalftone") { os.push({typ:"dict",val:{}}); }
else if(op=="currentblackgeneration" || op=="currentundercolorremoval") { os.push(env.funs[op.slice(7)]); }
else if(op=="currentcolortransfer") { for(var i=0; i<4; i++) os.push(env.funs["blackgeneration"]); }
else if(op=="findresource")
{
var cat = os.pop().val.slice(1), key = os.pop().val.slice(1), rs;
if (cat=="Font" ) { rs = {typ:"font",val:UDOC.getFont()}; rs.val.Tf=key; }
else if(cat=="ProcSet" ) rs = {typ:"dict",val:{}};
else if(cat=="Category") rs = {typ:"dict",val:{}};
else throw("Unknown resource category: "+cat+","+ key);
os.push(rs);
}
else if(op=="defineresource") {
var cat = os.pop().val.slice(1), ins = os.pop().val, key = os.pop().val.slice(1);
if(env.res[cat]==null) env.res[cat]={};
env.res[cat][key]=ins;
os.push(ins);
}
else if(op=="undefineresource") {
var cat = os.pop().val.slice(1), key = os.pop().val.slice(1);
if(env.res[cat]!=null) delete env.res[cat];
}
else if(op=="image" || op=="colorimage") {
var ncomp = 1, multi = false;
if(op=="colorimage") { ncomp = os.pop().val; multi = os.pop().val; }
var src0, src1, src2;
if(multi) { src2=os.pop(); src1=os.pop(); src0=os.pop(); } else src0 = os.pop();
var mat = FromPS.readArr(os.pop().val), bpc = os.pop().val, h = os.pop().val, w = os.pop().val;
if(ncomp!=3) throw "unsupported number of channels "+ncomp;
if(bpc!=8) throw "unsupported bits per channel: "+bpc;
var img = new Uint8Array(w*h*4); for(var i=0; i<img.length; i++) img[i]=255;
es.push({typ:"name",val:op+"---",ctx:[w,h,bpc,mat, ncomp,multi,img,0, src0,src1,src2]});
FromPS.addProc(src0, es);
if(multi) { FromPS.addProc(src1, es); FromPS.addProc(src2, es); }
//console.log(w,h,bpc,mat, src0,src1,src2, multi, ncomp); throw "e";
}
else if(op=="image---" || op=="colorimage---") {
var prm = tok.ctx, w=prm[0], h=prm[1], bpc=prm[2], mat=prm[3], ncomp=prm[4], multi=prm[5], img=prm[6], pind=prm[7];
var src0 = prm[8], src1 = prm[9], src2=prm[10], dlen = 0;
if(multi)
for(i=0; i<3; i++){ var row = os.pop().val; dlen = row.length;
for(var j=0; j<dlen; j++) img[(pind+j)*4 + 2-i] = row[j];
}
else {
var row = os.pop().val; dlen = Math.floor(row.length/3);
if(row[0]==null) { console.log(ds); throw "e"; }
for(var j=0; j<dlen; j++) { var tj=j*3, qj=(pind+j)*4; img[qj+0]=row[tj+0]; img[qj+1]=row[tj+1]; img[qj+2]=row[tj+2]; }
}
pind += dlen;
FromPS.checkPageStarted(env,genv);
if(pind==w*h) genv.PutImage(gst, img, w, h);
else { prm[7]=pind; es.push(tok);
FromPS.addProc(src0, es);
if(multi) { FromPS.addProc(src1, es); FromPS.addProc(src2, es); }
}
}
else if(op=="makefont") {
var mt = FromPS.readArr(os.pop().val), fnt = JSON.parse(JSON.stringify(os.pop()));
UDOC.M.concat(fnt.val.Tm, mt); os.push(fnt);
}
else if(op=="scalefont") {
var sc = os.pop().val, fnt = os.pop(); //console.log(ds);
fnt.val.Tfs *= sc; os.push(fnt);
}
else if(op=="stringwidth") {
var str=os.pop().val;
var sc = UDOC.M.getScale(gst.font.Tm) / UDOC.M.getScale(gst.ctm);
//console.log(FromPS.getString(str), gst.font, 0.6*sc*str.length);
os.push({typ:"real",val:0.6*sc*str.length}, {typ:"real",val:sc});
}
else if(op=="setfont" ) gst.font = os.pop().val;
else if(op=="setlinewidth") gst.lwidth = os.pop().val;
else if(op=="setstrokeadjust") gst.SA = os.pop().val;
else if(op=="setlinecap") gst.lcap = os.pop().val;
else if(op=="setlinejoin") gst.ljoin = os.pop().val;
else if(op=="setmiterlimit") gst.mlimit = os.pop().val;
else if(op=="setflat") gst.dd.flat=os.pop();
else if(op=="setdash" ) { gst.doff=os.pop().val; gst.dash = FromPS.readArr(os.pop().val); }
else if(op=="show"||op=="ashow"||op=="xshow"||op=="yshow"||op=="xyshow"||op=="widthshow"||op=="awidthshow"||op=="charpath") {
if(op=="charpath" || op=="xshow" || op=="xyshow" || op=="yshow") os.pop();
var sar = os.pop().val, str=FromPS.readStr(sar);
if(op=="awidthshow") { os.pop(); os.pop(); os.pop(); os.pop(); }
if(op=="widthshow" ) { os.pop(); os.pop(); os.pop(); }
if(op=="ashow" ) { os.pop(); os.pop(); }
var om = gst.ctm; gst.ctm = om.slice(0); gst.ctm[4]=gst.cpos[0]; gst.ctm[5]=gst.cpos[1];//UDOC.M.translate(gst.ctm,gst.cpos[0],gst.cpos[1]);
FromPS.checkPageStarted(env,genv);
genv.PutText(gst, str, str.length*0.55); gst.cpos[0] += str.length*UDOC.M.getScale(om)*gst.font.Tfs*0.55; //console.log(str, gst.font.Tfs);
gst.ctm = om;
}
else if(op=="cshow") { os.pop(); os.pop(); }
else if(op=="setgray" ) { var g=FromPS.nrm(os.pop().val); gst.colr = gst.COLR = [g,g,g]; }
else if(op=="currentgray") { os.push({typ:"real", val:(gst.colr[0]+gst.colr[1]+gst.colr[2])/3}); }
else if(op=="setrgbcolor") { var b=os.pop().val,g=os.pop().val,r=os.pop().val; gst.colr = gst.COLR = [FromPS.nrm(r),FromPS.nrm(g),FromPS.nrm(b)]; }
else if(op=="currentrgbcolor") { for(var i=0; i<3; i++) os.push({typ:"real", val:gst.colr[i]}); }
else if(op=="sethsbcolor") {
var v=os.pop().val,s=os.pop().val,h=os.pop().val;
var r, g, b, i, f, p, q, t;
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
gst.colr = gst.COLR = [FromPS.nrm(r),FromPS.nrm(g),FromPS.nrm(b)];
}
else if(op=="clip" || op=="eoclip") {
var bbN = UDOC.G.getBB(gst.pth .crds);
var bbO = UDOC.G.getBB(gst.cpth.crds);
if (UDOC.G.isBox(gst.pth, bbN) && UDOC.G.insideBox(bbO,bbN)) { } // clipping with a box, that contains a current clip path
else if(UDOC.G.isBox(gst.cpth,bbO) && UDOC.G.insideBox(bbN,bbO)) { gst.cpth = JSON.parse(JSON.stringify(gst.pth)); }
else {
var p0 = UDOC.G.toPoly(gst.pth), p1 = UDOC.G.toPoly(gst.cpth);
if(p0 && p1) {
//console.log(gst.pth, gst.cpth);
var p = UDOC.G.polyClip(p0, p1);
//console.log(p0, p1, p);
if(p.length!=0) gst.cpth = UDOC.G.fromPoly(p);
else console.log("strange intersection of polygons");
}
else {
// do an advanced shape - shape intersection
//console.log("replacing clipping path");
//console.log(bbO, gst.cpth);
//console.log(bbN, gst.pth );
gst.cpth = JSON.parse(JSON.stringify(gst.pth ));
}
}
}
else if(op=="clippath" ) { gst.pth = JSON.parse(JSON.stringify(gst.cpth)); }
else if(op=="pathbbox" ) {
var ps = gst.pth.crds;
var bb = UDOC.G.getBB(ps);
ps = [bb[0],bb[1], bb[2],bb[1], bb[0],bb[3], bb[2],bb[3]];
var im = gst.ctm.slice(0); UDOC.M.invert(im); UDOC.M.multArray(im,ps);
bb = UDOC.G.getBB(ps);
f32[0]=bb[0]; bb[0]=f32[0]; f32[0]=bb[1]; bb[1]=f32[0]; f32[0]=bb[2]; bb[2]=f32[0]; f32[0]=bb[3]; bb[3]=f32[0];
bb = FromPS.makeArr(bb,"real");
os.push(bb[0],bb[1],bb[2],bb[3]);
}
else if(op=="newpath" ) UDOC.G.newPath(gst);
else if(op=="stroke" ) { FromPS.checkPageStarted(env,genv); genv.Stroke(gst); UDOC.G.newPath(gst); }
else if(op=="fill" || op=="eofill") { FromPS.checkPageStarted(env,genv); genv.Fill(gst, op=="eofill"); UDOC.G.newPath(gst); }
else if(op=="closepath") UDOC.G.closePath(gst);
else if(op=="flattenpath") {}
else if(op=="showpage" ) { FromPS.checkPageStarted(env,genv); genv.ShowPage (); var ofnt=gst.font; gst = env.gst = UDOC.getState(env.bb); gst.font=ofnt; env.pgOpen = false; }
else if(op=="print" ) { var sar = os.pop().val, str=FromPS.readStr(sar); genv.Print(str); }
else if(op=="moveto" || op=="lineto" ) {
var y = os.pop().val, x = os.pop().val;
if(op=="moveto" ) UDOC.G.moveTo(gst,x,y); else UDOC.G.lineTo(gst,x,y);
}
else if(op=="rmoveto" || op=="rlineto") {
var y = os.pop().val, x = os.pop().val;
var im=gst.ctm.slice(0); UDOC.M.invert(im); var p = UDOC.M.multPoint(im, gst.cpos);
y+=p[1]; x+=p[0];
if(op=="rmoveto") UDOC.G.moveTo(gst,x,y); else UDOC.G.lineTo(gst,x,y);
}
else if(op=="curveto") {
var y3=os.pop().val, x3=os.pop().val, y2=os.pop().val, x2=os.pop().val, y1=os.pop().val, x1=os.pop().val;
UDOC.G.curveTo(gst,x1,y1,x2,y2,x3,y3);
}
else if(op=="arc" || op=="arcn") {
var a2 = os.pop().val, a1 = os.pop().val, r = os.pop().val, y = os.pop().val, x = os.pop().val;
//if(op=="arcn") a2=-a2;
UDOC.G.arc(gst,x,y,r,a1*Math.PI/180,a2*Math.PI/180, op=="arcn");
}
else if(["translate","scale","rotate","concat"].indexOf(op)!=-1) {
var v = os.pop(), m, x, y;
if(v.typ=="array") { m = FromPS.readArr(v.val); y = os.pop().val; }
else { m = [1,0,0,1,0,0]; y = v.val; }
if(op=="translate" || op=="scale") x = os.pop().val;
if(op=="translate") UDOC.M.translate(m,x,y);
if(op=="scale" ) UDOC.M.scale (m,x,y);
if(op=="rotate" ) UDOC.M.rotate (m,-y*Math.PI/180);
if(op=="concat" ) UDOC.M.concat (m,y);
if(v.typ=="array") os.push({typ:"array",val:FromPS.makeArr(m,"real")});
else { UDOC.M.concat(m,gst.ctm); gst.ctm = m; }
}
else if(op=="concatmatrix") { var rA = FromPS.readArr;
var m3 = rA(os.pop().val), m2 = rA(os.pop().val), m1 = rA(os.pop().val);
var m = m1.slice(0); UDOC.M.concat(m, m2); m = FromPS.makeArr(m, "real");
os.push({typ:"array",val:m});
}
else if(op=="invertmatrix") { var rA = FromPS.readArr;
var m2 = rA(os.pop().val), m1 = rA(os.pop().val);
var m = m1.slice(0); UDOC.M.invert(m); m = FromPS.makeArr(m, "real");
os.push({typ:"array",val:m});
}
else if(op=="currentmatrix" || op=="defaultmatrix") {
var m = os.pop(), cm = FromPS.makeArr(op=="currentmatrix"?gst.ctm:[1,0,0,1,0,0],"real");
for(var i=0; i<6; i++) m.val[i]=cm[i]; os.push(m);
}
else if(op=="setmatrix") {
gst.ctm = FromPS.readArr(os.pop().val);
}
else if(op=="cvi") {
var o = os.pop(), v=o.val, out = 0;
if (o.typ=="real" ) out = Math.round(v);
else if(o.typ=="integer") out = v;
else throw "unknown type "+o.typ;
os.push({typ:"integer",val:out});
}
else if(op=="cvr") {
var o = os.pop(), v=o.val, out = 0;
if (o.typ=="real" ) out = v;
else if(o.typ=="integer") out = v;
else if(o.typ=="string" ) out = parseFloat(FromPS.readStr(v));
else throw "unknown type "+o.typ;
os.push({typ:"real",val:out});
}
else if(op=="cvs") {
var str = os.pop(), any = os.pop(), nv = ""; str.val=[]; os.push(str);
if(any.typ=="real" || any.typ=="integer") {
if(Math.abs(Math.round(any.val)-any.val)<1e-6) nv=Math.round(any.val)+".0";
else nv = (Math.round(any.val*1000000)/1000000).toString();
}
else throw "unknown var type: "+any.typ;
for(var i=0; i<nv.length; i++) str.val[i]=nv.charCodeAt(i);
}
else if(op=="cvx") {
var o = os.pop();
//if(o.typ=="array") o.typ="procedure";
//else if(o.typ=="name" && o.val.charAt(0)=="/") o = {typ:"name",val:o.val.slice(1)};
//else { console.log(o); throw "e"; }
os.push(o);
}
else if(op=="cvn") {
os.push({typ:"name",val:FromPS.readStr(os.pop().val)});
}
else if(op=="cvlit") {}
else if(["add","sub","mul","div","idiv","bitshift","mod","exp","atan"].indexOf(op)!=-1) {
var o1 = os.pop(), o0 = os.pop(), v0=o0.val, v1=o1.val, out = 0, otp = "";
if(op=="add" || op=="sub" || op=="mul") otp = (o0.typ=="real" || o1.typ=="real") ? "real" : "integer";
else if(op=="div" || op=="atan" || op=="exp") otp = "real";
else if(op=="mod" || op=="idiv" || op=="bitshift") otp = "integer";
if(o0.typ=="real") { f32[0]=v0; v0=f32[0]; }
if(o1.typ=="real") { f32[0]=v1; v1=f32[0]; }
if(op=="add") out = v0+v1;
if(op=="sub") out = v0-v1;
if(op=="mul") out = v0*v1;
if(op=="div") out = v0/v1;
if(op=="idiv")out = ~~(v0/v1);
if(op=="bitshift") out = v1>0 ? (v0<<v1) : (v0>>>(-v1));
if(op=="mod") out = v0%v1;
if(op=="exp") out = Math.pow(v0, v1);
if(op=="atan")out = Math.atan2(v0, v1)*180/Math.PI;
if(otp=="real") { f32[0]=out; out=f32[0]; }
os.push({ typ:otp, val:out });
}
else if(["neg","abs","floor","round","truncate","sqrt","ln","sin","cos"].indexOf(op)!=-1) {
var o0 = os.pop(), v0=o0.val, out = 0, otp = "";
if(op=="neg" || op=="abs" || op=="truncate") otp=o0.typ;
else if(op=="round" || op=="floor") otp="integer";
else if(op=="sqrt" || op=="sin" || op=="cos" || op=="ln") otp="real";
if(o0.typ=="real") { f32[0]=v0; v0=f32[0]; }
if(op=="neg" ) out = -v0;
if(op=="abs" ) out = Math.abs(v0);
if(op=="floor")out = Math.floor(v0);
if(op=="round")out = Math.round(v0);
if(op=="truncate") out = Math.trunc(v0);
if(op=="sqrt") out = Math.sqrt(v0);
if(op=="ln" ) out = Math.log(v0);
if(op=="sin" ) out = Math.sin(v0*Math.PI/180);
if(op=="cos" ) out = Math.cos(v0*Math.PI/180);
if(op=="ln" && v0<=0) throw "e";
if(otp=="real") { f32[0]=out; out=f32[0]; }
os.push({typ:otp, val:out});
}
else if(["eq","ge","gt","le","lt","ne"].indexOf(op)!=-1) {
var o1=os.pop(), o0=os.pop(), v0=o0.val, v1=o1.val, out=false;
if(op=="eq") out=v0==v1;
if(op=="ge") out=v0>=v1;
if(op=="gt") out=v0> v1;
if(op=="le") out=v0<=v1;
if(op=="lt") out=v0< v1;
if(op=="ne") out=v0!=v1;
os.push({typ:"boolean",val:out});
}
else if(["and","or"].indexOf(op)!=-1) {
var b2 = os.pop(), b1 = os.pop(), v1=b1.val, v2 = b2.val, ints=(b1.typ=="integer"), out;
if(op=="and") out = ints ? (v1&v2) : (v1&&v2);
if(op=="or" ) out = ints ? (v1|v2) : (v1||v2);
os.push({typ:ints?"integer":"boolean", val:out});
}
else if(op=="not") {
var b=os.pop(), v=b.val, ints=b.typ=="integer";
var out = ints ? (~v) : (!v);
os.push({typ:ints?"integer":"boolean", val:out});
}
else if(op=="if") {
var proc = os.pop(), cnd = os.pop().val; //console.log(cnd);
if(cnd) FromPS.addProc(proc, es);//FromPS.callProcedure(proc, file, os, ds, es, gs, gst, genv);
}
else if(op=="ifelse") {
var proc2 = os.pop(), proc1 = os.pop(), cnd = os.pop().val;
FromPS.addProc(cnd?proc1:proc2, es);
}
else if(op=="exec" || op=="stopped") { var obj = os.pop();
if(op=="stopped") FromPS.addProc({typ:"procedure",val:[{typ:"boolean", val:false}]},es); //os.push({typ:"boolean", val:false});
if(obj.typ=="procedure") FromPS.addProc(obj, es);
else if(obj.typ=="name" || obj.typ=="operator" || obj.typ=="real" || obj.typ=="array") FromPS.addProc({typ:"procedure",val:[obj]},es);
else { console.log(obj); throw "unknown executable type: "+obj.typ; }
}
else if(op=="dup" ) { var v=os.pop(); os.push(v,v); }
else if(op=="exch") { os.push(os.pop(), os.pop()); }
else if(op=="copy") {
var n = os.pop(); //console.log(n);
if(n.typ=="integer") { var els=[]; for(var i=0; i<n.val; i++) els[n.val-1-i] = os.pop();
for(var i=0; i<n.val; i++) os.push(els[i]);
for(var i=0; i<n.val; i++) os.push(els[i]); }
else if(n.typ=="array") {
var m = os.pop().val;
for(var i=0; i<m.length; i++) { n.val[i]=m[i]; if(m[i].val==null) { console.log(ds); throw "e"; } }
os.push(n);
}
else if(n.typ=="dict") {
var m = os.pop().val;
for(var prp in m) { n.val[prp]=m[prp]; }
os.push(n);
}
else throw "e";
}
else if(op=="roll") { var j=os.pop().val, n = os.pop().val;
var els = []; for(var i=0; i<n; i++) els.push(os.pop()); els.reverse();
j = (n+j)%n;
for(var i=0; i<j; i++) els.unshift(els.pop());
for(var i=0; i<n; i++) os.push(els[i]);
}
else if(op=="index") { var n=os.pop().val; os.push(os[os.length-1-n]); }
else if(op=="transform" || op=="itransform" || op=="dtransform" || op=="idtransform") {
var m = os.pop(), y=0, x=0; //console.log(m);
if(m.typ=="array") { m = FromPS.readArr(m.val); y = os.pop().val; }
else { y = m.val; m = gst.ctm.slice(0); }
if(op=="itransform"||op=="idtransform") { UDOC.M.invert(m); }
x = os.pop().val;
var np = UDOC.M.multPoint(m, [x,y]);
if(op=="dtransform"||op=="idtransform") { np[0]-=m[4]; np[1]-=m[5]; }
//if(isNaN(np[0])) { console.log(m,gst.ctm.slice(0),x,y); throw "e"; }
os.push({typ:"real",val:np[0]},{typ:"real",val:np[1]});
}
else if(op=="pop" || op=="srand" || op=="==" ) { os.pop(); }
else if(op=="rand") { os.push({typ:"integer",val:Math.floor(Math.random()*0x7fffffff)}); }
else if(op=="put" ) {
var val=os.pop(), o=os.pop(), obj=os.pop(), otp=obj.typ; //console.log(obj,o,val); //throw "e";
if(otp=="array") obj.val[o.val] = val;
else if(otp=="dict") obj.val[o.val.slice(1)]=val;
else if(otp=="string") obj.val[o.val] = val.val;
else throw otp+" e";
//.val.slice(1), obj=os.pop(); obj.val[key]=obj.typ=="string" ? val.val : val;
}
else if(op=="get" ) {
var o=os.pop(), obj=os.pop(), otp=obj.typ; // console.log(o, obj);
if (otp=="string") os.push({typ:"integer",val:obj.val[o.val]});
else if(otp=="array" ) os.push(obj.val[o.val]);
else if(otp=="dict" ) {var v =obj.val[o.val.slice(1)]; /*if(v==null) { console.log(obj.val, o.val); throw "e"; }*/ os.push(v); }
else throw "getting from unknown type "+ obj.typ; //os.push(obj.val[key]);
}
else if(op=="load") { var key=os.pop().val.slice(1), val = FromPS.getFromStacks(key, ds);
if(val==null) { console.log(key, ds); throw "e"; } os.push(val); }
else if(op=="where"){ var key=os.pop().val.slice(1), dct=FromPS.where(key,ds); //console.log(dct);
if(dct!=null) os.push({typ:"dict",val:dct}); os.push({typ:"boolean",val:dct!=null}); }
else if(op=="store"){
var val=os.pop(), key=os.pop().val.slice(1), dct=FromPS.where(key,ds); //console.log(dct, key); throw "e";
if(dct==null) dct=ds[ds.length-1]; dct[key]=val; }
else if(op=="repeat" ) {
var proc=os.pop(), intg=os.pop().val;
es.push({typ:"name",val:op+"---", ctx:{ proc:proc, cur:0, cnt:intg }});
}
else if(op=="repeat---") {
var ctx = tok.ctx;
if(ctx.cur<ctx.cnt) { es.push(tok); FromPS.addProc(ctx.proc, es); ctx.cur++; }
}
else if(op=="for" ) {
var proc=os.pop(), liV=os.pop(), icV=os.pop(), itV=os.pop();
es.push({typ:"name",val:op+"---", ctx:{ proc:proc, isInt:(itV.typ=="integer" && icV.typ=="integer"),
init:itV.val, inc:icV.val, limit:liV.val }});
}
else if(op=="for---") {
var ctx = tok.ctx;
if(ctx.isInt) {
if((ctx.inc>0 && ctx.init<=ctx.limit) || (ctx.inc<0 && ctx.init>=ctx.limit)) {
es.push(tok); FromPS.addProc(ctx.proc, es);
os.push({typ:"integer",val:ctx.init}); ctx.init+=ctx.inc;
}
}
else {
var lf = new Float32Array(1);
lf[0]=ctx.limit; ctx.limit=lf[0];
lf[0]=ctx.inc ; ctx.inc =lf[0];
lf[0]=ctx.init;
if((ctx.inc>0 && lf[0]<=ctx.limit) || (ctx.inc<0 && lf[0]>=ctx.limit)) {
es.push(tok); FromPS.addProc(ctx.proc, es);
os.push({typ:"real",val:lf[0]}); lf[0]+=ctx.inc; ctx.init=lf[0];
}
}
}
else if(op=="loop" ) {
var proc=os.pop();
es.push({typ:"name",val:op+"---", ctx:{ proc:proc }});
}
else if(op=="loop---") {
var ctx = tok.ctx;
FromPS.addProc(ctx.proc, es);
}
else if(op=="forall") {
var proc = os.pop(), obj = os.pop();
es.push({typ:"name",val:op+"---",ctx:[proc,obj,0]});
}
else if(op=="forall---") {
var ctx=tok.ctx, proc=ctx[0],obj=ctx[1],i=ctx[2];
if(obj.typ=="dict") {
var keys = Object.keys(obj.val); //console.log(keys, obj.val, proc);
if(i<keys.length) {
es.push(tok); FromPS.addProc(proc, es);
os.push({typ:"name",val:"/"+keys[i]});
os.push(obj.val[keys[i]]); ctx[2]++;
//console.log(keys[i], obj.val[keys[i]]);
//for(var p in obj.val) { FromPS.addProcedure(proc.val, file); FromPS.addProcedure([obj.val[p]], file); }
}
}
else if(obj.typ=="procedure" || obj.typ=="array") {
if(i<obj.val.length) {
es.push(tok); FromPS.addProc(proc, es);
os.push(obj.val[i]); ctx[2]++;
}
//for(var i=obj.val.length-1; i>=0; i--) { FromPS.addProcedure(proc.val, file); FromPS.addProcedure([obj.val[i]], file); }
}
else { console.log(proc, obj); throw "forall: unknown type: "+obj.typ; }
}
else if(op=="exit") {
var i = es.length-1;
while(i!=0 && (es[i].typ!="name" || !es[i].val.endsWith("---"))) i--;
if(i!=0) while(es.length>i) es.pop();
//console.log(es,i); throw "e";
}
else if(op=="bind") {
/* var v=os.pop(), prc=v.val; os.push(v);
for(var i=0; i<prc.length; i++){
var nop = FromPS.getOperator(prc[i].val, ds);
//if(nop!=null) prc[i]=nop; // missing !!!
}*/
}
else if(op=="xcheck") {
var obj = os.pop(), typ=obj.typ;
os.push({typ:"boolean",val:(typ=="procedure")});
//console.log(obj); throw "e";
}
else if(op=="status" ) { var str = os.pop(); os.push({typ:"boolean",val:false}); }
else if(op=="cachestatus") { for(var i=0; i<7; i++) os.push({typ:"integer",val:5000}); }
else if(op=="setcachelimit") { os.pop(); }
else if(op=="type" ) {
var o = os.pop();
var tps = {"name":"nametype","dict":"dicttype","boolean":"booleantype","procedure":"operatortype","string":"stringtype","null":"nulltype",
"integer":"integertype","array":"arraytype","operator":"operatortype","real":"realtype"};
if(tps[o.typ]==null) { console.log(o); throw o.typ; }
os.push({typ:"name",val:"/"+tps[o.typ]})
}
else if(op=="save" ) { os.push({typ:"state",val:JSON.parse(JSON.stringify(gst))}); }
else if(op=="restore" ) { gst = env.gst = os.pop().val; }
else if(op=="gsave" ) { gs.push(JSON.parse(JSON.stringify(gst))); }
else if(op=="grestore") { gst = env.gst = gs.pop(); }
else if(op=="grestoreall") { while(gs.length!=0) gst = env.gst = gs.pop(); }
else if(op=="usertime" || op=="realtime") os.push({typ:"integer",val:(op=="usertime"?(Date.now()-otime):Date.now())});
else if(op=="flush" || op=="readonly" || op=="executeonly") {}
else if(op=="flushfile") os.pop();
else if(op=="filter") {
var fname = os.pop().val.slice(1), sarr;
if(fname=="ASCII85Decode") {
var sfile = os.pop().val; sarr = FromPS.F.ASCII85Decode(sfile);
}
else if(fname=="RunLengthDecode") {
var sfile = os.pop().val; sarr = FromPS.F.RunLengthDecode(sfile);
}
else if(fname=="SubFileDecode") {
var sfile = os.pop().val; sarr = new Uint8Array(sfile);
}
else { console.log(os); throw fname; }
os.push({typ:"file", val:{buff:sarr, off:0, stk:[], env:{pckn:false}}});
}
else if(op=="begincmap" || op=="endcmap") {}
else if(op=="begincodespacerange"||op=="beginbfrange"||op=="beginbfchar") { env.cmnum = os.pop().val; }
else if(op=="endcodespacerange" ||op=="endbfrange" ||op=="endbfchar" ) {
var cl = (op=="endbfrange"?3:2);
var pn = op.slice(3), dct = ds[ds.length-1], bpc=0;
if(dct[pn]==null) dct[pn]=[];
for(var i=0; i<env.cmnum; i++) {
var vs=[];
for(var j=cl-1; j>=0; j--) {
var ar=os.pop(), av=ar.val, nv;
if(ar.typ=="string") { nv = FromPS.strToInt(av); if(j==0) bpc=av.length; }
else { nv = []; for(var k=0; k<av.length; k++) nv.push(FromPS.strToInt(av[k].val)); }
vs[j]=nv;
}
dct[pn] = dct[pn].concat(vs);
}
if(op!="endcodespacerange") dct["bpc"] = bpc; // bytes per input character
}
else if(Oprs) Oprs(op, os, ds, es, gs, env, genv);
else { console.log(val, op); console.log(ds, os); throw "e"; }
}
}
return true;
}
FromPS.strToInt = function(str) { var v=0; for(var i=0; i<str.length; i++) v = (v<<8)|str[i]; return v; }
FromPS.checkPageStarted = function(env,genv) { if(!env.pgOpen) { genv.StartPage(env.bb[0], env.bb[1], env.bb[2], env.bb[3]); env.pgOpen = true; } }
FromPS.F = {
HexDecode : function(file) {
function num(cc) {
if(48<=cc && cc<= 57) return cc-48;
if(65<=cc && cc<= 70) return 10+cc-65;
if(97<=cc && cc<=102) return 10+cc-97;
throw "e";
}
//console.log(FromPS.B.readASCII(file.buff, 0, file.buff.length)); throw "e";
var arr = [], i=file.off;
while(true) {
if(file.buff[i]==0x3e) break;
while(FromPS.isWhite(file.buff[i])) i++;
var c0 = num(file.buff[i]); i++;
if(file.buff[i]==0x3e) { arr.push(c0<<4); break; }
while(FromPS.isWhite(file.buff[i])) i++;
var c1 = num(file.buff[i]); i++;
arr.push((c0<<4) + c1);
}
//console.log(file.buff.length, arr);
return new Uint8Array(arr);;
},
ASCII85Decode : function(file) {
var pws = [85*85*85*85, 85*85*85, 85*85, 85, 1];
var arr = [], i=0, tc=0, off=file.off;
while(true) {
if(off>=file.buff.length) throw "e";
var cc = file.buff[off]; off++;
if(FromPS.isWhite(cc)) continue;
if(cc==126) {
if(i!=0) {
if(i==3) { arr.push(((tc>>>24)&255)); }
if(i==4) { arr.push(((tc>>>24)&255), ((tc>>>16)&255)); }
var lb = (5-i)<<3; // i=2: 24, i=3: 16 ...
var nn=((tc>>>lb)&255); tc=(tc&((1<<lb)-1)); if(tc!=0)nn++; arr.push(nn);
}
file.off=off+1; //console.log(arr.join(","));
return new Uint8Array(arr);
}
if(cc==122) { arr.push(0,0,0,0); continue; }
if(cc<33 || cc-33>84) throw "e";
tc += (cc-33)*pws[i]; i++;
if(i==5) {
arr.push((tc>>>24)&255); arr.push((tc>>>16)&255);
arr.push((tc>>> 8)&255); arr.push((tc>>> 0)&255);
i=0; tc=0;
}
}
},
RunLengthDecode : function(file) {
var arr = [], off=file.off;
while(true) {
if(off>=file.buff.length) { console.log(arr); throw "e"; }
var cc = file.buff[off]; off++;
if(cc==128) { file.off=off; return new Uint8Array(arr); }
if(cc< 128) { for(var i=0; i<cc+1 ; i++) arr.push(file.buff[off+i]); off+=cc+1; }
else { for(var i=0; i<257-cc; i++) arr.push(file.buff[off] ); off++; }
}
},
FlateDecode : function(file) {
//console.log("FlateDecode", file);
//if(file.buff.length==26770) { console.log(FromPS.B.readASCII(file.buff, 0, file.buff.length)); throw "e"; }
var b = file.buff, ub = new Uint8Array(b.buffer,file.off,b.length); //console.log(ub);
var bytes = pako["inflate"](ub);
return bytes;
}
}
FromPS.B = {
readUshort : function(buff,p) { return (buff[p]<< 8) | buff[p+1]; },
readUint : function(buff,p) { return (buff[p]*(256*256*256)) + ((buff[p+1]<<16) | (buff[p+2]<< 8) | buff[p+3]); },
readASCII : function(buff,p,l){ var s = ""; for(var i=0; i<l; i++) s += String.fromCharCode(buff[p+i]); return s; }
}
FromPS.nrm = function(v) { return Math.max(0,Math.min(1,v)); }
FromPS.makeArr = function(a,typ) { var na=[]; for(var i=0; i<a.length; i++) na.push({typ:typ,val:a[i]}); return na; }
FromPS.readArr = function(a ) { var na=[]; for(var i=0; i<a.length; i++) na.push(a[i].val ); return na; }
FromPS.readStr = function(a ) { var s =""; for(var i=0; i<a.length; i++) s+=String.fromCharCode(a[i]); return s; }
FromPS.getFromStacks = function(name, ds)
{
//console.log(ds);
var di = ds.length-1;
while(di>=0) { if(ds[di][name]!=null) return ds[di][name]; di--; }
return null;
}
FromPS.where = function(name, ds)
{
var di = ds.length-1;
while(di>=0) { if(ds[di][name]!=null) return ds[di] ; di--; }
return null;
}
FromPS.skipWhite = function(file) {
var i = file.off, buff=file.buff, isWhite = FromPS.isWhite;
while(isWhite(buff[i]) || buff[i]==37) {
while(isWhite(buff[i])) i++; // not the first whitespace
if(buff[i]==37) { while(i<buff.length && !FromPS.isEOL(buff[i])) i++; i++; } // comments
}
file.off = i;
}
FromPS.getToken = function(es, ds) {
if(es.length==0) return null;
var src = es[es.length-1];
if(src.typ=="procedure") {
var tok = src.val[src.off]; src.off++;
if(src.off==src.val.length) es.pop();
return tok;
}
if(src.typ=="name") { es.pop(); return src; }
var ftok = FromPS.getFToken(src.val, ds);
if(ftok==null) { es.pop(); if(es.length!=0) ftok = FromPS.getFToken(es[es.length-1].val, ds); }
return ftok;
}
FromPS.getFToken = function(file, ds) {
FromPS.skipWhite(file);
var isWhite = FromPS.isWhite, isSpecl = FromPS.isSpecl;
var i = file.off, buff=file.buff, tok = null;
if(i>=buff.length) return null;
var cc = buff[i], ch = String.fromCharCode(cc); i++;
if(ch=="(") {
var dpth=0, end=i;
while(!(buff[end]==41 && dpth==0)) { if(buff[end]==40) dpth++; if(buff[end]==41) dpth--; if(buff[end]==92) end++; end++; }
var str = [];
for(var j=0; j<end-i; j++) str.push(buff[i+j]);
i = end+1;
str = FromPS.getString(str);
tok = {typ:"string", val:str};
}
else if(ch=="{" || ch=="}" || ch=="[" || ch=="]") { tok = {typ:"name", val:ch}; }
else if((ch=="<" && buff[i]==60) || (ch==">" && buff[i]==62)) { tok = {typ:"name", val:ch=="<" ? "<<" : ">>"}; i++; }
else if(ch=="<") {
var end = i; while(buff[end]!=62) end++;
var str = FromPS.readHex({buff:buff,off:i},(end-i)>>>1);
tok = {typ:"string",val:str}; i = end+1;
}
else {
var end = i;
while(end<buff.length && !isWhite(buff[end]) && (!isSpecl(buff[end]) || (buff[end]==47&&buff[end-1]==47&&end==i) )) end++; // read two slashes
var name = FromPS.B.readASCII(buff, i-1, end-i+1);
i = end;
var num = parseFloat(name);
if(false) {}
else if(name=="true" || name=="false") tok = {typ:"boolean", val:name=="true"};
else if(!isNaN(num)) {
var f32 = new Float32Array(1); f32[0]=num; num=f32[0];
tok = {typ:name.indexOf(".")==-1?"integer":"real", val:num};
}
else {
if(name.slice(0,2)=="//") {
var nn = name.slice(2);
var sbs = FromPS.getFromStacks(nn, ds);
if(sbs==null) throw "e";
tok = sbs;
}
else tok = {typ:"name", val:name};
}
}
file.off = i;
return tok;
}
// ( ) < > [ ] { } % /
FromPS.isSpecl = function(cc) { return [ 40,41, 60,62, 91,93, 123,125, 37, 47 ].indexOf(cc)!=-1; }
FromPS.isWhite = function(cc) { return cc==9 || cc==10 || cc==12 || cc==13 || cc==32; }
FromPS.isEOL = function(cc) { return cc==10 || cc==13; }
FromPS.getString = function(str) {
var s=[];
var m0 = ["n" , "r" , "t" , "b" , "f" , "\\", "(", ")", " ", "/"];
var m1 = ["\n", "\r", "\t", "", " ", "\\", "(", ")", " ", "/"];
for(var i=0; i<str.length; i++) {
var cc = str[i], ch = String.fromCharCode(cc);
if(ch=="\\") {
var nx = String.fromCharCode(str[i+1]); i++;
if(nx=="\r" || nx=="\n") continue;
var idx = m0.indexOf(nx);
if(idx!=-1) s.push(m1[idx].charCodeAt(0));
else {
var cod = nx + String.fromCharCode(str[i+1]) + String.fromCharCode(str[i+2]); i+=2;
s.push(parseInt(cod,8));
}
}
else s.push(cc);
}
return s;
}
FromPS.makeString = function(arr) {
var m0 = ["n" , "r" , "t" , "b" , "f" , "\\", "(", ")"];
var m1 = ["\n", "\r", "\t", "", " ", "\\", "(", ")"];
var out = [];
for(var i=0; i<arr.length; i++) {
var b = arr[i];
var mi = m1.indexOf(String.fromCharCode(b));
if(mi==-1) out.push(b);
else out.push(92, m0[mi].charCodeAt(0));
}
return out;
}
FromPS.readHex = function(fl, l)
{
var i=0, j=-1, val=[];
while(true) {
var cc = fl.buff[fl.off]; fl.off++;
var ci=0;
if(47<cc && cc<58) ci=cc-48;
else if(96<cc && cc<103) ci=10+cc-97;
else if(64<cc && cc<71 ) ci=10+cc-65;
else continue;
if(j==-1) j=ci;
else { val[i]=(j<<4)|ci; j=-1; i++; if(i==l) break; }
}
return val;
}
function FromWMF ()
{
}
FromWMF.Parse = function(buff, genv)
{
buff = new Uint8Array(buff); var off=0;
var prms = {fill:false, strk:false, bb:[0,0,1,1], lbb:[0,0,1,1], scl:1, fnt:{nam:"Arial",hgh:25,und:false,orn:0,chrst:0}, tclr:[0,0,0], talg:0};
var rS = FromWMF.B.readShort, rU = FromWMF.B.readUshort, rU32 = FromWMF.B.readUint;
var key = rU32(buff,0);
if(key==0x9AC6CDD7) {
off = 6;
var dpi = rS(buff, off+8); prms.scl=120/dpi;
for(var i=0; i<4; i++) { prms.bb[i] = Math.round(rS(buff,off)*prms.scl); off+=2; }
off+=2;
//console.log(prms.bb, dpi);
off += 6;
//console.log(bb, dpi);
}
genv.StartPage(prms.bb[0],prms.bb[1],prms.bb[2],prms.bb[3]);
var gst = UDOC.getState(prms.bb);
var type = rU(buff, off); off+=2;
var hSiz = rU(buff, off); off+=2;
var vrsn = rU(buff, off); off+=2;
var size = rU32(buff, off); off+=4;
var nomb = rU(buff, off); off+=2;
var mRec = rU32(buff, off); off+=4;
var nomb = rU(buff, off); off+=2;
//console.log(type, hSiz, vrsn, size, nomb, mRec, nomb);
//gst.colr= [0.8,0,0.8]; // purple fill color
//gst.pth = { cmds:["M","L","L","L","Z"], crds:[20,20,80,20,80,80,20,80] }; // a square
//genv.Fill(gst);
//console.log(buff.slice(0,64));
var tab = [];
var opn=0;
while(true) {
var siz = rU32(buff, off)<<1; off+=4;
var fnc = rU (buff, off); off+=2;
var fnm = FromWMF.K[fnc];
var loff = off;
//if(opn++==24) break;
var obj = null;
//console.log(fnm, siz);
if(false) {}
else if(fnm=="EOF") break;
else if(fnm=="ESCAPE") {
var esf = rU (buff, off); loff+=2;
var fnm2 = FromWMF.K2[esf];
console.log(fnm, fnm2);
}
else if(fnm=="SETMAPMODE" || fnm=="SETPOLYFILLMODE" || fnm=="SETBKMODE") {}
else if(fnm=="SELECTOBJECT") {
var ind = rU(buff, loff); loff+=2;
var co = tab[ind]; //console.log(co);
if(co.t=="br") {
prms.fill=co.stl!=1;
if (co.stl==0) {}
else if(co.stl==1) {}
else throw co.stl+" e";
gst.colr=co.clr;
//if(co.htc!=0) throw co.stl+" "+co.htc+" e";
}
else if(co.t=="pn") {
var stl = (co.stl&7);
prms.strk=stl!=5;
if (stl==0 || stl==6) gst.lwidth = co.px;
else if(stl==5) {}
else throw stl+" e";
if((co.stl&0x1000)!=0) gst.ljoin=2; // bevel
else if((co.stl&0x2000)!=0) gst.ljoin=0; // miter
else gst.ljoin = 1; // round
gst.COLR=co.clr;
}
else if(co.t=="fn") {
prms.fnt = co;
gst.font.Tf = co.nam;
gst.font.Tfs = Math.abs(co.hgh);
gst.font.Tun = co.und;
}
else throw "e";
}
else if(fnm=="DELETEOBJECT") {
var ind = rU(buff, loff); loff+=2;
tab[ind]=null;
}
else if(fnm=="SETWINDOWORG" || fnm=="SETWINDOWEXT") {
var coff = fnm=="SETWINDOWORG" ? 0 : 2;
prms.lbb[coff+1] = rS(buff, loff); loff+=2;
prms.lbb[coff ] = rS(buff, loff); loff+=2;
FromWMF._updateCtm(prms, gst);
}
else if(fnm=="CREATEBRUSHINDIRECT") {
obj = {t:"br"};
obj.stl = rU(buff, loff); loff+=2;
obj.clr = [buff[loff]/255, buff[loff+1]/255, buff[loff+2]/255]; loff+=4;
obj.htc = rU(buff, loff); loff+=2;
}
else if(fnm=="CREATEPENINDIRECT") {
obj = {t:"pn"};
obj.stl = rU(buff, loff); loff+=2;
obj.px = rS(buff, loff); loff+=2;
obj.py = rS(buff, loff); loff+=2; //console.log(stl, px, py);
obj.clr = [buff[loff]/255, buff[loff+1]/255, buff[loff+2]/255]; loff+=4;
}
else if(fnm=="CREATEFONTINDIRECT") {
obj = {t:"fn", nam:""};
//obj.stl = rU(buff, loff); loff+=2;
obj.hgh = rS(buff, loff); loff += 2;
loff += 2*2;
obj.orn = rS(buff, loff)/10; loff+=2;
var wgh = rS(buff, loff); loff+=2; //console.log(wgh);
obj.und = buff[loff+1]; loff += 2;
obj.stk = buff[loff ]; obj.chrst = buff[off+1]; loff += 2; //console.log(obj.chrst);
loff+=4;
//console.log(PUtils.readASCII(buff, off, 200));
while(buff[loff]!=0) { obj.nam+=String.fromCharCode(buff[loff]); loff++; }
if(wgh>500) obj.nam+="-Bold";
//console.log(wgh, obj.nam);
//console.log(obj);
}
else if(fnm=="CREATEPALETTE") { obj = {t:"pl"}; }
else if(fnm=="SETTEXTCOLOR") prms.tclr = [buff[loff]/255, buff[loff+1]/255, buff[loff+2]/255];
else if(fnm=="SETTEXTALIGN") prms.talg = rU(buff, loff);
else if(fnm=="MOVETO" ) { UDOC.G.moveTo(gst, rS(buff,loff+2), rS(buff,loff)); }
else if(fnm=="LINETO" ) {
if(gst.pth.cmds.length==0) { var im=gst.ctm.slice(0); UDOC.M.invert(im); var p = UDOC.M.multPoint(im, gst.cpos); UDOC.G.moveTo(gst, p[0], p[1]); }
UDOC.G.lineTo(gst, rS(buff,loff+2), rS(buff,loff)); var ofill=prms.fill; prms.fill=false; FromWMF._draw(genv, gst, prms); prms.fill=ofill;
}
else if(fnm=="POLYPOLYGON") {
var nop = rU(buff, loff); loff+=2;
var pi = loff; loff+= nop*2;
for(var i=0; i<nop; i++) {
var ppp = rU(buff, pi+i*2);
loff = FromWMF._drawPoly(buff,loff,ppp,gst, true);
}
FromWMF._draw(genv, gst, prms);
}
else if(fnm=="POLYGON" || fnm=="POLYLINE") {
var ppp = rU(buff, loff); loff+=2;
loff = FromWMF._drawPoly(buff,loff,ppp,gst, fnm=="POLYGON");
var ofill = prms.fill; prms.fill = (ofill && fnm=="POLYGON");
FromWMF._draw(genv, gst, prms);
prms.fill = ofill;
}
else if(fnm=="RECTANGLE" || fnm=="ELLIPSE") {
var y1 = rS(buff, loff); loff+=2;
var x1 = rS(buff, loff); loff+=2;
var y0 = rS(buff, loff); loff+=2;
var x0 = rS(buff, loff); loff+=2;
if(fnm=="RECTANGLE") {
UDOC.G.moveTo(gst, x0,y0); UDOC.G.lineTo(gst, x1,y0); UDOC.G.lineTo(gst, x1,y1); UDOC.G.lineTo(gst, x0,y1);
} else {
var x = (x0+x1)/2, y = (y0+y1)/2;
UDOC.G.arc(gst,x,y,(y1-y0)/2,0,2*Math.PI, false);
}
UDOC.G.closePath(gst);
var ofill = prms.fill; prms.fill = true;
FromWMF._draw(genv, gst, prms);
prms.fill = ofill;
}
else if(fnm=="STRETCHDIB") {
var rop = rU32(buff, loff); loff+=4;
var cu = rU(buff, loff); loff+=2;
var sh = rS(buff, loff); loff+=2;
var sw = rS(buff, loff); loff+=2;
var sy = rS(buff, loff); loff+=2;
var sx = rS(buff, loff); loff+=2;
var hD = rS(buff, loff); loff+=2;
var wD = rS(buff, loff); loff+=2;
var yD = rS(buff, loff); loff+=2;
var xD = rS(buff, loff); loff+=2;
//console.log(rop, cu, sx,sy,sw,sh,"-",dx,dy,dw,dh);
var img = FromWMF._loadDIB(buff, loff);
var ctm = gst.ctm.slice(0);
gst.ctm = [1,0,0,1,0,0];
UDOC.M.scale(gst.ctm, wD, -hD);
UDOC.M.translate(gst.ctm, xD, yD+hD);
UDOC.M.concat(gst.ctm, ctm);
genv.PutImage(gst, img, sw, sh);
gst.ctm = ctm;
}
else if(fnm=="EXTTEXTOUT") {
var rfy = rS(buff, loff); loff+=2;
var rfx = rS(buff, loff); loff+=2;
gst.font.Tm = [1,0,0,-1,0,0];
UDOC.M.rotate(gst.font.Tm, prms.fnt.orn*Math.PI/180);
UDOC.M.translate(gst.font.Tm, rfx, rfy);
var alg = prms.talg;
if ((alg&6)==6) gst.font.Tal = 2;
else if((alg&7)==0) gst.font.Tal = 0;
else throw alg+" e";
if((alg&24)==24) {} // baseline
else if((alg&24)==0) UDOC.M.translate(gst.font.Tm, 0, gst.font.Tfs);
else throw "e";
var crs = rU(buff, loff); loff+=2;
var ops = rU(buff, loff); loff+=2; //if(ops!=0) throw "e";
if(ops&4) loff+=8;
//console.log(buff.slice(loff, loff+crs));
var str = "";
for(var i=0; i<crs; i++) {
var cc = buff[loff+i];
if(cc>127) { i++; cc=(cc<<8)|buff[loff+i]; }
str+=String.fromCharCode(cc); //console.log(gst.font.Tfs, str);
}
//console.log(str);
//for(var i=0; i<crs; i++) str+=String.fromCharCode(rU(buff,loff+i*2)); //console.log(gst.font.Tfs, str);
var oclr = gst.colr; gst.colr = prms.tclr;
genv.PutText(gst, str, str.length*gst.font.Tfs*0.5); gst.colr=oclr;
}
else {
console.log(fnm, siz);
}
if(obj!=null) {
var li = 0;
while(tab[li]!=null) li++;
tab[li]=obj;
}
off+=siz-6;
}
genv.ShowPage(); genv.Done();
}
FromWMF._loadDIB = function(buff, off) {
var rS = FromWMF.B.readShort, rU = FromWMF.B.readUshort, rU32 = FromWMF.B.readUint;
var hsize = rU32(buff, off); off+=4;
var w, h, cu;
if(hsize==0xc) throw "e";
else {
w = rU32(buff, off); off+=4;
h = rU32(buff, off); off+=4;
var ps = rU(buff, off); off+=2; if(ps!= 1) throw "e";
var bc = rU(buff, off); off+=2; if(bc!=1 && bc!=24 && bc!=32) throw bc+" e";
//console.log(w,h,ps,bc);
var cmpr = rU32(buff, off); off+=4; if(cmpr!=0) throw "e";
var size = rU32(buff, off); off+=4;
var xppm = rU32(buff, off); off+=4;
var yppm = rU32(buff, off); off+=4;
cu = rU32(buff, off); off+=4; //if(cu!=0) throw cu+" e"; // number of colors used ... 0: all colors
var ci = rU32(buff, off); off+=4;
//console.log(cmpr, size, xppm, yppm, cu, ci);
}
var area = w*h;
var img = new Uint8Array(area*4);
var rl = Math.floor(((w * ps * bc + 31) & ~31) / 8);
if(bc==1 )
for(var y=0; y<h; y++) {
var j = off+cu*4+(h-1-y)*rl;
for(var x=0; x<w; x++) {
var qi = (y*w+x)<<2, ind = (buff[j+(x>>>3)]>>>(7-(x&7)))&1;
img[qi ] = buff[off+ind*4+2];
img[qi+1] = buff[off+ind*4+1];
img[qi+2] = buff[off+ind*4+0];
img[qi+3] = 255;
}
}
if(bc==24) {
for(var y=0; y<h; y++)
for(var x=0; x<w; x++) {
var qi = (y*w+x)<<2, ti=off+(h-1-y)*rl+x*3;
img[qi ] = buff[ti+2];
img[qi+1] = buff[ti+1];
img[qi+2] = buff[ti+0];
img[qi+3] = 255;
}
}
if(bc==32) {
for(var y=0; y<h; y++)
for(var x=0; x<w; x++) {
var qi = (y*w+x)<<2, ti=off+(h-1-y)*rl+x*4;
img[qi ] = buff[ti+2];
img[qi+1] = buff[ti+1];
img[qi+2] = buff[ti+0];
img[qi+3] = buff[ti+3];
}
}
return img;
}
FromWMF._updateCtm = function(prms, gst) {
var mat = [1,0,0,1,0,0];
var lbb = prms.lbb, bb = prms.bb;
UDOC.M.translate(mat, -lbb[0],-lbb[1]);
UDOC.M.scale(mat, 1/lbb[2], 1/lbb[3]);
UDOC.M.scale(mat, bb[2]-bb[0],bb[3]-bb[1]);
UDOC.M.translate(mat, bb[0],bb[1]);
gst.ctm = mat;
}
FromWMF._draw = function(genv, gst, prms) {
if(prms.fill ) genv.Fill (gst, false);
if(prms.strk && gst.lwidth!=0) genv.Stroke(gst, false);
UDOC.G.newPath(gst);
}
FromWMF._drawPoly = function(buff, off, ppp, gst, cls) {
var rS = FromWMF.B.readShort;
for(var j=0; j<ppp; j++) {
var px = rS(buff, off); off+=2;
var py = rS(buff, off); off+=2;
if(j==0) UDOC.G.moveTo(gst,px,py); else UDOC.G.lineTo(gst,px,py);
}
if(cls) UDOC.G.closePath(gst);
return off;
}
FromWMF.B = {
uint8 : new Uint8Array(4),
readShort : function(buff,p) { var u8=FromWMF.B.uint8; u8[0]=buff[p]; u8[1]=buff[p+1]; return FromWMF.B.int16 [0]; },
readUshort : function(buff,p) { var u8=FromWMF.B.uint8; u8[0]=buff[p]; u8[1]=buff[p+1]; return FromWMF.B.uint16[0]; },
readUint : function(buff,p) { var u8=FromWMF.B.uint8; u8[0]=buff[p]; u8[1]=buff[p+1]; u8[2]=buff[p+2]; u8[3]=buff[p+3]; return FromWMF.B.uint32[0]; },
//readUint : function(buff,p) { return (buff[p]*(256*256*256)) + ((buff[p+1]<<16) | (buff[p+2]<< 8) | buff[p+3]); },
readASCII : function(buff,p,l){ var s = ""; for(var i=0; i<l; i++) s += String.fromCharCode(buff[p+i]); return s; }
}
FromWMF.B.int16 = new Int16Array (FromWMF.B.uint8.buffer);
FromWMF.B.uint16 = new Uint16Array(FromWMF.B.uint8.buffer);
FromWMF.B.uint32 = new Uint32Array(FromWMF.B.uint8.buffer);
FromWMF.C = {
META_EOF : 0x0000,
META_REALIZEPALETTE : 0x0035,
META_SETPALENTRIES : 0x0037,
META_SETBKMODE : 0x0102,
META_SETMAPMODE : 0x0103,
META_SETROP2 : 0x0104,
META_SETRELABS : 0x0105,
META_SETPOLYFILLMODE : 0x0106,
META_SETSTRETCHBLTMODE : 0x0107,
META_SETTEXTCHAREXTRA : 0x0108,
META_RESTOREDC : 0x0127,
META_RESIZEPALETTE : 0x0139,
META_DIBCREATEPATTERNBRUSH : 0x0142,
META_SETLAYOUT : 0x0149,
META_SETBKCOLOR : 0x0201,
META_SETTEXTCOLOR : 0x0209,
META_OFFSETVIEWPORTORG : 0x0211,
META_LINETO : 0x0213,
META_MOVETO : 0x0214,
META_OFFSETCLIPRGN : 0x0220,
META_FILLREGION : 0x0228,
META_SETMAPPERFLAGS : 0x0231,
META_SELECTPALETTE : 0x0234,
META_POLYGON : 0x0324,
META_POLYLINE : 0x0325,
META_SETTEXTJUSTIFICATION : 0x020A,
META_SETWINDOWORG : 0x020B,
META_SETWINDOWEXT : 0x020C,
META_SETVIEWPORTORG : 0x020D,
META_SETVIEWPORTEXT : 0x020E,
META_OFFSETWINDOWORG : 0x020F,
META_SCALEWINDOWEXT : 0x0410,
META_SCALEVIEWPORTEXT : 0x0412,
META_EXCLUDECLIPRECT : 0x0415,
META_INTERSECTCLIPRECT : 0x0416,
META_ELLIPSE : 0x0418,
META_FLOODFILL : 0x0419,
META_FRAMEREGION : 0x0429,
META_ANIMATEPALETTE : 0x0436,
META_TEXTOUT : 0x0521,
META_POLYPOLYGON : 0x0538,
META_EXTFLOODFILL : 0x0548,
META_RECTANGLE : 0x041B,
META_SETPIXEL : 0x041F,
META_ROUNDRECT : 0x061C,
META_PATBLT : 0x061D,
META_SAVEDC : 0x001E,
META_PIE : 0x081A,
META_STRETCHBLT : 0x0B23,
META_ESCAPE : 0x0626,
META_INVERTREGION : 0x012A,
META_PAINTREGION : 0x012B,
META_SELECTCLIPREGION : 0x012C,
META_SELECTOBJECT : 0x012D,
META_SETTEXTALIGN : 0x012E,
META_ARC : 0x0817,
META_CHORD : 0x0830,
META_BITBLT : 0x0922,
META_EXTTEXTOUT : 0x0a32,
META_SETDIBTODEV : 0x0d33,
META_DIBBITBLT : 0x0940,
META_DIBSTRETCHBLT : 0x0b41,
META_STRETCHDIB : 0x0f43,
META_DELETEOBJECT : 0x01f0,
META_CREATEPALETTE : 0x00f7,
META_CREATEPATTERNBRUSH : 0x01F9,
META_CREATEPENINDIRECT : 0x02FA,
META_CREATEFONTINDIRECT : 0x02FB,
META_CREATEBRUSHINDIRECT : 0x02FC,
META_CREATEREGION : 0x06FF
};
FromWMF.C2 = {
NEWFRAME : 0x0001,
ABORTDOC : 0x0002,
NEXTBAND : 0x0003,
SETCOLORTABLE : 0x0004,
GETCOLORTABLE : 0x0005,
FLUSHOUT : 0x0006,
DRAFTMODE : 0x0007,
QUERYESCSUPPORT : 0x0008,
SETABORTPROC : 0x0009,
STARTDOC : 0x000A,
ENDDOC : 0x000B,
GETPHYSPAGESIZE : 0x000C,
GETPRINTINGOFFSET : 0x000D,
GETSCALINGFACTOR : 0x000E,
META_ESCAPE_ENHANCED_METAFILE : 0x000F,
SETPENWIDTH : 0x0010,
SETCOPYCOUNT : 0x0011,
SETPAPERSOURCE : 0x0012,
PASSTHROUGH : 0x0013,
GETTECHNOLOGY : 0x0014,
SETLINECAP : 0x0015,
SETLINEJOIN : 0x0016,
SETMITERLIMIT : 0x0017,
BANDINFO : 0x0018,
DRAWPATTERNRECT : 0x0019,
GETVECTORPENSIZE : 0x001A,
GETVECTORBRUSHSIZE : 0x001B,
ENABLEDUPLEX : 0x001C,
GETSETPAPERBINS : 0x001D,
GETSETPRINTORIENT : 0x001E,
ENUMPAPERBINS : 0x001F,
SETDIBSCALING : 0x0020,
EPSPRINTING : 0x0021,
ENUMPAPERMETRICS : 0x0022,
GETSETPAPERMETRICS : 0x0023,
POSTSCRIPT_DATA : 0x0025,
POSTSCRIPT_IGNORE : 0x0026,
GETDEVICEUNITS : 0x002A,
GETEXTENDEDTEXTMETRICS : 0x0100,
GETPAIRKERNTABLE : 0x0102,
EXTTEXTOUT : 0x0200,
GETFACENAME : 0x0201,
DOWNLOADFACE : 0x0202,
METAFILE_DRIVER : 0x0801,
QUERYDIBSUPPORT : 0x0C01,
BEGIN_PATH : 0x1000,
CLIP_TO_PATH : 0x1001,
END_PATH : 0x1002,
OPEN_CHANNEL : 0x100E,
DOWNLOADHEADER : 0x100F,
CLOSE_CHANNEL : 0x1010,
POSTSCRIPT_PASSTHROUGH : 0x1013,
ENCAPSULATED_POSTSCRIPT : 0x1014,
POSTSCRIPT_IDENTIFY : 0x1015,
POSTSCRIPT_INJECTION : 0x1016,
CHECKJPEGFORMAT : 0x1017,
CHECKPNGFORMAT : 0x1018,
GET_PS_FEATURESETTING : 0x1019,
MXDC_ESCAPE : 0x101A,
SPCLPASSTHROUGH2 : 0x11D8
}
FromWMF.K = [];
FromWMF.K2= [];
(function() {
var inp, out, stt;
inp = FromWMF.C; out = FromWMF.K; stt=5;
for(var p in inp) out[inp[p]] = p.slice(stt);
inp = FromWMF.C2; out = FromWMF.K2; stt=0;
for(var p in inp) out[inp[p]] = p.slice(stt);
//console.log(FromWMF.K, FromWMF.K2);
} )();
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
MIT License
Copyright (c) 2018 Photopea
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
function PDFI ()
{
}
PDFI.Parse = function(buff, genv)
{
buff = new Uint8Array(buff);
var offset = buff.length-5;
while(PSI.B.readASCII(buff,offset,5) != "%%EOF") offset--;
var eoff = offset;
offset--;
while( PSI.isEOL(buff[offset])) offset--;
while(!PSI.isEOL(buff[offset])) offset--;
var xref = parseInt(PSI.B.readASCII(buff, offset+1, eoff-offset-1));
if(isNaN(xref)) throw "e";
var xr = [];
var tr = PDFI.readXrefTrail(buff, xref, xr);
//console.log(xr);
var file = {buff:buff, off:0}, rt = tr["/Root"];
if(rt.typ=="ref") tr["/Root"] = PDFI.getIndirect(rt.ind,rt.gen,file,xr)
var ps = tr["/Root"]["/Pages"];
if(ps.typ=="ref") tr["/Root"]["/Pages"] = PDFI.getIndirect(ps.ind,ps.gen,file,xr)
//console.log(tr);
var stk = [tr["/Root"]["/Pages"]];
while(stk.length!=0) {
var pg = stk.pop();
if(pg["/Type"]=="/Pages") {
var ks = pg["/Kids"];
for(var i=0; i<ks.length; i++) {
if(ks[i].typ=="ref") ks[i] = PDFI.getIndirect(ks[i].ind,ks[i].gen,file,xr)
stk.push(ks[i]);
}
}
}
var time = Date.now();
PDFI.render(tr["/Root"], genv);
genv.Done();
//console.log(Date.now()-time);
}
PDFI.render = function(root, genv)
{
var rbb = root["/Pages"]["/MediaBox"];
var ops = [
"CS","cs","SCN","scn","SC","sc","sh",
"Do", "gs", "ID","EI", "re","cm","y","v","B","B*", "BT","ET",
"Tj","TJ","Tf","Tm","Td","T*",
"Tc","Tw","Tz","TL","Tr","Ts",
"MP","DP","BMC","BDC","EMC","BX","EX", "ri"
];
var prcs = {
"J":"setlinecap",
"j":"setlinejoin",
"w":"setlinewidth",
"d":"setdash",
"M":"setmiterlimit",
"i":"setflat",
"q":"gsave", "Q":"grestore",
"m":"moveto", "l":"lineto", "c":"curveto", "h":"closepath",
"W":"clip", "W*":"eoclip",
"f":"fill","F":"fill","f*":"eofill", "S":"stroke",
"n":"newpath",
"RG" : "/DeviceRGB CS SCN",
"rg" : "/DeviceRGB cs scn",
"G" : "/DeviceGray CS SCN",
"g" : "/DeviceGray cs scn",
"K" : "/DeviceCMYK CS SCN",
"k" : "/DeviceCMYK cs scn",
"TD" : "dup neg TL Td",
"\"" : "exch Tc exch Tw '",
"'" : "T* Tj",
"s" : "h S",
"BI" : "/BI"
}
prcs = PSI.makeProcs(prcs);
var stk = [root["/Pages"]], pi=0;
while(stk.length!=0) {
var pg = stk.pop();
if(pg["/Type"]=="/Pages") {
var ks = pg["/Kids"];
for(var i=ks.length-1; i>=0; i--) stk.push(ks[i]);
continue;
}
pi++; //if(pi!=2) continue;
var cts = pg["/Contents"]; //console.log(pg);
if(cts.length==null) cts = [cts];
var bb = pg["/MediaBox"]; if(bb==null) bb = rbb;
var env = PSI._getEnv(bb); env.pgOpen = true;
var gs = [];
var os = []; // operand stack
var ds = PSI._getDictStack(ops, prcs);
var es = [];
genv.StartPage(bb[0],bb[1],bb[2],bb[3]);
for(var j=0; j<cts.length; j++)
{
var cnt = cts[j]["stream"];
//console.log(PSI.B.readASCII(cnt,0,cnt.length));
es.push({ typ:"file", val: { buff:cnt, off:0, extra:pg } }); // execution stack
var repeat = true;
while(repeat) repeat = PSI.step(os, ds, es, gs, env, genv, PDFI.operator);
}
genv.ShowPage(); //if(pi>23) break;
}
}
PDFI.operator = function(op, os, ds, es, gs, env, genv)
{
//console.log(op);
var gst = env.gst;
var lfi = es.length-1; while(es[lfi].typ!="file") lfi--;
var fle = es[lfi].val;
var res = fle.extra["/Resources"];
if(op=="Do") {
var nam = os.pop().val, xo = res["/XObject"][nam];
//console.log(xo);
var st=xo["/Subtype"], stm = xo["stream"];
if(st=="/Form") {
//console.log(PSI.B.readASCII(stm,0,stm.length));
es.push( {typ:"file", val: { buff:stm, off:0, extra:xo }} );
}
else if(st=="/Image") {
var sms = null; //console.log(xo);
if(xo["/SMask"]) sms = PDFI.getImage(xo["/SMask"], gst);
var w=xo["/Width"], h=xo["/Height"], cs=xo["/ColorSpace"];
var img = PDFI.getImage(xo, gst);
if(xo["/ImageMask"]==true) {
sms = img;
img = new Uint8Array(w*h*4), r0 = gst.colr[0]*255, g0 = gst.colr[1]*255, b0 = gst.colr[2]*255;
for(var i=0; i<w*h*4; i+=4) { img[i]=r0; img[i+1]=g0; img[i+2]=b0; img[i+3]=255; }
}
genv.PutImage(gst, img, w,h, sms);
}
else console.log("Unknown XObject",st);
}
else if(op=="gs") {
var nm = os.pop().val;
var egs = res["/ExtGState"][nm];
for(var p in egs) {
var v = egs[p];
if(p=="/Type") continue;
else if(p=="/CA") gst.CA=v;
else if(p=="/ca") gst.ca=v;
else if(p=="/BM") gst.bmode = v;
else if(p=="/LC") gst.lcap = v;
else if(p=="/LJ") gst.ljoin = v;
else if(p=="/LW") gst.lwidth = v;
else if(p=="/ML") gst.mlimit = v;
else if(p=="/SA") gst.SA = v;
else if(p=="/OPM")gst.OPM = v;
else if(p=="/AIS")gst.AIS = v;
else if(p=="/OP") gst.OP = v;
else if(p=="/op") gst.op = v;
else if(p=="/SMask") { gst.SMask = ""; }
else if(p=="/SM") gst.SM = v;
else if(p=="/BG" || p=="/HT" || p=="/TR" || p=="/UCR") {}
else console.log("Unknown gstate property: ", p, v);
}
}
else if(op=="ID") {
var dic = {};
while(true) { var v = os.pop().val; if(v=="/BI") break; dic[os.pop().val] = v; } fle.off++;
var w=dic["/W"], h=dic["/H"], ar=w*h, img = new Uint8Array(ar*4), cs = dic["/CS"], bpc = dic["/BPC"];
var end = fle.off;
while(!PSI.isWhite(fle.buff[end]) || fle.buff[end+1]!=69 || fle.buff[end+2]!=73) end++;
var stm = fle.buff.slice(fle.off, end); fle.off+=stm.length;
if(dic["/F"]=="/Fl") { stm = PSI.F.FlateDecode({buff:stm, off:0}); delete dic["/F"]; }
if(cs=="/G" && dic["/F"]==null) {
PDFI.plteImage(stm, 0, img, null, w, h, bpc);
}
else if(cs[0].typ!=null) {
PDFI.plteImage(stm, 0, img, cs[3].val, w, h, bpc);
}
else img = stm;
genv.PutImage(gst, img, w,h);
}
else if(op=="n" || op=="BT" || op=="EI") {}
else if(op=="ET") { gst.font.Tm = [1,0,0,1,0,0]; gst.font.Tlm=gst.font.Tm.slice(0); }
else if(op=="re") {
var h=os.pop().val, w=os.pop().val, y=os.pop().val, x=os.pop().val;
PSI.G.moveTo(gst,x,y); PSI.G.lineTo(gst,x+w,y); PSI.G.lineTo(gst,x+w,y+h); PSI.G.lineTo(gst,x,y+h); PSI.G.closePath(gst);
}
else if(op=="y" || op=="v") {
var im=gst.ctm.slice(0); PSI.M.invert(im); var p=PSI.M.multPoint(im,gst.cpos);
var y3=os.pop().val, x3=os.pop().val, y1=os.pop().val, x1=os.pop().val;
if(op=="y") PSI.G.curveTo(gst,x1,y1,x3,y3,x3,y3);
else PSI.G.curveTo(gst,p[0],p[1],x1,y1,x3,y3);
}
else if(op=="B" || op=="B*") {
genv.Fill(gst, op=="B*"); //PSI.G.newPath(gst);
genv.Stroke(gst); PSI.G.newPath(gst);
}
else if(op=="cm" || op=="Tm") {
var m = []; for(var i=0; i<6; i++) m.push(os.pop().val); m.reverse();
if(op=="cm") { PSI.M.concat(m, gst.ctm); gst.ctm = m; }
else { gst.font.Tm = m; gst.font.Tlm = m.slice(0); }
}
else if(op=="Td" || op=="T*") {
var x=0, y=0;
if(op=="T*") { x=0; y=-gst.font.Tl; }
else { y=os.pop().val; x=os.pop().val; }
var tm = [1,0,0,1,x,y]; PSI.M.concat(tm,gst.font.Tlm);
gst.font.Tm = tm; gst.font.Tlm = tm.slice(0);
}
else if(op=="Tf") {
var sc = os.pop().val, fnt = os.pop().val;
gst.font.Tf=fnt;//rfnt["/BaseFont"].slice(1);
gst.font.Tfs=sc; //os.push(fnt);
}
else if(op=="Tj" || op=="TJ") {
var sar = os.pop();
if(sar.typ=="string") sar = [sar];
else sar = sar.val;
var rfnt = res["/Font"][fnt];
var tf = gst.font.Tf;
var fnt = res["/Font"][tf];
var scl = PSI.M.getScale(gst.font.Tm)*gst.font.Tfs/1000;
for(var i=0; i<sar.length; i++) {
//if(sar[i].typ!="string") { gst.font.Tm[4] += -scl*sar[i].val; continue; }
if(sar[i].typ!="string") { if(i==0) gst.font.Tm[4] += -scl*sar[i].val; continue; }
var str = PDFI.getString(sar[i].val, fnt);
if(sar[i+1] && sar[i+1].typ!="string") { var sv = sar[i+1].val; str[1] += -sv; if(-900<sv && sv<-100) str[0]+=" "; }
gst.font.Tf = str[2];
genv.PutText(gst, str[0], str[1]/1000); //gst.cpos[0] += str.length*gst.font.mat[0]*0.5;
gst.font.Tf = tf;
gst.font.Tm[4] += scl*str[1];
}
}
else if(op=="Tc") gst.font.Tc = os.pop().val;
else if(op=="Tw") gst.font.Tw = os.pop().val;
else if(op=="Tz") gst.font.Th = os.pop().val;
else if(op=="TL") gst.font.Tl = os.pop().val;
else if(op=="Tr") gst.font.Tmode = os.pop().val;
else if(op=="Ts") gst.font.Trise = os.pop().val;
else if(op=="CS" || op=="cs" ) { var cs = os.pop().val; if(op=="CS") gst.sspace=cs; else gst.space=cs; }
else if(op=="SCN" || op=="scn" || op=="SC" || op=="sc") {
var stk = (op=="SCN" || op=="SC");
var csi = stk ? gst.sspace : gst.space, cs, c = null;
//console.log(op, cs, os); throw "e";
var sps = res ? res["/ColorSpace"] : null; //if(sps!=null) console.log(sps[csi]);
if(sps!=null && sps[csi]!=null) {
if(sps[csi][1] && sps[csi][1]["/Alternate"]) cs = sps[csi][1]["/Alternate"]; //cs = sps[csi][0];
else cs = sps[csi][0];
}
else cs = csi;
//console.log(res, cs, os);
if(cs=="/Lab" || cs=="/ICCBased" || cs=="/DeviceRGB" || cs=="/DeviceN") { c=[os.pop().val, os.pop().val, os.pop().val]; c.reverse(); }
else if(cs=="/DeviceCMYK") { var cmyk=[os.pop().val,os.pop().val,os.pop().val,os.pop().val]; cmyk.reverse(); c = PSI.C.cmykToRgb(cmyk); }
else if(cs=="/DeviceGray" || cs=="/CalGray") { var gv=PSI.nrm(os.pop().val); c=[gv,gv,gv]; }
else if(cs=="/Separation") { var lab = PDFI.Func(sps[csi][3], [os.pop().val]); c = PSI.C.labToRgb(lab); }
else if(cs=="/Pattern") {
//*
var pt = res["/Pattern"][os.pop().val]; //console.log(pt);
var ptyp = pt["/PatternType"];
if(ptyp==1) { console.log("tile pattern"); return; }
PDFI.setShadingFill(pt["/Shading"], pt["/Matrix"], stk, gst);
return;//*/ os.pop(); c=[1,0.5,0];
}
else { console.log(cs, os, sps, res); throw("e"); }
//console.log(c);
if(stk) gst.COLR = c; else gst.colr=c;
}
else if(op=="sh") { //os.pop(); return;
//if(window.asdf==null) window.asdf=0;
//window.asdf++; if(window.asdf!=6) return;
var sh = res["/Shading"][os.pop().val]; //console.log(sh);
var ocolr = gst.colr, opth = gst.pth;
gst.pth = gst.cpth;
PDFI.setShadingFill(sh, gst.ctm.slice(0), false, gst);
genv.Fill(gst);
gst.colr = ocolr; gst.pth = opth;
}
else if(op=="MP" || op=="BMC" || op=="ri") { os.pop(); }
else if(op=="DP" || op=="BDC") { os.pop(); os.pop(); }
else if(op=="EMC"|| op=="BX" || op=="EX") { }
else
throw ("Unknown operator", op);
}
PDFI.setShadingFill = function(sh, mat, stk, gst)
{
var styp = sh["/ShadingType"], cs = sh["/ColorSpace"];
//console.log(cs);
//if(cs!="/DeviceRGB") throw "unknown shading space " + cs;
var ftyp = "";
if(styp==2) {
ftyp="lin";
}
else if(styp==3) {
ftyp="rad";
}
else { console.log("Unknown shading type", styp); return; }
var fill = {typ:ftyp, mat:mat, grad:PDFI.getGrad(sh["/Function"]), crds:sh["/Coords"]}
if(stk) gst.COLR = fill; else gst.colr=fill;
}
PDFI.getGrad = function(fn) {
var fs = fn["/Functions"], ft = fn["/FunctionType"], bs = fn["/Bounds"], enc = fn["/Encode"];
if(ft==0 || ft==2) return [ [0,PDFI.Func(fn,[0])], [1,PDFI.Func(fn,[1])] ];
var zero = enc[0];
var grd = [];
if(bs.length==0 || bs[0]>0) grd.push([0, PDFI.Func(fs[0], [zero])] );
for(var i=0; i<bs.length; i++) grd.push([bs[i], PDFI.Func(fs[i],[zero])]);
if(bs.length==0 || bs[bs.length-1]<1) grd.push([1, PDFI.Func(fs[fs.length-1], [1-zero])]);
//console.log(fn, grd);
return grd;
}
PDFI._clrSamp = function(stm, i) { return [stm[i]/255, stm[i+1]/255, stm[i+2]/255]; }
PDFI.getImage = function(xo, gst) {
var w=xo["/Width"], h=xo["/Height"], ar = w*h, ft=xo["/Filter"], cs=xo["/ColorSpace"], bpc=xo["/BitsPerComponent"], stm=xo["stream"];
var img = xo["image"]; //console.log(xo);
if(img==null) {
var msk = xo["/Mask"];
if(cs && cs[0]=="/Indexed") {
var pte;
if(cs[3].length!=null) { // palette in a string
var str = cs[3]; pte = new Uint8Array(256*3);
for(var i=0; i<str.length; i++) pte[i] = str.charCodeAt(i);
}
else pte = cs[3]["stream"];
var nc = new Uint8Array(ar*4);
PDFI.plteImage(stm, 0, nc, pte, w, h, bpc, msk);
img=nc;
}
else if(ft==null && cs && cs=="/DeviceGray") {
var pte = [0,0,0,255,255,255], nc = new Uint8Array(ar*4);
if(xo["/Decode"] && xo["/Decode"][0]==1) { pte.reverse(); }
if(xo["/ImageMask"]==true) pte.reverse();
PDFI.plteImage(stm, 0, nc, bpc==1?pte:null, w, h, bpc, msk);
img=nc;
}
else if(w*h*3<=stm.length) {
var nc = new Uint8Array(ar*4);
for(var i=0; i<ar; i++) { var ti=i*3, qi=i*4; nc[qi]=stm[ti]; nc[qi+1]=stm[ti+1]; nc[qi+2]=stm[ti+2]; nc[qi+3]=255; }
img = nc;
}
else { img = stm; }
xo["image"] = img;
}
return img;
}
PDFI.plteImage = function(buff, off, img, plt, w, h, bpc, msk)
{
var mlt = Math.round(255/((1<<bpc)-1));
var bpl = Math.ceil(w*bpc/8);
for(var y=0; y<h; y++) {
var so = off + bpl * y;
for(var x=0; x<w; x++) {
var ci = 0;
if (bpc==8) ci = buff[so+x];
else if(bpc==4) ci=(buff[so+(x>>1)]>>((1-(x&1))<<2))&15;
else if(bpc==2) ci=(buff[so+(x>>2)]>>((3-(x&3))<<1))&3;
else if(bpc==1) ci=(buff[so+(x>>3)]>>((7-(x&7))<<0))&1;
var qi = (y*w+x)<<2;
if(plt) { var c =ci*3; img[qi]=plt[c]; img[qi+1]=plt[c+1]; img[qi+2]=plt[c+2]; }
else { var nc=ci*mlt; img[qi]=nc; img[qi+1]=nc; img[qi+2]=nc; }
img[qi+3]=255;
if(msk && msk[0]<=ci && ci<=msk[1]) img[qi+3]=0;
}
}
}
PDFI.Func = function(f, vls)
{
var dom = f["/Domain"], rng = f["/Range"], typ = f["/FunctionType"], out = [];
for(var i=0; i<vls.length; i++) vls[i]=Math.max(dom[2*i], Math.min(dom[2*i+1], vls[i]));
if(typ==0) {
var enc = f["/Encode"], sz = f["/Size"], dec = f["/Decode"], n = rng.length/2;
if(enc==null) enc=[0,sz[0]-1];
if(dec==null) dec=[0,sz[0]-1,0,sz[0]-1,0,sz[0]-1];
for(var i=0; i<vls.length; i++) {
var ei = PDFI.intp(vls[i],dom[2*i],dom[2*i+1],enc[2*i],enc[2*i+1]);
vls[i] = Math.max(0, Math.min(sz[i]-1, ei));
}
for(var j=0; j<n; j++) {
var x = Math.round(vls[0]), rj = f["stream"][n*x+j];
rj = PDFI.intp(rj, 0,255, dec[2*j],dec[2*j+1]);
out.push(rj);
}
}
else if(typ==2) {
var c0=f["/C0"],c1=f["/C1"],N=f["/N"]
var x = vls[0];
for(var i=0; i<c0.length; i++) out[i] = c0[i] + Math.pow(x,N) * (c1[i]-c0[i]);
}
else throw "e";
if(rng) for(var i=0; i<out.length; i++) out[i]=Math.max(rng[2*i], Math.min(rng[2*i+1], out[i]));
return out;
}
PDFI.intp = function(x,xmin,xmax,ymin,ymax) { return ymin + (x-xmin) * (ymax-ymin)/(xmax-xmin); }
PDFI.getString = function(sv, fnt)
{
//console.log(sv, fnt); //throw "e";
var st = fnt["/Subtype"], s="", m=0, psn=null;
var tou = fnt["/ToUnicode"], enc = fnt["/Encoding"], sfnt=fnt; // font with a stream
if(st=="/Type0") sfnt = fnt["/DescendantFonts"][0]; // // only in type 0
if(tou!=null) s = PDFI.toUnicode(sv, tou);
else if(enc=="/WinAnsiEncoding") s = PDFI.fromWin(sv);
else if(st=="/Type0") {
var off=0;
if(enc=="/Identity-H") off=31;
for(var j=0; j<sv.length; j+=2) {
var gid = (sv[j]<<8)|sv[j+1]; //console.log(gid, stm);
s += String.fromCharCode(gid+off); // don't know why 31
}
}
else if(enc!=null && enc["/Type"]=="/Encoding") {
var dfs = enc["/Differences"];
if(dfs) {
var s = "";
for(var i=0; i<sv.length; i++) {
var ci = sv[i], coff=-5;
for(var j=0; j<dfs.length; j++)
{
if(typeof dfs[j] == "string") { if(ci==coff) s+=PDFI.fromCName(dfs[j].slice(1)); coff++; }
else coff=dfs[j];
}
}
}
//console.log(enc, sv); throw "e";
//s = PDFI.fromWin(sv);
}
else { /*console.log("reading simple string", sv, fnt);*/ s = PSI.readStr(sv); }
if(st=="/Type0") {
//console.log(df); //throw "e";
var ws = sfnt["/W"];
//console.log(sv, fnt);
for(var i=0; i<sv.length; i+=2) {
var cc = (sv[i]<<8)|sv[i+1], gotW = false;
for(var j=0; j<ws.length; j+=2) {
var i0=ws[j], i1 = ws[j+1];
if(i1.length) { if(0<=cc-i0 && cc-i0<i1.length) { m += i1[cc-i0]; gotW=true; } }
else { if(i0<=cc && cc<=i1) { m += ws[j+2]; gotW = true; } j++; }
}
if(!gotW) m += ws[1][0];
}
}
else if(st=="/Type1" || st=="/TrueType") {
var fc=fnt["/FirstChar"], ws = fnt["/Widths"];
if(ws) for(var i=0; i<sv.length; i++) m += ws[sv[i]-fc];
else { m = s.length*1000*0.4; console.log("approximating word width"); }
}
else throw "e";
//console.log(fnt);// throw "e";
//console.log(sfnt);
var fd = sfnt["/FontDescriptor"];
if(fd) {
if(fd["psName"]) psn=fd["psName"];
else {
var pp, ps = ["","2","3"];
for(var i=0; i<3; i++) if(fd["/FontFile"+ps[i]]) pp = "/FontFile"+ps[i];
if(pp) {
var fle = fd[pp]["stream"];
if(pp!=null && fle && PSI.B.readUint(fle,0)==65536) psn = fd["psName"] = PDFI._psName(fle);
}
}
}
if(psn==null) psn = fnt["/BaseFont"].slice(1);
return [s, m, psn.split("+").pop()];
}
PDFI._psName = function(fle) {
var rus = PSI.B.readUshort;
var num = rus(fle, 4);
var noff = 0;
for(var i=0; i<num; i++) {
var tn = PSI.B.readASCII(fle,12+i*16,4), to = PSI.B.readUint(fle, 12+i*16+8);
if(tn=="name") { noff=to; break; }
}
if(noff==0) return null;
var cnt=rus(fle, noff+2);
var offset0=noff+6, offset=noff+6;
for(var i=0; i<cnt; i++) {
var platformID = rus(fle, offset );
var eID = rus(fle, offset+ 2); // encoding ID
var languageID = rus(fle, offset+ 4);
var nameID = rus(fle, offset+ 6);
var length = rus(fle, offset+ 8);
var noffset = rus(fle, offset+10);
offset += 12;
var s;
var soff = offset0 + cnt*12 + noffset;
if(eID==1 || eID==10 || eID==3) { s=""; for(var j=1; j<length; j+=2) s += String.fromCharCode(fle[soff+j]); }
if(eID==0 || eID== 2) s = PSI.B.readASCII(fle, soff, length);
if(nameID==6 && s!=null && s.slice(0,3)!="OTS") return s.replace(/\s/g, "");
}
return null;
}
PDFI.fromWin = function(sv)
{
var map = PDFI._win1252; s="";
for(var j=0; j<sv.length; j++) {
var cc = sv[j], ci = map.indexOf(cc);
if(ci!=-1) cc = map[ci+1];
s+=String.fromCharCode(cc);
}
return s;
}
PDFI.fromCName = function(cn)
{
if(cn.length==1) return cn;
if(cn.slice(0,3)=="uni") return String.fromCharCode(parseInt(cn.slice(3),16));
//var gi = parseInt(cn.slice(1)); if(cn.charAt(0)=="g" && !isNaN(gi)) return String.fromCharCode(gi);
var map = {
"space":32,"exclam":33,"quotedbl":34,"numbersign":35,"dollar":36,"percent":37,"parenleft":40,
"parenright":41,"asterisk":42,"plus":43,"comma":44,"hyphen":45,"period":46,"slash":47,
"zero":48,"one":49,"two":50,"three":51,"four":52,"five":53,"six":54,"seven":55,"eight":56,"nine":57,
"colon":58,"semicolon":59,"less":60,"equal":61,"at":64,
"bracketleft":91,"bracketright":93,"underscore":95,"braceleft":123,"braceright":125,
"dieresis":168,"circlecopyrt":169,"Eacute":201,
"dotlessi":0x0131,
"alpha":0x03B1,"phi":0x03C6,
"endash":0x2013,"emdash":0x2014,"asteriskmath":0x2217,"quoteright":0x2019,"quotedblleft":0x201C,"quotedblright":0x201D,"bullet":0x2022,
"minus":0x2202,
"fi": 0xFB01,"fl":0xFB02 };
var mc = map[cn];
if(mc==null) { if(cn.charAt(0)!="g") console.log("unknown character "+cn);
return cn; }
return String.fromCharCode(mc);
}
PDFI.toUnicode = function(sar, tou) {
var cmap = tou["cmap"], s = "";
if(cmap==null) {
var file = {buff:tou["stream"], off:0};
//console.log(PSI.B.readASCII(file.buff, 0, file.buff.length));
var os = []; // operand stack
var ds = PSI._getDictStack({});
var es = [{ typ:"file", val: file }]; // execution stack
var gs = [];
var env = PSI._getEnv([0,0,1,1]); env.pgOpen = true;
var time = Date.now();
var repeat = true;
while(repeat) repeat = PSI.step(os, ds, es, gs, env, null, PDFI.operator);
cmap = env.res["CMap"];
tou["cmap"] = cmap;
//console.log(cmap); throw "e";
}
//console.log(cmap);
//cmap = cmap["Adobe-Identity-UCS"];
for(var p in cmap) { cmap=cmap[p]; break; }
//console.log(cmap, sar); throw "e";
var bfr = cmap.bfrange, bfc = cmap.bfchar, bpc = cmap["bpc"];
for(var i=0; i<sar.length; i+=bpc) {
var cc = sar[i]; if(bpc==2) cc = (cc<<8) | sar[i+1];
var mpd = false;
if(!mpd && bfr) for(var j=0; j<bfr.length; j+=3) {
var v0=bfr[j], v1=bfr[j+1], v2=bfr[j+2];
if(v0<=cc && cc<=v1) {
if(v2.length==null) cc+=v2-v0;
else cc = v2[cc-v0];
mpd=true; break;
}
}
if(!mpd && bfc) for(var j=0; j<bfc.length; j+=2) if(bfc[j]==cc) { cc=bfc[j+1]; mpd=true; break; }
s += String.fromCharCode(cc);
}
return s;
}
PDFI._win1252 = [ 0x80, 0x20AC, 0x82, 0x201A, 0x83, 0x0192, 0x84, 0x201E, 0x85, 0x2026, 0x86, 0x2020, 0x87, 0x2021, 0x88, 0x02C6, 0x89, 0x2030,
0x8A, 0x0160, 0x8B, 0x2039, 0x8C, 0x0152, 0x8E, 0x017D, 0x91, 0x2018, 0x92, 0x2019, 0x93, 0x201C, 0x94, 0x201D, 0x95, 0x2022, 0x96, 0x2013,
0x97, 0x2014, 0x98, 0x02DC, 0x99, 0x2122, 0x9A, 0x0161, 0x9B, 0x203A, 0x9C, 0x0153, 0x9E, 0x017E, 0x9F, 0x0178 ];
PDFI.readXrefTrail = function(buff, xref, out)
{
var kw = PSI.B.readASCII(buff, xref, 4);
if(kw=="xref") {
var off = xref+4;
if(buff[off]==13) off++; if(buff[off]==10) off++;
while(true) { // start of the line with M, N
var of0 = off;
while(!PSI.isEOL(buff[off])) off++;
var line = PSI.B.readASCII(buff, of0, off-of0); //console.log(line);
if(line=="trailer") break; line = line.split(" ");
var n = parseInt(line[1]);
if(buff[off]==13) off++; if(buff[off]==10) off++;
for(var i=0; i<n; i++)
{
var li = parseInt(line[0])+i;
if(out[li]==null) out[li] = {
off: parseInt(PSI.B.readASCII(buff, off, 10)),
gen: parseInt(PSI.B.readASCII(buff, off+11, 5)),
chr: PSI.B.readASCII(buff, off+17, 1),
val: null,
opn: false
};
off+=20;
}
}
var file = {buff:buff, off:off};//, trw = PSI.getFToken(file);
var trl = PDFI.readObject(file, file, out);
if(trl["/Prev"]) PDFI.readXrefTrail(buff, trl["/Prev"], out);
return trl;
}
else {
var off = xref;
while(!PSI.isEOL(buff[off])) off++; off++;
var xr = PDFI.readObject({buff:buff, off:off}, file, null); //console.log(xr);
var sof = 0, sb = xr["stream"], w = xr["/W"], ind = (xr["/Index"] ? xr["/Index"][0] : 0);
while(sof<sb.length) {
var typ=PDFI.getInt(sb,sof,w[0]); sof+=w[0];
var a =PDFI.getInt(sb,sof,w[1]); sof+=w[1];
var b =PDFI.getInt(sb,sof,w[2]); sof+=w[2];
var off=0, gen=0, chr="n";
if(typ==0) {off=a; gen=b; chr="f";}
if(typ==1) {off=a; gen=b; chr="n";}
if(typ==2) {off=a; gen=b; chr="s";}
out[ind] = { off: off, gen: gen, chr: chr, val: null, opn: false }; ind++;
}
if(xr["/Prev"]) PDFI.readXrefTrail(buff, xr["/Prev"], out);
//*
var fl = {buff:buff, off:0};
var ps = ["/Root","/Info"];
for(var i=0; i<ps.length; i++) {
var p = ps[i], val = xr[p];
if(val && val.typ=="ref") xr[p] = PDFI.getIndirect(val.ind, val.gen, fl, out);
}
//*/
return xr;
}
}
PDFI.getInt = function(b,o,l) {
if(l==1) return b[o];
if(l==2) return ((b[o]<< 8)|b[o+1]);
if(l==3) return ((b[o]<<16)|(b[o+1]<<8)|b[o+2]); throw "e";
}
PDFI.getIndirect = function(i,g,file,xr)
{
var xv = xr[i];
if(xv.chr=="f") return null;
if(xv.val!=null) return xv.val;
if(xv.opn) return {typ:"ref",ind:i, gen:g};
xv.opn = true;
var ooff = file.off, nval;
if(xv.chr=="s") {
var os = PDFI.getIndirect(xv.off, xv.gen, file, xr), fle = {buff:os["stream"], off:0};
var idx=0, ofs=0;
while(idx!=i) { idx=PSI.getFToken(fle).val; ofs=PSI.getFToken(fle).val; }
fle.off = ofs+os["/First"];
nval = PDFI.readObject(fle, file, xr);
}
else {
file.off = xv.off;
var a=PSI.getFToken(file), b=PSI.getFToken(file), c=PSI.getFToken(file);
//console.log(a,b,c);
nval = PDFI.readObject(file, file, xr);
}
xv.val = nval;
file.off = ooff; xv.opn = false;
return nval;
}
PDFI.readObject = function(file, mfile, xr)
{
//console.log(file.off, file.buff);
var tok = PSI.getFToken(file);
//console.log(tok);
if(tok.typ=="integer") {
var off = file.off;
var tok2 = PSI.getFToken(file);
if(tok2.typ=="integer") {
PSI.skipWhite(file);
if(file.buff[file.off]==82) {
file.off++;
if(xr && xr[tok.val]) return PDFI.getIndirect(tok.val, tok2.val, mfile, xr);
else return {typ:"ref",ind:tok.val, gen:tok2.val};
}
}
file.off = off;
}
if(tok.val=="<<") return PDFI.readDict(file, mfile, xr);
if(tok.val=="[" ) return PDFI.readArra(file, mfile, xr);
if(tok.typ=="string") {
var s = ""; for(var i=0; i<tok.val.length; i++) s+=String.fromCharCode(tok.val[i]);
return s;
}
return tok.val;
}
PDFI.readDict = function(file, mfile, xr) {
var o = {};
while(true) {
var off=file.off, tok = PSI.getFToken(file);
if(tok.typ=="name" && tok.val==">>") break;
file.off= off;
var key = PDFI.readObject(file, mfile, xr);
var val = PDFI.readObject(file, mfile, xr);
o[key] = val;
}
if(o["/Length"]!=null) {
var l = o["/Length"];
var tk = PSI.getFToken(file); if(file.buff[file.off]==13) file.off++; if(file.buff[file.off]==10) file.off++;
var buff = file.buff.slice(file.off, file.off+l); file.off += l; PSI.getFToken(file); // endstream
var flt = o["/Filter"], prm=o["/DecodeParms"];
if(flt!=null) {
var fla = (typeof flt == "string") ? [flt] : flt;
var keepFlt = false;
for(var i=0; i<fla.length; i++) {
var cf = fla[i], fl = {buff:buff, off:0};
if (cf=="/FlateDecode" ) { buff = PSI.F.FlateDecode(fl); }
else if(cf=="/ASCII85Decode") { buff = PSI.F.ASCII85Decode(fl); }
else if(cf=="/DCTDecode" || cf=="/CCITTFaxDecode" || cf=="/JPXDecode" || cf=="/JBIG2Decode") { keepFlt = true; } // JPEG
else { console.log(cf, buff); throw "e"; }
}
if(!keepFlt) delete o["/Filter"];
}
if(prm!=null) {
if(prm instanceof Array) prm = prm[0];
if(prm["/Predictor"]!=null && prm["/Predictor"]!=1) {
var w = prm["/Columns"], bpp = prm["/Colors"] ? prm["/Colors"]: 1, bpl = (bpp*w), h = (buff.length/(bpl+1));
PDFI._filterZero(buff, 0, w, h, bpp); buff = buff.slice(0, h*bpl);
}
}
o["stream"] = buff;
}
return o;
}
PDFI.readArra = function(file, mfile, xr) {
var o = [];
while(true) {
var off=file.off, tok = PSI.getFToken(file);
if(tok.typ=="name" && tok.val=="]") return o;
file.off = off;
var val = PDFI.readObject(file, mfile, xr);
o.push(val);
}
}
PDFI._filterZero = function(data, off, w, h, bpp) { // copied from UPNG.js
var bpl = bpp*w, paeth = PDFI._paeth;
for(var y=0; y<h; y++) {
var i = off+y*bpl, di = i+y+1;
var type = data[di-1];
if (type==0) for(var x= 0; x<bpl; x++) data[i+x] = data[di+x];
else if(type==1) {
for(var x= 0; x<bpp; x++) data[i+x] = data[di+x];
for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + data[i+x-bpp])&255;
}
else if(y==0) {
for(var x= 0; x<bpp; x++) data[i+x] = data[di+x];
if(type==2) for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x])&255;
if(type==3) for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + (data[i+x-bpp]>>1) )&255;
if(type==4) for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + paeth(data[i+x-bpp], 0, 0) )&255;
}
else {
if(type==2) { for(var x= 0; x<bpl; x++) data[i+x] = (data[di+x] + data[i+x-bpl])&255; }
if(type==3) { for(var x= 0; x<bpp; x++) data[i+x] = (data[di+x] + (data[i+x-bpl]>>1))&255;
for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + ((data[i+x-bpl]+data[i+x-bpp])>>1) )&255; }
if(type==4) { for(var x= 0; x<bpp; x++) data[i+x] = (data[di+x] + paeth(0, data[i+x-bpl], 0))&255;
for(var x=bpp; x<bpl; x++) data[i+x] = (data[di+x] + paeth(data[i+x-bpp], data[i+x-bpl], data[i+x-bpp-bpl]) )&255; }
}
}
return data;
}
PDFI._paeth = function(a,b,c) {
var p = a+b-c, pa = Math.abs(p-a), pb = Math.abs(p-b), pc = Math.abs(p-c);
if (pa <= pb && pa <= pc) return a;
else if (pb <= pc) return b;
return c;
}
function PSI ()
{
}
PSI.Parse = function(buff, genv)
{
buff = new Uint8Array(buff);
var str = PSI.B.readASCII(buff, 0, buff.length);
var lines = str.split(/[\n\r]+/);
var crds = null;
var epsv = null;
for(var li=0; li<lines.length; li++)
{
var line = lines[li].trim();
if(line.charAt(0)=="%") {
while(line.charAt(0)=="%") line = line.slice(1);
var pts = line.split(":");
if(pts[0]=="BoundingBox") crds = pts[1].trim().split(/[ ]+/).map(parseFloat);
if(line.indexOf("!PS-Adobe-3.0 EPSF-3.0")!=-1) epsv=line;
}
}
if(epsv==null || crds==null) crds = [0,0,595, 842];
var os = []; // operand stack
var ds = PSI._getDictStack([],{});
var es = [{ typ:"file", val: { buff:buff, off:0 } }]; // execution stack
var gs = [];
var env = PSI._getEnv(crds);
var time = Date.now();
var repeat = true;
while(repeat) repeat = PSI.step(os, ds, es, gs, env, genv);
if(env.pgOpen) genv.ShowPage();
genv.Done();
//PSI.interpret(file, os, ds, es, [], gst, genv);
console.log(Date.now()-time);
}
PSI._getDictStack = function(adefs, aprcs) {
var defs = [
"def","begin","end","currentfile","currentdict","known","version","currentpacking","setpacking","currentglobal","setglobal",
"currentflat",
"currentlinewidth","currentpoint","currentscreen","setscreen",
"dict","string","readstring","readhexstring","readline","getinterval","putinterval","token",
"array","aload","astore","length","matrix","mark","counttomark",
"makefont","scalefont","stringwidth",
"setfont", "setgray", "setrgbcolor","sethsbcolor", "setlinewidth", "setstrokeadjust","setflat","setlinecap","setlinejoin","setmiterlimit","setdash",
"clip","eoclip","clippath","pathbbox",
"newpath", "stroke", "fill", "eofill", "closepath","showpage","print",
"moveto", "lineto", "curveto", "arc","arcn", "show","ashow","widthshow",
"rmoveto","rlineto","rcurveto",
"translate","rotate","scale","concat","concatmatrix","currentmatrix","setmatrix",
"save","restore","gsave", "grestore",
"usertime","readtime",
"save", "restore","flush","readonly",
"findresource","defineresource","image","colorimage",
"xcheck",
"if","ifelse","exec","stopped","dup","exch","copy","roll","index","pop","put","get","load","where","store","repeat","for","forall","loop","exit",
"bind",
"cvi","cvr","cvs","cvx",
"add","sub","mul","div","idiv","bitshift","mod","exp","atan",
"neg","abs","round","truncate","sqrt","ln","sin","cos",
"srand","rand","==","transform","itransform","dtransform",
"eq","ge","gt","le","lt","ne",
"and","or","not",
"filter",
"begincmap","endcmap", "begincodespacerange","endcodespacerange", "beginbfrange","endbfrange","beginbfchar","endbfchar"
].concat(adefs);
var withCtx = ["image", "colorimage", "repeat", "for","forall","loop"];
for(var i=0; i<withCtx.length; i++) defs.push(withCtx[i]+"---");
var prcs = {
"findfont" : "/Font findresource",
"definefont" : "/Font defineresource",
"undefinefont": "/Font undefineresource"
};
prcs = PSI.makeProcs(prcs);
for(var p in aprcs) prcs[p] = aprcs[p];
var systemdict = {}, globaldict = {}, userdict = {}, statusdict = {};
systemdict["systemdict"] = {typ:"dict", val:systemdict};
systemdict["globaldict"] = {typ:"dict", val:globaldict};
systemdict["userdict" ] = {typ:"dict", val:userdict };
systemdict["statusdict"] = {typ:"dict", val:statusdict};
systemdict["null"] = {typ:"null", val:null};
for(var i=0; i<defs.length; i++) systemdict[defs[i]] = { typ:"operator", val:defs[i] };
for(var p in prcs) systemdict[p] = prcs[p];
return [ systemdict, globaldict, userdict ]; // dictionary stack
}
PSI._getEnv = function(crds) {
return {
bb:crds,
gst : PSI._getState(crds),
pckn:false, amodeGlobal:false,
cmnum:0, fnt:null,
res:{},
pgOpen:false
}
}
PSI._getState = function(crds) {
return {
font : PSI._getFont(),
dd: {flat:1}, // device-dependent
space :"/DeviceGray",
// fill
ca: 1,
colr : [0,0,0],
sspace:"/DeviceGray",
// stroke
CA: 1,
COLR : [0,0,0],
bmode: "/Normal",
SA:false, OPM:0, AIS:false, OP:false, op:false, SMask:"/None",
lwidth : 1,
lcap: 0,
ljoin: 0,
mlimit: 10,
SM : 0.1,
doff: 0,
dash: [],
strokeAdj : false,
ctm : [1,0,0,1,0,0],
cpos: [0,0],
pth : {cmds:[],crds:[]},
cpth: {cmds:["M","L","L","L","Z"],crds:[crds[0],crds[1],crds[2],crds[1], crds[2],crds[3],crds[0],crds[3]]}, // clipping path
};
}
PSI._getFont = function() {
return {
Tc: 0, // character spacing
Tw: 0, // word spacing
Th:100, // horizontal scale
Tl: 0, // leading
Tf:"Helvetica-Bold",
Tfs:1, // font size
Tmode:0, // rendering mode
Trise:0, // rise
Tk: 0, // knockout
Tm :[1,0,0,1,0,0],
Tlm:[1,0,0,1,0,0],
Trm:[1,0,0,1,0,0]
};
}
PSI.makeProcs = function(prcs) {
var out = {};
for(var p in prcs) {
var pts = prcs[p].replace(/ +/g, " ").split(" ");
out[p] = {typ:"procedure", val:[]};
for(var i=0; i<pts.length; i++) out[p].val.push({typ:"name",val:pts[i]});
}
return out;
}
PSI.addProc = function(obj, es) {
if(obj.val.length==0) return;
if(obj.off!=null && obj.off!=obj.val.length) es.push({typ:"procedure", val:obj.val, off:0});
else { obj.off=0; es.push( obj ); }
}
PSI._f32 = new Float32Array(1);
PSI.step = function(os, ds, es, gs, env, genv, Oprs)
{
var otime = Date.now(), f32 = PSI._f32;
var getToken = PSI.getToken;
var gst = env.gst;
var tok = getToken(es, ds); if(tok==null) return false;
var typ = tok.typ, val = tok.val;
if(!env.pgOpen && val!="end") { genv.StartPage(env.bb[0], env.bb[1], env.bb[2], env.bb[3]); env.pgOpen = true; }
//console.log(tok, os.slice(0));
/*ocnt++;
//if(ocnt>2*lcnt) { lcnt=ocnt; console.log(ocnt, os.length, file.stk.length); };
if(ocnt>8000000) {
for(var key in opoc) if(opoc[key][1]<1000) delete opoc[key];
console.log(Date.now()-otime, opoc); throw "e";
} */
if(typ=="integer" || typ=="real" || typ=="boolean" || typ=="string" || typ=="array" || typ=="procedure" || typ=="null") { os.push(tok); return true; }
if(typ!="name" && typ!="operator") throw "e";
//if(opoc[val]==null) opoc[val]=[0,0]; opoc[val][0]++; opoc[val][1]=ocnt;
if(val.charAt(0)=="/") {
if(val.charAt(1)=="/") throw "e";
else os.push(tok);
}
else if(val=="{") {
var ars = [], car = {typ:"procedure", val:[] };
var ltok=getToken(es,ds);
while(true) {
if (ltok.val=="{") { var ncr = {typ:"procedure", val:[]}; car.val.push(ncr); ars.push(car); car=ncr; }
else if(ltok.val=="}") { if(ars.length==0) break; car = ars.pop(); }
else car.val.push(ltok);
ltok=getToken(es,ds);
}
os.push( car );
}
else if(val=="[" || val=="<<") os.push( {typ:"mark"} );
else if(val=="]" || val==">>") {
var arr = []; while(os.length!=0) { var o=os.pop(); if(o.typ=="mark") break; arr.push(o); }
arr.reverse();
if(val=="]") os.push( {typ:"array", val:arr } );
else {
var ndct = {}; for(var i=0; i<arr.length; i+=2) ndct[arr[i].val.slice(1)] = arr[i+1];
os.push( {typ:"dict", val:ndct } );
}
}
else {
var obj = PSI.getFromStacks(val, ds);
//if(val=="rl^") { console.log(val, os.slice(0)); }
if(obj==null) { console.log("unknown operator", val, os, ds); throw "e"; }
else if(obj.typ=="procedure") PSI.addProc(obj, es); //{ obj.off=0; es.push(obj); }
/*
else if(op.typ=="string") {
var prc=[], sdta = {buff:op.val, off:0, stk:[]}, tk = getToken(sdta); while(tk!=null) { prc.push(tk); tk=getToken(sdta); }
PSI.addProcedure(prc, file);
}*/
else if(["array","string","dict","null","integer","real","boolean","state","font","name"].indexOf(obj.typ)!=-1) os.push(obj);
else if(obj.typ=="operator")
{
var op = obj.val;
//if(omap[op]) op = omap[op];
if(op=="def") { var nv = os.pop(), nn = os.pop(); nn=nn.val.slice(1); ds[ds.length-1][nn] = nv; }
else if(op=="dict" ) { os.pop().val; os.push({typ:"dict" , val:{} }); }
else if(op=="string" ) { var l=os.pop().val; os.push({typ:"string", val:new Array(l) }); }
else if(op=="readstring" || op=="readhexstring") {
var str = os.pop(), l=str.val.length, fl = os.pop().val; //console.log(op, str); throw "e";
if(op=="readstring") { for(var i=0; i<l; i++) str.val[i]=fl.buff[fl.off+i]; fl.off+=l; }
else {
var nv = PSI.readHex(fl, l);
for(var i=0; i<nv.length; i++) str.val[i]=nv[i];
}
os.push(str, {typ:"boolean",val:true});
}
else if(op=="readline") {
var str = os.pop(), fl = os.pop().val, i=0;
if(PSI.isEOL(fl.buff[fl.off])) fl.off++;
while(true) {
var cc = fl.buff[fl.off]; fl.off++;
if(PSI.isEOL(cc)) break;
str.val[i]=cc; i++;
}
if(i<str.val.length && str.val[i]!=null) str.val[i]=null;
os.push(str, {typ:"boolean",val:true});
}
else if(op=="getinterval") {
var cnt = os.pop().val, idx = os.pop().val, src = os.pop(), out=[];
if(src.typ=="string") for(var i=0; i<cnt; i++) out.push(src.val[idx+i]);
else throw "e";
//console.log(idx,cnt,out.slice(0));
os.push({typ:src.typ, val:out});
}
else if(op=="putinterval") {
var src=os.pop(), idx=os.pop().val, tgt=os.pop();
if(idx+src.val.length>=tgt.val.length) throw "e";
if(src.typ=="string") for(var i=0; i<src.val.length; i++) tgt.val[idx+i] = src.val[i];
else throw "e";
//console.log(src.val, tgt.val, idx); throw "e";
}
else if(op=="token") {
var src = os.pop(); if(src.typ!="string") throw "e";
var arr = [];
for(var i=0; i<src.val.length; i++) { var bv=src.val[i]; if(bv==null) break; arr.push(bv); }
var nfl = { buff:new Uint8Array(arr), off:0 }, tok = getToken([{typ:"file",val:nfl}], ds);
var ns = []; for(var i=nfl.off; i<arr.length; i++) ns.push(arr[i]);
os.push({typ:"string",val:ns}, tok, {typ:"boolean",val:true});
}
else if(op=="array" ) { var l=os.pop().val; os.push({typ:"array" , val:new Array(l) }); }
else if(op=="aload"){
var o = os.pop(), arr = o.val;
for(var i=0; i<arr.length; i++) os.push(arr[i]);
os.push(o);
}
else if(op=="astore") {
var o=os.pop(), arr = o.val; //console.log(arr.length); throw "e";
for(var i=0; i<arr.length; i++) arr[arr.length-1-i]=os.pop();
os.push(o);
}
else if(op=="length" ) {
var o = os.pop(), typ=o.typ, l=0;
if(typ=="array") l = o.val.length;
else if(typ=="procedure") l = o.val.length;
else { console.log(o); throw "e"; }
os.push({typ:"integer",val:l});
}
else if(op=="matrix" ) { os.push({typ:"array", val:PSI.makeArr([1,0,0,1,0,0],"real") }); }
else if(op=="mark" ) { os.push({typ:"mark"}); }
else if(op=="counttomark") {
var i=os.length-1; while(i!=-1 && os[i].typ!="mark") i--;
os.push({typ:"integer",val:os.length-1-i});
}
else if(op=="begin") { var o = os.pop(), dct=o.val; if(dct==null || o.typ!="dict") { console.log(o, ds); throw "e"; } ds.push(dct); }
else if(op=="end" ) { ds.pop(); }
else if(op=="currentfile") { var file; for(var i=es.length-1; i>=0; i--) if(es[i].typ=="file")file=es[i]; os.push(file); }
else if(op=="currentdict") { var dct=ds[ds.length-1]; os.push({typ:"dict", val:dct}); }
else if(op=="known") { var key=os.pop().val.slice(1), dct=os.pop().val; os.push({typ:"boolean",val:dct[key]!=null}); }
else if(op=="version") { os.push({typ:"string", val:[51]}); } // "3"
else if(op=="currentpacking") { os.push({typ:"boolean",val:env.pckn}); }
else if(op=="setpacking" ) { env.pckn = os.pop().val; }
else if(op=="currentglobal" ) { os.push({typ:"boolean",val:env.amodeGlobal}); }
else if(op=="setglobal" ) { env.amodeGlobal = os.pop().val; }
else if(op=="currentflat" ) { os.push({typ:"real",val:1}); }
else if(op=="currentlinewidth") { os.push({typ:"real",val:gst.lwidth}); }
else if(op=="currentpoint" ) { var im=gst.ctm.slice(0); PSI.M.invert(im); var p=PSI.M.multPoint(im,gst.cpos);
os.push({typ:"real",val:p[0]}, {typ:"real",val:p[1]}); }
else if(op=="currentscreen" ) { os.push({typ:"int",val:60}, {typ:"real",val:0},{typ:"real",val:0}); }
else if(op=="setscreen" ) { os.pop(); os.pop(); os.pop(); }
else if(op=="findresource")
{
var cat = os.pop().val.slice(1), key = os.pop().val.slice(1);
if (cat=="Font") { rs = {typ:"font",val:PSI._getFont()}; rs.val.Tf=key; }
else if(cat=="ProcSet") rs = {typ:"dict",val:{}};
else throw("Unknown resource category: "+cat);
os.push(rs);
}
else if(op=="defineresource") {
var cat = os.pop().val.slice(1), ins = os.pop().val, key = os.pop().val.slice(1);
if(env.res[cat]==null) env.res[cat]={};
env.res[cat][key]=ins;
}
else if(op=="image" || op=="colorimage") {
var ncomp = 1, multi = false;
if(op=="colorimage") { ncomp = os.pop().val; multi = os.pop().val; }
var src0, src1, src2;
if(multi) { src2=os.pop(); src1=os.pop(); src0=os.pop(); } else src0 = os.pop();
var mat = PSI.readArr(os.pop().val), bpc = os.pop().val, h = os.pop().val, w = os.pop().val;
if(ncomp!=3) throw "unsupported number of channels "+ncomp;
if(bpc!=8) throw "unsupported bits per channel: "+bpc;
var img = new Uint8Array(w*h*4); for(var i=0; i<img.length; i++) img[i]=255;
es.push({typ:"name",val:op+"---",ctx:[w,h,bpc,mat, ncomp,multi,img,0, src0,src1,src2]});
PSI.addProc(src0, es);
if(multi) { PSI.addProc(src1, es); PSI.addProc(src2, es); }
//console.log(w,h,bpc,mat, src0,src1,src2, multi, ncomp); throw "e";
}
else if(op=="image---" || op=="colorimage---") {
var prm = tok.ctx, w=prm[0], h=prm[1], bpc=prm[2], mat=prm[3], ncomp=prm[4], multi=prm[5], img=prm[6], pind=prm[7];
var src0 = prm[8], src1 = prm[9], src2=prm[10], dlen = 0;
if(multi)
for(i=0; i<3; i++){ var row = os.pop().val; dlen = row.length;
for(var j=0; j<dlen; j++) img[(pind+j)*4 + 2-i] = row[j];
}
else {
var row = os.pop().val; dlen = Math.floor(row.length/3);
if(row[0]==null) { console.log(ds); throw "e"; }
for(var j=0; j<dlen; j++) { var tj=j*3, qj=(pind+j)*4; img[qj+0]=row[tj+0]; img[qj+1]=row[tj+1]; img[qj+2]=row[tj+2]; }
}
pind += dlen;
if(pind==w*h) genv.PutImage(gst, img, w, h);
else { prm[7]=pind; es.push(tok);
PSI.addProc(src0, es);
if(multi) { PSI.addProc(src1, es); PSI.addProc(src2, es); }
}
}
else if(op=="makefont") {
var mt = PSI.readArr(os.pop().val), fnt = JSON.parse(JSON.stringify(os.pop()));
PSI.M.concat(fnt.val.Tm, mt); os.push(fnt);
}
else if(op=="scalefont") {
var sc = os.pop().val, fnt = os.pop(); //console.log(ds);
fnt.val.Tfs *= sc; os.push(fnt);
}
else if(op=="stringwidth") {
var str=os.pop().val;
var sc = PSI.M.getScale(gst.font.Tm) / PSI.M.getScale(gst.ctm);
//console.log(PSI.getString(str), gst.font, 0.6*sc*str.length);
os.push({typ:"real",val:0.6*sc*str.length}, {typ:"real",val:sc});
}
else if(op=="setfont" ) gst.font = os.pop().val;
else if(op=="setlinewidth") gst.lwidth = os.pop().val;
else if(op=="setstrokeadjust") gst.strokeAdj = os.pop().val;
else if(op=="setlinecap") gst.lcap = os.pop().val;
else if(op=="setlinejoin") gst.ljoin = os.pop().val;
else if(op=="setmiterlimit") gst.mlimit = os.pop().val;
else if(op=="setflat") gst.dd.flat=os.pop();
else if(op=="setdash" ) { gst.doff=os.pop().val; gst.dash = PSI.readArr(os.pop().val); }
else if(op=="show"||op=="ashow"||op=="widthshow") {
var sar = os.pop().val, str=PSI.readStr(sar);
if(op=="widthshow") { os.pop(); os.pop(); os.pop(); }
if(op=="ashow" ) { os.pop(); os.pop(); }
var om = gst.ctm; gst.ctm = om.slice(0); gst.ctm[4]=gst.cpos[0]; gst.ctm[5]=gst.cpos[1];//PSI.M.translate(gst.ctm,gst.cpos[0],gst.cpos[1]);
genv.PutText(gst, str, str.length*0.55); gst.cpos[0] += str.length*PSI.M.getScale(om)*gst.font.Tfs*0.55; //console.log(str, gst.font.Tfs);
gst.ctm = om;
}
else if(op=="setgray" ) { var g=PSI.nrm(os.pop().val); gst.colr = gst.COLR = [g,g,g]; }
else if(op=="setrgbcolor") { var b=os.pop().val,g=os.pop().val,r=os.pop().val; gst.colr = gst.COLR = [PSI.nrm(r),PSI.nrm(g),PSI.nrm(b)]; }
else if(op=="sethsbcolor") {
var v=os.pop().val,s=os.pop().val,h=os.pop().val;
var r, g, b, i, f, p, q, t;
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
gst.colr = gst.COLR = [PSI.nrm(r),PSI.nrm(g),PSI.nrm(b)];
}
else if(op=="clip" || op=="eoclip") { gst.cpth = JSON.parse(JSON.stringify(gst.pth )); }
else if(op=="clippath" ) { gst.pth = JSON.parse(JSON.stringify(gst.cpth)); }
else if(op=="pathbbox" ) {
var ps = gst.pth.crds;
var bb = PSI.G.getBB(ps);
ps = [bb[0],bb[1], bb[2],bb[1], bb[0],bb[3], bb[2],bb[3]];
var im = gst.ctm.slice(0); PSI.M.invert(im); PSI.M.multArray(im,ps);
bb = PSI.G.getBB(ps);
f32[0]=bb[0]; bb[0]=f32[0]; f32[0]=bb[1]; bb[1]=f32[0]; f32[0]=bb[2]; bb[2]=f32[0]; f32[0]=bb[3]; bb[3]=f32[0];
bb = PSI.makeArr(bb,"real");
os.push(bb[0],bb[1],bb[2],bb[3]);
}
else if(op=="newpath" ) PSI.G.newPath(gst);
else if(op=="stroke" ) { genv.Stroke(gst); PSI.G.newPath(gst); }
else if(op=="fill" || op=="eofill") { genv.Fill(gst, op=="eofill"); PSI.G.newPath(gst); }
else if(op=="closepath") PSI.G.closePath(gst);
else if(op=="showpage" ) { genv.ShowPage (); var ofnt=gst.font; gst = env.gst = PSI._getState(env.bb); gst.font=ofnt; env.pgOpen = false; }
else if(op=="print" ) { var sar = os.pop().val, str=PSI.readStr(sar); genv.Print(str); }
else if(op=="moveto" || op=="lineto" ) {
var y = os.pop().val, x = os.pop().val;
if(op=="moveto" ) PSI.G.moveTo(gst,x,y); else PSI.G.lineTo(gst,x,y);
}
else if(op=="rmoveto" || op=="rlineto") {
var y = os.pop().val, x = os.pop().val;
var im=gst.ctm.slice(0); PSI.M.invert(im); var p = PSI.M.multPoint(im, gst.cpos);
y+=p[1]; x+=p[0];
if(op=="rmoveto") PSI.G.moveTo(gst,x,y); else PSI.G.lineTo(gst,x,y);
}
else if(op=="curveto") {
var y3=os.pop().val, x3=os.pop().val, y2=os.pop().val, x2=os.pop().val, y1=os.pop().val, x1=os.pop().val;
PSI.G.curveTo(gst,x1,y1,x2,y2,x3,y3);
}
else if(op=="arc" || op=="arcn") {
var a2 = os.pop().val, a1 = os.pop().val, r = os.pop().val, y = os.pop().val, x = os.pop().val;
//if(op=="arcn") a2=-a2;
PSI.G.arc(gst,x,y,r,a1*Math.PI/180,a2*Math.PI/180, op=="arcn");
}
else if(["translate","scale","rotate","concat"].indexOf(op)!=-1) {
var v = os.pop(), m, x, y;
if(v.typ=="array") { m = PSI.readArr(v.val); y = os.pop().val; }
else { m = [1,0,0,1,0,0]; y = v.val; }
if(op=="translate" || op=="scale") x = os.pop().val;
if(op=="translate") PSI.M.translate(m,x,y);
if(op=="scale" ) PSI.M.scale (m,x,y);
if(op=="rotate" ) PSI.M.rotate (m,-y*Math.PI/180);
if(op=="concat" ) PSI.M.concat (m,y);
if(v.typ=="array") os.push({typ:"array",val:PSI.makeArr(m,"real")});
else { PSI.M.concat(m,gst.ctm); gst.ctm = m; }
}
else if(op=="concatmatrix") { var rA = PSI.readArr;
var m3 = rA(os.pop().val), m2 = rA(os.pop().val), m1 = rA(os.pop().val);
var m = m1.slice(0); PSI.M.concat(m, m2); m = PSI.makeArr(m, "real");
os.push({typ:"array",val:m});
}
else if(op=="currentmatrix") {
var m = os.pop(), cm = PSI.makeArr(gst.ctm,"real"); // console.log(m, cm); throw "e";
for(var i=0; i<6; i++) m.val[i]=cm[i]; os.push(m);
}
else if(op=="setmatrix") {
gst.ctm = PSI.readArr(os.pop().val);
}
else if(op=="cvi") {
var o = os.pop(), v=o.val, out = 0;
if (o.typ=="real" ) out = Math.round(v);
else if(o.typ=="integer") out = v;
else throw "unknown type "+o.typ;
os.push({typ:"integer",val:out});
}
else if(op=="cvr") {
var o = os.pop(), v=o.val, out = 0;
if (o.typ=="real" ) out = v;
else if(o.typ=="integer") out = v;
else if(o.typ=="string" ) out = parseFloat(PSI.readStr(v));
else throw "unknown type "+o.typ;
os.push({typ:"real",val:out});
}
else if(op=="cvs") {
var str = os.pop(), any = os.pop(), nv = ""; str.val=[]; os.push(str);
if(any.typ=="real" || any.typ=="integer") {
if(Math.abs(Math.round(any.val)-any.val)<1e-6) nv=Math.round(any.val)+".0";
else nv = (Math.round(any.val*1000000)/1000000).toString();
}
else throw "unknown var type: "+any.typ;
for(var i=0; i<nv.length; i++) str.val[i]=nv.charCodeAt(i);
}
else if(op=="cvx") {
var o = os.pop();
//if(o.typ=="array") o.typ="procedure";
//else if(o.typ=="name" && o.val.charAt(0)=="/") o = {typ:"name",val:o.val.slice(1)};
//else { console.log(o); throw "e"; }
os.push(o);
}
else if(["add","sub","mul","div","idiv","bitshift","mod","exp","atan"].indexOf(op)!=-1) {
var o1 = os.pop(), o0 = os.pop(), v0=o0.val, v1=o1.val, out = 0, otp = "";
if(op=="add" || op=="sub" || op=="mul") otp = (o0.typ=="real" || o1.typ=="real") ? "real" : "integer";
else if(op=="div" || op=="atan" || op=="exp") otp = "real";
else if(op=="mod" || op=="idiv" || op=="bitshift") otp = "integer";
if(o0.typ=="real") { f32[0]=v0; v0=f32[0]; }
if(o1.typ=="real") { f32[0]=v1; v1=f32[0]; }
if(op=="add") out = v0+v1;
if(op=="sub") out = v0-v1;
if(op=="mul") out = v0*v1;
if(op=="div") out = v0/v1;
if(op=="idiv")out = ~~(v0/v1);
if(op=="bitshift") out = v1>0 ? (v0<<v1) : (v0>>>(-v1));
if(op=="mod") out = v0%v1;
if(op=="exp") out = Math.pow(v0, v1);
if(op=="atan")out = Math.atan2(v0, v1)*180/Math.PI;
if(otp=="real") { f32[0]=out; out=f32[0]; }
os.push({ typ:otp, val:out });
}
else if(["neg","abs","round","truncate","sqrt","ln","sin","cos"].indexOf(op)!=-1) {
var o0 = os.pop(), v0=o0.val, out = 0, otp = "";
if(op=="neg" || op=="abs" || op=="truncate") otp=o0.typ;
else if(op=="round") otp="integer";
else if(op=="sqrt" || op=="sin" || op=="cos" || op=="ln") otp="real";
if(o0.typ=="real") { f32[0]=v0; v0=f32[0]; }
if(op=="neg" ) out = -v0;
if(op=="abs" ) out = Math.abs(v0);
if(op=="round")out = Math.round(v0);
if(op=="truncate") out = Math.trunc(v0);
if(op=="sqrt") out = Math.sqrt(v0);
if(op=="ln" ) out = Math.log(v0);
if(op=="sin" ) out = Math.sin(v0*Math.PI/180);
if(op=="cos" ) out = Math.cos(v0*Math.PI/180);
if(op=="ln" && v0<=0) throw "e";
if(otp=="real") { f32[0]=out; out=f32[0]; }
os.push({typ:otp, val:out});
}
else if(["eq","ge","gt","le","lt","ne"].indexOf(op)!=-1) {
var o1=os.pop(), o0=os.pop(), v0=o0.val, v1=o1.val, out=false;
if(op=="eq") out=v0==v1;
if(op=="ge") out=v0>=v1;
if(op=="gt") out=v0> v1;
if(op=="le") out=v0<=v1;
if(op=="lt") out=v0< v1;
if(op=="ne") out=v0!=v1;
os.push({typ:"boolean",val:out});
}
else if(["and","or"].indexOf(op)!=-1) {
var b2 = os.pop(), b1 = os.pop(), v1=b1.val, v2 = b2.val, ints=(b1.typ=="integer"), out;
if(op=="and") out = ints ? (v1&v2) : (v1&&v2);
if(op=="or" ) out = ints ? (v1|v2) : (v1||v2);
os.push({typ:ints?"integer":"boolean", val:out});
}
else if(op=="not") {
var b=os.pop(), v=b.val, ints=b.typ=="integer";
var out = ints ? (~v) : (!v);
os.push({typ:ints?"integer":"boolean", val:out});
}
else if(op=="if") {
var proc = os.pop(), cnd = os.pop().val;
if(cnd) PSI.addProc(proc, es);//PSI.callProcedure(proc, file, os, ds, es, gs, gst, genv);
}
else if(op=="ifelse") {
var proc2 = os.pop(), proc1 = os.pop(), cnd = os.pop().val;
PSI.addProc(cnd?proc1:proc2, es);
}
else if(op=="exec" || op=="stopped") { var obj = os.pop();
if(op=="stopped") os.push({typ:"boolean", val:false});
if(obj.typ=="procedure") PSI.addProc(obj, es);
else if(obj.typ=="name") PSI.addProc({typ:"procedure",val:[obj]},es);
else throw "unknown executable type: "+obj.typ;
}
else if(op=="dup" ) { var v=os.pop(); os.push(v,v); }
else if(op=="exch") { os.push(os.pop(), os.pop()); }
else if(op=="copy") {
var n = os.pop(); //console.log(n);
if(n.typ=="integer") { var els=[]; for(var i=0; i<n.val; i++) els[n.val-1-i] = os.pop();
for(var i=0; i<n.val; i++) os.push(els[i]);
for(var i=0; i<n.val; i++) os.push(els[i]); }
else if(n.typ=="array") {
var m = os.pop().val;
for(var i=0; i<m.length; i++) { n.val[i]=m[i]; if(m[i].val==null) { console.log(ds); throw "e"; } }
os.push(n);
}
else throw "e";
}
else if(op=="roll") { var j=os.pop().val, n = os.pop().val;
var els = []; for(var i=0; i<n; i++) els.push(os.pop()); els.reverse();
j = (n+j)%n;
for(var i=0; i<j; i++) els.unshift(els.pop());
for(var i=0; i<n; i++) os.push(els[i]);
}
else if(op=="index") { var n=os.pop().val;
var els=[]; for(var i=0; i<=n; i++) els.push(os.pop()); els.reverse();
for(var i=0; i<=n; i++) os.push(els[i]); os.push(els[0]);
}
else if(op=="transform" || op=="itransform" || op=="dtransform") {
var m = os.pop(), y=0, x=0; //console.log(m);
if(m.typ=="array") { m = PSI.readArr(m.val); y = os.pop().val; }
else { y = m.val; m = gst.ctm.slice(0); }
if(op=="itransform") { PSI.M.invert(m); }
x = os.pop().val;
var np = PSI.M.multPoint(m, [x,y]);
if(op=="dtransform") { np[0]-=m[4]; np[1]-=m[5]; }
os.push({typ:"real",val:np[0]},{typ:"real",val:np[1]});
}
else if(op=="pop" || op=="srand" || op=="==" ) { os.pop(); }
else if(op=="rand") { os.push({typ:"integer",val:Math.floor(Math.random()*0x7fffffff)}); }
else if(op=="put" ) {
var val=os.pop(), o=os.pop(), obj=os.pop(), otp=obj.typ; //console.log(obj,o,val); throw "e";
if(otp=="array") obj.val[o.val] = val;
else if(otp=="dict") obj.val[o.val.slice(1)]=val;
else throw "e";
//.val.slice(1), obj=os.pop(); obj.val[key]=obj.typ=="string" ? val.val : val;
}
else if(op=="get" ) {
var o=os.pop(), obj=os.pop(), otp=obj.typ; // console.log(o, obj);
if (otp=="string") os.push({typ:"integer",val:obj.val[o.val]});
else if(otp=="array" ) os.push(obj.val[o.val]);
else throw "getting from unknown type "+ obj.typ; //os.push(obj.val[key]);
}
else if(op=="load") { var key=os.pop().val.slice(1), val = PSI.getFromStacks(key, ds);
if(val==null) { console.log(key, ds); throw "e"; } os.push(val); }
else if(op=="where"){ var key=os.pop().val.slice(1), dct=PSI.where(key,ds); //console.log(dct);
if(dct!=null) os.push({typ:"dict",val:dct}); os.push({typ:"boolean",val:dct!=null}); }
else if(op=="store"){
var val=os.pop(), key=os.pop().val.slice(1), dct=PSI.where(key,ds); //console.log(dct, key); throw "e";
if(dct==null) dct=ds[ds.length-1]; dct[key]=val; }
else if(op=="repeat" ) {
var proc=os.pop(), intg=os.pop().val;
es.push({typ:"name",val:op+"---", ctx:{ proc:proc, cur:0, cnt:intg }});
}
else if(op=="repeat---") {
var ctx = tok.ctx;
if(ctx.cur<ctx.cnt) { es.push(tok); PSI.addProc(ctx.proc, es); ctx.cur++; }
}
else if(op=="for" ) {
var proc=os.pop(), liV=os.pop(), icV=os.pop(), itV=os.pop();
es.push({typ:"name",val:op+"---", ctx:{ proc:proc, isInt:(itV.typ=="integer" && icV.typ=="integer"),
init:itV.val, inc:icV.val, limit:liV.val }});
}
else if(op=="for---") {
var ctx = tok.ctx;
if(ctx.isInt) {
if((ctx.inc>0 && ctx.init<=ctx.limit) || (ctx.inc<0 && ctx.init>=ctx.limit)) {
es.push(tok); PSI.addProc(ctx.proc, es);
os.push({typ:"integer",val:ctx.init}); ctx.init+=ctx.inc;
}
}
else {
var lf = new Float32Array(1);
lf[0]=ctx.limit; ctx.limit=lf[0];
lf[0]=ctx.inc ; ctx.inc =lf[0];
lf[0]=ctx.init;
if((ctx.inc>0 && lf[0]<=ctx.limit) || (ctx.inc<0 && lf[0]>=ctx.limit)) {
es.push(tok); PSI.addProc(ctx.proc, es);
os.push({typ:"real",val:lf[0]}); lf[0]+=ctx.inc; ctx.init=lf[0];
}
}
}
else if(op=="loop" ) {
var proc=os.pop();
es.push({typ:"name",val:op+"---", ctx:{ proc:proc }});
}
else if(op=="loop---") {
var ctx = tok.ctx;
PSI.addProc(ctx.proc, es);
}
else if(op=="forall") {
var proc = os.pop(), obj = os.pop();
es.push({typ:"name",val:op+"---",ctx:[proc,obj,0]});
}
else if(op=="forall---") {
var ctx=tok.ctx, proc=ctx[0],obj=ctx[1],i=ctx[2];
if(obj.typ=="dict") {
throw "e";
for(var p in obj.val) { PSI.addProcedure(proc.val, file); PSI.addProcedure([obj.val[p]], file); }
}
else if(obj.typ=="procedure" || obj.typ=="array") {
if(i<obj.val.length) {
es.push(tok); PSI.addProc(proc, es);
os.push(obj.val[i]); ctx[2]++;
}
//for(var i=obj.val.length-1; i>=0; i--) { PSI.addProcedure(proc.val, file); PSI.addProcedure([obj.val[i]], file); }
}
else { console.log(proc, obj); throw "forall: unknown type: "+obj.typ; }
}
else if(op=="exit") {
var i = es.length-1;
while(es[i].typ!="name" || !es[i].val.endsWith("---")) i--;
while(es.length>i) es.pop();
//console.log(es,i); throw "e";
}
else if(op=="bind") {
/* var v=os.pop(), prc=v.val; os.push(v);
for(var i=0; i<prc.length; i++){
var nop = PSI.getOperator(prc[i].val, ds);
//if(nop!=null) prc[i]=nop; // missing !!!
}*/
}
else if(op=="xcheck") {
var obj = os.pop(), typ=obj.typ;
os.push({typ:"boolean",val:(typ=="procedure")});
//console.log(obj); throw "e";
}
else if(op=="save" ) { os.push({typ:"state",val:JSON.parse(JSON.stringify(gst))}); }
else if(op=="restore" ) { gst = env.gst = os.pop().val; }
else if(op=="gsave" ) { gs.push(JSON.parse(JSON.stringify(gst))); }
else if(op=="grestore") { gst = env.gst = gs.pop(); }
else if(op=="usertime" || op=="realtime") os.push({typ:"integer",val:(op=="usertime"?(Date.now()-otime):Date.now())});
else if(op=="flush" || op=="readonly") {}
else if(op=="filter") {
var fname = os.pop().val.slice(1), sarr;
if(fname=="ASCII85Decode") {
var sfile = os.pop().val; sarr = PSI.F.ASCII85Decode(sfile);
}
else if(fname=="RunLengthDecode") {
var sfile = os.pop().val; sarr = PSI.F.RunLengthDecode(sfile);
}
else throw fname;
os.push({typ:"file", val:{buff:sarr, off:0, stk:[], env:{pckn:false}}});
}
else if(op=="begincmap" || op=="endcmap") {}
else if(op=="begincodespacerange"||op=="beginbfrange"||op=="beginbfchar") { env.cmnum = os.pop().val; }
else if(op=="endcodespacerange" ||op=="endbfrange" ||op=="endbfchar" ) {
var cl = (op=="endbfrange"?3:2);
var pn = op.slice(3), dct = ds[ds.length-1], bpc=0;
if(dct[pn]==null) dct[pn]=[];
for(var i=0; i<env.cmnum; i++) {
var vs=[];
for(var j=cl-1; j>=0; j--) {
var ar=os.pop(), av=ar.val, nv;
if(ar.typ=="string") { nv = PSI.strToInt(av); if(j==0) bpc=av.length; }
else { nv = []; for(var k=0; k<av.length; k++) nv.push(PSI.strToInt(av[k].val)); }
vs[j]=nv;
}
dct[pn] = dct[pn].concat(vs);
}
if(op!="endcodespacerange") dct["bpc"] = bpc; // bytes per input character
}
else if(Oprs) Oprs(op, os, ds, es, gs, env, genv);
else { console.log(val, op); console.log(ds, os); throw "e"; }
}
}
return true;
}
PSI.strToInt = function(str) { var v=0; for(var i=0; i<str.length; i++) v = (v<<8)|str[i]; return v; }
PSI.F = {
ASCII85Decode : function(file) {
var pws = [85*85*85*85, 85*85*85, 85*85, 85, 1];
var arr = [], i=0, tc=0, off=file.off;
while(true) {
if(off>=file.buff.length) throw "e";
var cc = file.buff[off]; off++;
if(PSI.isWhite(cc)) continue;
if(cc==126) {
if(i!=0) {
if(i==3) { arr.push(((tc>>>24)&255)); }
if(i==4) { arr.push(((tc>>>24)&255), ((tc>>>16)&255)); }
var lb = (5-i)<<3; // i=2: 24, i=3: 16 ...
var nn=((tc>>>lb)&255); tc=(tc&((1<<lb)-1)); if(tc!=0)nn++; arr.push(nn);
}
file.off=off+1; //console.log(arr.join(","));
return new Uint8Array(arr);
}
if(cc<33 || cc-33>84) throw "e";
tc += (cc-33)*pws[i]; i++;
if(i==5) {
arr.push((tc>>>24)&255); arr.push((tc>>>16)&255);
arr.push((tc>>> 8)&255); arr.push((tc>>> 0)&255);
i=0; tc=0;
}
}
},
RunLengthDecode : function(file) {
var arr = [], off=file.off;
while(true) {
if(off>=file.buff.length) { console.log(arr); throw "e"; }
var cc = file.buff[off]; off++;
if(cc==128) { file.off=off; return new Uint8Array(arr); }
if(cc< 128) { for(var i=0; i<cc+1 ; i++) arr.push(file.buff[off+i]); off+=cc+1; }
else { for(var i=0; i<257-cc; i++) arr.push(file.buff[off] ); off++; }
}
},
FlateDecode : function(file) {
var b = file.buff, ub = new Uint8Array(b.buffer,file.off,b.length); //console.log(ub);
var bytes = pako["inflate"](ub);
return bytes;
}
}
PSI.G = {
concat : function(p,r) {
for(var i=0; i<r.cmds.length; i++) p.cmds.push(r.cmds[i]);
for(var i=0; i<r.crds.length; i++) p.crds.push(r.crds[i]);
},
getBB : function(ps) {
var x0=1e99, y0=1e99, x1=-x0, y1=-y0;
for(var i=0; i<ps.length; i+=2) { var x=ps[i],y=ps[i+1]; if(x<x0)x0=x; else if(x>x1)x1=x; if(y<y0)y0=y; else if(y>y1)y1=y; }
return [x0,y0,x1,y1];
},
newPath: function(gst ) { gst.pth = {cmds:[], crds:[]}; },
moveTo : function(gst,x,y) { var p=PSI.M.multPoint(gst.ctm,[x,y]); //if(gst.cpos[0]==p[0] && gst.cpos[1]==p[1]) return;
gst.pth.cmds.push("M"); gst.pth.crds.push(p[0],p[1]); gst.cpos = p; },
lineTo : function(gst,x,y) { var p=PSI.M.multPoint(gst.ctm,[x,y]); if(gst.cpos[0]==p[0] && gst.cpos[1]==p[1]) return;
gst.pth.cmds.push("L"); gst.pth.crds.push(p[0],p[1]); gst.cpos = p; },
curveTo: function(gst,x1,y1,x2,y2,x3,y3) { var p;
p=PSI.M.multPoint(gst.ctm,[x1,y1]); x1=p[0]; y1=p[1];
p=PSI.M.multPoint(gst.ctm,[x2,y2]); x2=p[0]; y2=p[1];
p=PSI.M.multPoint(gst.ctm,[x3,y3]); x3=p[0]; y3=p[1]; gst.cpos = p;
gst.pth.cmds.push("C");
gst.pth.crds.push(x1,y1,x2,y2,x3,y3);
},
closePath: function(gst ) { gst.pth.cmds.push("Z"); },
arc : function(gst,x,y,r,a0,a1, neg) {
// circle from a0 counter-clock-wise to a1
if(neg) while(a1>a0) a1-=2*Math.PI;
else while(a1<a0) a1+=2*Math.PI;
var th = (a1-a0)/4;
var x0 = Math.cos(th/2), y0 = -Math.sin(th/2);
var x1 = (4-x0)/3, y1 = y0==0 ? y0 : (1-x0)*(3-x0)/(3*y0);
var x2 = x1, y2 = -y1;
var x3 = x0, y3 = -y0;
var p0 = [x0,y0], p1 = [x1,y1], p2 = [x2,y2], p3 = [x3,y3];
var pth = {cmds:[(gst.pth.cmds.length==0)?"M":"L","C","C","C","C"], crds:[x0,y0,x1,y1,x2,y2,x3,y3]};
var rot = [1,0,0,1,0,0]; PSI.M.rotate(rot,-th);
for(var i=0; i<3; i++) {
p1 = PSI.M.multPoint(rot,p1); p2 = PSI.M.multPoint(rot,p2); p3 = PSI.M.multPoint(rot,p3);
pth.crds.push(p1[0],p1[1],p2[0],p2[1],p3[0],p3[1]);
}
var sc = [r,0,0,r,x,y];
PSI.M.rotate(rot, -a0+th/2); PSI.M.concat(rot, sc); PSI.M.multArray(rot, pth.crds);
PSI.M.multArray(gst.ctm, pth.crds);
PSI.G.concat(gst.pth, pth);
var y=pth.crds.pop(); x=pth.crds.pop();
gst.cpos = [x,y];
}
}
PSI.M = {
getScale : function(m) { return Math.sqrt(Math.abs(m[0]*m[3]-m[1]*m[2])); },
translate: function(m,x,y) { PSI.M.concat(m, [1,0,0,1,x,y]); },
rotate : function(m,a ) { PSI.M.concat(m, [Math.cos(a), -Math.sin(a), Math.sin(a), Math.cos(a),0,0]); },
scale : function(m,x,y) { PSI.M.concat(m, [x,0,0,y,0,0]); },
concat : function(m,w ) {
var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5];
m[0] = (a *w[0])+(b *w[2]); m[1] = (a *w[1])+(b *w[3]);
m[2] = (c *w[0])+(d *w[2]); m[3] = (c *w[1])+(d *w[3]);
m[4] = (tx*w[0])+(ty*w[2])+w[4]; m[5] = (tx*w[1])+(ty*w[3])+w[5];
},
invert : function(m ) {
var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5], adbc=a*d-b*c;
m[0] = d/adbc; m[1] = -b/adbc; m[2] =-c/adbc; m[3] = a/adbc;
m[4] = (c*ty - d*tx)/adbc; m[5] = (b*tx - a*ty)/adbc;
},
multPoint: function(m, p ) { var x=p[0],y=p[1]; return [x*m[0]+y*m[2]+m[4], x*m[1]+y*m[3]+m[5]]; },
multArray: function(m, a ) { for(var i=0; i<a.length; i+=2) { var x=a[i],y=a[i+1]; a[i]=x*m[0]+y*m[2]+m[4]; a[i+1]=x*m[1]+y*m[3]+m[5]; } }
}
PSI.C = {
srgbGamma : function(x) { return x < 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1.0 / 2.4) - 0.055; },
cmykToRgb : function(c) { var iK = 1-c[3]; return [(1-c[0])*iK, (1-c[1])*iK, (1-c[2])*iK]; },
labToRgb : function(lab) {
var k = 903.3, e = 0.008856, L = lab[0], a = lab[1], b = lab[2];
var fy = (L+16)/116, fy3 = fy*fy*fy;
var fz = fy - b/200, fz3 = fz*fz*fz;
var fx = a/500 + fy, fx3 = fx*fx*fx;
var zr = fz3>e ? fz3 : (116*fz-16)/k;
var yr = fy3>e ? fy3 : (116*fy-16)/k;
var xr = fx3>e ? fx3 : (116*fx-16)/k;
var X = xr*96.72, Y = yr*100, Z = zr*81.427, xyz = [X/100,Y/100,Z/100];
var x2s = [3.1338561, -1.6168667, -0.4906146, -0.9787684, 1.9161415, 0.0334540, 0.0719453, -0.2289914, 1.4052427];
var rgb = [ x2s[0]*xyz[0] + x2s[1]*xyz[1] + x2s[2]*xyz[2],
x2s[3]*xyz[0] + x2s[4]*xyz[1] + x2s[5]*xyz[2],
x2s[6]*xyz[0] + x2s[7]*xyz[1] + x2s[8]*xyz[2] ];
for(var i=0; i<3; i++) rgb[i] = Math.max(0, Math.min(1, PSI.C.srgbGamma(rgb[i])));
return rgb;
}
}
PSI.B = {
readUshort : function(buff,p) { return (buff[p]<< 8) | buff[p+1]; },
readUint : function(buff,p) { return (buff[p]*(256*256*256)) + ((buff[p+1]<<16) | (buff[p+2]<< 8) | buff[p+3]); },
readASCII : function(buff,p,l){ var s = ""; for(var i=0; i<l; i++) s += String.fromCharCode(buff[p+i]); return s; }
}
PSI.nrm = function(v) { return Math.max(0,Math.min(1,v)); }
PSI.makeArr = function(a,typ) { var na=[]; for(var i=0; i<a.length; i++) na.push({typ:typ,val:a[i]}); return na; }
PSI.readArr = function(a ) { var na=[]; for(var i=0; i<a.length; i++) na.push(a[i].val ); return na; }
PSI.readStr = function(a ) { var s =""; for(var i=0; i<a.length; i++) s+=String.fromCharCode(a[i]); return s; }
PSI.getFromStacks = function(name, ds)
{
//console.log(ds);
var di = ds.length-1;
while(di>=0) { if(ds[di][name]!=null) return ds[di][name]; di--; }
return null;
}
PSI.where = function(name, ds)
{
var di = ds.length-1;
while(di>=0) { if(ds[di][name]!=null) return ds[di] ; di--; }
return null;
}
PSI.skipWhite = function(file) {
var i = file.off, buff=file.buff, isWhite = PSI.isWhite;
while(isWhite(buff[i]) || buff[i]==37) {
while(isWhite(buff[i])) i++; // not the first whitespace
if(buff[i]==37) { while(i<buff.length && !PSI.isEOL(buff[i])) i++; i++; } // comments
}
file.off = i;
}
PSI.getToken = function(es, ds) {
var src = es[es.length-1];
if(src.typ=="procedure") {
var tok = src.val[src.off]; src.off++;
if(src.off==src.val.length) es.pop();
return tok;
}
if(src.typ=="name") { es.pop(); return src; }
var ftok = PSI.getFToken(src.val, ds);
if(ftok==null) { es.pop(); if(es.length!=0) ftok = PSI.getFToken(es[es.length-1].val, ds); }
return ftok;
}
PSI.getFToken = function(file, ds) {
PSI.skipWhite(file);
var isWhite = PSI.isWhite, isSpecl = PSI.isSpecl;
var i = file.off, buff=file.buff, tok = null;
if(i>=buff.length) return null;
var cc = buff[i], ch = String.fromCharCode(cc); i++;
if(ch=="(") {
var dpth=0, end=i;
while(!(buff[end]==41 && dpth==0)) { if(buff[end]==40) dpth++; if(buff[end]==41) dpth--; if(buff[end]==92) end++; end++; }
var str = [];
for(var j=0; j<end-i; j++) str.push(buff[i+j]);
i = end+1;
str = PSI.getString(str);
tok = {typ:"string", val:str};
}
else if(ch=="{" || ch=="}" || ch=="[" || ch=="]") { tok = {typ:"name", val:ch}; }
else if((ch=="<" && buff[i]==60) || (ch==">" && buff[i]==62)) { tok = {typ:"name", val:ch=="<" ? "<<" : ">>"}; i++; }
else if(ch=="<") {
var end = i; while(buff[end]!=62) end++;
var str = PSI.readHex({buff:buff,off:i},(end-i)>>>1);
tok = {typ:"string",val:str}; i = end+1;
}
else {
var end = i;
while(end<buff.length && !isWhite(buff[end]) && (!isSpecl(buff[end]) || (buff[end]==47&&buff[end-1]==47&&end==i) )) end++; // read two slashes
var name = PSI.B.readASCII(buff, i-1, end-i+1);
i = end;
var num = parseFloat(name);
if(false) {}
else if(name=="true" || name=="false") tok = {typ:"boolean", val:name=="true"};
else if(!isNaN(num)) {
var f32 = new Float32Array(1); f32[0]=num; num=f32[0];
tok = {typ:name.indexOf(".")==-1?"integer":"real", val:num};
}
else {
if(name.slice(0,2)=="//") {
var nn = name.slice(2);
var sbs = PSI.getFromStacks(nn, ds);
if(sbs==null) throw "e";
tok = sbs;
}
else tok = {typ:"name", val:name};
}
}
file.off = i;
return tok;
}
// ( ) < > [ ] { } % /
PSI.isSpecl = function(cc) { return [ 40,41, 60,62, 91,93, 123,125, 37, 47 ].indexOf(cc)!=-1; }
PSI.isWhite = function(cc) { return cc==9 || cc==10 || cc==12 || cc==13 || cc==32; }
PSI.isEOL = function(cc) { return cc==10 || cc==13; }
PSI.getString = function(str) {
var s=[];
var m0 = ["n" , "r" , "t" , "b" , "f" , "\\", "(", ")", " ", "/"];
var m1 = ["\n", "\r", "\t", "", " ", "\\", "(", ")", " ", "/"];
for(var i=0; i<str.length; i++) {
var cc = str[i], ch = String.fromCharCode(cc);
if(ch=="\\") {
var nx = String.fromCharCode(str[i+1]); i++;
if(nx=="\r" || nx=="\n") continue;
var idx = m0.indexOf(nx);
if(idx!=-1) s.push(m1[idx].charCodeAt(0));
else {
var cod = nx + String.fromCharCode(str[i+1]) + String.fromCharCode(str[i+2]); i+=2;
s.push(parseInt(cod,8));
}
}
else s.push(cc);
}
return s;
}
PSI.makeString = function(arr) {
var m0 = ["n" , "r" , "t" , "b" , "f" , "\\", "(", ")"];
var m1 = ["\n", "\r", "\t", "", " ", "\\", "(", ")"];
var out = [];
for(var i=0; i<arr.length; i++) {
var b = arr[i];
var mi = m1.indexOf(String.fromCharCode(b));
if(mi==-1) out.push(b);
else out.push(92, m0[mi].charCodeAt(0));
}
return out;
}
PSI.readHex = function(fl, l)
{
var i=0, j=-1, val=[];
while(true) {
var cc = fl.buff[fl.off]; fl.off++;
var ci=0;
if(47<cc && cc<58) ci=cc-48;
else if(96<cc && cc<103) ci=10+cc-97;
else if(64<cc && cc<71 ) ci=10+cc-65;
else continue;
if(j==-1) j=ci;
else { val[i]=(j<<4)|ci; j=-1; i++; if(i==l) break; }
}
return val;
}
function ToContext2D(needPage, scale)
{
this.canvas = document.createElement("canvas");
this.ctx = this.canvas.getContext("2d");
this.bb = null;
this.currPage = 0;
this.needPage = needPage;
this.scale = scale;
}
ToContext2D.prototype.StartPage = function(x,y,w,h) {
if(this.currPage!=this.needPage) return;
this.bb = [x,y,w,h];
var scl = this.scale, dpr = window.devicePixelRatio;
var cnv = this.canvas, ctx = this.ctx;
cnv.width = Math.round(w*scl); cnv.height = Math.round(h*scl);
ctx.translate(0,h*scl); ctx.scale(scl,-scl);
cnv.setAttribute("style", "border:1px solid; width:"+(cnv.width/dpr)+"px; height:"+(cnv.height/dpr)+"px");
}
ToContext2D.prototype.Fill = function(gst, evenOdd) {
if(this.currPage!=this.needPage) return;
var ctx = this.ctx;
ctx.beginPath();
this._setStyle(gst, ctx);
this._draw(gst.pth, ctx);
ctx.fill();
}
ToContext2D.prototype.Stroke = function(gst) {
if(this.currPage!=this.needPage) return;
var ctx = this.ctx;
ctx.beginPath();
this._setStyle(gst, ctx);
this._draw(gst.pth, ctx);
ctx.stroke();
}
ToContext2D.prototype.PutText = function(gst, str, stw) {
if(this.currPage!=this.needPage) return;
var scl = this._scale(gst.ctm);
var ctx = this.ctx;
this._setStyle(gst, ctx);
ctx.save();
var m = [1,0,0,-1,0,0]; this._concat(m, gst.font.Tm); this._concat(m, gst.ctm);
//console.log(str, m, gst); throw "e";
ctx.transform(m[0],m[1],m[2],m[3],m[4],m[5]);
ctx.fillText(str,0,0);
ctx.restore();
}
ToContext2D.prototype.PutImage = function(gst, buff, w, h, msk) {
if(this.currPage!=this.needPage) return;
var ctx = this.ctx;
if(buff.length==w*h*4) {
buff = buff.slice(0);
if(msk && msk.length==w*h*4) for(var i=0; i<buff.length; i+=4) buff[i+3] = msk[i+1];
var cnv = document.createElement("canvas"), cctx = cnv.getContext("2d");
cnv.width = w; cnv.height = h;
var imgd = cctx.createImageData(w,h);
for(var i=0; i<buff.length; i++) imgd.data[i]=buff[i];
cctx.putImageData(imgd,0,0);
ctx.save();
var m = [1,0,0,1,0,0]; this._concat(m, [1/w,0,0,-1/h,0,1]); this._concat(m, gst.ctm);
ctx.transform(m[0],m[1],m[2],m[3],m[4],m[5]);
ctx.drawImage(cnv,0,0);
ctx.restore();
}
}
ToContext2D.prototype.ShowPage = function() { this.currPage++; }
ToContext2D.prototype.Done = function() {}
ToContext2D.prototype._setStyle = function(gst, ctx) {
var scl = this._scale(gst.ctm);
ctx.fillStyle = this._getFill(gst.colr, gst.ca, ctx);
ctx.strokeStyle=this._getFill(gst.COLR, gst.CA, ctx);
ctx.lineCap = ["butt","round","square"][gst.lcap];
ctx.lineJoin= ["miter","round","bevel"][gst.ljoin];
ctx.lineWidth=gst.lwidth*scl;
var dsh = gst.dash.slice(0); for(var i=0; i<dsh.length; i++) dsh[i] = ToPDF._flt(dsh[i]*scl);
ctx.setLineDash(dsh);
ctx.miterLimit = gst.mlimit*scl;
var fn = gst.font.Tf, ln = fn.toLowerCase();
var p0 = ln.indexOf("bold")!=-1 ? "bold " : "";
var p1 = (ln.indexOf("italic")!=-1 || ln.indexOf("oblique")!=-1) ? "italic " : "";
ctx.font = p0+p1 + gst.font.Tfs+"px \""+fn+"\"";
}
ToContext2D.prototype._getFill = function(colr, ca, ctx)
{
if(colr.typ==null) return this._colr(colr,ca);
else {
var grd = colr, crd = grd.crds, mat = grd.mat, scl=this._scale(mat), gf;
if (grd.typ=="lin") {
var p0 = this._multPoint(mat,crd.slice(0,2)), p1 = this._multPoint(mat,crd.slice(2));
gf=ctx.createLinearGradient(p0[0],p0[1],p1[0],p1[1]);
}
else if(grd.typ=="rad") {
var p0 = this._multPoint(mat,crd.slice(0,2)), p1 = this._multPoint(mat,crd.slice(3));
gf=ctx.createRadialGradient(p0[0],p0[1],crd[2]*scl,p1[0],p1[1],crd[5]*scl);
}
for(var i=0; i<grd.grad.length; i++) gf.addColorStop(grd.grad[i][0],this._colr(grd.grad[i][1], ca));
return gf;
}
}
ToContext2D.prototype._colr = function(c,a) { return "rgba("+Math.round(c[0]*255)+","+Math.round(c[1]*255)+","+Math.round(c[2]*255)+","+a+")"; };
ToContext2D.prototype._scale = function(m) { return Math.sqrt(Math.abs(m[0]*m[3]-m[1]*m[2])); };
ToContext2D.prototype._concat= function(m,w ) {
var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5];
m[0] = (a *w[0])+(b *w[2]); m[1] = (a *w[1])+(b *w[3]);
m[2] = (c *w[0])+(d *w[2]); m[3] = (c *w[1])+(d *w[3]);
m[4] = (tx*w[0])+(ty*w[2])+w[4]; m[5] = (tx*w[1])+(ty*w[3])+w[5];
}
ToContext2D.prototype._multPoint= function(m, p) { var x=p[0],y=p[1]; return [x*m[0]+y*m[2]+m[4], x*m[1]+y*m[3]+m[5]]; },
ToContext2D.prototype._draw = function(path, ctx)
{
var c = 0, crds = path.crds;
for(var j=0; j<path.cmds.length; j++) {
var cmd = path.cmds[j];
if (cmd=="M") { ctx.moveTo(crds[c], crds[c+1]); c+=2; }
else if(cmd=="L") { ctx.lineTo(crds[c], crds[c+1]); c+=2; }
else if(cmd=="C") { ctx.bezierCurveTo(crds[c], crds[c+1], crds[c+2], crds[c+3], crds[c+4], crds[c+5]); c+=6; }
else if(cmd=="Q") { ctx.quadraticCurveTo(crds[c], crds[c+1], crds[c+2], crds[c+3]); c+=4; }
else if(cmd=="Z") { ctx.closePath(); }
}
}
function ToPDF()
{
this._res = {
"/Font": {},
"/XObject":{},
"/ExtGState":{},
"/Pattern":{}
};
this._xr = [
null,
{ "/Type":"/Catalog", "/Pages":{typ:"ref",ind:2}},
{ "/Type":"/Pages", "/Kids" :[ ], "/Count":0 },
this._res
];
this._bnds = [];
this._cont = "";
this._gst = ToPDF.defState();
}
ToPDF.defState = function() {
return {"colr":"[0,0,0]", "COLR":"[0,0,0]", "lcap":"0","ljoin":"0", "lwidth":"1", "mlimit":"10", "dash":"[]","doff":"0", "bmode":"/Normal","CA":"1","ca":"1"}
}
ToPDF.prototype.StartPage = function(x0,y0,x1,y1) { this._bnds = [x0,y0,x1,y1] ; }
ToPDF.prototype.Stroke = function(gst) {
if(gst.CA==0) return;
this.setGState(gst, true);
this._cont += " S\n";
}
ToPDF.prototype.Fill = function(gst, evenOdd)
{
if(gst.ca==0) return;
this.setGState(gst, true);
this._cont += " f\n";
}
ToPDF._flt = function(n) { return ""+parseFloat(n.toFixed(2)); }
ToPDF._scale = function(m) { return Math.sqrt(Math.abs(m[0]*m[3]-m[1]*m[2])); };
ToPDF._mat = function(m){ var ms = m.map(ToPDF._flt).join(" ");
if(ms=="1 0 0 1 0 0") return ""; return ms+" cm "; }
ToPDF._eq = function(a,b){ if(a.length!=b.length) return false;
for(var i=0; i<a.length; i++) if(a[i]!=b[i]) return false;
return true;
}
ToPDF._format = function(b) {
var pfx = [ [0xff, 0xd8, 0xff ], // "jpg";
[0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20], // JPX
[0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x01, 0x00] ] // JBIG2
var fmt = ["/DCTDecode", "/JPXDecode", "/JBIG2Decode"];
for(var i=0; i<pfx.length; i++){
var pf = pfx[i], good = true;
for(var j=0; j<pf.length; j++) good = good && (b[j]==pf[j]);
if(good) return fmt[i];
}
}
ToPDF.prototype.setGState = function(gst, withPath) {
var ost = this._gst, nst = {};
for(var p in gst) nst[p] = (typeof gst[p]=="string") ? gst[p] : JSON.stringify(gst[p]);
var scl = ToPDF._scale(gst.ctm);
var dsh = gst.dash.slice(0); for(var i=0; i<dsh.length; i++) dsh[i] = ToPDF._flt(dsh[i]*scl);
var cnt = this._cont;
if(ost.lcap !=nst.lcap ) cnt += gst.lcap + " J ";
if(ost.ljoin!=nst.ljoin ) cnt += gst.ljoin + " j ";
if(ost.lwidth!=nst.lwidth) cnt += ToPDF._flt(gst.lwidth*scl) + " w ";
if(ost.mlimit!=nst.mlimit) cnt += ToPDF._flt(gst.mlimit) + " M ";
if(ost.dash!=nst.dash || ost.doff!=nst.doff) cnt += "["+dsh.join(" ")+"] "+gst.doff+" d ";
if(ost.COLR !=nst.COLR ) cnt += gst.COLR.map(ToPDF._flt).join(" ") + " RG ";
if(ost.colr !=nst.colr ) {
if(gst.colr.length!=null) cnt += gst.colr .map(ToPDF._flt).join(" ") + " rg \n";
else {
var ps = this._res["/Pattern"], grd = gst.colr;
var pi = "/P"+(ToPDF.maxI(ps)+1);
var sh = {
"/ShadingType":(grd.typ=="lin"?2:3),
"/ColorSpace":"/DeviceRGB",
"/Extend":[true, true],
"/Function" : ToPDF._makeGrad(grd.grad),
"/Coords" : grd.crds
};
ps[pi] = {
"/Type":"/Pattern",
"/PatternType":2,
"/Matrix":grd.mat,
"/Shading":sh
}
cnt += "/Pattern cs "+pi+" scn ";
}
}
var eg = this._res["/ExtGState"];
if(ost.bmode!=nst.bmode ) {
var sname = nst.bmode;
if(eg[sname]==null) eg[sname] = {"/Type":"/ExtGState", "/BM":gst.bmode};
cnt += sname + " gs ";
}
if(ost.CA!=nst.CA) {
var sname = "/Alpha"+Math.round(255*nst.CA);
if(eg[sname]==null) eg[sname] = {"/Type":"/ExtGState", "/CA":gst.CA};
cnt += sname + " gs ";
}
if(ost.ca!=nst.ca) {
var sname = "/alpha"+Math.round(255*nst.ca);
if(eg[sname]==null) eg[sname] = {"/Type":"/ExtGState", "/ca":gst.ca};
cnt += sname + " gs ";
}
/*if(ost.pth !=nst.pth )*/
if(withPath) cnt += ToPDF.drawPath(gst.pth);
//console.log(ost, nst);
this._cont = cnt;
this._gst = nst;
}
ToPDF.drawPath = function(pth) {
var co = 0, out = "", F = ToPDF._flt;
for(var i=0; i<pth.cmds.length; i++) {
var cmd = pth.cmds[i];
if (cmd=="M") { for(var j=0; j<2; j++) out += F(pth.crds[co++]) + " "; out += "m "; }
else if(cmd=="L") { for(var j=0; j<2; j++) out += F(pth.crds[co++]) + " "; out += "l "; }
else if(cmd=="C") { for(var j=0; j<6; j++) out += F(pth.crds[co++]) + " "; out += "c "; }
else if(cmd=="Z") { out += "h "; }
else throw cmd;
}
return out;
}
ToPDF._makeGrad = function(grd) {
//grd = grd.slice(0); grd[1]=grd[2]; grd = grd.slice(0,2);
var bs = [], fs = [], sf = ToPDF._stopFun;
if(grd.length==2) return sf(grd[0][1], grd[1][1]);
fs.push(sf(grd[0][1], grd[1][1]));
for(var i=1; i<grd.length-1; i++) { bs.push(grd[i][0]); fs.push(sf(grd[i][1], grd[i+1][1])); }
return {
"/FunctionType":3,"/Encode":[0,1,0,1],"/Domain":[0,1],
"/Bounds":bs, "/Functions":fs
}
}
ToPDF._stopFun = function(c0, c1) { return { "/FunctionType":2, "/C0":c0, "/C1":c1, "/Domain":[0,1], "/N":1}; }
ToPDF.prototype.PutText = function(gst,str, stw)
{
this.setGState(gst, false);
var fi = this.addFont(gst.font.Tf);
this._cont += "q ";
this._cont += ToPDF._mat(gst.ctm);
this._cont += ToPDF._mat(gst.font.Tm);
this._cont += "BT "+fi+" "+ToPDF._flt(gst.font.Tfs)+" Tf 0 0 Td ("
var win = [ 0x80, 0x20AC, 0x82, 0x201A, 0x83, 0x0192, 0x84, 0x201E, 0x85, 0x2026, 0x86, 0x2020, 0x87, 0x2021, 0x88, 0x02C6, 0x89, 0x2030,
0x8A, 0x0160, 0x8B, 0x2039, 0x8C, 0x0152, 0x8E, 0x017D, 0x91, 0x2018, 0x92, 0x2019, 0x93, 0x201C, 0x94, 0x201D, 0x95, 0x2022, 0x96, 0x2013,
0x97, 0x2014, 0x98, 0x02DC, 0x99, 0x2122, 0x9A, 0x0161, 0x9B, 0x203A, 0x9C, 0x0153, 0x9E, 0x017E, 0x9F, 0x0178 ];
var bys = [];
for(var i=0; i<str.length; i++) {
var cc=str.charCodeAt(i);
if(cc>255) {
var bi = win.indexOf(cc);
bys.push(bi==-1 ? 32 : win[bi-1]);
}
else bys.push(cc);
}
bys = FromPS.makeString(bys);
for(var i=0; i<bys.length; i++) this._cont += String.fromCharCode(bys[i]);
this._cont += ") Tj ET ";
this._cont += " Q\n";
}
ToPDF.prototype.PutImage = function(gst, img, w, h, msk) {
if(img.length==w*h*4 && msk==null) {
var area = w*h;
var alph = new Uint8Array(area), aand = 255;
for(var i=0; i<area; i++) { alph[i] = img[(i<<2)+3]; aand &= img[(i<<2)+3]; }
if(aand!=255) msk = alph;
}
var ii = this.addImage(img,w,h, msk);
this.setGState(gst, false);
this._cont += "q "+ToPDF._mat(gst.ctm);
this._cont += ii + " Do Q\n";
}
ToPDF.prototype.ShowPage = function() {
//console.log(this._cont);
//console.log(this._res);
ToPDF.addPage(this._xr, this._cont, this._bnds);
this._cont = "";
this._gst = ToPDF.defState();
}
ToPDF.prototype.Print = function(str) {
}
ToPDF.prototype.Done = function() {
var res = this._res;
for(var p in res) if(Object.keys(res[p])==0) delete res[p];
this.buffer = ToPDF.xrToPDF(this._xr);
}
ToPDF.prototype.addImage= function(img, w, h, msk){
//console.log(img.length, w*h);
var mii;
if(msk) {
var mst = msk;
if(msk.length==w*h*4) {
mst = new Uint8Array(w*h);
for(var i=0; i<mst.length; i++) mst[i] = msk[(i<<2)+1];
}
mii = this.addImage(mst, w, h, null);
}
var fmt = ToPDF._format(img);
var ist = img;
if(img.length==w*h*4) {
ist = new Uint8Array(w*h*3);
for(var i=0; i<img.length; i+=4) { var ti = 3*(i>>2); ist[ti]=img[i+0]; ist[ti+1]=img[i+1]; ist[ti+2]=img[i+2]; }
}
var xo = this._res["/XObject"];
for(var ii in xo) if(ToPDF._eq(this._xr[xo[ii].ind]["stream"],ist)) return ii;
var ii = "/I"+(ToPDF.maxI(xo)+1);
xo[ii] = {"typ":"ref",ind:this._xr.length};
var io = {
"/Type":"/XObject",
"/Subtype":"/Image",
"/BitsPerComponent":8,
"/ColorSpace":(img.length==w*h || (fmt=="/DCTDecode" && ToPDF.jpgProp(img) && ToPDF.jpgProp(img).comps==1)) ? "/DeviceGray" : "/DeviceRGB",
"/Height":h,
"/Width":w,
"stream":ist
}
if(fmt!=null) io["/Filter"] = ToPDF._format(img);
if(msk) { io["/SMask"] = {"typ":"ref","ind":this._xr.length-1}; delete xo[mii]; }
this._xr.push(io);
return ii;
}
ToPDF.jpgProp = function(data) {
var off = 0;
while(off<data.length) {
while(data[off]==0xff) off++;
var mrkr = data[off]; off++;
if(mrkr==0xd8) continue; // SOI
if(mrkr==0xd9) break; // EOI
if(0xd0<=mrkr && mrkr<=0xd7) continue;
if(mrkr==0x01) continue; // TEM
var len = ((data[off]<<8)|data[off+1])-2; off+=2;
if(mrkr==0xc0) return {
bpp : data[off],
w : (data[off+1]<<8)|data[off+2],
h : (data[off+3]<<8)|data[off+4],
comps : data[off+5]
}
off+=len;
}
}
ToPDF.readUshort = function(data, o) { return ((data[o]<<8)|data[o+1]); }
ToPDF.maxI = function(xo) {
var max;
for(var ii in xo) max = ii;
return max==null ? 0 : parseInt(max.slice(2));
}
ToPDF.prototype.addFont = function(fn) {
var fs = this._res["/Font"];
for(var fi in fs) if(fs[fi]["/BaseFont"].slice(1)==fn) return fi;
var fi = "/F"+(ToPDF.maxI(fs)+1);
fs[fi] = { "/Type":"/Font", "/Subtype":"/Type1", "/BaseFont": "/"+fn, "/Encoding":"/WinAnsiEncoding" // Type1 supports only 1 Byte per character, otherwise use Type0
////"/Encoding":"/Identity-H", "/DescendantFonts":[{ "/BaseFont":"/"+fn, "/CIDToGIDMap":"/Identity" }], "/ToUnicode":{"typ":"ref",ind:4}
};
return fi;
}
ToPDF.addPage = function(xr, stm, box) {
var i = xr.length;
xr[2]["/Kids"].push({typ:"ref",ind:i});
xr[2]["/Count"]++;
xr.push({ "/Type":"/Page",
"/Parent" :{ typ:"ref",ind:2 },
"/Resources":{ typ:"ref",ind:3 },
"/MediaBox": box,
"/Contents" :{ typ:"ref",ind:i+1 }
});
xr.push({"stream":stm});
}
ToPDF.xrToPDF = function(xr)
{
var F = {file:new ToPDF.MFile(), off:0}, W = ToPDF.write, offs = [];
W(F, "%PDF-1.1\n");
for(var i=1; i<xr.length; i++) {
offs.push(F.off);
W(F, i+" 0 obj\n");
ToPDF.writeDict(F, xr[i], 0);
W(F, "\nendobj\n");
}
var sxr = F.off;
W(F, "xref\n");
W(F, "0 "+xr.length+"\n");
W(F, "0000000000 65535 f \n");
for(var i=0; i<offs.length; i++) {
var oo = offs[i]+""; while(oo.length<10) oo = "0"+oo;
W(F, oo+" 00000 n \n");
}
W(F, "trailer\n");
ToPDF.writeDict(F, {"/Root": {typ:"ref", ind:1}, "/Size":xr.length}, 0);
W(F, "\nstartxref\n"+sxr+"\n%%EOF\n");
return F.file.data.buffer.slice(0, F.off);
}
ToPDF.write = function(F, s)
{
F.file.req(F.off, s.length);
for(var i=0; i<s.length; i++) F.file.data[F.off+i] = s.charCodeAt(i);
F.off+=s.length;
}
ToPDF._tab = " ";
ToPDF.spc = function(n) { var out=""; for(var i=0; i<n; i++) out+=ToPDF._tab; return out; }
ToPDF.writeValue = function(F, v, dpt)
{
var W = ToPDF.write;
if(false) {}
else if(typeof v == "string" ) W(F, v);
else if(typeof v == "number" ) W(F, ""+v);
else if(typeof v == "boolean") W(F, ""+v);
else if(v.typ!=null) W(F, v.ind+" 0 R");
else if(v instanceof Array ) ToPDF.writeArray(F, v, dpt+1);
else if(v instanceof Object) ToPDF.writeDict (F, v, dpt+1);
else { console.log(v); throw "e"; }
}
ToPDF.writeDict = function(F, d, dpt) {
var W = ToPDF.write, S = ToPDF.spc;
var stm = d["stream"];
if(stm) {
if((typeof stm)=="string") {
var nstm = new Uint8Array(stm.length);
for(var i=0; i<stm.length; i++) nstm[i]=stm.charCodeAt(i);
stm = nstm;
}
if(d["/Filter"]==null) {
d["/Filter"]="/FlateDecode";
stm = pako["deflate"](stm);
}
}
W(F,"<<\n");
for(var p in d) {
if(p.charAt(0)!="/") continue;
W(F, S(dpt+1)+p+" ");
ToPDF.writeValue(F, d[p], dpt);
W(F, "\n");
}
if(stm) W(F, S(dpt+1)+"/Length "+stm.length+"\n");
W(F,S(dpt)+">>");
if(stm) {
W(F, S(dpt)+"\nstream\n");
F.file.req(F.off, stm.length);
for(var i=0; i<stm.length; i++) F.file.data[F.off+i]=stm[i];
F.off += stm.length;
W(F, S(dpt)+"\nendstream");
}
}
ToPDF.writeArray = function(F, a, dpt)
{
var W = ToPDF.write;
W(F,"[ ");
for(var i=0; i<a.length; i++) {
ToPDF.writeValue(F, a[i], dpt+1);
if(i!=a.length-1) W(F, " ");
}
W(F," ]");
}
ToPDF.MFile = function()
{
this.size = 16;
this.data = new Uint8Array(16);
}
ToPDF.MFile.prototype.req = function(off, len)
{
if(off + len <= this.size) return;
var ps = this.size;
while(off+len>this.size) this.size *= 2;
var ndata = new Uint8Array(this.size);
for(var i=0; i<ps; i++) ndata[i] = this.data[i];
this.data = ndata;
}
function ToEMF()
{
/*
this._gst = ToEMF.defState();*/
this._file = {file:new ToEMF.MFile(), off:0};
this._lstw = 0;
this._curx = 0;
this._curh = 0;
this._recs = 0;
this._lenp = 0;
this._objs = {};
this._tabl = 1;
this._stkf = 0;
this._tclr = 0; // text color
this._curt = {"p":-1, "b":-1, "t":-1};
this._inited = false;
}
ToEMF.prototype.StartPage = function(x0,y0,x1,y1) {
this._check();
var f = this._file, wU32=ToEMF.B.writeUint, wI32=ToEMF.B.writeInt;
this._curh = Math.max(this._curh, y1*10);
if(!this._inited) {
this._inited = true;
this._addRec("HEADER", 88);
ToEMF._writeHeadBox(f, [x0,y0,x1,y1]); f.off+=32;
ToEMF.B.writeASCII(f.file,f.off," EMF"); f.off+=4;
wU32(f.file,f.off,65536); f.off+=4;
this._lenp = f.off; f.off+=4+4+4;
f.off += 4+4+4;
wI32(f.file,f.off,1440); f.off+=4;
wI32(f.file,f.off, 900); f.off+=4;
wI32(f.file,f.off, 508); f.off+=4;
wI32(f.file,f.off, 318); f.off+=4;
this._trsf([0.1,0,0,0.1,0,0]);
this._addRec("SETBKMODE", 12); // makes text background transparent
wU32(f.file,f.off,1); f.off+=4;
this._addRec("SETTEXTALIGN", 12);
wU32(f.file,f.off,24); f.off+=4;
}
else {
this._curx += this._lstw;
ToEMF._writeHeadBox(f, [0,0, this._curx+x1, Math.round(this._curh/10)]);
}
this._lstw = x1;
}
ToEMF.prototype.Stroke = function(gst ) { this._draw(gst, 1); }
ToEMF.prototype.Fill = function(gst, evenOdd) { this._draw(gst, 2); }
ToEMF.prototype.PutImage=function(gst, img, w, h, msk) {
var imgl = img.length; if((imgl&3)!=0) imgl += 4-(imgl&3);
var m = [1,0,0,-1,0,1]; UDOC.M.concat(m,gst.ctm);
UDOC.M.scale(m, 10, 10);
UDOC.M.scale(m, 1, -1);
UDOC.M.translate(m, this._curx, this._curh);
this._trsf(m);
var f = this._file, wU32=ToEMF.B.writeUint, wI32=ToEMF.B.writeInt, wU16=ToEMF.B.writeUshort;
var soff = 8+16+14*4;
this._addRec("STRETCHDIBITS",soff+40+imgl);
//console.log(img.length, w*h*4);
f.off+=16; // bbox
wI32(f.file,f.off,Math.round(0)); f.off+=4;
wI32(f.file,f.off,Math.round(0)); f.off+=4;
f.off+=8;
wI32(f.file,f.off,w); f.off+=4;
wI32(f.file,f.off,h); f.off+=4;
wU32(f.file,f.off,soff); f.off+=4;
wU32(f.file,f.off,40); f.off+=4;
wU32(f.file,f.off,soff+40); f.off+=4;
wU32(f.file,f.off,img.length); f.off+=4;
f.off+=4;
wU32(f.file,f.off,0x00cc0020); f.off+=4;
wI32(f.file,f.off,Math.round(1)); f.off+=4;
wI32(f.file,f.off,Math.round(1)); f.off+=4;
wI32(f.file,f.off,40); f.off+=4;
wI32(f.file,f.off, w); f.off+=4;
wI32(f.file,f.off, h); f.off+=4;
wU16(f.file,f.off, 1); f.off+=2;
wU16(f.file,f.off,32); f.off+=2;
wI32(f.file,f.off, 0); f.off+=4;
wI32(f.file,f.off,img.length); f.off+=4;
wI32(f.file,f.off,3800); f.off+=4;
wI32(f.file,f.off,3800); f.off+=4;
f.off+=8;
f.file.req(f.off, img.length);
if(img.length==w*h*4) {
for(var y=0; y<h; y++)
for(var x=0; x<w; x++) {
var qi=(y*w+x)<<2, ti=f.off + (((h-1-y)*w+x)<<2);
f.file.data[ti ]=img[qi+2];
f.file.data[ti+1]=img[qi+1];
f.file.data[ti+2]=img[qi ];
f.file.data[ti+3]=img[qi+3];
}
}
else for(var i=0; i<img.length; i++) f.file.data[f.off+i] = img[i];
f.off+=imgl;
UDOC.M.invert(m); this._trsf(m);
}
ToEMF.prototype.PutText= function(gst, str,stw) {
var strl = str.length;
if((strl&1)==1) strl++;
this._check(); //return;
var f = this._file, wU32=ToEMF.B.writeUint, wI32=ToEMF.B.writeInt, wU=ToEMF.B.writeUshort, wF=ToEMF.B.writeFloat;
//*
var tclr = ToEMF._color(gst.colr);
if(tclr!=this._tclr) {
this._addRec("SETTEXTCOLOR", 12);
wU32(f.file, f.off, tclr); f.off+=4;
this._tclr = tclr;
}//*/
this._setTool("f", [gst.font.Tf, Math.round(gst.font.Tfs*10)]);
var ox = 10*(gst.ctm[4]+this._curx), oy = this._curh-10*gst.ctm[5], gotRot = Math.abs(gst.ctm[1])>0.05, rm;
if(gotRot) { rm=gst.ctm.slice(0); rm[1]*=-1; rm[2]*=-1; rm[4]=ox; rm[5]=oy; ox=oy=0; this._trsf(rm); }
var soff = 8+16+12 +4*6 +16;
this._addRec("EXTTEXTOUTW", soff+ strl*2);
//ToEMF._writeBox(f, [0,0,500,500]);
f.off+=16;
wU32(f.file,f.off,2); f.off+=4;
wF (f.file,f.off,31.25); f.off+=4;
wF (f.file,f.off,31.25); f.off+=4;
wI32(f.file,f.off,Math.round(ox)); f.off+=4;
wI32(f.file,f.off,Math.round(oy)); f.off+=4;
wU32(f.file,f.off,str.length); f.off+=4;
wU32(f.file,f.off,soff); f.off+=4;
wU32(f.file,f.off,0); f.off+=4;
//ToEMF._writeBox(f, [0,0,3000,3000]);
f.off+=16;
wU32(f.file,f.off,0); f.off+=4;
for(var i=0; i<str.length; i++) wU(f.file, f.off+i*2, str.charCodeAt(i));
f.off+=2*strl;
if(gotRot) { UDOC.M.invert(rm); this._trsf(rm); }
}
ToEMF.prototype.ShowPage=function() { this._check(); }
ToEMF.prototype.Done = function() {
this._check();
var f = this._file, wU32=ToEMF.B.writeUint;
this._addRec("EOF", 20);
wU32(f.file,f.off, 0); f.off+=4;
wU32(f.file,f.off,16); f.off+=4;
wU32(f.file,f.off,20); f.off+=4;
wU32(f.file,this._lenp , f.off);
wU32(f.file,this._lenp+4, this._recs);
wU32(f.file,this._lenp+8, this._tabl);
this.buffer = f.file.data.buffer.slice(0,f.off);
}
ToEMF.prototype._check = function() {
var f = this._file, sf = this._stkf; if(sf==0) return;
if(sf==1) this._addRec("STROKEPATH",24);
if(sf==2) this._addRec("FILLPATH",24);
if(sf==3) this._addRec("STROKEANDFILLPATH",24);
f.off+=16;
this._stkf=0;
}
ToEMF.prototype._addRec = function(fnm, siz) {
var f = this._file, wU32=ToEMF.B.writeUint;
this._recs++;
wU32(f.file,f.off,ToEMF.C["EMR_"+fnm]); f.off+=4;
wU32(f.file,f.off,siz); f.off+=4;
}
ToEMF.prototype._trsf = function(mat) {
var f = this._file, wI32=ToEMF.B.writeInt;
this._addRec("MODIFYWORLDTRANSFORM", 36);
for(var i=0; i<mat.length; i++) { ToEMF.B.writeFloat(f.file, f.off, mat[i]); f.off+=4; }
wI32(f.file,f.off, 2); f.off+=4;
}
ToEMF._writeHeadBox = function(f, box) {
var loff = f.off; f.off = 8;
ToEMF._writeBox(f, box);
var scl = (1/72)*25.4*100;
ToEMF._writeBox(f, [0,0,Math.round((box[2]-box[0])*scl), Math.round((box[3]-box[1])*scl)]);
f.off = loff;
}
ToEMF._writeBox = function(f, box) {
for(var i=0; i<4; i++) { ToEMF.B.writeInt(f.file, f.off, box[i]); f.off+=4; }
}
ToEMF.prototype._draw = function(gst, stkf) { // stkf is 1 or 2
var f = this._file, wU32=ToEMF.B.writeUint, wI32=ToEMF.B.writeInt;
var pth = gst.pth, spth = JSON.stringify(pth);
if(this._cpth!=spth) this._check();
if(stkf==1) this._setTool("p", [gst.COLR, gst.lwidth, gst.ljoin]);
else this._setTool("b", [gst.colr]);
if(this._cpth==spth) {
this._stkf += stkf;
}
else {
var ops = { "M":["MOVETOEX",1], "L":["LINETO",1], "C":["POLYBEZIERTO",3], "Z":["CLOSEFIGURE",0] }
var coff=0, cl=pth.cmds.length;
this._addRec("BEGINPATH",8);
for(var i=0; i<cl; i++) {
var c = pth.cmds[i];
var op = ops[c]; if(op==null) throw c+" e";
var cnum = op[1]*2, fnm=op[0], hsz = 8 + 4*cnum, cnt=1;
while(true) { if(i+cnt<cl && pth.cmds[i+cnt]==c) cnt++; else break; }
var useMulti = c=="C" || (c=="L" && cnt>1);
if(useMulti) {
cnum *= cnt;
if(c=="L") fnm="POLYLINETO";
hsz = 8 + 20 + 4*cnum;
}
this._addRec(fnm,hsz);
if(useMulti) { f.off+=16; wU32(f.file, f.off, cnt*op[1]); f.off+=4; i+=cnt-1; }
for(var j=0; j<cnum; j+=2) {
wI32(f.file, f.off, Math.round(10*(pth.crds[coff]+this._curx))); f.off+=4; coff++;
wI32(f.file, f.off, Math.round(this._curh-10*pth.crds[coff])); f.off+=4; coff++;
}
}
this._addRec("ENDPATH",8);
this._cpth = spth;
this._stkf = stkf;
}
}
ToEMF.prototype._setTool = function(t, pms) {
var f = this._file, wU32=ToEMF.B.writeUint, wI32=ToEMF.B.writeInt;
var bkey = t+JSON.stringify(pms);
var bid = this._objs[bkey];
if(bid==null) {
bid = this._objs[bkey] = this._tabl; this._tabl++;
if(t=="b") this._addRec("CREATEBRUSHINDIRECT",24);
if(t=="p") this._addRec("CREATEPEN", 28);
if(t=="f") this._addRec("EXTCREATEFONTINDIRECTW",104);
wU32(f.file, f.off, bid); f.off+=4;
if(t=="b" || t=="p") {
if(t=="p") {
wU32(f.file, f.off, 0/*[0x2000,0,0x1000][pms[2]]*/); f.off+=4;
var lw = Math.round(pms[1]*10);
wU32(f.file, f.off, lw); f.off+=4;
wU32(f.file, f.off, lw); f.off+=4;
}
else { wU32(f.file, f.off, 0); f.off+=4; }
wU32(f.file, f.off, ToEMF._color(pms[0])); f.off+=4;
if(t=="b") { wU32(f.file, f.off, 0); f.off+=4; }
}
if(t=="f") {
var fn = pms[0], isB = fn.toLowerCase().indexOf("bold")!=-1;
if(fn.endsWith("-Bold")) fn=fn.slice(0,fn.length-5);
wI32(f.file, f.off, -pms[1]); f.off+=4;
f.off+=12; // wid, esc, orn,
wU32(f.file, f.off, isB ? 700 : 400); f.off+=4;
wU32(f.file, f.off, 0x00000000); f.off+=4; // 0, 0, 0, 0
wU32(f.file, f.off, 0x00040007); f.off+=4; // 7, 0, 4, 0
for(var i=0; i<fn.length; i++) ToEMF.B.writeUshort(f.file, f.off+i*2, fn.charCodeAt(i));
//ToEMF.B.writeASCII(f.file, f.off, fn);
f.off+=64;
}
}
if(this._curt[t]!=bid) {
this._addRec("SELECTOBJECT",12);
wU32(f.file, f.off, bid); f.off+=4;
this._curt[t]=bid;
}
}
ToEMF._color = function(clr) { var r=Math.round(clr[0]*255), g=Math.round(clr[1]*255), b=Math.round(clr[2]*255); return (b<<16)|(g<<8)|(r<<0); }
ToEMF.B = {
uint8 : new Uint8Array(4),
writeShort : function(f,p,v) { ToEMF.B.int16 [0]=v; f.req(p,2); var u8=ToEMF.B.uint8,b=f.data; b[p]=u8[0]; b[p+1]=u8[1]; },
writeUshort : function(f,p,v) { ToEMF.B.uint16[0]=v; f.req(p,2); var u8=ToEMF.B.uint8,b=f.data; b[p]=u8[0]; b[p+1]=u8[1]; },
writeInt : function(f,p,v) { ToEMF.B.int32 [0]=v; f.req(p,4); var u8=ToEMF.B.uint8,b=f.data; b[p]=u8[0]; b[p+1]=u8[1]; b[p+2]=u8[2]; b[p+3]=u8[3]; },
writeUint : function(f,p,v) { ToEMF.B.uint32[0]=v; f.req(p,4); var u8=ToEMF.B.uint8,b=f.data; b[p]=u8[0]; b[p+1]=u8[1]; b[p+2]=u8[2]; b[p+3]=u8[3]; },
writeFloat : function(f,p,v) { ToEMF.B.flot32[0]=v; f.req(p,4); var u8=ToEMF.B.uint8,b=f.data; b[p]=u8[0]; b[p+1]=u8[1]; b[p+2]=u8[2]; b[p+3]=u8[3]; },
writeASCII : function(f,p,v) { f.req(p,v.length); for(var i=0; i<v.length; i++) f.data[p+i]=v.charCodeAt(i); }
}
ToEMF.B.int16 = new Int16Array (ToEMF.B.uint8.buffer);
ToEMF.B.uint16 = new Uint16Array(ToEMF.B.uint8.buffer);
ToEMF.B.int32 = new Int32Array (ToEMF.B.uint8.buffer);
ToEMF.B.uint32 = new Uint32Array(ToEMF.B.uint8.buffer);
ToEMF.B.flot32 = new Float32Array(ToEMF.B.uint8.buffer);
ToEMF.MFile = function()
{
this.size = 16;
this.data = new Uint8Array(16);
}
ToEMF.MFile.prototype.req = function(off, len)
{
if(off + len <= this.size) return;
var ps = this.size;
while(off+len>this.size) this.size *= 2;
var ndata = new Uint8Array(this.size);
for(var i=0; i<ps; i++) ndata[i] = this.data[i];
this.data = ndata;
}
ToEMF.C = {
EMR_HEADER : 0x00000001,
EMR_POLYBEZIER : 0x00000002,
EMR_POLYGON : 0x00000003,
EMR_POLYLINE : 0x00000004,
EMR_POLYBEZIERTO : 0x00000005,
EMR_POLYLINETO : 0x00000006,
EMR_POLYPOLYLINE : 0x00000007,
EMR_POLYPOLYGON : 0x00000008,
EMR_SETWINDOWEXTEX : 0x00000009,
EMR_SETWINDOWORGEX : 0x0000000A,
EMR_SETVIEWPORTEXTEX : 0x0000000B,
EMR_SETVIEWPORTORGEX : 0x0000000C,
EMR_SETBRUSHORGEX : 0x0000000D,
EMR_EOF : 0x0000000E,
EMR_SETPIXELV : 0x0000000F,
EMR_SETMAPPERFLAGS : 0x00000010,
EMR_SETMAPMODE : 0x00000011,
EMR_SETBKMODE : 0x00000012,
EMR_SETPOLYFILLMODE : 0x00000013,
EMR_SETROP2 : 0x00000014,
EMR_SETSTRETCHBLTMODE : 0x00000015,
EMR_SETTEXTALIGN : 0x00000016,
EMR_SETCOLORADJUSTMENT : 0x00000017,
EMR_SETTEXTCOLOR : 0x00000018,
EMR_SETBKCOLOR : 0x00000019,
EMR_OFFSETCLIPRGN : 0x0000001A,
EMR_MOVETOEX : 0x0000001B,
EMR_SETMETARGN : 0x0000001C,
EMR_EXCLUDECLIPRECT : 0x0000001D,
EMR_INTERSECTCLIPRECT : 0x0000001E,
EMR_SCALEVIEWPORTEXTEX : 0x0000001F,
EMR_SCALEWINDOWEXTEX : 0x00000020,
EMR_SAVEDC : 0x00000021,
EMR_RESTOREDC : 0x00000022,
EMR_SETWORLDTRANSFORM : 0x00000023,
EMR_MODIFYWORLDTRANSFORM : 0x00000024,
EMR_SELECTOBJECT : 0x00000025,
EMR_CREATEPEN : 0x00000026,
EMR_CREATEBRUSHINDIRECT : 0x00000027,
EMR_DELETEOBJECT : 0x00000028,
EMR_ANGLEARC : 0x00000029,
EMR_ELLIPSE : 0x0000002A,
EMR_RECTANGLE : 0x0000002B,
EMR_ROUNDRECT : 0x0000002C,
EMR_ARC : 0x0000002D,
EMR_CHORD : 0x0000002E,
EMR_PIE : 0x0000002F,
EMR_SELECTPALETTE : 0x00000030,
EMR_CREATEPALETTE : 0x00000031,
EMR_SETPALETTEENTRIES : 0x00000032,
EMR_RESIZEPALETTE : 0x00000033,
EMR_REALIZEPALETTE : 0x00000034,
EMR_EXTFLOODFILL : 0x00000035,
EMR_LINETO : 0x00000036,
EMR_ARCTO : 0x00000037,
EMR_POLYDRAW : 0x00000038,
EMR_SETARCDIRECTION : 0x00000039,
EMR_SETMITERLIMIT : 0x0000003A,
EMR_BEGINPATH : 0x0000003B,
EMR_ENDPATH : 0x0000003C,
EMR_CLOSEFIGURE : 0x0000003D,
EMR_FILLPATH : 0x0000003E,
EMR_STROKEANDFILLPATH : 0x0000003F,
EMR_STROKEPATH : 0x00000040,
EMR_FLATTENPATH : 0x00000041,
EMR_WIDENPATH : 0x00000042,
EMR_SELECTCLIPPATH : 0x00000043,
EMR_ABORTPATH : 0x00000044,
EMR_COMMENT : 0x00000046,
EMR_FILLRGN : 0x00000047,
EMR_FRAMERGN : 0x00000048,
EMR_INVERTRGN : 0x00000049,
EMR_PAINTRGN : 0x0000004A,
EMR_EXTSELECTCLIPRGN : 0x0000004B,
EMR_BITBLT : 0x0000004C,
EMR_STRETCHBLT : 0x0000004D,
EMR_MASKBLT : 0x0000004E,
EMR_PLGBLT : 0x0000004F,
EMR_SETDIBITSTODEVICE : 0x00000050,
EMR_STRETCHDIBITS : 0x00000051,
EMR_EXTCREATEFONTINDIRECTW : 0x00000052,
EMR_EXTTEXTOUTA : 0x00000053,
EMR_EXTTEXTOUTW : 0x00000054,
EMR_POLYBEZIER16 : 0x00000055,
EMR_POLYGON16 : 0x00000056,
EMR_POLYLINE16 : 0x00000057,
EMR_POLYBEZIERTO16 : 0x00000058,
EMR_POLYLINETO16 : 0x00000059,
EMR_POLYPOLYLINE16 : 0x0000005A,
EMR_POLYPOLYGON16 : 0x0000005B,
EMR_POLYDRAW16 : 0x0000005C,
EMR_CREATEMONOBRUSH : 0x0000005D,
EMR_CREATEDIBPATTERNBRUSHPT : 0x0000005E,
EMR_EXTCREATEPEN : 0x0000005F,
EMR_POLYTEXTOUTA : 0x00000060,
EMR_POLYTEXTOUTW : 0x00000061,
EMR_SETICMMODE : 0x00000062,
EMR_CREATECOLORSPACE : 0x00000063,
EMR_SETCOLORSPACE : 0x00000064,
EMR_DELETECOLORSPACE : 0x00000065,
EMR_GLSRECORD : 0x00000066,
EMR_GLSBOUNDEDRECORD : 0x00000067,
EMR_PIXELFORMAT : 0x00000068,
EMR_DRAWESCAPE : 0x00000069,
EMR_EXTESCAPE : 0x0000006A,
EMR_SMALLTEXTOUT : 0x0000006C,
EMR_FORCEUFIMAPPING : 0x0000006D,
EMR_NAMEDESCAPE : 0x0000006E,
EMR_COLORCORRECTPALETTE : 0x0000006F,
EMR_SETICMPROFILEA : 0x00000070,
EMR_SETICMPROFILEW : 0x00000071,
EMR_ALPHABLEND : 0x00000072,
EMR_SETLAYOUT : 0x00000073,
EMR_TRANSPARENTBLT : 0x00000074,
EMR_GRADIENTFILL : 0x00000076,
EMR_SETLINKEDUFIS : 0x00000077,
EMR_SETTEXTJUSTIFICATION : 0x00000078,
EMR_COLORMATCHTOTARGETW : 0x00000079,
EMR_CREATECOLORSPACEW : 0x0000007A
};
ToEMF.K = [];
(function() {
var inp, out, stt;
inp = ToEMF.C; out = ToEMF.K; stt=4;
for(var p in inp) out[inp[p]] = p.slice(stt);
} )();
var UDOC = {};
UDOC.G = {
concat : function(p,r) {
for(var i=0; i<r.cmds.length; i++) p.cmds.push(r.cmds[i]);
for(var i=0; i<r.crds.length; i++) p.crds.push(r.crds[i]);
},
getBB : function(ps) {
var x0=1e99, y0=1e99, x1=-x0, y1=-y0;
for(var i=0; i<ps.length; i+=2) { var x=ps[i],y=ps[i+1]; if(x<x0)x0=x; else if(x>x1)x1=x; if(y<y0)y0=y; else if(y>y1)y1=y; }
return [x0,y0,x1,y1];
},
rectToPath: function(r) { return {cmds:["M","L","L","L","Z"],crds:[r[0],r[1],r[2],r[1], r[2],r[3],r[0],r[3]]}; },
// a inside b
insideBox: function(a,b) { return b[0]<=a[0] && b[1]<=a[1] && a[2]<=b[2] && a[3]<=b[3]; },
isBox : function(p, bb) {
var sameCrd8 = function(pcrd, crds) {
for(var o=0; o<8; o+=2) { var eq = true; for(var j=0; j<8; j++) if(Math.abs(crds[j]-pcrd[(j+o)&7])>=2) { eq = false; break; } if(eq) return true; }
return false;
};
if(p.cmds.length>10) return false;
var cmds=p.cmds.join(""), crds=p.crds;
var sameRect = false;
if((cmds=="MLLLZ" && crds.length== 8)
||(cmds=="MLLLLZ" && crds.length==10) ) {
if(crds.length==10) crds=crds.slice(0,8);
var x0=bb[0],y0=bb[1],x1=bb[2],y1=bb[3];
if(!sameRect) sameRect = sameCrd8(crds, [x0,y0,x1,y0,x1,y1,x0,y1]);
if(!sameRect) sameRect = sameCrd8(crds, [x0,y1,x1,y1,x1,y0,x0,y0]);
}
return sameRect;
},
boxArea: function(a) { var w=a[2]-a[0], h=a[3]-a[1]; return w*h; },
newPath: function(gst ) { gst.pth = {cmds:[], crds:[]}; },
moveTo : function(gst,x,y) { var p=UDOC.M.multPoint(gst.ctm,[x,y]); //if(gst.cpos[0]==p[0] && gst.cpos[1]==p[1]) return;
gst.pth.cmds.push("M"); gst.pth.crds.push(p[0],p[1]); gst.cpos = p; },
lineTo : function(gst,x,y) { var p=UDOC.M.multPoint(gst.ctm,[x,y]); if(gst.cpos[0]==p[0] && gst.cpos[1]==p[1]) return;
gst.pth.cmds.push("L"); gst.pth.crds.push(p[0],p[1]); gst.cpos = p; },
curveTo: function(gst,x1,y1,x2,y2,x3,y3) { var p;
p=UDOC.M.multPoint(gst.ctm,[x1,y1]); x1=p[0]; y1=p[1];
p=UDOC.M.multPoint(gst.ctm,[x2,y2]); x2=p[0]; y2=p[1];
p=UDOC.M.multPoint(gst.ctm,[x3,y3]); x3=p[0]; y3=p[1]; gst.cpos = p;
gst.pth.cmds.push("C");
gst.pth.crds.push(x1,y1,x2,y2,x3,y3);
},
closePath: function(gst ) { gst.pth.cmds.push("Z"); },
arc : function(gst,x,y,r,a0,a1, neg) {
// circle from a0 counter-clock-wise to a1
if(neg) while(a1>a0) a1-=2*Math.PI;
else while(a1<a0) a1+=2*Math.PI;
var th = (a1-a0)/4;
var x0 = Math.cos(th/2), y0 = -Math.sin(th/2);
var x1 = (4-x0)/3, y1 = y0==0 ? y0 : (1-x0)*(3-x0)/(3*y0);
var x2 = x1, y2 = -y1;
var x3 = x0, y3 = -y0;
var p0 = [x0,y0], p1 = [x1,y1], p2 = [x2,y2], p3 = [x3,y3];
var pth = {cmds:[(gst.pth.cmds.length==0)?"M":"L","C","C","C","C"], crds:[x0,y0,x1,y1,x2,y2,x3,y3]};
var rot = [1,0,0,1,0,0]; UDOC.M.rotate(rot,-th);
for(var i=0; i<3; i++) {
p1 = UDOC.M.multPoint(rot,p1); p2 = UDOC.M.multPoint(rot,p2); p3 = UDOC.M.multPoint(rot,p3);
pth.crds.push(p1[0],p1[1],p2[0],p2[1],p3[0],p3[1]);
}
var sc = [r,0,0,r,x,y];
UDOC.M.rotate(rot, -a0+th/2); UDOC.M.concat(rot, sc); UDOC.M.multArray(rot, pth.crds);
UDOC.M.multArray(gst.ctm, pth.crds);
UDOC.G.concat(gst.pth, pth);
var y=pth.crds.pop(); x=pth.crds.pop();
gst.cpos = [x,y];
},
toPoly : function(p) {
if(p.cmds[0]!="M" || p.cmds[p.cmds.length-1]!="Z") return null;
for(var i=1; i<p.cmds.length-1; i++) if(p.cmds[i]!="L") return null;
var out = [], cl = p.crds.length;
if(p.crds[0]==p.crds[cl-2] && p.crds[1]==p.crds[cl-1]) cl-=2;
for(var i=0; i<cl; i+=2) out.push([p.crds[i],p.crds[i+1]]);
if(UDOC.G.polyArea(p.crds)<0) out.reverse();
return out;
},
fromPoly : function(p) {
var o = {cmds:[],crds:[]};
for(var i=0; i<p.length; i++) { o.crds.push(p[i][0], p[i][1]); o.cmds.push(i==0?"M":"L"); }
o.cmds.push("Z");
return o;
},
polyArea : function(p) {
if(p.length <6) return 0;
var l = p.length - 2;
var sum = (p[0]-p[l]) * (p[l+1]+p[1]);
for(var i=0; i<l; i+=2)
sum += (p[i+2]-p[i]) * (p[i+1]+p[i+3]);
return - sum * 0.5;
},
polyClip : function(p0, p1) { // p0 clipped by p1
var cp1, cp2, s, e;
var inside = function (p) {
return (cp2[0]-cp1[0])*(p[1]-cp1[1]) > (cp2[1]-cp1[1])*(p[0]-cp1[0]);
};
var isc = function () {
var dc = [ cp1[0] - cp2[0], cp1[1] - cp2[1] ],
dp = [ s[0] - e[0], s[1] - e[1] ],
n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0],
n2 = s[0] * e[1] - s[1] * e[0],
n3 = 1.0 / (dc[0] * dp[1] - dc[1] * dp[0]);
return [(n1*dp[0] - n2*dc[0]) * n3, (n1*dp[1] - n2*dc[1]) * n3];
};
var out = p0;
cp1 = p1[p1.length-1];
for (j in p1) {
var cp2 = p1[j];
var inp = out;
out = [];
s = inp[inp.length - 1]; //last on the input list
for (i in inp) {
var e = inp[i];
if (inside(e)) {
if (!inside(s)) {
out.push(isc());
}
out.push(e);
}
else if (inside(s)) {
out.push(isc());
}
s = e;
}
cp1 = cp2;
}
return out
}
}
UDOC.M = {
getScale : function(m) { return Math.sqrt(Math.abs(m[0]*m[3]-m[1]*m[2])); },
translate: function(m,x,y) { UDOC.M.concat(m, [1,0,0,1,x,y]); },
rotate : function(m,a ) { UDOC.M.concat(m, [Math.cos(a), -Math.sin(a), Math.sin(a), Math.cos(a),0,0]); },
scale : function(m,x,y) { UDOC.M.concat(m, [x,0,0,y,0,0]); },
concat : function(m,w ) {
var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5];
m[0] = (a *w[0])+(b *w[2]); m[1] = (a *w[1])+(b *w[3]);
m[2] = (c *w[0])+(d *w[2]); m[3] = (c *w[1])+(d *w[3]);
m[4] = (tx*w[0])+(ty*w[2])+w[4]; m[5] = (tx*w[1])+(ty*w[3])+w[5];
},
invert : function(m ) {
var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5], adbc=a*d-b*c;
m[0] = d/adbc; m[1] = -b/adbc; m[2] =-c/adbc; m[3] = a/adbc;
m[4] = (c*ty - d*tx)/adbc; m[5] = (b*tx - a*ty)/adbc;
},
multPoint: function(m, p ) { var x=p[0],y=p[1]; return [x*m[0]+y*m[2]+m[4], x*m[1]+y*m[3]+m[5]]; },
multArray: function(m, a ) { for(var i=0; i<a.length; i+=2) { var x=a[i],y=a[i+1]; a[i]=x*m[0]+y*m[2]+m[4]; a[i+1]=x*m[1]+y*m[3]+m[5]; } }
}
UDOC.C = {
srgbGamma : function(x) { return x < 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1.0 / 2.4) - 0.055; },
cmykToRgb : function(clr) {
var c=clr[0], m=clr[1], y=clr[2], k=clr[3];
// return [1-Math.min(1,c+k), 1-Math.min(1, m+k), 1-Math.min(1,y+k)];
var r = 255
+ c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k + -285.2331026137004)
+ m * ( 1.7149763477362134 * m - 5.6096736904047315 * y + -17.873870861415444 * k - 5.497006427196366)
+ y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813)
+ k * (-21.86122147463605 * k - 189.48180835922747);
var g = 255
+ c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k + -79.2970844816548)
+ m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951)
+ y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878)
+ k * (-20.737325471181034 * k - 187.80453709719578);
var b = 255
+ c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k + -14.183576799673286)
+ m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248)
+ y * (0.03296041114873217 * y + 115.60384449646641 * k + -193.58209356861505)
+ k * (-22.33816807309886 * k - 180.12613974708367);
return [Math.max(0, Math.min(1, r/255)), Math.max(0, Math.min(1, g/255)), Math.max(0, Math.min(1, b/255))];
//var iK = 1-c[3];
//return [(1-c[0])*iK, (1-c[1])*iK, (1-c[2])*iK];
},
labToRgb : function(lab) {
var k = 903.3, e = 0.008856, L = lab[0], a = lab[1], b = lab[2];
var fy = (L+16)/116, fy3 = fy*fy*fy;
var fz = fy - b/200, fz3 = fz*fz*fz;
var fx = a/500 + fy, fx3 = fx*fx*fx;
var zr = fz3>e ? fz3 : (116*fz-16)/k;
var yr = fy3>e ? fy3 : (116*fy-16)/k;
var xr = fx3>e ? fx3 : (116*fx-16)/k;
var X = xr*96.72, Y = yr*100, Z = zr*81.427, xyz = [X/100,Y/100,Z/100];
var x2s = [3.1338561, -1.6168667, -0.4906146, -0.9787684, 1.9161415, 0.0334540, 0.0719453, -0.2289914, 1.4052427];
var rgb = [ x2s[0]*xyz[0] + x2s[1]*xyz[1] + x2s[2]*xyz[2],
x2s[3]*xyz[0] + x2s[4]*xyz[1] + x2s[5]*xyz[2],
x2s[6]*xyz[0] + x2s[7]*xyz[1] + x2s[8]*xyz[2] ];
for(var i=0; i<3; i++) rgb[i] = Math.max(0, Math.min(1, UDOC.C.srgbGamma(rgb[i])));
return rgb;
}
}
UDOC.getState = function(crds) {
return {
font : UDOC.getFont(),
dd: {flat:1}, // device-dependent
space :"/DeviceGray",
// fill
ca: 1,
colr : [0,0,0],
sspace:"/DeviceGray",
// stroke
CA: 1,
COLR : [0,0,0],
bmode: "/Normal",
SA:false, OPM:0, AIS:false, OP:false, op:false, SMask:"/None",
lwidth : 1,
lcap: 0,
ljoin: 0,
mlimit: 10,
SM : 0.1,
doff: 0,
dash: [],
ctm : [1,0,0,1,0,0],
cpos: [0,0],
pth : {cmds:[],crds:[]},
cpth: crds ? UDOC.G.rectToPath(crds) : null // clipping path
};
}
UDOC.getFont = function() {
return {
Tc: 0, // character spacing
Tw: 0, // word spacing
Th:100, // horizontal scale
Tl: 0, // leading
Tf:"Helvetica-Bold",
Tfs:1, // font size
Tmode:0, // rendering mode
Trise:0, // rise
Tk: 0, // knockout
Tal:0, // align, 0: left, 1: right, 2: center
Tun:0, // 0: no, 1: underline
Tm :[1,0,0,1,0,0],
Tlm:[1,0,0,1,0,0],
Trm:[1,0,0,1,0,0]
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment