A circle or curve isn't contiguous : ppmraw -r300 012-09.ps ppmraw -r300 013-09.ps ppmraw -r300 083-09.ps ppmraw -r300 093-01.ps ppmraw -r300 123-09.ps Reported by Julia as a regression from June 09, 2004. Reproduced by Igor with today's HEAD
Reproduced on the current CVS build: gswin32c -r300 -c 0 setlinewidth 300 400 28 0 360 arc showpage
Sorry, the correct command line is: gswin32c -r300 -c 0 setlinewidth 300 400 28 0 360 arc stroke showpage
Need to re-test after the patch http://ghostscript.com/pipermail/gs-cvs/2005-January/005180.html Some dropouts could dissappear with it.
Still have dropouts in 012-09.ps, the box 012-1, 2nd row, at the "1.5 hours" direction.
Created attachment 2526 [details] GPRS test This attachment ia absolutely unrelated to the subject. I'm testing the http file uploading via GPRS.
Comment on attachment 2526 [details] GPRS test When I get a chance, I'll remove this incorrect upload from the database.
The correct method to demonstrate the problem is given in Comment #2 I rendered this to TIFF at 300 dpi using Adobe Acrobat Professional 7 and the comparison files are attached. While there are some minor shape variations, the issue is the dropout at 45 degrees down from vertical on either side. The attached screen snapshots are 3:1 zoom views of the data.
Created attachment 2999 [details] circle_ar7_zoom_3x.png Output from AR7 (3:1 zoom)
Created attachment 3000 [details] circle_gs_zoom_3x.png Output from Ghostscript 8.57 (and HEAD as of rev 8014) showing problem
Created attachment 4162 [details] Figures to help explain the problem. This image illustrates a problem with the gx_default_draw_thin_line function. The current implementation uses a pixel center fill rule and a 1-pixel wide parallelogram to draw the line along its major axis. Figures A-1 and A-2 show examples of when the pixel containing the end point of the line is not filled resulting in the dropouts which can be seen in the testcase. One solution is to use a crosshair brush to draw the line, which would add a second parallelogram to the area of the line. Figures B-1 and B-2 show the additional parallelogram in green along with the now filled end points.
Created attachment 4163 [details] Proposed fix. I am interested in the bounty for this bug. Attached is a patch with fixes the bug by filling pixels whose centers fall in the green triangles outside of the blue parallelograms as illustrated in Figures B-1 and B-2 in the previous attachment.
If the patch is accepted (by Igor), possibly with modifications he may want, we will gladly pay the bounty. Once the patch is committed (Igor will post that fact here), please email Miles Jones (miles.jones@artifex.com) and let him know the bug number. He'll get the information from you about your preferred method to receive payment. Thanks for looking into this.
Before verifying the patch 4163, I'd like to know whether it can paint a pixel several times. Another possible problem here is a non-uniform visible line width. We need a solution, which doesn't paint extra pixels like this : xxx xx x x (use a monospaced font to view this diagram properly). The 1st x in the 2nd row is extra : it may be removed with no dropout. Generally I'm pretty sceptical about creating a simple decomposition rule based on considering individual linear segments without analyzing angles between neighbour segments. While it is more or less easy for circles, with random beziers it is much more complex. Due to that IMO the problem to be addressed to another level of decomposition - to gxstroke.c . My old idea is to apply the general dropout prevention code to narrow curves (gxfdrop.c). "Narrow" means here <= 1.5 pixels wide or so. I want to apply it together with a "static" adjustment of the width and dropping the .setfilladjust rudiments. But this is another story, which would need to restart the patch development for this bug. IMO the development should go in another direction. Nevertheless if someone proves that the constraints are satisfied, I can change my opinion.
Created attachment 5446 [details] Diagram to try to explain problem/proposed solution When ghostscript renders a 'thin' line, it actually renders a trapezoid shape, best illustrated by looking at the attachment in comment #10. In the case of 'mostly vertical' lines, 2 sides of the trapezoid are horizontally aligned. In the case of 'mostly horizontal' lines, 2 sides of the trapezoid are vertically aligned. (These 2 cases can be seen in figure A2). A 1 pixel wide line conceptually looks like the red area in Figure 1. If we chose to fill according to pixel centres being covered, we'd end up with the given shaded squares being filled. Ghostscript renders a slightly different thing; rather than rendering a rotated rectangle for each path, it instead renders a trapezoid of width 1, with (in the "near vertical" case) horizontal edges. (See figure 2). As Figure A2 in the attachment in comment #10 shows, pixels can be completely omitted when lines are rendered in this way. I propose to add a 'fudge' to ghostscripts 'thin line' rendering output, whereby we extend each trapezoid slightly by adding a triangular "extension region" to each of these trapezoids, equivalent to 1/4 of a pixel. If this region happens to encompass the pixel centre, we additionally shade that pixel. (See figure 3). The net effect of this change is that 1/4 of the time, we will extend the end of a thin line by 1 pixel. It captures both the cases A1 and A2 shown as being problem. This is not an exact fix (and cannot be, I believe, as thin lines are inherently a fudge), but is relatively inexpensive. Objections raised to the original patch were that 1) pixels might be painted multiple times, and 2) it might cause non uniform visible line widths and that. W.r.t 1) I believe the solution here is no worse that the existing code (which can, I think, cause pixels to be repainted in the end pixels of adjacent line segments). Certainly it never causes pixels within a given line segment to be painted more than once. I do not believe 2) is an issue either, as lines are only ever extended. I do not currently have access to the test files to show this bug, but back to back renderings of tiger.ps show improved renderings with the patch in.
Created attachment 5447 [details] Proposed patch Simple patch to add triangular 'extension regions' onto the end of thin lines to cure dropouts.
What does adobe acrobat 8.0 and 9.0 do? We know the 7.0 rendering is broken and we are no longer trying to emulate it. The original problem should be rendered in Acrobat (8.0 or higher) to a tiff format without antialiasing at different resolutions to establish exactly which pixels are being painted. I am skeptical of adding hacks and workarounds to the path code since the underlying adjustments (690620) are incorrect, that should be addressed first, but it does seem you have dug into the code adequately to receive the bounty.
Created attachment 5453 [details] Various figures illustrating the problem. > What does adobe acrobat 8.0 and 9.0 do? We know the 7.0 rendering is > broken and we are no longer trying to emulate it. The original problem > should be rendered in Acrobat (8.0 or higher) to a tiff format without > antialiasing at different resolutions to establish exactly which pixels > are being painted. I do not have access to the original test files for this, but I have done some quick experiments with a simple pdf file generated from the following postscript (which shows up problems in bug 687721): 0 setlinewidth 288.2 288.3 10 0 360 arc stroke showpage The top 2 bitmaps in the image show ghostscripts output at 72dpi, with/without the bugfixes respectively. The bugfix for 687666 results in the 'extra' pixel in the top left being removed, and the bugfix for 687721 results in the 'extra' pixel in the top right being added. I've drawn a scale diagram on paper with the exact coordinates used the for the path in ghostscript to convince myself that the new pixel in the top right is in fact correct :) After fiddling Acrobats options to avoid thin lines being smoothed, and setting it's resolution to 72dpi. I took various snapshots. The 100% rendering actually results in a shape that's a pixel wider/higher than ghostscripts rendering. Knocking the magnification down to 99%, I get a shape that is the same size, and knocking it down to 98%, I get a shape that exhibits the same 'extra' pixel, as we get, but in the bottom left "corner". I think it's clear that we don't exactly match Acrobats rendering, but we are unquestionably in the same spirit. > I am skeptical of adding hacks and workarounds to the path code since the > underlying adjustments (690620) are incorrect, that should be addressed > first, but it does seem you have dug into the code adequately to receive > the bounty. I believe 690620 talks about fill adjustment, which (if I understand correctly) does not apply to ghostscripts handling of thin lines. GS does not exactly match acrobats output pixel for pixel, but I suspect it is unlikely ever to achieve that. One alternative approach might be to follow the model that acrobat uses with its default options, and to allow 'thin' lines to be antialiased too. I believe we'd simply assign a 1 pixel equivalent stroke widths to zero widthed lines and render them in the same way as non thin lines. This is the approach Picsel take. Also, by default, antialiased lines are done with hardware assistance (on my windows installation of Acrobat at least). As such I suspect this may mean that the exact output will vary between graphics cards, making it impossible for us to exactly match the output. Finally, on the attached image, I include fragments of tiger.ps rendered through ghostscript with/without the bugfixes, showing 2 dropouts that get fixed. Regardless of how precisely our output matches acrobat, I think that this is a definite improvement in rendering.
As I said you will need to render the pdf or ps file to a tiff, you need Acrobat 8.0 or 9.0, we are aware you cannot emulate the display output. My guess would be that stroking is going to be similar to filling. I really don't want to do anything until we understand what adobe does (as done in 690620). I am also concerned an intermediate step was left out of this analysis. The curve was flattened to individual line segments before rendering. Those line segments can be used to create a new postscript file. A breakpoint on gxstroke.c:376 and (gdb) print gx_path_print(&fpath) state_flags=7 subpaths=1, curves=0, point=(338.398438,404.316406) box=(93289.007812,-4194326.468750),(0.000000,0.000000) last=0x0 segments=0xbfffe33c (refct=1, first=0x14db554, current=0x14db554) 0x14db554<0x0,0x14db598>:0: 338.3984 404.3164 moveto % #curves=0 last=0x14db978 0x14db598<0x14db554,0x14db5b8>:2: 337.8086 398.4922 lineto 0x14db5b8<0x14db598,0x14db5d8>:3: 336.1250 393.0703 lineto 0x14db5d8<0x14db5b8,0x14db5f8>:3: 333.4648 388.1641 lineto 0x14db5f8<0x14db5d8,0x14db618>:3: 329.9375 383.8906 lineto 0x14db618<0x14db5f8,0x14db638>:3: 325.6602 380.3594 lineto 0x14db638<0x14db618,0x14db658>:3: 320.7539 377.6992 lineto 0x14db658<0x14db638,0x14db678>:3: 315.3320 376.0156 lineto 0x14db678<0x14db658,0x14db698>:3: 309.5117 375.4297 lineto 0x14db698<0x14db678,0x14db6b8>:3: 303.6875 376.0156 lineto 0x14db6b8<0x14db698,0x14db6d8>:3: 298.2656 377.6992 lineto 0x14db6d8<0x14db6b8,0x14db6f8>:3: 293.3594 380.3594 lineto 0x14db6f8<0x14db6d8,0x14db718>:3: 289.0859 383.8906 lineto 0x14db718<0x14db6f8,0x14db738>:3: 285.5547 388.1641 lineto 0x14db738<0x14db718,0x14db758>:3: 282.8945 393.0703 lineto 0x14db758<0x14db738,0x14db778>:3: 281.2109 398.4922 lineto 0x14db778<0x14db758,0x14db798>:3: 280.6250 404.3164 lineto 0x14db798<0x14db778,0x14db7b8>:3: 281.2109 410.1367 lineto 0x14db7b8<0x14db798,0x14db7d8>:3: 282.8945 415.5586 lineto 0x14db7d8<0x14db7b8,0x14db7f8>:3: 285.5547 420.4648 lineto 0x14db7f8<0x14db7d8,0x14db818>:3: 289.0859 424.7422 lineto 0x14db818<0x14db7f8,0x14db838>:3: 293.3594 428.2695 lineto 0x14db838<0x14db818,0x14db858>:3: 298.2656 430.9297 lineto 0x14db858<0x14db838,0x14db878>:3: 303.6875 432.6133 lineto 0x14db878<0x14db858,0x14db898>:3: 309.5117 433.2031 lineto 0x14db898<0x14db878,0x14db8b8>:3: 315.3320 432.6133 lineto 0x14db8b8<0x14db898,0x14db8d8>:3: 320.7539 430.9297 lineto 0x14db8d8<0x14db8b8,0x14db8f8>:3: 325.6602 428.2695 lineto 0x14db8f8<0x14db8d8,0x14db918>:3: 329.9375 424.7422 lineto 0x14db918<0x14db8f8,0x14db938>:3: 333.4648 420.4648 lineto 0x14db938<0x14db918,0x14db958>:3: 336.1250 415.5586 lineto 0x14db958<0x14db938,0x14db978>:3: 337.8086 410.1367 lineto 0x14db978<0x14db958,0x0>:3: 338.3984 404.3164 lineto reveals the flattened path, now you can construct a postscript file from this data and I assume lines will be missing. Exactly which ones? Wouldn't it make more sense to recast this problem to a single line segment missing? Another issue is the scanline algorithm (gxfill.c), does that work properly? Various conditions will cause it to be used but it is straightforward to force its use in the debugger. It is much easier to quickly make postscript files and feed those to Acrobat 8.0. It will distill them automatically. Sorry to be a nit about these changes but my plan was to step back from the mess that we have and try to start fresh, right now we have a collection of "rendering improvements" which has obscured the original intent of the design and lost track of the original goal: emulate Adobe. I started this with 690620 and got sidetracked with other issues.
> I am also concerned an intermediate step was left out of this analysis. > The curve was flattened to individual line segments before rendering. I have debug in my local copy of ghostscript here that prints out the flattened line segments, yes. > Those line segments can be used to create a new postscript file. I have not yet tried that, but I will do. > now you can construct a postscript file from this data and I assume lines > will be missing. No. The problem is not that complete line segments are missing, just that when gs renders these 'thin lines', it misses out end pixels in some cases. Most of the time this does not matter as, in general, if an end pixel is omitted from the end of one line segment, it will be rendered by the next segment anyway. In some cases though (as demonstrated by figures A1 and A2 in the attachment in comment #10) neither line segment will cause the pixel to be written, causing dropouts. This can happen either where one line segment 'reverses direction' (figure A1) or where we move between one line segment being 'mostly vertical' and the next one being 'mostly horizontal' (figure A2). > Exactly which ones? Wouldn't it make more sense to recast this problem to a > single line segment missing? I will attempt to construct an example file with just 2 line segments in it, showing a dropout at the join. > Another issue is the scanline algorithm (gxfill.c), does that work > properly? Clearly, there is a mismatch between the (somewhat wierd and wacky) algorithm used by ghostscripts 'thin line' stroking, and that of its shape filling algorithm. If you look at tiger.eps rendered in ghostscript, you can clearly see the problem with the whiskers. These are constructed by filling a path in white, and then stroking around the edge 'thinly' in black. It is a reasonable expectation that no white sections should protrude outside the black stroked area, but the outermost 'jaggies' of the white fill do. This mismatch may be best avoided by simply ditching ghostscripts use of thin line plotting, and instead rendering thin lines as conventional antialiased lines with a 1 pixel wide strokewidth. (This sounds simple, and it is what I've seen done elsewhere, but I don't know how hard it is to do in the gs codebase). If you convert tiger.eps to tiger.pdf and render it in Adobe Reader, 2 things become apparent. Firstly, thin lines in Adobe Reader are antialiased by default (so we'd be "emulating adobe" better by switching away from thin lines). Secondly, if you disable hardware acceleration/line smoothing etc, so that it does 'pixel' thin lines, then their 'thin lines' appear somewhat heavier than ghostscripts, and they do not suffer from the fill extending beyond the stroke. > Sorry to be a nit about these changes but my plan was to step back from the > mess that we have and try to start fresh, right now we have a collection of > "rendering improvements" which has obscured the original intent of the design > and lost track of the original goal: emulate Adobe. I started this with > 690620 and got sidetracked with other issues. To successfully emulate Adobe, we either need to 1) abandon gs's current thin line code and switch to feeding thin lines through the normal stroking code, or 2) figure out why gs's thin line code differs from Adobe when Adobe is 'nobbled' back into that way of working. 1) would be my personal preference; the rendering output looks *much* prettier like this, and it should hopefully eliminate the problem of stroke/fill mismatches. 2) requires more than the simple band aid I offer here - I suspect the whole "thin line stroking using trapezoids" approach needs to be rethought.
Created attachment 5457 [details] File showing problem Simple file containing 2 lines that shows the problem. gswin32c.exe -r72 dropout.ps
Reassigning path and fill problems to Robin Watts.
Fixed in revision 10429 using the method described in comment #14. This resolves the dropout issues in tiger.eps and the other files mentioned here.