diff options
-rw-r--r-- | mupdf/shade.c | 6 | ||||
-rw-r--r-- | mupdf/shade2.c | 70 | ||||
-rw-r--r-- | mupdf/shade3.c | 335 |
3 files changed, 387 insertions, 24 deletions
diff --git a/mupdf/shade.c b/mupdf/shade.c index 05a53e72..cbe319f7 100644 --- a/mupdf/shade.c +++ b/mupdf/shade.c @@ -85,8 +85,7 @@ pdf_loadshadedict(fz_shade **shadep, pdf_xref *xref, fz_obj *shading, fz_obj *re shade->bbox.max.x, shade->bbox.max.y); } - switch(type) - { + switch(type) { case 1: // error = pdf_loadtype1shade(shade, xref, shading, ref, mat); if (error) goto cleanup; @@ -105,13 +104,10 @@ pdf_loadshadedict(fz_shade **shadep, pdf_xref *xref, fz_obj *shading, fz_obj *re break; }; - pdf_logshade("}\n"); - *shadep = shade; return nil; cleanup: - pdf_logshade("have an error: %s\n", error->msg); return error; } diff --git a/mupdf/shade2.c b/mupdf/shade2.c index 459933b6..8871b6bf 100644 --- a/mupdf/shade2.c +++ b/mupdf/shade2.c @@ -8,6 +8,7 @@ pdf_buildt2shademesh(fz_shade *shade, pdf_xref *xref, fz_obj *shading, fz_error *error; float x0, y0, x1, y1; float t0, t1; + int e0, e1; fz_obj *obj; pdf_function *func; @@ -30,21 +31,35 @@ pdf_buildt2shademesh(fz_shade *shade, pdf_xref *xref, fz_obj *shading, t1 = 1.; } + obj = fz_dictgets(shading, "Extend"); + if (obj) { + e0 = fz_tobool(fz_arrayget(obj, 0)); + e1 = fz_tobool(fz_arrayget(obj, 1)); + } else { + e0 = 0; + e1 = 0; + } + pdf_logshade("domain %g %g\n", t0, t1); + pdf_logshade("extend %d %d\n", e0, e1); pdf_loadshadefunction(shade, xref, shading, t0, t1); - shade->meshlen = 2; + shade->meshlen = 2 + e0 *2 + e1 * 2; shade->mesh = (float*) malloc(sizeof(float) * 3*3 * shade->meshlen); float theta; - theta = atan2(x1 - x0, y1 - y0); + theta = atan2(y1 - y0, x1 - x0); + theta += M_PI / 2.0; pdf_logshade("theta=%g\n", theta); fz_point p1, p2, p3, p4; + fz_point ep1, ep2, ep3, ep4; + float dist; + dist = hypot(x1 - x0, y1 - y0); -#define BIGNUM 10000 +#define BIGNUM 1000 p1.x = x0 + BIGNUM * cos(theta); p1.y = y0 + BIGNUM * sin(theta); @@ -55,27 +70,46 @@ pdf_buildt2shademesh(fz_shade *shade, pdf_xref *xref, fz_obj *shading, p4.x = x1 - BIGNUM * cos(theta); p4.y = y1 - BIGNUM * sin(theta); + ep1.x = p1.x - (x1 - x0) / dist * BIGNUM; + ep1.y = p1.y - (y1 - y0) / dist * BIGNUM; + ep2.x = p2.x + (x1 - x0) / dist * BIGNUM; + ep2.y = p2.y + (y1 - y0) / dist * BIGNUM; + ep3.x = p3.x - (x1 - x0) / dist * BIGNUM; + ep3.y = p3.y - (y1 - y0) / dist * BIGNUM; + ep4.x = p4.x + (x1 - x0) / dist * BIGNUM; + ep4.y = p4.y + (y1 - y0) / dist * BIGNUM; + pdf_logshade("p1 %g %g\n", p1.x, p1.y); pdf_logshade("p2 %g %g\n", p2.x, p2.y); pdf_logshade("p3 %g %g\n", p3.x, p3.y); pdf_logshade("p4 %g %g\n", p4.x, p4.y); - pdf_setmeshvalue(shade->mesh, 0, p1.x, p1.y, 0); - pdf_setmeshvalue(shade->mesh, 1, p2.x, p2.y, 1); - pdf_setmeshvalue(shade->mesh, 2, p4.x, p4.y, 1); - pdf_setmeshvalue(shade->mesh, 3, p1.x, p1.y, 0); - pdf_setmeshvalue(shade->mesh, 4, p4.x, p4.y, 1); - pdf_setmeshvalue(shade->mesh, 5, p3.x, p3.y, 0); - - /* - if (shade->extend) { - e0 = fz_toint(fz_arrayget(shade->extend, 0)); - e1 = fz_toint(fz_arrayget(shade->extend, 1)); - } else { - e0 = 0; - e1 = 0; + int n = 0; + + pdf_setmeshvalue(shade->mesh, n++, p1.x, p1.y, 0); + pdf_setmeshvalue(shade->mesh, n++, p2.x, p2.y, 1); + pdf_setmeshvalue(shade->mesh, n++, p4.x, p4.y, 1); + pdf_setmeshvalue(shade->mesh, n++, p1.x, p1.y, 0); + pdf_setmeshvalue(shade->mesh, n++, p4.x, p4.y, 1); + pdf_setmeshvalue(shade->mesh, n++, p3.x, p3.y, 0); + + if (e0) { + pdf_setmeshvalue(shade->mesh, n++, ep1.x, ep1.y, 0); + pdf_setmeshvalue(shade->mesh, n++, p1.x, p1.y, 0); + pdf_setmeshvalue(shade->mesh, n++, p3.x, p3.y, 0); + pdf_setmeshvalue(shade->mesh, n++, ep1.x, ep1.y, 0); + pdf_setmeshvalue(shade->mesh, n++, p3.x, p3.y, 0); + pdf_setmeshvalue(shade->mesh, n++, ep3.x, ep3.y, 0); + } + + if (e1) { + pdf_setmeshvalue(shade->mesh, n++, p2.x, p2.y, 1); + pdf_setmeshvalue(shade->mesh, n++, ep2.x, ep2.y, 1); + pdf_setmeshvalue(shade->mesh, n++, ep4.x, ep4.y, 1); + pdf_setmeshvalue(shade->mesh, n++, p2.x, p2.y, 1); + pdf_setmeshvalue(shade->mesh, n++, ep4.x, ep4.y, 1); + pdf_setmeshvalue(shade->mesh, n++, p4.x, p4.y, 1); } - */ pdf_logshade("}\n"); diff --git a/mupdf/shade3.c b/mupdf/shade3.c index 1e077cb5..eb2badac 100644 --- a/mupdf/shade3.c +++ b/mupdf/shade3.c @@ -1,6 +1,340 @@ #include <fitz.h> #include <mupdf.h> +#ifdef NONE__ +double +fz_shadet3rectradius(fz_rect rect, double x0, double y0) +{ + double d, dd; + + dd = hypot(rect.min.x - x0, rect.min.y - y0); + d = hypot(rect.min.x - x0, rect.max.y - y0); + dd = max(dd, d); + d = hypot(rect.max.x - x0, rect.max.y - y0); + dd = max(dd, d); + d = hypot(rect.max.x - x0, rect.min.y - y0); + dd = max(dd, d); + + return dd; +} + +void +fz_outercircle(const fz_rect rect, + double x0, double y0, double r0, + double x1, double y1, double r1, + double *x2, double *y2, double *r2) +{ + double dx = x1 - x0, dy = y1 - y0; + double sp, sq, s; + + + /* Compute a cone circle, which contacts the rect externally. */ + /* Don't bother with all 4 sides of the rect, + just do with the X or Y span only, + so it's not an exact contact, sorry. */ + if (fabs(dx) > fabs(dy)) { + /* Solving : + x0 + (x1 - x0) * s - r0 - (r1 - r0) * s == bbox_x + (x1 - x0) * s - (r1 - r0) * s == bbox_x - x0 + r0 + s = (bbox_x - x0 + r0) / (x1 - x0 - r1 + r0) + */ + assert(x1 - x0 + r1 - r0); /* We checked for obtuse cone. */ + sp = (rect.min.x - x0 + r0) / (x1 - x0 - r1 + r0); + sq = (rect.max.x - x0 + r0) / (x1 - x0 - r1 + r0); + } else { + /* Same by Y. */ + sp = (rect.min.y - y0 + r0) / (y1 - y0 - r1 + r0); + sq = (rect.max.y - y0 + r0) / (y1 - y0 - r1 + r0); + } + if (sp >= 1 && sq >= 1) + s = min(sp, sq); + else if(sp >= 1) + s = sp; + else if (sq >= 1) + s = sq; + else { + /* The circle 1 is outside the rect, use it. */ + s = 1; + } + if (r0 + (r1 - r0) * s < 0) { + /* Passed the cone apex, use the apex. */ + s = r0 / (r0 - r1); + *r2 = 0; + } else + *r2 = r0 + (r1 - r0) * s; + *x2 = x0 + (x1 - x0) * s; + *y2 = y0 + (y1 - y0) * s; +} + +int +fz_iscovered(double ax, double ay, + const fz_point *p0, const fz_point *p1, const fz_point *p) +{ + double dx0 = p0->x - ax, dy0 = p0->y - ay; + double dx1 = p1->x - ax, dy1 = p1->y - ay; + double dx = p->x - ax, dy = p->y - ay; + double vp0 = dx0 * dy - dy0 * dx; + double vp1 = dx * dy1 - dy * dx1; + + return vp0 >= 0 && vp1 >= 0; +} + +fz_error * +fz_shadet3obtusecone(fz_rect rect, + float x0, float y0, float r0, + float x1, float y1, float r1, + double t1, double r, + fz_matrix ctm, fz_pixmap *dstp, int destcol[512][4]) +{ + fz_error *error; + double dx = x1 - x0, dy = y1 - y0, dr = fabs(r1 - r0); + double d = hypot(dx, dy); + double ax, ay, as; /* Cone apex. */ + fz_point p0, p1; /* Tangent limits. */ + fz_point cp[4]; /* Corners.. */ + fz_point rp[4]; /* Covered corners.. */ + fz_point pb; + int rp_count = 0, cp_start, i; + int covered[4]; + + + + as = r0 / (r0 - r1); + ax = x0 + (x1 - x0) * as; + ay = y0 + (y1 - y0) * as; + + if (fabs(d - dr) < 1e-7 * (d + dr)) { + /* Nearly degenerate, replace with half-plane. */ + p0.x = ax - dy * r / d; + p0.y = ay + dx * r / d; + p1.x = ax + dy * r / d; + p1.y = ay - dx * r / d; + } else { + /* Tangent limits by proportional triangles. */ + double da = hypot(ax - x0, ay - y0); + double h = r * r0 / da, g; + + assert(h <= r); + g = sqrt(r * r - h * h); + p0.x = ax - dx * g / d - dy * h / d; + p0.y = ay - dy * g / d + dx * h / d; + p1.x = ax - dx * g / d + dy * h / d; + p1.y = ay - dy * g / d - dx * h / d; + } + /* Now we have 2 limited tangents, and 4 corners of the rect. + Need to know what corners are covered. */ + cp[0].x = rect.min.x, cp[0].y = rect.min.y; + cp[1].x = rect.max.x, cp[1].y = rect.min.y; + cp[2].x = rect.max.x, cp[2].y = rect.max.y; + cp[3].x = rect.min.x, cp[3].y = rect.max.y; + covered[0] = fz_iscovered(ax, ay, &p0, &p1, &cp[0]); + covered[1] = fz_iscovered(ax, ay, &p0, &p1, &cp[1]); + covered[2] = fz_iscovered(ax, ay, &p0, &p1, &cp[2]); + covered[3] = fz_iscovered(ax, ay, &p0, &p1, &cp[3]); + + if (!covered[0] && !covered[1] && !covered[2] && !covered[3]) { + fz_point pt1, pt2, pt3; + pt1.x = ax; pt1.y = ay; + pt2 = p0; + pt3 = p1; + + pt1 = fz_transformpoint(ctm, pt1); + pt2 = fz_transformpoint(ctm, pt2); + pt3 = fz_transformpoint(ctm, pt3); + + fz_triangle triangle; + triangle.vertex[0].x = pt1.x; + triangle.vertex[0].y = pt1.y; + triangle.vertex[0].l = t1; + triangle.vertex[1].x = pt2.x; + triangle.vertex[1].y = pt2.y; + triangle.vertex[1].l = t1; + triangle.vertex[2].x = pt3.x; + triangle.vertex[2].y = pt3.y; + triangle.vertex[2].l = t1; + + error = fz_drawgouraudtriangle(triangle, dstp, destcol, + rect.min.x, rect.min.y, rect.max.x, rect.max.y); + goto end; + } + if (!covered[0] && covered[1]) + cp_start = 1; + else if (!covered[1] && covered[2]) + cp_start = 2; + else if (!covered[2] && covered[3]) + cp_start = 3; + else if (!covered[3] && covered[0]) + cp_start = 0; + else { + /* Must not happen, handle somehow for safety. */ + cp_start = 0; + } + for (i = cp_start; i < cp_start + 4 && covered[i % 4]; i++) { + rp[rp_count] = cp[i % 4]; + rp_count++; + } + /* Do paint. */ + pb = p0; + for (i = 0; i < rp_count; i++) { + fz_point pt1, pt2, pt3; + pt1.x = ax; pt1.y = ay; + pt2 = pb; + pt3 = rp[i]; + + pt1 = fz_transformpoint(ctm, pt1); + pt2 = fz_transformpoint(ctm, pt2); + pt3 = fz_transformpoint(ctm, pt3); + + fz_triangle triangle; + triangle.vertex[0].x = pt1.x; + triangle.vertex[0].y = pt1.y; + triangle.vertex[0].l = t1; + triangle.vertex[1].x = pt2.x; + triangle.vertex[1].y = pt2.y; + triangle.vertex[1].l = t1; + triangle.vertex[2].x = pt3.x; + triangle.vertex[2].y = pt3.y; + triangle.vertex[2].l = t1; + + error = fz_drawgouraudtriangle(triangle, dstp, destcol, + rect.min.x, rect.min.y, rect.max.x, rect.max.y); + if (error < 0) + return error; + pb = rp[i]; + } + + fz_point pt1, pt2, pt3; + pt1.x = ax; pt1.y = ay; + pt2 = pb; + pt3 = p1; + + pt1 = fz_transformpoint(ctm, pt1); + pt2 = fz_transformpoint(ctm, pt2); + pt3 = fz_transformpoint(ctm, pt3); + + fz_triangle triangle; + triangle.vertex[0].x = pt1.x; + triangle.vertex[0].y = pt1.y; + triangle.vertex[0].l = t1; + triangle.vertex[1].x = pt2.x; + triangle.vertex[1].y = pt2.y; + triangle.vertex[1].l = t1; + triangle.vertex[2].x = pt3.x; + triangle.vertex[2].y = pt3.y; + triangle.vertex[2].l = t1; + + error = fz_drawgouraudtriangle(triangle, dstp, destcol, + rect.min.x, rect.min.y, rect.max.x, rect.max.y); + +end: + return error; +} + +fz_error * +fz_shadet3tensorconeapex(fz_rect rect, + double x0, double y0, double r0, + double x1, double y1, double r1, double t, + fz_matrix ctm, fz_pixmap *dstp, int destcol[512][4]) +{ + double as = r0 / (r0 - r1); + double ax = x0 + (x1 - x0) * as; + double ay = y0 + (y1 - y0) * as; + + return fz_renderannulus(x1, y1, r1, ax, ay, 0, t, t, ctm, dstp, destcol); +} + + +fz_error * +fz_rendershadet3extentions(fz_rect rect, + float x0, float y0, float r0, + float x1, float y1, float r1, + double t0, double t1, int Extend0, int Extend1, + fz_matrix ctm, fz_pixmap *dstp, int destcol[512][4]) +{ + double dx = x1 - x0, dy = y1 - y0, dr = fabs(r1 - r0); + double d = hypot(dx, dy), r; + fz_error *error; + + if (dr >= d - 1e-7 * (d + dr)) { + /* Nested circles, or degenerate. */ + if (r0 > r1) { + if (Extend0) { + r = fz_shadet3rectradius(rect, x0, y0); + if (r > r0) { + error = fz_renderannulus(x0, y0, r, x0, y0, r0, t0, t0, ctm, dstp, destcol); + if (error) + return error; + } + } + if (Extend1 && r1 > 0) + return fz_renderannulus(x1, y1, r1, x1, y1, 0, t1, t1, ctm, dstp, destcol); + } else { + if (Extend1) { + r = fz_shadet3rectradius(rect, x1, y1); + if (r > r1) { + error = fz_renderannulus(x1, y1, r, x1, y1, r1, t1, t1, ctm, dstp, destcol); + if (error < 0) + return error; + } + } + if (Extend0 && r0 > 0) + return fz_renderannulus(x0, y0, r0, x0, y0, 0, t0, t0, ctm, dstp, destcol); + } + } else if (dr > d / 3) { + /* Obtuse cone. */ + if (r0 > r1) { + if (Extend0) { + r = fz_shadet3rectradius(rect, x0, y0); + error = fz_shadet3obtusecone(rect, x0, y0, r0, x1, y1, r1, t0, r, + ctm, dstp, destcol); + if (error < 0) + return error; + } + if (Extend1 && r1 != 0) + return fz_shadet3tensorconeapex(rect, x0, y0, r0, x1, y1, r1, t1, + ctm, dstp, destcol); + return 0; + } else { + if (Extend1) { + r = fz_shadet3rectradius(rect, x1, y1); + error = fz_shadet3obtusecone(rect, x1, y1, r1, x0, y0, r0, t1, r, + ctm, dstp, destcol); + if (error < 0) + return error; + } + if (Extend0 && r0 != 0) + return fz_shadet3tensorconeapex(rect, x1, y1, r1, x0, y0, r0, t0, + ctm, dstp, destcol); + } + } else { + /* Acute cone or cylinder. */ + double x2, y2, r2, x3, y3, r3; + + if (Extend0) { + fz_outercircle(rect, x1, y1, r1, x0, y0, r0, &x3, &y3, &r3); + if (x3 != x1 || y3 != y1) { + error = fz_renderannulus(x0, y0, r0, x3, y3, r3, t0, t0, + ctm, dstp, destcol); + if (error < 0) + return error; + } + } + if (Extend1) { + fz_outercircle(rect, x0, y0, r0, x1, y1, r1, &x2, &y2, &r2); + if (x2 != x0 || y2 != y0) { + error = fz_renderannulus(x1, y1, r1, x2, y2, r2, t1, t1, + ctm, dstp, destcol); + if (error < 0) + return error; + } + } + } + return 0; +} + +#endif + + fz_error * fz_buildannulusmesh(float* mesh, int x0, int y0, int r0, int x1, int y1, int r1, @@ -109,4 +443,3 @@ pdf_loadtype3shade(fz_shade *shade, pdf_xref *xref, fz_obj *shading, cleanup: return error; } - |