#include <u.h>#include <libc.h>#include <draw.h>#include <memdraw.h>#include "pdf.h" enum { Evenodd = 1<<0, Nonstroking = 1<<1, Leading = 1<<2, Nextline = 1<<3, TwTc = 1<<4,}; typedef struct Op Op; static voidmatidentity(double *arr){ double src[6] = { 1, 0, 0, 1, 0, 0 }; memcpy(arr, src, sizeof(double) * 6);} static voidmatmult(double *m1, double *m2, double *out){ double result[6]; result[0] = m1[0] * m2[0] + m1[1] * m2[2]; result[1] = m1[0] * m2[1] + m1[1] * m2[3]; result[2] = m1[2] * m2[0] + m1[3] * m2[2]; result[3] = m1[2] * m2[1] + m1[3] * m2[3]; result[4] = m1[4] * m2[0] + m1[5] * m2[2] + m2[4]; result[5] = m1[4] * m2[1] + m1[5] * m2[3] + m2[5]; memcpy(out, result, sizeof(double) * 6);} static voidmattrans(double *m1, double x, double y, double *out){ double mult[6] = { 1, 0, 0, 1, x, y, }; matmult(mult, m1, out);} static voidmatscale(double *m1, double x, double y, double *out){ double mult[6] = { x, 0, 0, y, 0, 0, }; matmult(mult, m1, out);} struct Op { char *s; int (*f)(Op *op, Page *p); int argc; int flags;}; static intflagless(Op *op){ if(op->flags != 0){ werrstr("op %q: expected no flags", op->s); return -1; } return 0;} static intcobegin(Op *op, Page *p){ USED(op, p); return -1;} static intcoend(Op *op, Page *p){ USED(op, p); return -1;} static intgspush(Op *op, Page *p){ GS *r; USED(op); if((r = realloc(p->GS, sizeof(GS) * (p->nGS + 1))) == nil) return -1; p->GS = r; p->nGS++; p->GSactive = &p->GS[p->nGS - 1]; *(p->GSactive) = p->GS[p->nGS - 2]; if(p->GSactive->Font.widths != nil){ p->GSactive->Font.widths = malloc(sizeof(int) * (p->GSactive->Font.last - p->GSactive->Font.first + 1)); if(p->GSactive->Font.widths == nil){ werrstr("gspush: out of memory allocating space for glyph widths"); return -1; } memcpy(p->GSactive->Font.widths, p->GS[p->nGS - 2].Font.widths, sizeof(int) * (p->GSactive->Font.last - p->GSactive->Font.first + 1)); } return 0;} static intgspop(Op *op, Page *p){ USED(op); free(p->GSactive->Font.widths); GS *r = realloc(p->GS, sizeof(GS) * (p->nGS - 1)); if(r == nil) return -1; p->GS = r; p->nGS--; p->GSactive = &p->GS[p->nGS - 1]; return 0;} /* six parameters give the inputs a,b,c,d,e,f for the matrix [a b 0] [c d 0] [e f 1] That matrix should be premultiplied with the current matrix newCTM = input x oldCTM (8.3.4) */static intgsctm(Op *op, Page *p){ double input[6]; int i; for(i = 0; i < 6; i++) input[i] = arrayget(p->stack, i)->num.d; matmult(input, p->GSactive->CTM, p->GSactive->CTM); return flagless(op);} static intgswidth(Op *op, Page *p){ p->GSactive->LW = arrayget(p->stack, 0)->num.d; if(p->GSactive->LW < 0){ werrstr("gswidth: invalid line width: %f", p->GSactive->LW); return -1; } return flagless(op);} static intgscap(Op *op, Page *p){ p->GSactive->LC = arrayget(p->stack, 0)->num.d; if(p->GSactive->LC > CapEND){ werrstr("gscap: invalid line cap: %d", p->GSactive->LC); return -1; } return flagless(op);} static intgsjoin(Op *op, Page *p){ p->GSactive->LJ = arrayget(p->stack, 0)->num.d; if(p->GSactive->LJ > JoinEND){ werrstr("gsjoin: invalid line join: %d", p->GSactive->LJ); return -1; } return flagless(op);} static intgsmiterlim(Op *op, Page *p){ p->GSactive->ML = arrayget(p->stack, 0)->num.d; if(p->GSactive->ML < 0){ werrstr("gsmiterlim: invalidmiter limit: %f", p->GSactive->ML); return -1; } return flagless(op);} static intgsdash(Op *op, Page *p){ USED(op, p); return -1;} static intgsintent(Op *op, Page *p){ USED(op, p); return -1;} static intgsflatness(Op *op, Page *p){ p->GSactive->FL = arrayget(p->stack, 0)->num.d; return flagless(op);} static intgsstate(Op *op, Page *p){ char *name = arrayget(p->stack, 0)->name; Object *gs, *o; if((gs = dictget(dictget(dictget(p->obj, "Resources"), "ExtGState"), name)) == &null){ werrstr("extgstate dictionary not found: %s", name); goto err; } if((o = dictget(gs, "Type")) != &null && strcmp(o->name, "ExtGState") != 0){ werrstr("invalid type on ExtGState object: %s", o->name); goto err; } if((o = dictget(gs, "LW")) != &null){ if(o->type != Onum){ werrstr("line width is not a number"); goto err; } p->GSactive->LW = o->num.d; } if((o = dictget(gs, "LC")) != &null){ if(o->type != Onum){ werrstr("line cap is not a number"); goto err; } p->GSactive->LC = o->num.i; } if((o = dictget(gs, "LJ")) != &null){ if(o->type != Onum){ werrstr("line join is not a number"); goto err; } p->GSactive->LJ = o->num.i; } if((o = dictget(gs, "ML")) != &null){ if(o->type != Onum){ werrstr("miter limit is not a number"); goto err; } p->GSactive->ML = o->num.d; } return flagless(op);err: werrstr("gsstate: %r"); return -1;} static intpcmove(Op *op, Page *p){ USED(op, p); return -1;} static intpcline(Op *op, Page *p){ USED(op, p); return -1;} static intpccurve(Op *op, Page *p){ USED(op, p); return -1;} static intpcsubpath(Op *op, Page *p){ USED(op, p); return -1;} static intpcrect(Op *op, Page *p){ USED(op, p); return -1;} static intppstroke(Op *op, Page *p){ USED(op, p); return -1;} static intppstrokec(Op *op, Page *p){ USED(op, p); return -1;} static intppfill(Op *op, Page *p){ USED(op, p); return -1;} static intppfills(Op *op, Page *p){ USED(op, p); return -1;} static intppfillcfs(Op *op, Page *p){ USED(op, p); return -1;} static intppc(Op *op, Page *p){ USED(op, p); return -1;} static intcpclip(Op *op, Page *p){ USED(op, p); return -1;} static char *colorspacedevices[] = {"DeviceGray", "DeviceRGB", "DeviceCMYK"};static ColorSpace colorspacechans[] = { [1] = DeviceGray, [3] = DeviceRGB, [4] = DeviceCMYK,}; static inticcbasedcspace(Object *icc, ColorSpace *c){ Object *o; *c = colorspacechans[dictint(icc, "N")]; if((o = dictget(icc, "Alternate")) != &null){ if(*c > 2 || strcmp(colorspacedevices[*c], o->name) != 0){ werrstr("iccbasedcspace: TODO: handle non-device alternate %q", o->name); return -1; } } return 0;} static intcspace(Op *op, Page *p){ ColorSpace *c = (op->flags & Nonstroking) ? &p->GSactive->NSCS : &p->GSactive->SCS; u32int *color = (op->flags & Nonstroking) ? &p->GSactive->NSC : &p->GSactive->SC; char *s = arrayget(p->stack, 0)->name; Object *o; int i; for(i = 0; i < nelem(colorspacedevices); i++){ if(strcmp(s, colorspacedevices[i]) == 0){ *c = i; *color = i == 2 ? 0xFF : 0; return 0; } } if((o = dictget(dictget(p->obj, "Resources"), "ColorSpace")) == &null || (o = dictget(o, s)) == &null){ werrstr("colorspace not found: %q", s); return -1; } if(strcmp(arrayget(o, 0)->name, "ICCBased") == 0){ /* Don't support ICC; fall back to Alternate or default */ o = arrayget(o, 1); if(!iccbasedcspace(o, c)) return -1; *color = *c == 2 ? 0xFF : 0; return 0; } werrstr("cspace: TODO: color space %q", arrayget(o, 0)->name); return -1;} static intccolour(Op *op, Page *p){ ColorSpace c = op->flags & Nonstroking ? p->GSactive->NSCS : p->GSactive->SCS; u32int *color = op->flags & Nonstroking ? &p->GSactive->NSC : &p->GSactive->SC; if(c == DeviceRGB){ *color = ((u8int)(255 * arrayget(p->stack, 0)->num.d)) << 24 | ((u8int)(255 * arrayget(p->stack, 1)->num.d)) << 16 | ((u8int)(255 * arrayget(p->stack, 2)->num.d)) << 8 | 0xff; return 0; } return -1;} static intccolour2(Op *op, Page *p){ ColorSpace c = op->flags & Nonstroking ? p->GSactive->NSCS : p->GSactive->SCS; if(c < 3) return ccolour(op, p); return -1;} static intcgray(Op *op, Page *p){ int value = 255 * arrayget(p->stack, 0)->num.d; u32int *color; int i; if(op->flags & Nonstroking){ color = &p->GSactive->NSC; p->GSactive->NSCS = DeviceGray; }else{ color = &p->GSactive->SC; p->GSactive->SCS = DeviceGray; } *color = 0; for(i = 0; i < 3; i++) *color = (*color | value) << 8; *color |= 255; return 0;} static intcrgb(Op *op, Page *p){ USED(op, p); return -1;} static intccmyk(Op *op, Page *p){ USED(op, p); return -1;} static intsshade(Op *op, Page *p){ USED(op, p); return -1;} static inteoobject(Op *op, Page *p){ USED(op, p); return -1;} static intiibegin(Op *op, Page *p){ USED(op, p); return -1;} static intiidata(Op *op, Page *p){ USED(op, p); return -1;} static intiiend(Op *op, Page *p){ USED(op, p); return -1;} static inttsspace(Op *op, Page *p){ USED(op); p->TS.Tc = arrayget(p->stack, 0)->num.d; return 0;}Lines 1–500 of 1564. Load more
#include <u.h> #include <libc.h> #include <draw.h> #include <memdraw.h> #include "pdf.h" enum { Evenodd = 1<<0, Nonstroking = 1<<1, Leading = 1<<2, Nextline = 1<<3, TwTc = 1<<4, }; typedef struct Op Op; static void matidentity(double *arr) { double src[6] = { 1, 0, 0, 1, 0, 0 }; memcpy(arr, src, sizeof(double) * 6); } static void matmult(double *m1, double *m2, double *out) { double result[6]; result[0] = m1[0] * m2[0] + m1[1] * m2[2]; result[1] = m1[0] * m2[1] + m1[1] * m2[3]; result[2] = m1[2] * m2[0] + m1[3] * m2[2]; result[3] = m1[2] * m2[1] + m1[3] * m2[3]; result[4] = m1[4] * m2[0] + m1[5] * m2[2] + m2[4]; result[5] = m1[4] * m2[1] + m1[5] * m2[3] + m2[5]; memcpy(out, result, sizeof(double) * 6); } static void mattrans(double *m1, double x, double y, double *out) { double mult[6] = { 1, 0, 0, 1, x, y, }; matmult(mult, m1, out); } static void matscale(double *m1, double x, double y, double *out) { double mult[6] = { x, 0, 0, y, 0, 0, }; matmult(mult, m1, out); } struct Op { char *s; int (*f)(Op *op, Page *p); int argc; int flags; }; static int flagless(Op *op) { if(op->flags != 0){ werrstr("op %q: expected no flags", op->s); return -1; } return 0; } static int cobegin(Op *op, Page *p) { USED(op, p); return -1; } static int coend(Op *op, Page *p) { USED(op, p); return -1; } static int gspush(Op *op, Page *p) { GS *r; USED(op); if((r = realloc(p->GS, sizeof(GS) * (p->nGS + 1))) == nil) return -1; p->GS = r; p->nGS++; p->GSactive = &p->GS[p->nGS - 1]; *(p->GSactive) = p->GS[p->nGS - 2]; if(p->GSactive->Font.widths != nil){ p->GSactive->Font.widths = malloc(sizeof(int) * (p->GSactive->Font.last - p->GSactive->Font.first + 1)); if(p->GSactive->Font.widths == nil){ werrstr("gspush: out of memory allocating space for glyph widths"); return -1; } memcpy(p->GSactive->Font.widths, p->GS[p->nGS - 2].Font.widths, sizeof(int) * (p->GSactive->Font.last - p->GSactive->Font.first + 1)); } return 0; } static int gspop(Op *op, Page *p) { USED(op); free(p->GSactive->Font.widths); GS *r = realloc(p->GS, sizeof(GS) * (p->nGS - 1)); if(r == nil) return -1; p->GS = r; p->nGS--; p->GSactive = &p->GS[p->nGS - 1]; return 0; } /* six parameters give the inputs a,b,c,d,e,f for the matrix [a b 0] [c d 0] [e f 1] That matrix should be premultiplied with the current matrix newCTM = input x oldCTM (8.3.4) */ static int gsctm(Op *op, Page *p) { double input[6]; int i; for(i = 0; i < 6; i++) input[i] = arrayget(p->stack, i)->num.d; matmult(input, p->GSactive->CTM, p->GSactive->CTM); return flagless(op); } static int gswidth(Op *op, Page *p) { p->GSactive->LW = arrayget(p->stack, 0)->num.d; if(p->GSactive->LW < 0){ werrstr("gswidth: invalid line width: %f", p->GSactive->LW); return -1; } return flagless(op); } static int gscap(Op *op, Page *p) { p->GSactive->LC = arrayget(p->stack, 0)->num.d; if(p->GSactive->LC > CapEND){ werrstr("gscap: invalid line cap: %d", p->GSactive->LC); return -1; } return flagless(op); } static int gsjoin(Op *op, Page *p) { p->GSactive->LJ = arrayget(p->stack, 0)->num.d; if(p->GSactive->LJ > JoinEND){ werrstr("gsjoin: invalid line join: %d", p->GSactive->LJ); return -1; } return flagless(op); } static int gsmiterlim(Op *op, Page *p) { p->GSactive->ML = arrayget(p->stack, 0)->num.d; if(p->GSactive->ML < 0){ werrstr("gsmiterlim: invalidmiter limit: %f", p->GSactive->ML); return -1; } return flagless(op); } static int gsdash(Op *op, Page *p) { USED(op, p); return -1; } static int gsintent(Op *op, Page *p) { USED(op, p); return -1; } static int gsflatness(Op *op, Page *p) { p->GSactive->FL = arrayget(p->stack, 0)->num.d; return flagless(op); } static int gsstate(Op *op, Page *p) { char *name = arrayget(p->stack, 0)->name; Object *gs, *o; if((gs = dictget(dictget(dictget(p->obj, "Resources"), "ExtGState"), name)) == &null){ werrstr("extgstate dictionary not found: %s", name); goto err; } if((o = dictget(gs, "Type")) != &null && strcmp(o->name, "ExtGState") != 0){ werrstr("invalid type on ExtGState object: %s", o->name); goto err; } if((o = dictget(gs, "LW")) != &null){ if(o->type != Onum){ werrstr("line width is not a number"); goto err; } p->GSactive->LW = o->num.d; } if((o = dictget(gs, "LC")) != &null){ if(o->type != Onum){ werrstr("line cap is not a number"); goto err; } p->GSactive->LC = o->num.i; } if((o = dictget(gs, "LJ")) != &null){ if(o->type != Onum){ werrstr("line join is not a number"); goto err; } p->GSactive->LJ = o->num.i; } if((o = dictget(gs, "ML")) != &null){ if(o->type != Onum){ werrstr("miter limit is not a number"); goto err; } p->GSactive->ML = o->num.d; } return flagless(op); err: werrstr("gsstate: %r"); return -1; } static int pcmove(Op *op, Page *p) { USED(op, p); return -1; } static int pcline(Op *op, Page *p) { USED(op, p); return -1; } static int pccurve(Op *op, Page *p) { USED(op, p); return -1; } static int pcsubpath(Op *op, Page *p) { USED(op, p); return -1; } static int pcrect(Op *op, Page *p) { USED(op, p); return -1; } static int ppstroke(Op *op, Page *p) { USED(op, p); return -1; } static int ppstrokec(Op *op, Page *p) { USED(op, p); return -1; } static int ppfill(Op *op, Page *p) { USED(op, p); return -1; } static int ppfills(Op *op, Page *p) { USED(op, p); return -1; } static int ppfillcfs(Op *op, Page *p) { USED(op, p); return -1; } static int ppc(Op *op, Page *p) { USED(op, p); return -1; } static int cpclip(Op *op, Page *p) { USED(op, p); return -1; } static char *colorspacedevices[] = {"DeviceGray", "DeviceRGB", "DeviceCMYK"}; static ColorSpace colorspacechans[] = { [1] = DeviceGray, [3] = DeviceRGB, [4] = DeviceCMYK, }; static int iccbasedcspace(Object *icc, ColorSpace *c) { Object *o; *c = colorspacechans[dictint(icc, "N")]; if((o = dictget(icc, "Alternate")) != &null){ if(*c > 2 || strcmp(colorspacedevices[*c], o->name) != 0){ werrstr("iccbasedcspace: TODO: handle non-device alternate %q", o->name); return -1; } } return 0; } static int cspace(Op *op, Page *p) { ColorSpace *c = (op->flags & Nonstroking) ? &p->GSactive->NSCS : &p->GSactive->SCS; u32int *color = (op->flags & Nonstroking) ? &p->GSactive->NSC : &p->GSactive->SC; char *s = arrayget(p->stack, 0)->name; Object *o; int i; for(i = 0; i < nelem(colorspacedevices); i++){ if(strcmp(s, colorspacedevices[i]) == 0){ *c = i; *color = i == 2 ? 0xFF : 0; return 0; } } if((o = dictget(dictget(p->obj, "Resources"), "ColorSpace")) == &null || (o = dictget(o, s)) == &null){ werrstr("colorspace not found: %q", s); return -1; } if(strcmp(arrayget(o, 0)->name, "ICCBased") == 0){ /* Don't support ICC; fall back to Alternate or default */ o = arrayget(o, 1); if(!iccbasedcspace(o, c)) return -1; *color = *c == 2 ? 0xFF : 0; return 0; } werrstr("cspace: TODO: color space %q", arrayget(o, 0)->name); return -1; } static int ccolour(Op *op, Page *p) { ColorSpace c = op->flags & Nonstroking ? p->GSactive->NSCS : p->GSactive->SCS; u32int *color = op->flags & Nonstroking ? &p->GSactive->NSC : &p->GSactive->SC; if(c == DeviceRGB){ *color = ((u8int)(255 * arrayget(p->stack, 0)->num.d)) << 24 | ((u8int)(255 * arrayget(p->stack, 1)->num.d)) << 16 | ((u8int)(255 * arrayget(p->stack, 2)->num.d)) << 8 | 0xff; return 0; } return -1; } static int ccolour2(Op *op, Page *p) { ColorSpace c = op->flags & Nonstroking ? p->GSactive->NSCS : p->GSactive->SCS; if(c < 3) return ccolour(op, p); return -1; } static int cgray(Op *op, Page *p) { int value = 255 * arrayget(p->stack, 0)->num.d; u32int *color; int i; if(op->flags & Nonstroking){ color = &p->GSactive->NSC; p->GSactive->NSCS = DeviceGray; }else{ color = &p->GSactive->SC; p->GSactive->SCS = DeviceGray; } *color = 0; for(i = 0; i < 3; i++) *color = (*color | value) << 8; *color |= 255; return 0; } static int crgb(Op *op, Page *p) { USED(op, p); return -1; } static int ccmyk(Op *op, Page *p) { USED(op, p); return -1; } static int sshade(Op *op, Page *p) { USED(op, p); return -1; } static int eoobject(Op *op, Page *p) { USED(op, p); return -1; } static int iibegin(Op *op, Page *p) { USED(op, p); return -1; } static int iidata(Op *op, Page *p) { USED(op, p); return -1; } static int iiend(Op *op, Page *p) { USED(op, p); return -1; } static int tsspace(Op *op, Page *p) { USED(op); p->TS.Tc = arrayget(p->stack, 0)->num.d; return 0; }