Ask a questionAsk a question
 

AnswerLine blurring

  • Monday, April 23, 2007 7:16 PMWynApse Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Somebody else please try this to help me 'pull my head out'.

     

    Of course there are other ways to do this, but I've seen similar effects using other techniques and finally got it down to 3 simple lines:

     

    <Canvas
       xmlns="http://schemas.microsoft.com/client/2007"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

       <Canvas Canvas.Left="0" Canvas.Top="0" Width="100" Height="22">
          <Line x:Name="Tab0_Left" Stroke="Black" StrokeThickness="1"
                X1="0" Y1="21" X2="0" Y2="0" />
          <Line Stroke="Black" StrokeThickness="1"
                X1="0" Y1="0" X2="98" Y2="0" />
          <Line Stroke="Black" StrokeThickness="1"
                X1="98" Y1="21" X2="98" Y2="0" />
       </Canvas>

    </Canvas>

    The right-hand line from (98,21) to (98,0) is blurred across two pixels.

     

    I've done it from (98,0) to (98,21) and get the same.

     

    I actually started with a path, and the right-hand side was blurred.

     

    What am I not seeing?

     

    Thanks!

     

    -Dave

Answers

  • Wednesday, April 25, 2007 7:41 PMsmall_mountain_0705 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

     

    I think I just realized what's going on here.  The line defined by the points (10,10) and (20,10) is actually a zero-width horizontal line *between* vertical pixels 10 and 11.  When you draw a one-pixel-wide line on that line, WPF wants to center it on that line, which means that since the line is between pixels, half has to go *above* the line and half has to go *below* the line.  Hence, instead of getting single line of black pixels, you get a double line of gray pixels.  If what you want is a one-pixel-wide line, you need to draw it from (10, 10.5) to (20, 10.5).  Since a path is just a bunch of lines, it follows the same rules. 

    The Shape classes work differently. A Rectangle with upper left corner (10, 10) and bottom right corner (20, 20) includes all of the pixels to the right of the zero-width line x=10 and to the left of zero-width line x=20.  So it includes all of the whole pixels.  Actually, I guess I'm not sure if it stops at pixel 20 or 21, but you get the point.  In the XAML I've included below, I repeat the examples from this thread, plus I redo them on half-pixel boundaries where necessary to avoid having lines split across two pixels.

    Code Snippet
    <Page
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        >

     

    <Canvas>
      <Canvas Canvas.Left="0" Canvas.Top="5" Width="100" Height="100">
         <Rectangle Width="60" Height="60" Stroke="Black" StrokeThickness="1" Canvas.Left="50"/>
         <Rectangle Width="60" Height="60" Stroke="Black" StrokeThickness="2" Canvas.Left="111"/>
         <Rectangle Width="60" Height="60" Stroke="Black" StrokeThickness="3" Canvas.Left="172"/>
         <Rectangle Width="60" Height="60" Stroke="Black" StrokeThickness="10" Canvas.Left="233"/>
      </Canvas>

     

      <Canvas Canvas.Left="0" Canvas.Top="35" Width="300" Height="300">
         <Polygon Points="50,50 50,110 110,110 110,50" Stroke="Black" StrokeThickness="1" Fill="LightBlue"/>
         <Polygon Points="111,50 111,110 171,110 171,50" Stroke="Black" StrokeThickness="2" Fill="LightBlue"/>
         <Polygon Points="172,50 172,110 232,110 232,50" Stroke="Black" StrokeThickness="3" Fill="LightBlue"/>
         <Polygon Points="233,50 233,110 293,110 293,50" Stroke="Black" StrokeThickness="10" Fill="LightBlue"/>
      </Canvas>

     

      <Canvas Canvas.Left="0" Canvas.Top="115" Width="300" Height="300">
         <Path Stroke="Black" StrokeThickness="1" Fill="LightGreen">
              <Path.Data><RectangleGeometry Rect="50 50 60 60"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="2" Fill="LightGreen">
              <Path.Data><RectangleGeometry Rect="111 50 60 60"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="3" Fill="LightGreen">
              <Path.Data><RectangleGeometry Rect="172 50 60 60"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="10" Fill="LightGreen">
              <Path.Data><RectangleGeometry Rect="233 50 60 60"/></Path.Data>
         </Path>
      </Canvas>

     

      <Canvas Canvas.Left="0" Canvas.Top="195" Width="300" Height="300">
         <Path Stroke="Black" StrokeThickness="1" Fill="LightYellow">
              <Path.Data><RectangleGeometry Rect="50.5 50.5 59 59"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="2" Fill="LightYellow">
              <Path.Data><RectangleGeometry Rect="112 51 58 58"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="3" Fill="LightYellow">
              <Path.Data><RectangleGeometry Rect="173.5 51.5 57 57"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="10" Fill="LightYellow">
              <Path.Data><RectangleGeometry Rect="238 55 50 50"/></Path.Data>
         </Path>
      </Canvas>

     

      <Canvas Canvas.Left="350" Canvas.Top="0" Width="300" Height="300">
     <Rectangle Canvas.Left="50" Canvas.Top="5" Width="50" Height="50" Stroke="Black" StrokeThickness="1" />   
     <Path Stroke="Black" StrokeThickness="1" Data="M20,20 L70,20 L70,70 L20,70z"/>   
     <Line Stroke="Black" StrokeThickness="1" X1="80" Y1="20" X2="130" Y2="20" />
     <Line Stroke="Black" StrokeThickness="1" X1="130" Y1="20" X2="130" Y2="70" />
     <Line Stroke="Black" StrokeThickness="1" X1="130" Y1="70" X2="80" Y2="70" />   
     <Line Stroke="Black" StrokeThickness="1" X1="80" Y1="70" X2="80" Y2="20" />   
     <Path Stroke="Red" StrokeThickness="2" Data="M35,40 L115,40 L115,85 L35,85z"/>
      </Canvas>

     

      <Canvas Canvas.Left="550" Canvas.Top="10" Width="300" Height="300">
         <Line Stroke="Black" StrokeThickness="1" X1="1" Y1="21" X2="1" Y2="0" />
         <Line Stroke="Red" StrokeThickness="1" X1="2" Y1="41" X2="2" Y2="0" />
         <Line Stroke="Yellow" StrokeThickness="1" X1="3" Y1="61" X2="3" Y2="0" />

     

         <Line Stroke="Blue" StrokeThickness="1" X1="10" Y1="21" X2="10" Y2="0" />
         <Line Stroke="White" StrokeThickness="1" X1="11" Y1="41" X2="11" Y2="0" />
         <Line Stroke="Yellow" StrokeThickness="1" X1="12" Y1="61" X2="12" Y2="0" />

     

         <Line Stroke="Black" StrokeThickness="1" X1="20" Y1="21" X2="20" Y2="0" />
         <Line Stroke="Yellow" StrokeThickness="1" X1="21" Y1="41" X2="21" Y2="0" />
         <Line Stroke="Black" StrokeThickness="1" X1="22" Y1="61" X2="22" Y2="0" />

     

         <Line Stroke="Black" X1="30" Y1="21" X2="30" Y2="0" />
         <Line Stroke="Yellow" X1="33" Y1="41" X2="34" Y2="0" />
         <Line Stroke="Black" X1="36" Y1="61" X2="36" Y2="0" />
      </Canvas>

     

      <Canvas Canvas.Left="350" Canvas.Top="150" Width="300" Height="300">
     <Rectangle Canvas.Left="50" Canvas.Top="5" Width="50" Height="50" Stroke="Black" StrokeThickness="1" />   
     <Path Stroke="Black" StrokeThickness="1" Data="M20.5,20.5 L69.5,20.5 L69.5,69.5 L20.5,69.5z"/>   
     <Line Stroke="Black" StrokeThickness="1" X1="80.5" Y1="20.5" X2="129.5" Y2="20.5" />
     <Line Stroke="Black" StrokeThickness="1" X1="129.5" Y1="20.5" X2="129.5" Y2="69.5" />
     <Line Stroke="Black" StrokeThickness="1" X1="129.5" Y1="69.5" X2="80.5" Y2="69.5" />   
     <Line Stroke="Black" StrokeThickness="1" X1="80.5" Y1="69.5" X2="80.5" Y2="20.5" />   
     <Path Stroke="Red" StrokeThickness="2" Data="M35,40 115,40 L115,85 L35,85z"/>
      </Canvas>

     

      <Canvas Canvas.Left="550" Canvas.Top="160" Width="300" Height="300">
         <Line Stroke="Black" StrokeThickness="1" X1="1.5" Y1="21.5" X2="1.5" Y2="0.5" />
         <Line Stroke="Red" StrokeThickness="1" X1="2.5" Y1="41.5" X2="2.5" Y2="0.5" />
         <Line Stroke="Yellow" StrokeThickness="1" X1="3.5" Y1="61.5" X2="3.5" Y2="0.5" />

     

         <Line Stroke="Blue" StrokeThickness="1.5" X1="10.5" Y1="21.5" X2="10.5" Y2="0.5" />
         <Line Stroke="White" StrokeThickness="1.5" X1="11.5" Y1="41.5" X2="11.5" Y2="0.5" />
         <Line Stroke="Yellow" StrokeThickness="1.5" X1="12.5" Y1="61.5" X2="12.5" Y2="0.5" />

     

         <Line Stroke="Black" StrokeThickness="1.5" X1="20.5" Y1="21.5" X2="20.5" Y2="0.5" />
         <Line Stroke="Yellow" StrokeThickness="1.5" X1="21.5" Y1="41.5" X2="21.5" Y2="0.5" />
         <Line Stroke="Black" StrokeThickness="1.5" X1="22.5" Y1="61.5" X2="22.5" Y2="0.5" />

     

         <Line Stroke="Black" X1="30.5" Y1="21.5" X2="30.5" Y2="0.5" />
         <Line Stroke="Yellow" X1="33.5" Y1="41.5" X2="34.5" Y2="0.5" />
         <Line Stroke="Black" X1="36.5" Y1="61.5" X2="36.5" Y2="0.5" />
     
      </Canvas>
    </Canvas>

     

    </Page>

     




     
        
        
        
        
     

     
        
        
        
        
     

     
        
             
        
        
             
        
        
             
        
        
             
        
     

     
        
             
        
        
             
        
        
             
        
        
             
        
     

     
       
       


       
       

     

     
        
        
        

        
        
        

        
        
        

        
        
        
     

     
       
       


       
       

     

     
        
        
        

        
        
        

        
        
        

        
        
        

     




