Re: [SVG] optimizeSpeed misbehavior pixel rendering at 100% zoom level in Adobe

>FP> Well, it should not allow for 1 pixel
>FP> mis-behavior, since this mean there is a 100% error tolerance for
>FP> every pixel being drawn.  In other words, for every pixel drawn a
>FP> misbehaving pixel can also be drawn.
> >> >> In cases where a line falls exactly between two pixles which
> >> pixel >> do you render (see below)?  Implementations are allowed to
> >> choose.
>
>FP> Okay, implementation may chose but a circle is a circle not a
>FP> coleco E.T. monster.
>
>FP> I always drawn and specified a 4 pixels diameter circle with r='2'
>FP> or 2*r = diameter = 4 pixels, since the beginning:
>FP> http://lists.w3.org/Archives/Public/www-svg/2003Apr/0041.html
>
>FP> YOU specified a modified version with 5 pixels, but that doesn't
>FP> matter.
>
>     Wrong again, please read the SVG specification of stroke-width.
>The width of your circle is 'r*2+stroke-width'.

Okay, this explains why it gives 5 pixels.

>This is fundamental to
>understanding why your content is wrong, why you need end points in
>the middle of pixels not on the edges if you want the level of control
>you want over line drawing.  There are very important differences
>between graphics on discrete coordinate systems (pixels) and floating
>point coordinate systems (svg).
>
>     You have to view SVG stroking operation as insetting and
>outsetting the given path by 1/2 the stroke-width this region is then
>filled based on the underlying pixel grid.

That's what I understood.

>FP> In other words, a circle of 4 pixel diameter will always look the
>FP> same, I don't think it is too much to ask to get this in SVG
>FP> viewer, is it?
>
> >>  I strongly doubt SVG will ever guarantee pixel and code value
> >> precision, if this happens then there will essentially be only one
> >> SVG viewer - which would be a pitty.
>
>FP> Yes, it does. You know why? because you draw PERFECT RECTANGLE
>FP> covering every pixel PERFECTLY.
>
>     The fact that you get "exact" results in one (very simple) case
>does not mean that it is reasonable to get "exact" results in all
>cases.
>
>FP><path style='fill:#FFFFFF; stroke:#000000; shape-rendering: 
>optimizeSpeed;'
>FP>d='M 5 17 L 2 14 L 2 10 L 3 9 L 5 9 L 5 12 L 5 5 L 6 4 L 8 4 L 8 10 L 8 
>4 L
>FP>9 3 L 10 3 L 11 4 L 11 10 L 11 4 L 13 4 L 14 5 L 14 10 L 14 6 L 16 6 L 
>17 7
>FP>L 17 15 L 16 16 L 16 17'
>FP>/>
>
>FP>is a perfect line in theory, it covers all pixel precisely to their
>FP>middle point BUT because of the triangles for diagonal lines,
>FP>the Adobe SVG renderer will make them pixels and corrupt the picture,
>FP>there is no reason here to make have a misbehaving pixel,
>FP>its a damn diagonal line.
>
>     Still wrong...
>
>     Now let's try making that something that makes some sense (the
>transform just shifts the data so all the end points are in the middle
>of pixles - as I suggested in my last two posts).
>
>    <path transform="translate(.5,.5)"
>          style='fill:#FFFFFF; stroke:#000000; shape-rendering: 
>optimizeSpeed;'
>d='M 5 17 L 2 14 L 2 10 L 3 9 L 5 9 L 5 12 L 5 5 L 6 4 L 8 4 L 8 10 L 8 4 L
>9 3 L 10 3 L 11 4 L 11 10 L 11 4 L 13 4 L 14 5 L 14 10 L 14 6 L 16 6 L 17 7
>L 17 15 L 16 16 L 16 17' />
>
>    Amazing! we get the pixel perfect result! I probably should have
>let you go ahead with your 'rectification' given you ignored my
>suggestions to do the above in my last two responses but perhaps you
>will be happy that I actually spelled the solution out for you (which
>is a lot more than you deserve based on your insulting tone in this
>mail-list).

Thanks a lot, but this transform(.5,.5)
looks like pure magic as far as I'm concern,
since it makes no mathematical sense to me, see below.

>    You _are_ a beginner here you need to spend a lot more time
>thinking about this stuff - the renderers are not perfect they may not
>be able to give you what you want in all cases but the issues are
>about a 100x deeper than you seem to think they are so listen when
>people tell you things you might learn something.

I love to learn new stuff, especially
if people points me to the right direction.

