Patch to allow Cairo-based software to print to laser cutters on Windows

Submitted by Rick Yorgason on Oct. 24, 2018, 6:34 p.m.

Details

Message ID 6c83001a-bde5-c0a6-4120-5d2078107144@firefang.com
State New
Series "Patch to allow Cairo-based software to print to laser cutters on Windows"
Headers show

Commit Message

Rick Yorgason Oct. 24, 2018, 6:34 p.m.
Apologies for the delay. Here's the promised updated patch.

The difference is now it considers the minimum size of both the canvas 
and the printer instead of just the canvas, zero-width strokes count as 
hairlines (although Cairo still seems to be culling strokes from getting 
to this function — that's a separate bug) and the documentation was 
updated for clarity.

Cheers,

-Rick-


On 2018-10-19 12:12, Rick Yorgason wrote:
> That shouldn't be. See page 675 of the Postscript Language Reference: 
> https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf
>
>> A line width of 0 is acceptable, and is interpreted as the thinnest 
>> line that can be rendered at device resolution—1 device pixel wide. 
>> However, some devices cannot reproduce 1-pixel lines, and on 
>> high-resolution devices, they are nearly invisible.
>
> -Rick-
>
>
> On 2018-10-19 09:27, Bill Spitzak wrote:
>> Hairlines are not always 1 pixel wide. For Postscript setting the 
>> line width to 0.0 gives you a hairline that seems to be about 1/150" 
>> which is quite a few pixels on modern printers, and was > 1 even on 
>> the first Apple Laserwriter.
>>
>> On Fri, Oct 19, 2018 at 6:21 AM Rick Yorgason <rick@firefang.com 
>> <mailto:rick@firefang.com>> wrote:
>>
>>     It looks like you're right about the device units. In cases where
>>     the
>>     canvas DPI is lower than the device DPI, the "smallest printable
>>     line"
>>     is 1, as in my original patch (because ExtCreatePen only accepts
>>     integral pen widths), but when the canvas DPI is higher, the
>>     "smallest
>>     printable line" is
>>     `_cairo_matrix_transformed_circle_major_axis(stroke_ctm_inverse,
>>     1.0)`.
>>
>>     I haven't looked any further into what's culling zero-width lines
>>     yet.
>>     For now, I'm focusing on the "use PS_COSMETIC for smallest printable
>>     lines" patch, which I believe should be separate from the "allow
>>     printing zero-width lines" patch.
>>
>>     Tomorrow I'll post a new patch based on the feedback I've
>>     received so far.
>>
>>     -Rick-
>>
>>
>>     On 2018-10-19 00:56, Adrian Johnson wrote:
>>     > There were some patches to fix the culling on narrow lines on
>>     vector
>>     > surfaces:
>>     >
>>     >
>>     https://gitlab.freedesktop.org/cairo/cairo/commit/b1192beac7c5b56a8ff356d20af5ebfb65404109
>>     >
>>     >
>>     https://gitlab.freedesktop.org/cairo/cairo/commit/bec8c7508ebc0f69266f9aebe9903539391c519b
>>     >
>>     > Those patches should allow zero width lines. I'm not sure what else
>>     > could be preventing zero width lines from getting through to
>>     the win32
>>     > print surface.
>>     >
>>     > You code that sets the cosmetic flag is not checking the line
>>     width in
>>     > device units. The StrokePath() is called in user coordinates so
>>     that the
>>     > line width will be in user coordinates. The reason emitting the
>>     path in
>>     > device space and stroking in user space is demonstrated here
>>     > https://cairographics.org/tutorial/#L2linewidth
>>     >
>>     > To check if the line width is < 1 device unit you would need to do
>>     > something line in the second commit above to find the line
>>     width in user
>>     > space.
>>     >
>>     >
>>     > On 19/10/18 07:32, Rick Yorgason wrote:
>>     >> Sure enough, Cairo seems to be culling zero-width lines
>>     somewhere, so it
>>     >> doesn't matter whether or not I check for zero here.
>>     >>
>>     >> For now, I propose that I get rid of the zero-check in my
>>     patch, so
>>     >> anything <= 1 device unit is drawn with a PS_COSMETIC pen.
>>     This value
>>     >> gets rounded to an integer, so this approach is consistent
>>     with the
>>     >> definition of a hairline being the smallest thing a printer
>>     can print.
>>     >>
>>     >> In the long run, it would be nice to track down where Cairo is
>>     culling
>>     >> zero-width lines and allow them through, as I believe
>>     postscript and pdf
>>     >> both treat zero-width lines as hairlines.
>>     >>
>>     >> -Rick-
>>     >>
>>     >>
>>     >> On 2018-10-18 12:09, Bill Spitzak wrote:
>>     >>> I suspect there is code in Cairo that assumes zero-width
>>     strokes are
>>     >>> invisible, so it may be difficult to fix it for only this device.
>>     >>>
>>     >>> The main reason for using zero rather than any other number
>>     is that it
>>     >>> survives scaling, which is pretty important for a magic value.
>>     >>>
>>     >>> On Thu, Oct 18, 2018 at 11:12 AM Rick Yorgason
>>     <rick@firefang.com <mailto:rick@firefang.com>
>>     >>> <mailto:rick@firefang.com <mailto:rick@firefang.com>>> wrote:
>>     >>>
>>     >>>      Including zero-width strokes makes sense to me. After
>>     all, true
>>     >>>      hairlines are supposed to act as though they're zero-width.
>>     >>>
>>     >>>      The reason I implemented it this way it's because I was
>>     worried
>>     >>>      about two use cases:
>>     >>>
>>     >>>      1) Some applications might rely on zero-width lines being
>>     >>>      invisible. (Imagine an artist who selects all the lines
>>     he wants
>>     >>>      to hide and changes their line width to zero.)
>>     >>>
>>     >>>      2) Maybe some CNC machines rely on zero-width lines?
>>     PS_COSMETIC
>>     >>>      lines are always 1 unit wide, so there would be no way
>>     to send
>>     >>>      zero-width lines to the printer any more. This seems
>>     unlikely to
>>     >>>      be a problem, but it's possible.
>>     >>>
>>     >>>      (1) can be fixed by the calling application, and (2)
>>     isn't likely
>>     >>>      a real problem, and if we include zero-width strokes it
>>     would make
>>     >>>      it easier for developers to make true zero-width
>>     hairlines (since
>>     >>>      they don't need to know the target device's minimum unit
>>     size), so
>>     >>>      I'm down for it.
>>     >>>
>>     >>>      -Rick-
>>     >>>
>>     >>>      On October 18, 2018 9:10:07 AM PDT, Carl Worth
>>     <cworth@cworth.org <mailto:cworth@cworth.org>
>>     >>>      <mailto:cworth@cworth.org <mailto:cworth@cworth.org>>>
>>     wrote:
>>     >>>
>>     >>>          On Wed, Oct 17 2018, Rick Yorgason wrote:
>>     >>>
>>     >>>              With this patch, I can use Inkscape to set my
>>     stroke width
>>     >>>              to 0.001" and it will cut through the material
>>     as expected.
>>     >>>
>>     >>>
>>     >>>          If we're going to have a magic value here, I think
>>     I'd be much happier
>>     >>>          to have 0 be the magic value.
>>     >>>
>>     >>>          (I know that your code isn't actually making 0.001"
>>     be magic, but a
>>     >>>          whole range of values. I think I would really prefer
>>     to have that range
>>     >>>          include rather then exclude 0.0.)
>>     >>>
>>     >>>          Does anyone see any reason why a stroke width of 0
>>     shouldn't be treated
>>     >>>          this way?
>>     >>>
>>     >>>          I think that would make a much better way to be able
>>     to document
>>     >>>          this. ("Use a value of 0 to get a PS_COSMETIC pen
>>     which is useful when
>>     >>>          targeting devices such as laser cutters".)
>>     >>>
>>     >>>          And speaking of documentation, it seems this patch
>>     should also be
>>     >>>          touching up the documentation, such as in
>>     cairo_set_line_width?
>>     >>>
>>     >>>          I know the code is specific to the Windows backend,
>>     but I think it's
>>     >>>          reasonable to put a backend-specific note into the
>>     general documentation
>>     >>>          in a case like this.
>>     >>>
>>     >>>          -Carl
>>     >>>
>>     >>>
>>     >>>      --
>>     >>>      Sent from my Android device with K-9 Mail. Please excuse
>>     my brevity.
>>     >>>      --
>>     >>>      cairo mailing list
>>     >>> cairo@cairographics.org <mailto:cairo@cairographics.org>
>>     <mailto:cairo@cairographics.org <mailto:cairo@cairographics.org>>
>>     >>> https://lists.cairographics.org/mailman/listinfo/cairo
>>     >>>
>>     >>
>>     >>
>>
>>     -- 
>>     cairo mailing list
>>     cairo@cairographics.org <mailto:cairo@cairographics.org>
>>     https://lists.cairographics.org/mailman/listinfo/cairo
>>
>
>
>
cairo.c                              |  5 +++++
 win32/cairo-win32-printing-surface.c | 24 ++++++++++++++++++++----
 2 files changed, 25 insertions(+), 4 deletions(-)

Patch hide | download patch | download mbox

diff --git a/cairo.c b/cairo.c
index 92724a2..6cef288 100644
--- a/cairo.c
+++ b/cairo.c
@@ -1164,6 +1164,11 @@  cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
  * cairo_stroke_to_path(), but does not have any effect during path
  * construction.
  *
+ * The print driver in Windows will use the PS_COSMETIC pen to render
+ * anything smaller than the smallest printable detail (ie hairlines).
+ * This is how many CNC machines, such as laser cutters, specify
+ * cuts.
+ *
  * The default line width value is 2.0.
  *
  * Since: 1.0
diff --git a/win32/cairo-win32-printing-surface.c b/win32/cairo-win32-printing-surface.c
index da7357c..ec5e2a3 100644
--- a/win32/cairo-win32-printing-surface.c
+++ b/win32/cairo-win32-printing-surface.c
@@ -1467,6 +1467,7 @@  _cairo_win32_printing_surface_stroke (void			*abstract_surface,
     cairo_matrix_t mat;
     double scale;
     cairo_composite_rectangles_t extents;
+    cairo_bool_t cosmetic;
 
     status = _cairo_composite_rectangles_init_for_stroke (&extents,
 							  &surface->win32.base,
@@ -1520,7 +1521,18 @@  _cairo_win32_printing_surface_stroke (void			*abstract_surface,
     cairo_matrix_multiply (&mat, stroke_ctm, &surface->ctm);
     _cairo_matrix_factor_out_scale (&mat, &scale);
 
-    pen_style = PS_GEOMETRIC;
+    // Calculate the minimum printable size. This is either one device pixel, or one canvas unit.
+    double min_stroke_width = max(1.0, _cairo_matrix_transformed_circle_major_axis(stroke_ctm_inverse, 1.0));
+
+    /* When we're printing anything smaller than the smallest printable detail (ie, a hairline) we should
+       use the PS_COSMETIC pen, which is how Windows defines hairlines. This is how some CNC machines, such
+       as laser cutters, differentiate between cuts and etching.
+       We're still using geometric pens if we have dashes, because calculating dash lengths for cosmetic pens
+       requires them to be specified in device-specific "style units", and I can't find any documentation on
+       how to query that. */
+    cosmetic = scale * style->line_width <= min_stroke_width && !style->num_dashes;
+
+    pen_style = cosmetic ? PS_COSMETIC : PS_GEOMETRIC;
     dash_array = NULL;
     if (style->num_dashes) {
 	pen_style |= PS_USERSTYLE;
@@ -1546,10 +1558,14 @@  _cairo_win32_printing_surface_stroke (void			*abstract_surface,
     brush.lbStyle = BS_SOLID;
     brush.lbColor = color;
     brush.lbHatch = 0;
-    pen_style |= _cairo_win32_line_cap (style->line_cap);
-    pen_style |= _cairo_win32_line_join (style->line_join);
+    /* Only geometric pens accept cap/join styles, which is fine, because you can't see them at <= 1
+       printer unit anyway. */
+    if (!cosmetic) {
+        pen_style |= _cairo_win32_line_cap (style->line_cap);
+        pen_style |= _cairo_win32_line_join (style->line_join);
+    }
     pen = ExtCreatePen(pen_style,
-		       scale * style->line_width,
+		       cosmetic ? 1 : scale * style->line_width,
 		       &brush,
 		       style->num_dashes,
 		       dash_array);

Comments

Bill Spitzak Oct. 29, 2018, 5:12 p.m.
Seems like it would be better to consistently use one device unit rather
than the maximum of one device unit and one unit in the CTM.

The zero stuff is a real pain but I suspect trying to fix this in Cairo
(and also support hairlines on other output devices) will be a lot of work.

On Fri, Oct 26, 2018 at 7:10 PM Rick Yorgason <rick@firefang.com> wrote:

> Apologies for the delay. Here's the promised updated patch.
>
> The difference is now it considers the minimum size of both the canvas and
> the printer instead of just the canvas, zero-width strokes count as
> hairlines (although Cairo still seems to be culling strokes from getting to
> this function — that's a separate bug) and the documentation was updated
> for clarity.
>
> Cheers,
>
> -Rick-
>
> On 2018-10-19 12:12, Rick Yorgason wrote:
>
> That shouldn't be. See page 675 of the Postscript Language Reference:
> https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf
>
> A line width of 0 is acceptable, and is interpreted as the thinnest line
> that can be rendered at device resolution—1 device pixel wide. However,
> some devices cannot reproduce 1-pixel lines, and on high-resolution
> devices, they are nearly invisible.
>
>
> -Rick-
>
>
> On 2018-10-19 09:27, Bill Spitzak wrote:
>
> Hairlines are not always 1 pixel wide. For Postscript setting the line
> width to 0.0 gives you a hairline that seems to be about 1/150" which is
> quite a few pixels on modern printers, and was > 1 even on the first Apple
> Laserwriter.
>
> On Fri, Oct 19, 2018 at 6:21 AM Rick Yorgason <rick@firefang.com> wrote:
>
>> It looks like you're right about the device units. In cases where the
>> canvas DPI is lower than the device DPI, the "smallest printable line"
>> is 1, as in my original patch (because ExtCreatePen only accepts
>> integral pen widths), but when the canvas DPI is higher, the "smallest
>> printable line" is
>> `_cairo_matrix_transformed_circle_major_axis(stroke_ctm_inverse, 1.0)`.
>>
>> I haven't looked any further into what's culling zero-width lines yet.
>> For now, I'm focusing on the "use PS_COSMETIC for smallest printable
>> lines" patch, which I believe should be separate from the "allow
>> printing zero-width lines" patch.
>>
>> Tomorrow I'll post a new patch based on the feedback I've received so far.
>>
>> -Rick-
>>
>>
>> On 2018-10-19 00:56, Adrian Johnson wrote:
>> > There were some patches to fix the culling on narrow lines on vector
>> > surfaces:
>> >
>> >
>> https://gitlab.freedesktop.org/cairo/cairo/commit/b1192beac7c5b56a8ff356d20af5ebfb65404109
>> >
>> >
>> https://gitlab.freedesktop.org/cairo/cairo/commit/bec8c7508ebc0f69266f9aebe9903539391c519b
>> >
>> > Those patches should allow zero width lines. I'm not sure what else
>> > could be preventing zero width lines from getting through to the win32
>> > print surface.
>> >
>> > You code that sets the cosmetic flag is not checking the line width in
>> > device units. The StrokePath() is called in user coordinates so that the
>> > line width will be in user coordinates. The reason emitting the path in
>> > device space and stroking in user space is demonstrated here
>> > https://cairographics.org/tutorial/#L2linewidth
>> >
>> > To check if the line width is < 1 device unit you would need to do
>> > something line in the second commit above to find the line width in user
>> > space.
>> >
>> >
>> > On 19/10/18 07:32, Rick Yorgason wrote:
>> >> Sure enough, Cairo seems to be culling zero-width lines somewhere, so
>> it
>> >> doesn't matter whether or not I check for zero here.
>> >>
>> >> For now, I propose that I get rid of the zero-check in my patch, so
>> >> anything <= 1 device unit is drawn with a PS_COSMETIC pen. This value
>> >> gets rounded to an integer, so this approach is consistent with the
>> >> definition of a hairline being the smallest thing a printer can print.
>> >>
>> >> In the long run, it would be nice to track down where Cairo is culling
>> >> zero-width lines and allow them through, as I believe postscript and
>> pdf
>> >> both treat zero-width lines as hairlines.
>> >>
>> >> -Rick-
>> >>
>> >>
>> >> On 2018-10-18 12:09, Bill Spitzak wrote:
>> >>> I suspect there is code in Cairo that assumes zero-width strokes are
>> >>> invisible, so it may be difficult to fix it for only this device.
>> >>>
>> >>> The main reason for using zero rather than any other number is that it
>> >>> survives scaling, which is pretty important for a magic value.
>> >>>
>> >>> On Thu, Oct 18, 2018 at 11:12 AM Rick Yorgason <rick@firefang.com
>> >>> <mailto:rick@firefang.com>> wrote:
>> >>>
>> >>>      Including zero-width strokes makes sense to me. After all, true
>> >>>      hairlines are supposed to act as though they're zero-width.
>> >>>
>> >>>      The reason I implemented it this way it's because I was worried
>> >>>      about two use cases:
>> >>>
>> >>>      1) Some applications might rely on zero-width lines being
>> >>>      invisible. (Imagine an artist who selects all the lines he wants
>> >>>      to hide and changes their line width to zero.)
>> >>>
>> >>>      2) Maybe some CNC machines rely on zero-width lines? PS_COSMETIC
>> >>>      lines are always 1 unit wide, so there would be no way to send
>> >>>      zero-width lines to the printer any more. This seems unlikely to
>> >>>      be a problem, but it's possible.
>> >>>
>> >>>      (1) can be fixed by the calling application, and (2) isn't likely
>> >>>      a real problem, and if we include zero-width strokes it would
>> make
>> >>>      it easier for developers to make true zero-width hairlines (since
>> >>>      they don't need to know the target device's minimum unit size),
>> so
>> >>>      I'm down for it.
>> >>>
>> >>>      -Rick-
>> >>>
>> >>>      On October 18, 2018 9:10:07 AM PDT, Carl Worth <
>> cworth@cworth.org
>> >>>      <mailto:cworth@cworth.org>> wrote:
>> >>>
>> >>>          On Wed, Oct 17 2018, Rick Yorgason wrote:
>> >>>
>> >>>              With this patch, I can use Inkscape to set my stroke
>> width
>> >>>              to 0.001" and it will cut through the material as
>> expected.
>> >>>
>> >>>
>> >>>          If we're going to have a magic value here, I think I'd be
>> much happier
>> >>>          to have 0 be the magic value.
>> >>>
>> >>>          (I know that your code isn't actually making 0.001" be
>> magic, but a
>> >>>          whole range of values. I think I would really prefer to have
>> that range
>> >>>          include rather then exclude 0.0.)
>> >>>
>> >>>          Does anyone see any reason why a stroke width of 0 shouldn't
>> be treated
>> >>>          this way?
>> >>>
>> >>>          I think that would make a much better way to be able to
>> document
>> >>>          this. ("Use a value of 0 to get a PS_COSMETIC pen which is
>> useful when
>> >>>          targeting devices such as laser cutters".)
>> >>>
>> >>>          And speaking of documentation, it seems this patch should
>> also be
>> >>>          touching up the documentation, such as in
>> cairo_set_line_width?
>> >>>
>> >>>          I know the code is specific to the Windows backend, but I
>> think it's
>> >>>          reasonable to put a backend-specific note into the general
>> documentation
>> >>>          in a case like this.
>> >>>
>> >>>          -Carl
>> >>>
>> >>>
>> >>>      --
>> >>>      Sent from my Android device with K-9 Mail. Please excuse my
>> brevity.
>> >>>      --
>> >>>      cairo mailing list
>> >>>      cairo@cairographics.org <mailto:cairo@cairographics.org>
>> >>>      https://lists.cairographics.org/mailman/listinfo/cairo
>> >>>
>> >>
>> >>
>>
>> --
>> cairo mailing list
>> cairo@cairographics.org
>> https://lists.cairographics.org/mailman/listinfo/cairo
>
>
>
>
>
>
Rick Yorgason Oct. 29, 2018, 8:29 p.m.
I think it makes sense to do both, but if we're only going to have one 
check, it should be the CTM, like i originally had.

If we only test the device unit, then we run into weird scenarios. Let's 
say 1 device pixel is 0.3 CTM units. That means anything from [0-0.3] 
units *will* draw as a hairline, but anything from (0.3-1) will get 
rounded to 0 and won't draw at all. (Remember, ExtCreatePen takes the 
pen width as an integer.) So 0.3 and 1.0 draw, but 0.5 doesn't.

-Rick-


On 2018-10-29 10:12, Bill Spitzak wrote:
> Seems like it would be better to consistently use one device unit 
> rather than the maximum of one device unit and one unit in the CTM.
>
> The zero stuff is a real pain but I suspect trying to fix this in 
> Cairo (and also support hairlines on other output devices) will be a 
> lot of work.
>
> On Fri, Oct 26, 2018 at 7:10 PM Rick Yorgason <rick@firefang.com 
> <mailto:rick@firefang.com>> wrote:
>
>     Apologies for the delay. Here's the promised updated patch.
>
>     The difference is now it considers the minimum size of both the
>     canvas and the printer instead of just the canvas, zero-width
>     strokes count as hairlines (although Cairo still seems to be
>     culling strokes from getting to this function — that's a separate
>     bug) and the documentation was updated for clarity.
>
>     Cheers,
>
>     -Rick-
>
>
>     On 2018-10-19 12:12, Rick Yorgason wrote:
>>     That shouldn't be. See page 675 of the Postscript Language
>>     Reference:
>>     https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf
>>
>>>     A line width of 0 is acceptable, and is interpreted as the
>>>     thinnest line that can be rendered at device resolution—1 device
>>>     pixel wide. However, some devices cannot reproduce 1-pixel
>>>     lines, and on high-resolution devices, they are nearly invisible.
>>
>>     -Rick-
>>
>>
>>     On 2018-10-19 09:27, Bill Spitzak wrote:
>>>     Hairlines are not always 1 pixel wide. For Postscript setting
>>>     the line width to 0.0 gives you a hairline that seems to be
>>>     about 1/150" which is quite a few pixels on modern printers, and
>>>     was > 1 even on the first Apple Laserwriter.
>>>
>>>     On Fri, Oct 19, 2018 at 6:21 AM Rick Yorgason <rick@firefang.com
>>>     <mailto:rick@firefang.com>> wrote:
>>>
>>>         It looks like you're right about the device units. In cases
>>>         where the
>>>         canvas DPI is lower than the device DPI, the "smallest
>>>         printable line"
>>>         is 1, as in my original patch (because ExtCreatePen only
>>>         accepts
>>>         integral pen widths), but when the canvas DPI is higher, the
>>>         "smallest
>>>         printable line" is
>>>         `_cairo_matrix_transformed_circle_major_axis(stroke_ctm_inverse,
>>>         1.0)`.
>>>
>>>         I haven't looked any further into what's culling zero-width
>>>         lines yet.
>>>         For now, I'm focusing on the "use PS_COSMETIC for smallest
>>>         printable
>>>         lines" patch, which I believe should be separate from the
>>>         "allow
>>>         printing zero-width lines" patch.
>>>
>>>         Tomorrow I'll post a new patch based on the feedback I've
>>>         received so far.
>>>
>>>         -Rick-
>>>
>>>
>>>         On 2018-10-19 00:56, Adrian Johnson wrote:
>>>         > There were some patches to fix the culling on narrow lines
>>>         on vector
>>>         > surfaces:
>>>         >
>>>         >
>>>         https://gitlab.freedesktop.org/cairo/cairo/commit/b1192beac7c5b56a8ff356d20af5ebfb65404109
>>>         >
>>>         >
>>>         https://gitlab.freedesktop.org/cairo/cairo/commit/bec8c7508ebc0f69266f9aebe9903539391c519b
>>>         >
>>>         > Those patches should allow zero width lines. I'm not sure
>>>         what else
>>>         > could be preventing zero width lines from getting through
>>>         to the win32
>>>         > print surface.
>>>         >
>>>         > You code that sets the cosmetic flag is not checking the
>>>         line width in
>>>         > device units. The StrokePath() is called in user
>>>         coordinates so that the
>>>         > line width will be in user coordinates. The reason
>>>         emitting the path in
>>>         > device space and stroking in user space is demonstrated here
>>>         > https://cairographics.org/tutorial/#L2linewidth
>>>         >
>>>         > To check if the line width is < 1 device unit you would
>>>         need to do
>>>         > something line in the second commit above to find the line
>>>         width in user
>>>         > space.
>>>         >
>>>         >
>>>         > On 19/10/18 07:32, Rick Yorgason wrote:
>>>         >> Sure enough, Cairo seems to be culling zero-width lines
>>>         somewhere, so it
>>>         >> doesn't matter whether or not I check for zero here.
>>>         >>
>>>         >> For now, I propose that I get rid of the zero-check in my
>>>         patch, so
>>>         >> anything <= 1 device unit is drawn with a PS_COSMETIC
>>>         pen. This value
>>>         >> gets rounded to an integer, so this approach is
>>>         consistent with the
>>>         >> definition of a hairline being the smallest thing a
>>>         printer can print.
>>>         >>
>>>         >> In the long run, it would be nice to track down where
>>>         Cairo is culling
>>>         >> zero-width lines and allow them through, as I believe
>>>         postscript and pdf
>>>         >> both treat zero-width lines as hairlines.
>>>         >>
>>>         >> -Rick-
>>>         >>
>>>         >>
>>>         >> On 2018-10-18 12:09, Bill Spitzak wrote:
>>>         >>> I suspect there is code in Cairo that assumes zero-width
>>>         strokes are
>>>         >>> invisible, so it may be difficult to fix it for only
>>>         this device.
>>>         >>>
>>>         >>> The main reason for using zero rather than any other
>>>         number is that it
>>>         >>> survives scaling, which is pretty important for a magic
>>>         value.
>>>         >>>
>>>         >>> On Thu, Oct 18, 2018 at 11:12 AM Rick Yorgason
>>>         <rick@firefang.com <mailto:rick@firefang.com>
>>>         >>> <mailto:rick@firefang.com <mailto:rick@firefang.com>>>
>>>         wrote:
>>>         >>>
>>>         >>>      Including zero-width strokes makes sense to me.
>>>         After all, true
>>>         >>>      hairlines are supposed to act as though they're
>>>         zero-width.
>>>         >>>
>>>         >>>      The reason I implemented it this way it's because I
>>>         was worried
>>>         >>>      about two use cases:
>>>         >>>
>>>         >>>      1) Some applications might rely on zero-width lines
>>>         being
>>>         >>>      invisible. (Imagine an artist who selects all the
>>>         lines he wants
>>>         >>>      to hide and changes their line width to zero.)
>>>         >>>
>>>         >>>      2) Maybe some CNC machines rely on zero-width
>>>         lines? PS_COSMETIC
>>>         >>>      lines are always 1 unit wide, so there would be no
>>>         way to send
>>>         >>>      zero-width lines to the printer any more. This
>>>         seems unlikely to
>>>         >>>      be a problem, but it's possible.
>>>         >>>
>>>         >>>      (1) can be fixed by the calling application, and
>>>         (2) isn't likely
>>>         >>>      a real problem, and if we include zero-width
>>>         strokes it would make
>>>         >>>      it easier for developers to make true zero-width
>>>         hairlines (since
>>>         >>>      they don't need to know the target device's minimum
>>>         unit size), so
>>>         >>>      I'm down for it.
>>>         >>>
>>>         >>>      -Rick-
>>>         >>>
>>>         >>>      On October 18, 2018 9:10:07 AM PDT, Carl Worth
>>>         <cworth@cworth.org <mailto:cworth@cworth.org>
>>>         >>>      <mailto:cworth@cworth.org
>>>         <mailto:cworth@cworth.org>>> wrote:
>>>         >>>
>>>         >>>          On Wed, Oct 17 2018, Rick Yorgason wrote:
>>>         >>>
>>>         >>>              With this patch, I can use Inkscape to set
>>>         my stroke width
>>>         >>>              to 0.001" and it will cut through the
>>>         material as expected.
>>>         >>>
>>>         >>>
>>>         >>>          If we're going to have a magic value here, I
>>>         think I'd be much happier
>>>         >>>          to have 0 be the magic value.
>>>         >>>
>>>         >>>          (I know that your code isn't actually making
>>>         0.001" be magic, but a
>>>         >>>          whole range of values. I think I would really
>>>         prefer to have that range
>>>         >>>          include rather then exclude 0.0.)
>>>         >>>
>>>         >>>          Does anyone see any reason why a stroke width
>>>         of 0 shouldn't be treated
>>>         >>>          this way?
>>>         >>>
>>>         >>>          I think that would make a much better way to be
>>>         able to document
>>>         >>>          this. ("Use a value of 0 to get a PS_COSMETIC
>>>         pen which is useful when
>>>         >>>          targeting devices such as laser cutters".)
>>>         >>>
>>>         >>>          And speaking of documentation, it seems this
>>>         patch should also be
>>>         >>>          touching up the documentation, such as in
>>>         cairo_set_line_width?
>>>         >>>
>>>         >>>          I know the code is specific to the Windows
>>>         backend, but I think it's
>>>         >>>          reasonable to put a backend-specific note into
>>>         the general documentation
>>>         >>>          in a case like this.
>>>         >>>
>>>         >>>          -Carl
>>>         >>>
>>>         >>>
>>>         >>>      --
>>>         >>>      Sent from my Android device with K-9 Mail. Please
>>>         excuse my brevity.
>>>         >>>      --
>>>         >>>      cairo mailing list
>>>         >>> cairo@cairographics.org <mailto:cairo@cairographics.org>
>>>         <mailto:cairo@cairographics.org
>>>         <mailto:cairo@cairographics.org>>
>>>         >>> https://lists.cairographics.org/mailman/listinfo/cairo
>>>         >>>
>>>         >>
>>>         >>
>>>
>>>         -- 
>>>         cairo mailing list
>>>         cairo@cairographics.org <mailto:cairo@cairographics.org>
>>>         https://lists.cairographics.org/mailman/listinfo/cairo
>>>
>>
>>
>>
>
Rick Yorgason Nov. 5, 2018, 5:41 a.m.
If it's helpful, I've created a gitlab branch here: 
https://gitlab.freedesktop.org/Skrapion/cairo/commit/9c81cdd255cd2553ff99cf11e086f905d577e4a0

Thanks for the reviews! Let me know if you would prefer for this to be 
based on just the CTM instead of both the CTM and device pixel.

-Rick-

On 2018-10-29 13:29, Rick Yorgason wrote:
>
> I think it makes sense to do both, but if we're only going to have one 
> check, it should be the CTM, like i originally had.
>
> If we only test the device unit, then we run into weird scenarios. 
> Let's say 1 device pixel is 0.3 CTM units. That means anything from 
> [0-0.3] units *will* draw as a hairline, but anything from (0.3-1) 
> will get rounded to 0 and won't draw at all. (Remember, ExtCreatePen 
> takes the pen width as an integer.) So 0.3 and 1.0 draw, but 0.5 doesn't.
>
> -Rick-
>
>
> On 2018-10-29 10:12, Bill Spitzak wrote:
>> Seems like it would be better to consistently use one device unit 
>> rather than the maximum of one device unit and one unit in the CTM.
>>
>> The zero stuff is a real pain but I suspect trying to fix this in 
>> Cairo (and also support hairlines on other output devices) will be a 
>> lot of work.
>>
>> On Fri, Oct 26, 2018 at 7:10 PM Rick Yorgason <rick@firefang.com 
>> <mailto:rick@firefang.com>> wrote:
>>
>>     Apologies for the delay. Here's the promised updated patch.
>>
>>     The difference is now it considers the minimum size of both the
>>     canvas and the printer instead of just the canvas, zero-width
>>     strokes count as hairlines (although Cairo still seems to be
>>     culling strokes from getting to this function — that's a separate
>>     bug) and the documentation was updated for clarity.
>>
>>     Cheers,
>>
>>     -Rick-
>>
>>
>>     On 2018-10-19 12:12, Rick Yorgason wrote:
>>>     That shouldn't be. See page 675 of the Postscript Language
>>>     Reference:
>>>     https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf
>>>
>>>>     A line width of 0 is acceptable, and is interpreted as the
>>>>     thinnest line that can be rendered at device resolution—1
>>>>     device pixel wide. However, some devices cannot reproduce
>>>>     1-pixel lines, and on high-resolution devices, they are nearly
>>>>     invisible.
>>>
>>>     -Rick-
>>>
>>>
>>>     On 2018-10-19 09:27, Bill Spitzak wrote:
>>>>     Hairlines are not always 1 pixel wide. For Postscript setting
>>>>     the line width to 0.0 gives you a hairline that seems to be
>>>>     about 1/150" which is quite a few pixels on modern printers,
>>>>     and was > 1 even on the first Apple Laserwriter.
>>>>
>>>>     On Fri, Oct 19, 2018 at 6:21 AM Rick Yorgason
>>>>     <rick@firefang.com <mailto:rick@firefang.com>> wrote:
>>>>
>>>>         It looks like you're right about the device units. In cases
>>>>         where the
>>>>         canvas DPI is lower than the device DPI, the "smallest
>>>>         printable line"
>>>>         is 1, as in my original patch (because ExtCreatePen only
>>>>         accepts
>>>>         integral pen widths), but when the canvas DPI is higher,
>>>>         the "smallest
>>>>         printable line" is
>>>>         `_cairo_matrix_transformed_circle_major_axis(stroke_ctm_inverse,
>>>>         1.0)`.
>>>>
>>>>         I haven't looked any further into what's culling zero-width
>>>>         lines yet.
>>>>         For now, I'm focusing on the "use PS_COSMETIC for smallest
>>>>         printable
>>>>         lines" patch, which I believe should be separate from the
>>>>         "allow
>>>>         printing zero-width lines" patch.
>>>>
>>>>         Tomorrow I'll post a new patch based on the feedback I've
>>>>         received so far.
>>>>
>>>>         -Rick-
>>>>
>>>>
>>>>         On 2018-10-19 00:56, Adrian Johnson wrote:
>>>>         > There were some patches to fix the culling on narrow
>>>>         lines on vector
>>>>         > surfaces:
>>>>         >
>>>>         >
>>>>         https://gitlab.freedesktop.org/cairo/cairo/commit/b1192beac7c5b56a8ff356d20af5ebfb65404109
>>>>         >
>>>>         >
>>>>         https://gitlab.freedesktop.org/cairo/cairo/commit/bec8c7508ebc0f69266f9aebe9903539391c519b
>>>>         >
>>>>         > Those patches should allow zero width lines. I'm not sure
>>>>         what else
>>>>         > could be preventing zero width lines from getting through
>>>>         to the win32
>>>>         > print surface.
>>>>         >
>>>>         > You code that sets the cosmetic flag is not checking the
>>>>         line width in
>>>>         > device units. The StrokePath() is called in user
>>>>         coordinates so that the
>>>>         > line width will be in user coordinates. The reason
>>>>         emitting the path in
>>>>         > device space and stroking in user space is demonstrated here
>>>>         > https://cairographics.org/tutorial/#L2linewidth
>>>>         >
>>>>         > To check if the line width is < 1 device unit you would
>>>>         need to do
>>>>         > something line in the second commit above to find the
>>>>         line width in user
>>>>         > space.
>>>>         >
>>>>         >
>>>>         > On 19/10/18 07:32, Rick Yorgason wrote:
>>>>         >> Sure enough, Cairo seems to be culling zero-width lines
>>>>         somewhere, so it
>>>>         >> doesn't matter whether or not I check for zero here.
>>>>         >>
>>>>         >> For now, I propose that I get rid of the zero-check in
>>>>         my patch, so
>>>>         >> anything <= 1 device unit is drawn with a PS_COSMETIC
>>>>         pen. This value
>>>>         >> gets rounded to an integer, so this approach is
>>>>         consistent with the
>>>>         >> definition of a hairline being the smallest thing a
>>>>         printer can print.
>>>>         >>
>>>>         >> In the long run, it would be nice to track down where
>>>>         Cairo is culling
>>>>         >> zero-width lines and allow them through, as I believe
>>>>         postscript and pdf
>>>>         >> both treat zero-width lines as hairlines.
>>>>         >>
>>>>         >> -Rick-
>>>>         >>
>>>>         >>
>>>>         >> On 2018-10-18 12:09, Bill Spitzak wrote:
>>>>         >>> I suspect there is code in Cairo that assumes
>>>>         zero-width strokes are
>>>>         >>> invisible, so it may be difficult to fix it for only
>>>>         this device.
>>>>         >>>
>>>>         >>> The main reason for using zero rather than any other
>>>>         number is that it
>>>>         >>> survives scaling, which is pretty important for a magic
>>>>         value.
>>>>         >>>
>>>>         >>> On Thu, Oct 18, 2018 at 11:12 AM Rick Yorgason
>>>>         <rick@firefang.com <mailto:rick@firefang.com>
>>>>         >>> <mailto:rick@firefang.com <mailto:rick@firefang.com>>>
>>>>         wrote:
>>>>         >>>
>>>>         >>>      Including zero-width strokes makes sense to me.
>>>>         After all, true
>>>>         >>>      hairlines are supposed to act as though they're
>>>>         zero-width.
>>>>         >>>
>>>>         >>>      The reason I implemented it this way it's because
>>>>         I was worried
>>>>         >>>      about two use cases:
>>>>         >>>
>>>>         >>>      1) Some applications might rely on zero-width
>>>>         lines being
>>>>         >>>      invisible. (Imagine an artist who selects all the
>>>>         lines he wants
>>>>         >>>      to hide and changes their line width to zero.)
>>>>         >>>
>>>>         >>>      2) Maybe some CNC machines rely on zero-width
>>>>         lines? PS_COSMETIC
>>>>         >>>      lines are always 1 unit wide, so there would be no
>>>>         way to send
>>>>         >>>      zero-width lines to the printer any more. This
>>>>         seems unlikely to
>>>>         >>>      be a problem, but it's possible.
>>>>         >>>
>>>>         >>>      (1) can be fixed by the calling application, and
>>>>         (2) isn't likely
>>>>         >>>      a real problem, and if we include zero-width
>>>>         strokes it would make
>>>>         >>>      it easier for developers to make true zero-width
>>>>         hairlines (since
>>>>         >>>      they don't need to know the target device's
>>>>         minimum unit size), so
>>>>         >>>      I'm down for it.
>>>>         >>>
>>>>         >>>      -Rick-
>>>>         >>>
>>>>         >>>      On October 18, 2018 9:10:07 AM PDT, Carl Worth
>>>>         <cworth@cworth.org <mailto:cworth@cworth.org>
>>>>         >>>      <mailto:cworth@cworth.org
>>>>         <mailto:cworth@cworth.org>>> wrote:
>>>>         >>>
>>>>         >>>          On Wed, Oct 17 2018, Rick Yorgason wrote:
>>>>         >>>
>>>>         >>>              With this patch, I can use Inkscape to set
>>>>         my stroke width
>>>>         >>>              to 0.001" and it will cut through the
>>>>         material as expected.
>>>>         >>>
>>>>         >>>
>>>>         >>>          If we're going to have a magic value here, I
>>>>         think I'd be much happier
>>>>         >>>          to have 0 be the magic value.
>>>>         >>>
>>>>         >>>          (I know that your code isn't actually making
>>>>         0.001" be magic, but a
>>>>         >>>          whole range of values. I think I would really
>>>>         prefer to have that range
>>>>         >>>          include rather then exclude 0.0.)
>>>>         >>>
>>>>         >>>          Does anyone see any reason why a stroke width
>>>>         of 0 shouldn't be treated
>>>>         >>>          this way?
>>>>         >>>
>>>>         >>>          I think that would make a much better way to
>>>>         be able to document
>>>>         >>>          this. ("Use a value of 0 to get a PS_COSMETIC
>>>>         pen which is useful when
>>>>         >>>          targeting devices such as laser cutters".)
>>>>         >>>
>>>>         >>>          And speaking of documentation, it seems this
>>>>         patch should also be
>>>>         >>>          touching up the documentation, such as in
>>>>         cairo_set_line_width?
>>>>         >>>
>>>>         >>>          I know the code is specific to the Windows
>>>>         backend, but I think it's
>>>>         >>>          reasonable to put a backend-specific note into
>>>>         the general documentation
>>>>         >>>          in a case like this.
>>>>         >>>
>>>>         >>>          -Carl
>>>>         >>>
>>>>         >>>
>>>>         >>>      --
>>>>         >>>      Sent from my Android device with K-9 Mail. Please
>>>>         excuse my brevity.
>>>>         >>>      --
>>>>         >>>      cairo mailing list
>>>>         >>> cairo@cairographics.org
>>>>         <mailto:cairo@cairographics.org>
>>>>         <mailto:cairo@cairographics.org
>>>>         <mailto:cairo@cairographics.org>>
>>>>         >>> https://lists.cairographics.org/mailman/listinfo/cairo
>>>>         >>>
>>>>         >>
>>>>         >>
>>>>
>>>>         -- 
>>>>         cairo mailing list
>>>>         cairo@cairographics.org <mailto:cairo@cairographics.org>
>>>>         https://lists.cairographics.org/mailman/listinfo/cairo
>>>>
>>>
>>>
>>>
>>
>