35

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

Jason
  • 2,572
  • 3
  • 34
  • 41
  • not an answer to your question... but another interesting [question](http://stackoverflow.com/questions/8966175/why-is-drawing-a-line-less-than-1-5-pixels-thick-twice-as-slow-as-drawing-a-line) – Whiler May 15 '12 at 07:37
  • 7
    I don't know FireMonkey, but this sounds like nothing more or less than an ordinary antialiasing. – TLama May 15 '12 at 07:46
  • 1
    This has nothing to do with FireMonkey. It is completely dependent on the underlying graphic system (GDI+, D2D, OpenGL). – Uwe Raabe May 15 '12 at 07:50
  • 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 May 15 '12 at 09:01
  • @Giel - unfortunately it didn't make much difference. it just returned a different value (in this case $FFEBEB00). – Jason May 16 '12 at 22:10
  • what I might go with is "hard coding" the mapping between the colour I'm drawing with (it will only ever be one of 10 known colours) and what the colour is rendered in. But will need to confirm that mapping will be consistent all the time. Thanks for comments though. – Jason May 16 '12 at 22:12
  • In FMX you can layer the objects (with transparency and alignement handling), so I don't know why do you want to parse the bitmap but basically the idea is: if you want to detect what you add, just add it in a layer and draw on this layer... – az01 Jun 01 '12 at 14:20
  • Could you attach the resulting bitmap screenshot please? That will make it easier for those of us who don't have FMX at hand. – Kromster Aug 02 '12 at 05:50

2 Answers2

5

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

Yaroslav Brovin
  • 964
  • 6
  • 19
  • Thanks. I've only just been able to get back to this. Can you elaborate on your answer and illustrate how those functions would be utilised in the above example. There's pretty much 0 documentation about those functions anywhere, and what I've tried doesn't change the read - even if I now use Map/Unmap of the bitmap. – Jason Dec 03 '14 at 00:37
1

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.

Community
  • 1
  • 1
biaxynte
  • 11
  • 1