Bug 694084 - Radial gradient (sh /ShadingType 3) should appear circular, not as 32-sided polygon
Summary: Radial gradient (sh /ShadingType 3) should appear circular, not as 32-sided p...
Status: RESOLVED FIXED
Alias: None
Product: MuPDF
Classification: Unclassified
Component: mupdf (show other bugs)
Version: unspecified
Hardware: PC Linux
: P4 minor
Assignee: Robin Watts
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-05-20 05:44 UTC by Paul Sladen
Modified: 2014-05-01 06:25 UTC (History)
1 user (show)

See Also:
Customer:
Word Size: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Paul Sladen 2013-05-20 05:44:38 UTC
(This is the first time I've found a testcase where default-mupdf produces a  result visbly worse than default-Poppler, so flagging it up here).

With a PDF using /ShadingType 3 (radial) such as the following:

  % http://www.pdfvt.com/pdf/RadialShading.pdf
  10 0 obj
  <<
        /ShadingType 3
        /ColorSpace /DeviceGray
	/Coords [0 0 0 0 0 150]
        /AntiAlias true
        /Function <</FunctionType 2  /N 1  /Domain [0 1]  /C1 [0]  /C0 [1]>>
  >>
  endobj
  …
  /Radial1 sh

The appropriate flattening appears to be under-evaluated; the resulting line-segments to form the circular arc have tangents of over 5-degrees between sides and the result is highly visible as a 64-sided polygon.

The same visible result happens with radial used as a soft-mask in the default configuration:

  http://www.pdfvt.com/pdf/SoftMask-Clipped.pdf
Comment 1 Paul Sladen 2013-06-04 14:45:12 UTC
In Fitz:

fitz/res_shade.c:166:
  /* FIXME: Nasty */
  #define RADSEGS 32 /* how many segments to generate for radial meshes */

this is then used immediately after in fz_paint_annulus() calling fz_point_on_circle() to generate quard coordinates from inner radius to outer radius, using a step size.

This is thus slightly harder, since the flattening precision suitable for the outer radius will generally be finer than for the inner radius.  To keep the generated coordinates collinear at each radius either (a) the subdivisions need to be evaluated per the flattening suitable for the outer-most radius, or when the flattening for the inner and outer is different additional quads need to be generated, which is somewhat hard, but easier if locked to a multiple of the inner radius-flattening (eg. power-of-two).

From a code point of view it would be easier to only using the flattening level for the outer-most annulus radius, but then this needs to be known, and thus recorded in advance even when rendering the inner annulus slices.
Comment 2 Tor Andersson 2014-04-30 07:39:23 UTC
I've tried an adaptive calculation of the number of segments based on the
matrix scaling factor and gradient radius... the problem with this approach
is that adjacent shadings (where the inner radius of one shading touches
the outer radius of another) end up having different number of segments,
and this leads to cracks between them.

The ideal approach would be to render radial shadings directly without
tesselating them into triangles.
Comment 3 Tor Andersson 2014-05-01 06:25:48 UTC
Mostly fixed in commit eac3d6f4db3ba06637c02fd7aa3b69bafb1b6e81
Author: Tor Andersson <tor.andersson@artifex.com>
Date:   Thu May 1 14:05:42 2014 +0200

    Fix 694084: compute number of segments in radial shading from radius.

The above mentioned cracks can still appear, but I'll treat that as a
separate issue.