All Replies

  • Monday, April 23, 2007 9:04 PMLuis Miguel AbreuMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    hello.

     

    i think that clipping is not working as you might expect. Even though i really don't have much experience with wpf/e, it seems like you're getting a clipping behavior on the  top left sides but not on the right side. So, if you "push" the top and left corners 1 pixel in you should see all sides with the same stroke thickness. Another thing you can do is specify a clipping rectangle and put all the borders on that rectangle (which would clip the thickness and produce a thiner border - thoug i think that moving the borders is the correct approach):

    <Canvas

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Canvas Canvas.Left="0" Canvas.Top="0" Width="100" Height="22">

    <Canvas.Clip>

    <RectangleGeometry Rect="0,0,100,22" />

    </Canvas.Clip>

    <Line x:Name="Tab0_Left" Stroke="Black" StrokeThickness="1"

    X1="0" Y1="21" X2="0" Y2="0" />

    <Line Stroke="Black" StrokeThickness="1"

    X1="0" Y1="0" X2="100" Y2="0" />

    <Line Stroke="Black" StrokeThickness="1"

    X1="100" Y1="21" X2="100" Y2="0" />

    </Canvas>

    </Canvas>

  • Monday, April 23, 2007 9:18 PMWynApse Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    But all I'm doing is drawing 3 straight lines... I'm not expecting any clipping to take place.

     

    If I draw a rectangle of stroke thickness 1, I'd get a single pixel line all the way around.

     

    From the looks of this, if I try to do a rectangle with 4 line segments I'll get a pixel blur on one of the side, which definitely isn't consistent.

     

    I could certainly do a rectangle and clip the bottom off, but I'd like to know what's going on with that one line...

     

    Thanks!

     

    -Dave

     

  • Monday, April 23, 2007 9:31 PMM. SchwarzMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi Dave,

     

    for me it looks like an anti alias effect, I posted another example in the Google group here:

     

    http://groups.google.com/group/wpf-everywhere/browse_thread/thread/905e2e6684d013c7

     

    Michael

  • Monday, April 23, 2007 9:33 PMLuis Miguel AbreuMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hello again.

    Let me explain what i was trying to say. try running the following:

     

    <Line x:Name="Tab0_Left" Stroke="Black" StrokeThickness="1"

    X1="1" Y1="21" X2="1" Y2="1" />

    <Line Stroke="Black" StrokeThickness="1"

    X1="1" Y1="1" X2="100" Y2="1" />

    <Line Stroke="Black" StrokeThickness="1"

    X1="100" Y1="21" X2="100" Y2="1" />

     

    note that I've changed the 0 coords to 1. what do you see now? all the lines have the same thickness. what i was saying was that, even though you didn't set a clipping region, if you set the coord to 0 and you're on the lef or top side, the thicknes of the line won't be correct: it seems like you're only getting half of it drawn and the other half of it will be clipped (but only if you're on the lef or top side, which happens when you set x and y to 0 in your previous code). Not sure why this doesn't happen in the right side (note that you can even set the last line to 200 (which is out of the canvas -i expected not seeing the line, but the fact is that i can)

     

    To prove this point, I've set a clipping region in the previous sample I've written and you'll get this behavior (boder thickness being clipped on all sides now) when you use coordinates which are delimited by the canvas (the clipping region has the same size as the canvas) as i did in the previous example.

     

    I agree that this makes no sense and maybe we're seeing a bug. But that is what i'm seeing here. hope i've explained myself better this time.

  • Monday, April 23, 2007 9:39 PMLuis Miguel AbreuMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    hello Michael.

     

    if this is an anti-alias effect, why does clipping affect it? why does it disappear when you "move" the point 1 pixel in? and why does it happen only when the point is on the left or top borders of the canvas (ie, if it's  1 px in, it doesn't happen)?

     

    just trying to learn Smile

    thanks.

  • Monday, April 23, 2007 9:42 PMWynApse Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Good point, Luis... and I definitely see what you're saying, and you're right.

     

    My issue on this is if I do a rectangle:

     

    <Canvas
       xmlns="http://schemas.microsoft.com/client/2007"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

       <Canvas Canvas.Left="0" Canvas.Top="0" Width="100" Height="22">
          <Rectangle Canvas.Left="10" Canvas.Top="10" Width="100" Height="100" Stroke="Black" StrokeThickness="1" />
       </Canvas>

    </Canvas>

    I see a single-pixel line all the way around... and this one is 10 pixels from a border Smile

     

    If I try this with a path:

     

    <Canvas
       xmlns="http://schemas.microsoft.com/client/2007"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

       <Canvas Canvas.Left="0" Canvas.Top="0" Width="100" Height="22">
          <Path Stroke="Black" StrokeThickness="1"
                Data="M10,10 L110,10 L110,110 L10,110z"/>
       </Canvas>

    </Canvas>

    I get the anti-aliasing or blurring, and it's definitely different, although I don't believe it should be.

     

    Thanks for explaining that!

     

    -Dave

  • Monday, April 23, 2007 9:49 PMM. SchwarzMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I think if you render a rectangle it is clear that it will have 4 corners with each 90° angle. Anti alias doesn't need to do something. If you do the same with a path it could be any angle, and I think this is the reason. If you do something similar i.e. with Adobe Photoshop you get similar results.

     

    Michael

  • Monday, April 23, 2007 9:59 PMLuis Miguel AbreuMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hello Michael.

     

    your explanation is good, but what about lines?

     

    I mean, i find interesting that  straight lines have this problem but if you give it any angle, the width does look different...do you have any references where we can learn more about this?

  • Monday, April 23, 2007 10:02 PMLuis Miguel AbreuMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    oh, and one more question: shouldn't anti-aliasing improve the quality and sharpness of the figure (again, asked by someone who doesn't understand much about graphics Smile)
  • Monday, April 23, 2007 10:03 PMWynApse Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    That makes sense too...

     

    And I got to thinking it could have something to do with clipping inside the rectangle object itself.

     

    I'm still going to expect a single-pixel line if I do this:

     

    <Line Stroke="Black" StrokeThickness="1" X1="2" Y1="2" X2="200" Y2="2" />

     

    But if I copy and paste that into my favorite image editor, and zoom in... that line is not StrokeThickness 1, it is 2 pixels.

     

    I see no anti-aliasing 'blur' on the ends or anything, it's just a solid line 2 pixels wide.

     

    -Dave

  • Monday, April 23, 2007 10:09 PMLuis Miguel AbreuMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hello.

     

    just to add that this

     

    http://en.wikipedia.org/wiki/Antialias

     

    seems to explain why we see som blur...not sure on why the rectange doesn't produce the same result as the path or the line though (maybe i should finish reading the previous link before asking anything more? Smile )

  • Monday, April 23, 2007 10:12 PMM. SchwarzMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi,

     

    try following code:


         <Line Stroke="Black" X1="30" Y1="21" X2="30" Y2="0" />
         <Line Stroke="Yellow" X1="33" Y1="41" X2="34" Y2="0" />
         <Line Stroke="Black" X1="36" Y1="61" X2="36" Y2="0" />

     

    What do you see? Use the magnifier with factor 10x i.e.

     

    What I see? I first see a 2px gray line left and a 2px gray line on the right side. Note that it is not black, it is gray. In the middle I see a 1px line which will have on the upper right side and on the lower left side a gradient from yellow to white.

     

    Do you see the same? So, there is a strange anti alias effect, I'm not sure if it is wrong, but it looks not very nice if you want to display a rectangle of 1px. But think about something like a animation, then this effect could be nicer to our eyes.

     

    Michael

  • Monday, April 23, 2007 10:19 PMM. SchwarzMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Yes, good article.

     

    I still think that if you use a rectangle you could not do any optimisation for the display. The best is to have clear corners and 90° angles. If using a line or path it could be any angle, and for angles anti alias will help to have a better display.

     

    So, what could Microsoft do better? It could detect if it is a real path or something like a rectangle, star, triangle,... or if the line is displayed without a background (with a background the example will look better already).

     

    Michael

  • Monday, April 23, 2007 10:23 PMWynApse Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

     

    I definitely see the same effect, Michael..

     

    And I understand from an animation point of view about tha anti-aliasing, it's just a little disconcerting to say "give me a one pixel line" and I get 2.

     

    A little more info:

     

    I added a line onto your set of 3:

     

         <Line Stroke="Black" X1="30" Y1="21" X2="30" Y2="0" />
         <Line Stroke="Yellow" X1="33" Y1="41" X2="34" Y2="0" />
         <Line Stroke="Black" X1="36" Y1="61" X2="36" Y2="0" />
         <Line Stroke="Black" X1="40" Y1="61" X2="40" Y2="0" StrokeThickness="2"/>

     

    and that 2-pixel black line IS 2 pixels...

     

    So... maybe it's the 1-pixel stuff that's problematic, as you already pointed out with the black==gray

     

    Interesting...

     

    -Dave

     

  • Monday, April 23, 2007 10:36 PMM. SchwarzMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Maybe there is a real bug inside. What I could imagine is that maybe the plugin is rendered with a different DPI than the system. So, a 1px line is less than one pixel on screen. But the rectangle is working, so I think it is a not so good implementation for the anti alias algorithm. If you have Adobe Photoshop (or similar software) try to use the rectangle tool or the line tool, you get similar "wrong" results.

     

    Maybe someone from Microsoft can clear this effect...?!

     

    Michael

  • Tuesday, April 24, 2007 8:36 AMLuis Miguel AbreuMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    hello.

    I agree with you Michael.

     

    Even thougn I'm not a designer (or even a guy that likes graphics), i think that if we're getting the anti-alias rendering, it should be performed everywhere and not only in some cases...

  • Tuesday, April 24, 2007 11:55 AMM. SchwarzMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi,

     

    I put an example online at http://groups.google.com/group/wpf-everywhere/browse_thread/thread/905e2e6684d013c7/# which will show the "real problem". The thing is that a rectangle is calculating the border different to the path or line elements. The path and line elements are calculating the border centered on the line which means 1px thickness will add 0.5px on each side of the path which will end in an anti alias effect.

     

    A line with 1px is a line with a 0.5px border on each side of the line path. If you look with a magnifier you will see that it is transparent because anti alias is doing his job. I think we have to see if this is a real problem when designing Web apps.

     

    I hope this will help.

     

    Michael

  • Tuesday, April 24, 2007 12:50 PMWynApse Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I think you're right, Michael...

     

    Particularly based on the last 2 xaml-snippets you and I hacked out:

     

    A 1-pixel black line becomes a 2-pixel gray line.

     

    But a 2-pixel black line is exactly that.

     

    I think it's at least good information to know, since I've been using 1-pixel rectangles for bordering things, like on my menu, for instance:

     

    http://www.wynapse.com/Silverlight/Tutor/Silverlight_Code_Samples.aspx

     

    Now that I go back and look, if I pick a menu item, I have a very crisp thin border around the bottom part, but the line underneath the sections isn't 1 pixel, it's 2, and I didn't notice it until now.

     

    If I had tried to do a path to join something to that 1-pixel border, this would have become obvious earlier.

     

    It's something we can work around, but would be interesting to know the thought process behind it.

     

    -Dave

  • Tuesday, April 24, 2007 5:57 PMM. SchwarzMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Dave,

     

    if it should be 100% correct the 1px black line does not become a 2px gray line, instead it becomes a 2px black and transparent (anti alias) line. If you put anything under the lines you will see that it is transparent. So, each 1px line (not rectangle) will allways be a 2px transparent line.

     

    But as you write already, I think in most scenarios it is ok, but if you think about writing Power Point replacement it would be unbeautiful.

     

    Michael

  • Tuesday, April 24, 2007 6:13 PMWynApse Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Point taken, Michael...

     

    You're definitely correct about that Smile

     

    -Dave

  • Wednesday, April 25, 2007 6:27 PMsmall_mountain_0705 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

     

    FYI - there is nothing WPF/E a.k.a. Silverlight-specific about this.  You can see the same thing in plain old WPF.  What I really found odd is that XamlPad, IE, and WPF top-level windows all look the same, but in XamlPadX the anti-aliasing looks different -- the <Rectangle> version exhibits some anti-aliasing in that tool, and the Line and Path anti-aliasing is different.  I reported that difference in the XamlPadX blog.

     

    At least as annoying is that even using <Path> with <RectangleGeometry>, you still get the behavior that the stroke is centered on the line, rather than pushed inside like with <Rectangle>. 

     

    Eric

  • Wednesday, April 25, 2007 7:41 PMsmall_mountain_0705 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

     

    I think I just realized what's going on here.  The line defined by the points (10,10) and (20,10) is actually a zero-width horizontal line *between* vertical pixels 10 and 11.  When you draw a one-pixel-wide line on that line, WPF wants to center it on that line, which means that since the line is between pixels, half has to go *above* the line and half has to go *below* the line.  Hence, instead of getting single line of black pixels, you get a double line of gray pixels.  If what you want is a one-pixel-wide line, you need to draw it from (10, 10.5) to (20, 10.5).  Since a path is just a bunch of lines, it follows the same rules. 

    The Shape classes work differently. A Rectangle with upper left corner (10, 10) and bottom right corner (20, 20) includes all of the pixels to the right of the zero-width line x=10 and to the left of zero-width line x=20.  So it includes all of the whole pixels.  Actually, I guess I'm not sure if it stops at pixel 20 or 21, but you get the point.  In the XAML I've included below, I repeat the examples from this thread, plus I redo them on half-pixel boundaries where necessary to avoid having lines split across two pixels.

    Code Snippet
    <Page
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        >

     

    <Canvas>
      <Canvas Canvas.Left="0" Canvas.Top="5" Width="100" Height="100">
         <Rectangle Width="60" Height="60" Stroke="Black" StrokeThickness="1" Canvas.Left="50"/>
         <Rectangle Width="60" Height="60" Stroke="Black" StrokeThickness="2" Canvas.Left="111"/>
         <Rectangle Width="60" Height="60" Stroke="Black" StrokeThickness="3" Canvas.Left="172"/>
         <Rectangle Width="60" Height="60" Stroke="Black" StrokeThickness="10" Canvas.Left="233"/>
      </Canvas>

     

      <Canvas Canvas.Left="0" Canvas.Top="35" Width="300" Height="300">
         <Polygon Points="50,50 50,110 110,110 110,50" Stroke="Black" StrokeThickness="1" Fill="LightBlue"/>
         <Polygon Points="111,50 111,110 171,110 171,50" Stroke="Black" StrokeThickness="2" Fill="LightBlue"/>
         <Polygon Points="172,50 172,110 232,110 232,50" Stroke="Black" StrokeThickness="3" Fill="LightBlue"/>
         <Polygon Points="233,50 233,110 293,110 293,50" Stroke="Black" StrokeThickness="10" Fill="LightBlue"/>
      </Canvas>

     

      <Canvas Canvas.Left="0" Canvas.Top="115" Width="300" Height="300">
         <Path Stroke="Black" StrokeThickness="1" Fill="LightGreen">
              <Path.Data><RectangleGeometry Rect="50 50 60 60"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="2" Fill="LightGreen">
              <Path.Data><RectangleGeometry Rect="111 50 60 60"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="3" Fill="LightGreen">
              <Path.Data><RectangleGeometry Rect="172 50 60 60"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="10" Fill="LightGreen">
              <Path.Data><RectangleGeometry Rect="233 50 60 60"/></Path.Data>
         </Path>
      </Canvas>

     

      <Canvas Canvas.Left="0" Canvas.Top="195" Width="300" Height="300">
         <Path Stroke="Black" StrokeThickness="1" Fill="LightYellow">
              <Path.Data><RectangleGeometry Rect="50.5 50.5 59 59"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="2" Fill="LightYellow">
              <Path.Data><RectangleGeometry Rect="112 51 58 58"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="3" Fill="LightYellow">
              <Path.Data><RectangleGeometry Rect="173.5 51.5 57 57"/></Path.Data>
         </Path>
         <Path Stroke="Black" StrokeThickness="10" Fill="LightYellow">
              <Path.Data><RectangleGeometry Rect="238 55 50 50"/></Path.Data>
         </Path>
      </Canvas>

     

      <Canvas Canvas.Left="350" Canvas.Top="0" Width="300" Height="300">
     <Rectangle Canvas.Left="50" Canvas.Top="5" Width="50" Height="50" Stroke="Black" StrokeThickness="1" />   
     <Path Stroke="Black" StrokeThickness="1" Data="M20,20 L70,20 L70,70 L20,70z"/>   
     <Line Stroke="Black" StrokeThickness="1" X1="80" Y1="20" X2="130" Y2="20" />
     <Line Stroke="Black" StrokeThickness="1" X1="130" Y1="20" X2="130" Y2="70" />
     <Line Stroke="Black" StrokeThickness="1" X1="130" Y1="70" X2="80" Y2="70" />   
     <Line Stroke="Black" StrokeThickness="1" X1="80" Y1="70" X2="80" Y2="20" />   
     <Path Stroke="Red" StrokeThickness="2" Data="M35,40 L115,40 L115,85 L35,85z"/>
      </Canvas>

     

      <Canvas Canvas.Left="550" Canvas.Top="10" Width="300" Height="300">
         <Line Stroke="Black" StrokeThickness="1" X1="1" Y1="21" X2="1" Y2="0" />
         <Line Stroke="Red" StrokeThickness="1" X1="2" Y1="41" X2="2" Y2="0" />
         <Line Stroke="Yellow" StrokeThickness="1" X1="3" Y1="61" X2="3" Y2="0" />

     

         <Line Stroke="Blue" StrokeThickness="1" X1="10" Y1="21" X2="10" Y2="0" />
         <Line Stroke="White" StrokeThickness="1" X1="11" Y1="41" X2="11" Y2="0" />
         <Line Stroke="Yellow" StrokeThickness="1" X1="12" Y1="61" X2="12" Y2="0" />

     

         <Line Stroke="Black" StrokeThickness="1" X1="20" Y1="21" X2="20" Y2="0" />
         <Line Stroke="Yellow" StrokeThickness="1" X1="21" Y1="41" X2="21" Y2="0" />
         <Line Stroke="Black" StrokeThickness="1" X1="22" Y1="61" X2="22" Y2="0" />

     

         <Line Stroke="Black" X1="30" Y1="21" X2="30" Y2="0" />
         <Line Stroke="Yellow" X1="33" Y1="41" X2="34" Y2="0" />
         <Line Stroke="Black" X1="36" Y1="61" X2="36" Y2="0" />
      </Canvas>

     

      <Canvas Canvas.Left="350" Canvas.Top="150" Width="300" Height="300">
     <Rectangle Canvas.Left="50" Canvas.Top="5" Width="50" Height="50" Stroke="Black" StrokeThickness="1" />   
     <Path Stroke="Black" StrokeThickness="1" Data="M20.5,20.5 L69.5,20.5 L69.5,69.5 L20.5,69.5z"/>   
     <Line Stroke="Black" StrokeThickness="1" X1="80.5" Y1="20.5" X2="129.5" Y2="20.5" />
     <Line Stroke="Black" StrokeThickness="1" X1="129.5" Y1="20.5" X2="129.5" Y2="69.5" />
     <Line Stroke="Black" StrokeThickness="1" X1="129.5" Y1="69.5" X2="80.5" Y2="69.5" />   
     <Line Stroke="Black" StrokeThickness="1" X1="80.5" Y1="69.5" X2="80.5" Y2="20.5" />   
     <Path Stroke="Red" StrokeThickness="2" Data="M35,40 115,40 L115,85 L35,85z"/>
      </Canvas>

     

      <Canvas Canvas.Left="550" Canvas.Top="160" Width="300" Height="300">
         <Line Stroke="Black" StrokeThickness="1" X1="1.5" Y1="21.5" X2="1.5" Y2="0.5" />
         <Line Stroke="Red" StrokeThickness="1" X1="2.5" Y1="41.5" X2="2.5" Y2="0.5" />
         <Line Stroke="Yellow" StrokeThickness="1" X1="3.5" Y1="61.5" X2="3.5" Y2="0.5" />

     

         <Line Stroke="Blue" StrokeThickness="1.5" X1="10.5" Y1="21.5" X2="10.5" Y2="0.5" />
         <Line Stroke="White" StrokeThickness="1.5" X1="11.5" Y1="41.5" X2="11.5" Y2="0.5" />
         <Line Stroke="Yellow" StrokeThickness="1.5" X1="12.5" Y1="61.5" X2="12.5" Y2="0.5" />

     

         <Line Stroke="Black" StrokeThickness="1.5" X1="20.5" Y1="21.5" X2="20.5" Y2="0.5" />
         <Line Stroke="Yellow" StrokeThickness="1.5" X1="21.5" Y1="41.5" X2="21.5" Y2="0.5" />
         <Line Stroke="Black" StrokeThickness="1.5" X1="22.5" Y1="61.5" X2="22.5" Y2="0.5" />

     

         <Line Stroke="Black" X1="30.5" Y1="21.5" X2="30.5" Y2="0.5" />
         <Line Stroke="Yellow" X1="33.5" Y1="41.5" X2="34.5" Y2="0.5" />
         <Line Stroke="Black" X1="36.5" Y1="61.5" X2="36.5" Y2="0.5" />
     
      </Canvas>
    </Canvas>

     

    </Page>

     




     
        
        
        
        
     

     
        
        
        
        
     

     
        
             
        
        
             
        
        
             
        
        
             
        
     

     
        
             
        
        
             
        
        
             
        
        
             
        
     

     
       
       


       
       

     

     
        
        
        

        
        
        

        
        
        

        
        
        
     

     
       
       


       
       

     

     
        
        
        

        
        
        

        
        
        

        
        
        

     




  • Wednesday, April 25, 2007 9:07 PMWynApse Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Awesome!

     

    I'm going to have to think about it a bit, but I ran your code and dang if it doesn't look good...

     

    In your previous message you mentioned the "stroke being centered on the line", and I had filed that away for something to think about, because that was something Michael had discussed as well.

     

    I guess it all comes down to thinking of the coordinates not in terms of "pixel-row" and "pixel-column", but in terms of the canvas.

     

    (0,0) as we all know is the upper-left-hand-corner of an image, NOT the pixel at (0,0)

     

    So, as you point out, my line is actually (10.5, 10.5) to (20.5, 10.5)

     

    This raises other questions for me, but I'm going to try not to think about it because my head is already hurting from this one Smile

     

    Very cool!

     

    It's obvious from the xaml that you viewed my blog... I'll update that with your results .. hopefully tonight!

     

    Since I was the original questioner, I will mark yours as the answer, thanks!

     

    -Dave