>FP> What about this line not being drawn properly!!!
>FP> (101,101)-(109,109)
>
>     (101.5,101.5) -> (109.5,109.5) [pixel center->pixel center] is
>rendered "correctly".  In your given example the path has a bunch of
>stuff hanging off the 'top' of the pixel the Adobe rasterizer probably
>moves that to the 'wrong' pixel to ensure when drawn as a whole you
>don't get 'drop outs (these are very complex issues and usually fixing
>this particular 'broken' output would simply move the problem to other
>cases - it is much better to give the rasterizer something that makes
>sense to start with).

So, basically, they have a fix that broke different thing instead.

>
>FP> How can you explain Paintbrush can do it nicely, but that Adobe
>FP> can do it at all?
>
>FP> I mean Paintbrush must have a hard time drawing a circle, it
>FP> doesn't fit on every pixel, poor Paintbrush; weirdly this simple
>FP> drawing tool, can do a perfect job, isn't that weird, isn't it?
>
>     Because Painbrush shifts your circle to lie directly on pixels
>'for you' SVG viewers don't move your content on you it renders the
>circle where you say it should even if what you are telling it makes
>no sense.  In short you can't possible describe in paintbrush (the UI won't 
>let you) what you are describing SVG.

Okay, I'll take your word for it.

>     I am just stating the truth, your posts repeatedly show that you
>don't know very much about the real details of vector graphics.

It is the case, like I said I'm from a bitmap world,
I used to draw bitmap graphics for decades,
so vectorial is kinda new to me.

I appreciate your patience towards me.

Maybe you can tell me simply what's wrong in my logic?

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"
      "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" 
xmlns:xlink="http://www.w3.org/1999/xlink">


   <path transform="translate(.5,.5)"
         style='fill:#FFFFFF; stroke:#000000; shape-rendering: 
optimizeSpeed;'
d='M 5 17 L 2 14 L 2 10 L 3 9 L 5 9 L 5 12 L 5 5 L 6 4 L 8 4 L 8 10 L 8 4 L 
9 3 L 10 3 L 11 4 L 11 10 L 11 4 L 13 4 L 14 5 L 14 10 L 14 6 L 16 6 L 17 7 
L 17 15 L 16 16 L 16 17' />

   <path transform="translate(.5,.5)"
         style='fill:#FFFFFF; stroke:#000000; shape-rendering: 
optimizeSpeed;'
d='M 55 55 L 58 58'
/>

   <path transform="translate(0,0)"
         style='fill:#FFFFFF; stroke:#000000; shape-rendering: 
optimizeSpeed;'
d='M 155 155 L 158 158'
/>

   <path transform="translate(.5,0)"
         style='fill:#FFFFFF; stroke:#000000; shape-rendering: 
optimizeSpeed;'
d='M 165 165 L 168 168'
/>

   <path transform="translate(0,.5)"
         style='fill:#FFFFFF; stroke:#000000; shape-rendering: 
optimizeSpeed;'
d='M 175 175 L 178 178'
/>


   <path transform="translate(.6,.6)"
         style='fill:#0000FF; stroke:#0000FF; shape-rendering: 
optimizeSpeed;'
d='M 85 85 L 88 88'
/>

   <rect x='84' y='85'
         style='fill:#FF0000; shape-rendering: optimizeSpeed;'
         height='1' width='1'
/>

   <rect x='54' y='55'
         style='fill:#FF0000; shape-rendering: optimizeSpeed;'
         height='1' width='1'
/>

  <circle
    transform="translate(0 ,0 )"
    style='fill:#FFFFFF; stroke:#000000; shape-rendering: optimizeSpeed;'
    cx='20' cy='60' r='1.5'/>

  <circle
    transform="translate(.5 ,.5 )"
    style='fill:#FFFFFF; stroke:#000000; shape-rendering: optimizeSpeed;'
    cx='30' cy='60' r='1.5'/>

  <circle
    transform="translate(.5 ,0 )"
    style='fill:#FFFFFF; stroke:#000000; shape-rendering: optimizeSpeed;'
    cx='40' cy='60' r='1.5'/>

  <circle
    transform="translate( 0 ,.5)"
    style='fill:#FFFFFF; stroke:#000000; shape-rendering: optimizeSpeed;'
    cx='50' cy='60' r='1.5'/>

    <!-- 1.5*2 + 1 = 4x4 pixels circle? -->


</svg>


<!--

Pixel = 4x4 [ ]

Logical  sub-pixel drawn     = [B]
Logical  sub-pixel not-drawn = [-]
Desired  sub-pixel drawn     = [x]
Unwanted sub-pixel drawn     = [+]
Blank    sub-pixel           = [ ]
Overlapping sub-pixels       = [*]

Desired view of a line (101.0, 101.0)-(104.0, 104.0)

(101.0, 101.0)
  [B][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][B][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][B][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][x][B]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [B][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][B][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][x][B][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][x][x][B]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [B][x][x][x]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][B][x][x]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][B][x]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][B]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [B][x][x][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][B][x][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][B][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][B] (104.0, 104.0)

Logical view of a line (101.0, 101.0)-(104.0, 104.0)

(101.0, 101.0)
  [B][*][*][*]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [*][B][*][*]  [*][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [*][*][B][*]  [*][*][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [*][*][*][B]  [*][*][*][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][*][*][*]  [B][*][*][*]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][*][*]  [*][B][*][*]  [*][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][*]  [*][*][B][*]  [*][*][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [*][*][*][B]  [*][*][*][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [ ][*][*][*]  [B][*][*][*]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][*][*]  [*][B][*][*]  [*][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][*]  [*][*][B][*]  [*][*][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [*][*][*][B]  [*][*][*][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][*][*][*]  [B][*][*][*]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][*][*]  [*][B][*][*]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][*]  [*][*][B][*]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [*][*][*][B] (104.0, 104.0)


Drawed view of a line (101.0, 101.0)-(104.0, 104.0)

only top-right-right pixel is buggy

(101.0, 101.0)
  [B][x][x][x]  [+][+][+][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][B][x][x]  [+][+][+][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][B][x]  [+][+][+][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][x][B]  [+][+][+][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [B][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][B][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][x][B][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][x][x][B]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [B][x][x][x]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][B][x][x]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][B][x]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][B]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [B][x][x][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][B][x][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][B][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][B] (104.0, 104.0)

Logical view of a line (101.5, 101.0)-(104.5, 104.0)
only top-right-right pixel is buggy

(101.5, 101.0)
  [x][x][B][x]  [+][+][+][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][x][B]  [+][+][+][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][x][x]  [B][+][+][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][x][x]  [+][B][+][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [x][x][B][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][x][x][B]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][x][x][x]  [-][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][x][x][x]  [ ][-][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][B][x]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][B]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][x]  [-][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][x]  [ ][-][ ][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][B][x]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][B]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][x]  [-][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][x]  [ ][-][ ][ ]  
(104.5, 104.0)

Logical view of a line (101.0, 101.5)-(104.0, 104.5)
curvy look

(101.0, 101.5)
  [x][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [B][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][B][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [+][+][B][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [+][+][+][B]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [+][+][+][+]  [-][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [+][+][+][+]  [ ][-][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [+][+][B][+]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [+][+][+][B]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [+][+][+][+]  [-][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [+][+][+][+]  [ ][-][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [+][+][B][+]  [x][x][x][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [+][+][+][B]  [x][x][x][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [+][+][+][+]  [B][x][x][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [+][+][+][+]  [x][B][x][x]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][-][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][-] (104.0, 104.5)
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

Logical view of a line (101.5, 101.5)-(104.5, 104.5)
i.e. Desired line drawn.

(101.5, 101.5)
  [x][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][B][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [x][x][x][B]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [B][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][B][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][x][B][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [x][x][x][B]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [B][x][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][B][x][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][B][x]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][B]  [ ][ ][ ][ ]  [ ][ ][ ][ ]

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [B][x][x][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][B][x][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][B][x]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [x][x][x][B]  (104.5, 104.5)

  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [-][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][-][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]
  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]  [ ][ ][ ][ ]


As far as I can understand, I can accept the transform(0.5,0.5) work around. 
I'm amused by the fact that it give 4 pixels line instead
of 5 pixels, even though I wanted a 4 pixel diagonal line.

Why does the top pixel get drawn correctly
and not the bottom is not drawn?

How come the little top-right-right pixel doesn't appear anymore?

Seems you solved my problem using the workaround,
you have my gratitude, but I still don't get it.

For me it still doesn't make sense.

When you tell me the middle point the (.5, .5) offset makes sense,
but if we take your word then (101.5,101.5)-(104.5, 104.5)
should really be (101,101)-(105,105)
unless you are taking the 'floor' rounding value,
but (101.6,101.6)-(104.6, 104.6) is still (101,101)-(104,104).
Weirdly.


-->

Thanks again for the trick.

Sincerely yours,
Fred.


_________________________________________________________________
STOP MORE SPAM with the new MSN 8 and get 2 months FREE*   
http://join.msn.com/?page=features/junkmail

Received on Tuesday, 29 April 2003 21:24:23 UTC