Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python/PDF Creation Using ReportLab - self-made grid prints with a pattern but looks fine on the screen

I am trying to make my own grid (that looks very much like this: http://tinyurl.com/cdyre6k - ECG paper that is in metric units of millimeters).

I am using ReportLab/Python (opensource) to make these reports. Below is a snippet of my code.

On the screen, it looks GREAT!:

>What I see on the screen<

However, when I send this to a printer (and yes, I've also tinkered with printer settings) it prints some lines, and not others (sometimes it's methodical and prints a pattern-esque plaid, other times it is thicker/thinner lines; keep in mind, the output at the printer is consistent depending on strokewidths I set).

>What I see at the printer!<

I have tried all sorts of strokewidth combinations, and all sorts of printer setting combinations... I can't get it to print correctly! I have tried an alternative printer and gotten MUCH better results, but I have to set the printer settings to over 1200 dpi (CAD level printing). The other printer is set to 600dpi. On that SAME PRINTER (600dpi) I print a document made by a former coworker and it print's just fine (please note, he was not using ReportLab so I cannot use his code/solution).

What is going on? Is this an aliasing issue at the printer? Would it help me if I coverted my grids to bitmaps (or some other format)? How can I fix this (my only options are to use Python and ReportLab)? ReportLab manual didn't help, "Google" didn't help, and previous StackExchange questions didn't seem to cover this specific topic. I can get the grid to print all the lines if I set the strokewidth to "1", but then the minor grid lines are too thick.

The end result is for a line chart I am working on, and I know ReportLab has chart functions, but reportlabs charts/grid function(s) don't give me what I need for my project, so I have been forced to make my own grid with major/minor lines (maybe I missed something and open to alternative techniques, but currently it looks fine in PDF form, just not at the printer).

ANY advice is appreciated!

TIA,

-J

    for i in decimal_range(0, _time, 1):
        if (i % 5.0 == 0):
            if (i % 25.0 == 0):
                grid_pattern.add(shapes.Line(_temp_x, 
                                             (_temp_y + _height_of_box), 
                                             _temp_x,
                                             (_temp_y + _height_of_box+4),
                                             strokeWidth=1,
                                             strokeColor=colors.black))
            else:
                pass

            grid_pattern.add(shapes.Line(_temp_x, _temp_y, _temp_x,
                                         (_temp_y + _height_of_box),
                                         strokeWidth=.12,
                                         strokeColor=colors.pink))
        else:
            grid_pattern.add(shapes.Line(_temp_x, _temp_y, _temp_x,
                                         (_temp_y + _height_of_box),
                                         strokeWidth=.12,
                                         strokeColor=colors.pink))
        _temp_x += 1 * mm

    _temp_x = xorigin

    for i in range(0, _mv, 1):
        if (i % 5.0 == 0):
            grid_pattern.add(shapes.Line(_temp_x, _temp_y,
                                         _temp_x + _width_of_box,
                                         _temp_y, strokeWidth=.12,
                                         strokeColor=colors.pink))
        else:
            grid_pattern.add(shapes.Line(_temp_x, _temp_y,
                                         _temp_x + _width_of_box,
                                         _temp_y, strokeWidth=.12,
                                         strokeColor=colors.pink))    
        _temp_y += 1 * mm

UPDATE1

I have tried setting the stroke width to "0" as recommended by several posters (and the ReportLab community/mailing list) as follows:

grid_pattern.add(shapes.Line(_temp_x, _temp_y, _temp_x,
                            (_temp_y + _height_of_box),
                            strokeWidth=0,
                            strokeColor=colors.pink))

This does make a single pixel-wide line, which again, looks great on the PC, but still prints with a funky pattern in PDF.

UPDATE2 + SOLUTION

After LOTS of tantrums and arguments with ReportLab and my computer it turns out it wasn't my PC or ReportLab. It was the printers (I was using two totally different printers Canon and HP - models notwithstanding) - I felt that I had enough coverage to rule out the printer, but there is more to this problem! Continue reading...

ReportLab doesn't actually draw the line, it just adds a postscript line that tells the render to draw the line.

Part of my initial debugging included changing the colors I was using to see if that was an issue - well - I changed the colors from pink to red (not much of a change, I know, but again, I assumed I changed it enough to rule out colors as an issue).

Well from what I have recently, and painfully learned, is that the printers convert colors to grayscale using a formula and that formula has a tendency to produce antialiasing side-effects (like what I was seeing).

THE SOLUTION: was to change the colors of the grid. Certain colors perform better than others. So, to test this, I wrote a simple script which you can download here that will generate a PDF document using all of the colors stored in reportlabs colors dictionary - print a sample grid that was causing me the problems and provide the RGB values. As it turns out, alllllllll sorts of colors don't print well across several printers (all different) - it's not just reds/pinks... some "red-like" colors print fine, some printers handle the grayscale conversion better than another.

So now, our task is to use this PDF document I created to find a color that looks fine in print (both color and grayscale) and on the screen.

If you don't want to download the script for fear I'm evil - at least check out the PDF and print your own samples to see if you can recreate the problem I was having (I was printing at 600dpi - standard - nothing fancy... remember, if I turned up the DPI/quality settings, it printed fine, but the standard settings were causing me grief!).

Script

or

PDF

like image 548
Justin Carroll Avatar asked Nov 27 '12 19:11

Justin Carroll


3 Answers

If I understand how ReportLab handles lines correctly, you're asking it to create lines with respectively 1 and 0.12 user space units. In PDF, one "user space unit" is effectively 1/72 of an inch.

This means the lines you're drawing will be respectively 0.014 and 0.0017 inch wide. That's really not much. Depending on the resolution of your output device and where on the page the line happens to be (so, depending on whether it happens to be aligned with the pixel grid of your screen or printer or not) you'll probably get different results.

Your printer likely will try to optimise output by anti-aliasing which will make the final result even more uncertain.

The alignment effect with your printer's pixel grid is probably why you see some lines and don't see others.

A couple of things to try / play with.

1) Output your lines with 0 line width. This is a special case in PDF and it means "output a line of exactly one pixel wide". Keep in mind that such a line should be visible on your screen (which is only 72 or 96 dpi) but might not be on your printer (which will now print a dot that is 1/1200 of an inch). But if your printer obeys the rules, it should always print that one dot.

2) Make your lines wider - probably the only way to achieve consistent results. If the smaller lines look too thick, consider printing a dotted line instead of a solid one (set a dash pattern).

like image 178
David van Driessche Avatar answered Sep 18 '22 17:09

David van Driessche


Not exactly sure how to apply this to what you're doing, but the traditional Postscript way is to round the device coordinates to integers.

/roundpoint { % x y -> x' y'
    transform %convert user-space coords to device-space coords
    round
    itransform %convert device-space back to user-space
} def

...
x y roundpoint moveto
x y roundpoint lineto
...

If all your lines are placed consistently with respect to the device pixels, then they should be drawn consistently as well.

like image 38
luser droog Avatar answered Sep 18 '22 17:09

luser droog


I think setting a stroke width of 0 is what you want. This produces a special type of line that is often referred to as a hairline. It basically tells the printer to print the thinnest possible line that it can (the width of a droplet from an ink jet printer or the width of the laser in a laser printer). I'm not sure if all PDF viewers will display it as you expect but you should try printing it anyway.

like image 22
Damian Moore Avatar answered Sep 18 '22 17:09

Damian Moore