35
votes

Assume I have a small bitmap in Firemonkey (say 32x24 pixels). So I put a TImage onto a form and in the constructor there is this code:

  Image1.Bitmap.Create(32, 24);
  if Image1.Bitmap.Canvas.BeginScene then
  try
    Image1.Bitmap.Canvas.Fill.Color := claBlack;
    Image1.Bitmap.Canvas.Stroke.Color := claYellow;
    Image1.Bitmap.Canvas.FillRect(RectF(0,0,32,24), 0, 0, AllCorners, $FF);
    Image1.Bitmap.Canvas.DrawLine(PointF(1,1), PointF(10,10), $FF);
  finally
    Image1.Bitmap.Canvas.EndScene;
    Image1.Bitmap.BitmapChanged;
  end;

This draws a nice diagonal line on blackground.

What I want to do is now parse the bitmap to determine the pixels affected by the line draw. If I do a basic pixel by pixel check using:

  for y := 0 to 23 do
    for x := 0 to 31 do
      if Image1.Bitmap.Pixels[x,y] <> claBlack then
        memo1.Lines.Add(Format('x=%d. y=%d. c=%x', [x,y,Image1.Bitmap.Pixels[x,y]]));

the output onto my Memo is:

x=0. y=0. c=FF3C3C00
x=1. y=0. c=FF3C3C00
x=0. y=1. c=FF3C3C00
x=1. y=1. c=FFE7E700
x=2. y=1. c=FF3C3C00
x=1. y=2. c=FF3C3C00
x=2. y=2. c=FFE7E700
x=3. y=2. c=FF3C3C00
x=2. y=3. c=FF3C3C00
x=3. y=3. c=FFE7E700
x=4. y=3. c=FF3C3C00
x=3. y=4. c=FF3C3C00
x=4. y=4. c=FFE7E700
x=5. y=4. c=FF3C3C00
x=4. y=5. c=FF3C3C00
x=5. y=5. c=FFE7E700
x=6. y=5. c=FF3C3C00
x=5. y=6. c=FF3C3C00
x=6. y=6. c=FFE7E700
x=7. y=6. c=FF3C3C00
x=6. y=7. c=FF3C3C00
x=7. y=7. c=FFE7E700
x=8. y=7. c=FF3C3C00
x=7. y=8. c=FF3C3C00
x=8. y=8. c=FFE7E700
x=9. y=8. c=FF3C3C00
x=8. y=9. c=FF3C3C00
x=9. y=9. c=FFE7E700
x=10. y=9. c=FF3C3C00
x=9. y=10. c=FF3C3C00
x=10. y=10. c=FF3C3C00

so it's interpreting and "blurring"? my line as the colours (represented by c above) are not equal to claYellow ($FFFF00). If I draw a horizontal or vertical line, the effect is the same. If I change my stroke thickness to 2 and draw a non-diagonal line it draws in claYellow but it covers 2 pixels.

So how can I determine the "true" pixels I've drawn on. In the above sample I would (could) look for $FFE7E700 but how do I know to look for that value (given that if I drew the line in a different colour, that value would be different). I tried to see if there's a consistent "difference" between the colour I drew with and the actual colour rendered but couldn't locate one.

Thanks

2
not an answer to your question... but another interesting questionWhiler
I don't know FireMonkey, but this sounds like nothing more or less than an ordinary antialiasing.TLama
This has nothing to do with FireMonkey. It is completely dependent on the underlying graphic system (GDI+, D2D, OpenGL).Uwe Raabe
If you draw the line using "PointF(1.5,1.5), PointF(10.5,10.5), " there may be no anti aliasing and it will work the way you expect it to.Giel
@Giel - unfortunately it didn't make much difference. it just returned a different value (in this case $FFEBEB00).Jason

2 Answers

5
votes

FMX use antialiazing for drawing. If you would like draw line without blur effect you should use special function for pixel alignment:

  • TCanvas.AlignToPixel
  • TCanvas.AlignToPixelVertically
  • TCanvas.AlignToPixelHorizontally

This functions automatically calculate pixel position for drawing without blur.

Thank you

1
votes

The colors in the example are anti-aliased, meaning they're part the color you set, and part the background color. The precise ratio is based on many considerations done behind the scenes.

Not familiar with FireMonkey(or delphi), so I can't tell you if there's a way around it, but if you want to know where a certain color lands what you could do is test the ratios between RGB values, that's assuming you draw only one line on a black background(otherwise, the ratios must be a range to catch pixels with large amounts of noise)

example: yellow(#ffff00)

red/green=1

red/blue=green/blue=#inf(or if you want, 255/1=255)

a sampled pixel could be #fcfc00 maintaining the ratios

a sampled pixel with noise could be #fcff09 has

red/green=0.988

red/blue=28

green/blue=28.33

red and green are still pretty close and both much higher than blue.