2010. október 26., kedd
Draw a filled circle using ScanLine
Problem/Question/Abstract:
I am looking for some code to draw a filled circle on a bitmap or change colors of pixels within a circle on it, using Bitmap.Scanline. Any suggestions or ideas on how to do this, the edges need to be perfect and it has to be fast.
Answer:
Perfect edges mean you will have to work with an alpha channel and do anti-aliasing. This means, that you either have to use a 32-bit bitmap (see e.g. Graphics32) or you have to first draw the background image in the bitmap and directly blend it when rendering the circle. Next question: do you want to use integer precision or floating point precision for the circle properties like center point and diameter? If you use integer, you only have to draw 1/8 of the circle and the rest can be copied/mirrored/flipped around. Assuming floating point, and a grayscale bitmap, here's an approach:
CX, CY: center of circle (single)
R: radius of circle (single)
F: feather size (the number of pixels used as blend area, usually 1 pix) (single)
Determine bounds in Y (integers):
LX := floor(CX - R - F * 0.5);
RX := ceil(CX + R + F * 0.5);
LY := floor(CY - R - F * 0.5);
RY := ceil(CY + R + F * 0.5);
Determine some helpful values (singles)
RPF2 = sqr(R + F/2);
RMF2 = sqr(R - F/2);
{ ... }
var
P: PByteArray
sqdist: single;
{ ... }
{Loop through Y values}
{for y := LY to RY do begin -> not very safe}
for y := max(LY, 0) to Min(RY, Bitmap.Height - 1) do
P := Bitmap.Scanline[y];
{Loop through X values}
for x := Max(LX, 0) to Min(RX, Bitmap.Width - 1) do
begin
{Determine squared distance from center for this pixel}
sqdist := sqr(y - CY) + sqr(x - CX); {Or use hypot() function}
{Inside outer circle?}
if sqdist < RPF2 then
begin
{Inside inner circle?}
if sqdist < RMF1 then
{Inside the inner circle.. just give the scanline the new color}
P[x] := 255
else
begin
{We are inbetween the inner and outer bound, now mix the color}
Fact := Max(0, Min(255, round(((R - sqrt(sqdist)) * 2 / F) * 128 + 128)));
P[x] := (255 - Fact) * P[x] + Fact;
end;
end;
{ ... }
This algorithm is optimized a bit but could be made faster probably. Untested!
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése