B
This commit is contained in:
parent
e5e8880e41
commit
518da4a923
1019 changed files with 15877 additions and 0 deletions
8
Task/Bitmap-Flood-fill/0DESCRIPTION
Normal file
8
Task/Bitmap-Flood-fill/0DESCRIPTION
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
Implement a [[wp:flood fill|flood fill]].
|
||||
|
||||
A flood fill is a way of filling an area using ''color banks'' to define the contained area or a ''target color'' which "determines" the area (the ''valley'' that can be flooded; Wikipedia uses the term ''target color''). It works almost like a water flooding from a point towards the banks (or: inside the valley): if there's a hole in the banks, the flood is not contained and all the image (or all the "connected valleys") get filled.
|
||||
|
||||
To accomplish the task, you need to implement just one of the possible algorithms (examples are on [[wp:flood fill|Wikipedia]]). Variations on the ''theme'' are allowed (e.g. adding a tolerance parameter or argument for color-matching of the ''banks'' or ''target'' color).
|
||||
|
||||
[[Image:Unfilledcirc.png|128px|thumb|right]]
|
||||
'''Testing''': the basic algorithm is not suitable for ''truecolor'' images; a possible test image is the one shown on the right box; you can try to fill the white area, or the black inner circle.
|
||||
4
Task/Bitmap-Flood-fill/1META.yaml
Normal file
4
Task/Bitmap-Flood-fill/1META.yaml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category:
|
||||
- Graphics algorithms
|
||||
note: Raster graphics operations
|
||||
106
Task/Bitmap-Flood-fill/Ada/bitmap-flood-fill-1.ada
Normal file
106
Task/Bitmap-Flood-fill/Ada/bitmap-flood-fill-1.ada
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
procedure Flood_Fill
|
||||
( Picture : in out Image;
|
||||
From : Point;
|
||||
Fill : Pixel;
|
||||
Replace : Pixel;
|
||||
Distance : Luminance := 20
|
||||
) is
|
||||
function Diff (A, B : Luminance) return Luminance is
|
||||
pragma Inline (Diff);
|
||||
begin
|
||||
if A > B then
|
||||
return A - B;
|
||||
else
|
||||
return B - A;
|
||||
end if;
|
||||
end Diff;
|
||||
|
||||
function "-" (A, B : Pixel) return Luminance is
|
||||
pragma Inline ("-");
|
||||
begin
|
||||
return Luminance'Max (Luminance'Max (Diff (A.R, B.R), Diff (A.G, B.G)), Diff (A.B, B.B));
|
||||
end "-";
|
||||
procedure Column (From : Point);
|
||||
procedure Row (From : Point);
|
||||
|
||||
Visited : array (Picture'Range (1), Picture'Range (2)) of Boolean :=
|
||||
(others => (others => False));
|
||||
|
||||
procedure Column (From : Point) is
|
||||
X1 : Positive := From.X;
|
||||
X2 : Positive := From.X;
|
||||
begin
|
||||
Visited (From.X, From.Y) := True;
|
||||
for X in reverse Picture'First (1)..From.X - 1 loop
|
||||
exit when Visited (X, From.Y);
|
||||
declare
|
||||
Color : Pixel renames Picture (X, From.Y);
|
||||
begin
|
||||
Visited (X, From.Y) := True;
|
||||
exit when Color - Replace > Distance;
|
||||
Color := Fill;
|
||||
X1 := X;
|
||||
end;
|
||||
end loop;
|
||||
for X in From.X + 1..Picture'Last (1) loop
|
||||
exit when Visited (X, From.Y);
|
||||
declare
|
||||
Color : Pixel renames Picture (X, From.Y);
|
||||
begin
|
||||
Visited (X, From.Y) := True;
|
||||
exit when Color - Replace > Distance;
|
||||
Color := Fill;
|
||||
X2 := X;
|
||||
end;
|
||||
end loop;
|
||||
for X in X1..From.X - 1 loop
|
||||
Row ((X, From.Y));
|
||||
end loop;
|
||||
for X in From.X + 1..X2 loop
|
||||
Row ((X, From.Y));
|
||||
end loop;
|
||||
end Column;
|
||||
|
||||
procedure Row (From : Point) is
|
||||
Y1 : Positive := From.Y;
|
||||
Y2 : Positive := From.Y;
|
||||
begin
|
||||
Visited (From.X, From.Y) := True;
|
||||
for Y in reverse Picture'First (2)..From.Y - 1 loop
|
||||
exit when Visited (From.X, Y);
|
||||
declare
|
||||
Color : Pixel renames Picture (From.X, Y);
|
||||
begin
|
||||
Visited (From.X, Y) := True;
|
||||
exit when Color - Replace > Distance;
|
||||
Color := Fill;
|
||||
Y1 := Y;
|
||||
end;
|
||||
end loop;
|
||||
for Y in From.Y + 1..Picture'Last (2) loop
|
||||
exit when Visited (From.X, Y);
|
||||
declare
|
||||
Color : Pixel renames Picture (From.X, Y);
|
||||
begin
|
||||
Visited (From.X, Y) := True;
|
||||
exit when Color - Replace > Distance;
|
||||
Color := Fill;
|
||||
Y2 := Y;
|
||||
end;
|
||||
end loop;
|
||||
for Y in Y1..From.Y - 1 loop
|
||||
Column ((From.X, Y));
|
||||
end loop;
|
||||
for Y in From.Y + 1..Y2 loop
|
||||
Column ((From.X, Y));
|
||||
end loop;
|
||||
end Row;
|
||||
|
||||
Color : Pixel renames Picture (From.X, From.Y);
|
||||
begin
|
||||
if Color - Replace <= Distance then
|
||||
Visited (From.X, From.Y) := True;
|
||||
Color := Fill;
|
||||
Column (From);
|
||||
end if;
|
||||
end Flood_Fill;
|
||||
19
Task/Bitmap-Flood-fill/Ada/bitmap-flood-fill-2.ada
Normal file
19
Task/Bitmap-Flood-fill/Ada/bitmap-flood-fill-2.ada
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
declare
|
||||
File : File_Type;
|
||||
begin
|
||||
Open (File, In_File, "Unfilledcirc.ppm");
|
||||
declare
|
||||
Picture : Image := Get_PPM (File);
|
||||
begin
|
||||
Close (File);
|
||||
Flood_Fill
|
||||
( Picture => Picture,
|
||||
From => (122, 30),
|
||||
Fill => (255,0,0),
|
||||
Replace => White
|
||||
);
|
||||
Create (File, Out_File, "Filledcirc.ppm");
|
||||
Put_PPM (File, Picture);
|
||||
Close (File);
|
||||
end;
|
||||
end;
|
||||
41
Task/Bitmap-Flood-fill/AutoHotkey/bitmap-flood-fill-1.ahk
Normal file
41
Task/Bitmap-Flood-fill/AutoHotkey/bitmap-flood-fill-1.ahk
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
SetBatchLines, -1
|
||||
CoordMode, Mouse
|
||||
CoordMode, Pixel
|
||||
CapsLock::
|
||||
KeyWait, CapsLock
|
||||
MouseGetPos, X, Y
|
||||
PixelGetColor, color, X, Y
|
||||
FloodFill(x, y, color, 0x000000, 1, "CapsLock")
|
||||
MsgBox Done!
|
||||
Return
|
||||
FloodFill(x, y, target, replacement, mode=1, key="")
|
||||
{
|
||||
If GetKeyState(key, "P")
|
||||
Return
|
||||
PixelGetColor, color, x, y
|
||||
If (color <> target || color = replacement || target = replacement)
|
||||
Return
|
||||
VarSetCapacity(Rect, 16, 0)
|
||||
NumPut(x, Rect, 0)
|
||||
NumPut(y, Rect, 4)
|
||||
NumPut(x+1, Rect, 8)
|
||||
NumPut(y+1, Rect, 12)
|
||||
hDC := DllCall("GetDC", UInt, 0)
|
||||
hBrush := DllCall("CreateSolidBrush", UInt, replacement)
|
||||
DllCall("FillRect", UInt, hDC, Str, Rect, UInt, hBrush)
|
||||
DllCall("ReleaseDC", UInt, 0, UInt, hDC)
|
||||
DllCall("DeleteObject", UInt, hBrush)
|
||||
FloodFill(x+1, y, target, replacement, mode, key)
|
||||
FloodFill(x-1, y, target, replacement, mode, key)
|
||||
FloodFill(x, y+1, target, replacement, mode, key)
|
||||
FloodFill(x, y-1, target, replacement, mode, key)
|
||||
If (mode = 2 || mode = 4)
|
||||
FloodFill(x, y, target, replacement, mode, key)
|
||||
If (Mode = 3 || mode = 4)
|
||||
{
|
||||
FloodFill(x+1, y+1, target, replacement, key)
|
||||
FloodFill(x-1, y+1, target, replacement, key)
|
||||
FloodFill(x+1, y-1, target, replacement, key)
|
||||
FloodFill(x-1, y-1, target, replacement, key)
|
||||
}
|
||||
}
|
||||
55
Task/Bitmap-Flood-fill/AutoHotkey/bitmap-flood-fill-2.ahk
Normal file
55
Task/Bitmap-Flood-fill/AutoHotkey/bitmap-flood-fill-2.ahk
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#NoEnv
|
||||
#SingleInstance, Force
|
||||
|
||||
SetBatchLines, -1
|
||||
CoordMode, Mouse
|
||||
CoordMode, Pixel
|
||||
return
|
||||
|
||||
CapsLock::
|
||||
KeyWait, CapsLock
|
||||
MouseGetPos, X, Y
|
||||
PixelGetColor, color, X, Y
|
||||
FloodFill(x, y, color, 0x000000, 1, "Esc")
|
||||
MsgBox Done!
|
||||
Return
|
||||
|
||||
FloodFill( 0x, 0y, target, replacement, mode=1, key="" )
|
||||
{
|
||||
VarSetCapacity(Rect, 16, 0)
|
||||
hDC := DllCall("GetDC", UInt, 0)
|
||||
hBrush := DllCall("CreateSolidBrush", UInt, replacement)
|
||||
|
||||
l := 0
|
||||
while l >= 0
|
||||
{
|
||||
if getkeystate(key, "P")
|
||||
return
|
||||
x := %l%x, y := %l%y
|
||||
%l%p++
|
||||
p := %l%p
|
||||
PixelGetColor, color, x, y
|
||||
if (color = target)
|
||||
{
|
||||
NumPut(x, Rect, 0)
|
||||
NumPut(y, Rect, 4)
|
||||
NumPut(x+1, Rect, 8)
|
||||
NumPut(y+1, Rect, 12)
|
||||
DllCall("FillRect", UInt, hDC, Str, Rect, UInt, hBrush)
|
||||
}
|
||||
else if (p = 1)
|
||||
{
|
||||
%l%x := %l%y := %l%p := "", l--
|
||||
continue
|
||||
}
|
||||
if (p < 5)
|
||||
ol := l++
|
||||
, %l%x := %ol%x + (p = 1 ? 1 : p = 2 ? -1 : 0)
|
||||
, %l%y := %ol%y + (p = 3 ? 1 : p = 4 ? -1 : 0)
|
||||
else
|
||||
%l%x := %l%y := %l%p := "", l--
|
||||
}
|
||||
|
||||
DllCall("ReleaseDC", UInt, 0, UInt, hDC)
|
||||
DllCall("DeleteObject", UInt, hBrush)
|
||||
}
|
||||
24
Task/Bitmap-Flood-fill/BBC-BASIC/bitmap-flood-fill.bbc
Normal file
24
Task/Bitmap-Flood-fill/BBC-BASIC/bitmap-flood-fill.bbc
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
MODE 8
|
||||
GCOL 15
|
||||
CIRCLE FILL 640, 512, 500
|
||||
GCOL 0
|
||||
CIRCLE FILL 500, 600, 200
|
||||
GCOL 3
|
||||
PROCflood(600, 200, 15)
|
||||
GCOL 4
|
||||
PROCflood(600, 700, 0)
|
||||
END
|
||||
|
||||
DEF PROCflood(X%, Y%, C%)
|
||||
LOCAL L%, R%
|
||||
IF POINT(X%,Y%) <> C% ENDPROC
|
||||
L% = X%
|
||||
R% = X%
|
||||
WHILE POINT(L%-2,Y%) = C% : L% -= 2 : ENDWHILE
|
||||
WHILE POINT(R%+2,Y%) = C% : R% += 2 : ENDWHILE
|
||||
LINE L%,Y%,R%,Y%
|
||||
FOR X% = L% TO R% STEP 2
|
||||
PROCflood(X%, Y%+2, C%)
|
||||
PROCflood(X%, Y%-2, C%)
|
||||
NEXT
|
||||
ENDPROC
|
||||
106
Task/Bitmap-Flood-fill/C/bitmap-flood-fill-1.c
Normal file
106
Task/Bitmap-Flood-fill/C/bitmap-flood-fill-1.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// http://commons.wikimedia.org/wiki/File:Julia_immediate_basin_1_3.png
|
||||
|
||||
unsigned int f(unsigned int _iX, unsigned int _iY)
|
||||
/*
|
||||
gives position of point (iX,iY) in 1D array ; uses also global variables
|
||||
it does not check if index is good so memory error is possible
|
||||
*/
|
||||
{return (_iX + (iYmax-_iY-1)*iXmax );}
|
||||
|
||||
|
||||
int FillContour(int iXseed, int iYseed, unsigned char color, unsigned char _data[])
|
||||
{
|
||||
/*
|
||||
fills contour with black border ( color = iJulia) using seed point inside contour
|
||||
and horizontal lines
|
||||
it starts from seed point, saves max right( iXmaxLocal) and max left ( iXminLocal) interior points of horizontal line,
|
||||
in new line ( iY+1 or iY-1) it computes new interior point : iXmidLocal=iXminLocal + (iXmaxLocal-iXminLocal)/2;
|
||||
result is stored in _data array : 1D array of 1-bit colors ( shades of gray)
|
||||
it does not check if index of _data array is good so memory error is possible
|
||||
*/
|
||||
|
||||
|
||||
int iX, /* seed integer coordinate */
|
||||
iY=iYseed,
|
||||
/* most interior point of line iY */
|
||||
iXmidLocal=iXseed,
|
||||
/* min and max of interior points of horizontal line iY */
|
||||
iXminLocal,
|
||||
iXmaxLocal;
|
||||
int i ; /* index of _data array */;
|
||||
|
||||
|
||||
/* --------- move up --------------- */
|
||||
do{
|
||||
iX=iXmidLocal;
|
||||
i =f(iX,iY); /* index of _data array */;
|
||||
|
||||
/* move to right */
|
||||
while (_data[i]==iInterior)
|
||||
{ _data[i]=color;
|
||||
iX+=1;
|
||||
i=f(iX,iY);
|
||||
}
|
||||
iXmaxLocal=iX-1;
|
||||
|
||||
/* move to left */
|
||||
iX=iXmidLocal-1;
|
||||
i=f(iX,iY);
|
||||
while (_data[i]==iInterior)
|
||||
{ _data[i]=color;
|
||||
iX-=1;
|
||||
i=f(iX,iY);
|
||||
}
|
||||
iXminLocal=iX+1;
|
||||
|
||||
|
||||
iY+=1; /* move up */
|
||||
iXmidLocal=iXminLocal + (iXmaxLocal-iXminLocal)/2; /* new iX inside contour */
|
||||
i=f(iXmidLocal,iY); /* index of _data array */;
|
||||
if ( _data[i]==iJulia) break; /* it should not cross the border */
|
||||
|
||||
} while (iY<iYmax);
|
||||
|
||||
|
||||
/* ------ move down ----------------- */
|
||||
iXmidLocal=iXseed;
|
||||
iY=iYseed-1;
|
||||
|
||||
|
||||
do{
|
||||
iX=iXmidLocal;
|
||||
i =f(iX,iY); /* index of _data array */;
|
||||
|
||||
/* move to right */
|
||||
while (_data[i]==iInterior) /* */
|
||||
{ _data[i]=color;
|
||||
iX+=1;
|
||||
i=f(iX,iY);
|
||||
}
|
||||
iXmaxLocal=iX-1;
|
||||
|
||||
/* move to left */
|
||||
iX=iXmidLocal-1;
|
||||
i=f(iX,iY);
|
||||
while (_data[i]==iInterior) /* */
|
||||
{ _data[i]=color;
|
||||
iX-=1; /* move to right */
|
||||
i=f(iX,iY);
|
||||
}
|
||||
iXminLocal=iX+1;
|
||||
|
||||
iY-=1; /* move down */
|
||||
iXmidLocal=iXminLocal + (iXmaxLocal-iXminLocal)/2; /* new iX inside contour */
|
||||
i=f(iXmidLocal,iY); /* index of _data array */;
|
||||
if ( _data[i]==iJulia) break; /* it should not cross the border */
|
||||
} while (0<iY);
|
||||
|
||||
/* mark seed point by big pixel */
|
||||
const int iSide =iXmax/500; /* half of width or height of big pixel */
|
||||
for(iY=iYseed-iSide;iY<=iYseed+iSide;++iY){
|
||||
for(iX=iXseed-iSide;iX<=iXseed+iSide;++iX){
|
||||
i= f(iX,iY); /* index of _data array */
|
||||
_data[i]=10;}}
|
||||
|
||||
return 0;
|
||||
}
|
||||
9
Task/Bitmap-Flood-fill/C/bitmap-flood-fill-2.c
Normal file
9
Task/Bitmap-Flood-fill/C/bitmap-flood-fill-2.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* #include <sys/queue.h> */
|
||||
typedef struct {
|
||||
color_component red, green, blue;
|
||||
} rgb_color;
|
||||
typedef rgb_color *rgb_color_p;
|
||||
|
||||
void floodfill(image img, int px, int py,
|
||||
rgb_color_p bankscolor,
|
||||
rgb_color_p rcolor);
|
||||
93
Task/Bitmap-Flood-fill/C/bitmap-flood-fill-3.c
Normal file
93
Task/Bitmap-Flood-fill/C/bitmap-flood-fill-3.c
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#include "imglib.h"
|
||||
|
||||
typedef struct _ffill_node {
|
||||
int px, py;
|
||||
TAILQ_ENTRY(_ffill_node) nodes;
|
||||
} _ffill_node_t;
|
||||
TAILQ_HEAD(_ffill_queue_s, _ffill_node);
|
||||
typedef struct _ffill_queue_s _ffill_queue;
|
||||
|
||||
inline void _ffill_removehead(_ffill_queue *q)
|
||||
{
|
||||
_ffill_node_t *n = q->tqh_first;
|
||||
if ( n != NULL ) {
|
||||
TAILQ_REMOVE(q, n, nodes);
|
||||
free(n);
|
||||
}
|
||||
}
|
||||
|
||||
inline void _ffill_enqueue(_ffill_queue *q, int px, int py)
|
||||
{
|
||||
_ffill_node_t *node;
|
||||
node = malloc(sizeof(_ffill_node_t));
|
||||
if ( node != NULL ) {
|
||||
node->px = px; node->py = py;
|
||||
TAILQ_INSERT_TAIL(q, node, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
inline double color_distance( rgb_color_p a, rgb_color_p b )
|
||||
{
|
||||
return sqrt( (double)(a->red - b->red)*(a->red - b->red) +
|
||||
(double)(a->green - b->green)*(a->green - b->green) +
|
||||
(double)(a->blue - b->blue)*(a->blue - b->blue) ) / (256.0*sqrt(3.0));
|
||||
}
|
||||
|
||||
inline void _ffill_rgbcolor(image img, rgb_color_p tc, int px, int py)
|
||||
{
|
||||
tc->red = GET_PIXEL(img, px, py)[0];
|
||||
tc->green = GET_PIXEL(img, px, py)[1];
|
||||
tc->blue = GET_PIXEL(img, px, py)[2];
|
||||
}
|
||||
|
||||
|
||||
#define NSOE(X,Y) do { \
|
||||
if ( ((X)>=0)&&((Y)>=0) && ((X)<img->width)&&((Y)<img->height)) { \
|
||||
_ffill_rgbcolor(img, &thisnode, (X), (Y)); \
|
||||
if ( color_distance(&thisnode, bankscolor) > tolerance ) { \
|
||||
if (color_distance(&thisnode, rcolor) > 0.0) { \
|
||||
put_pixel_unsafe(img, (X), (Y), rcolor->red, \
|
||||
rcolor->green, \
|
||||
rcolor->blue); \
|
||||
_ffill_enqueue(&head, (X), (Y)); \
|
||||
pixelcount++; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
unsigned int floodfill(image img, int px, int py,
|
||||
rgb_color_p bankscolor,
|
||||
rgb_color_p rcolor)
|
||||
{
|
||||
_ffill_queue head;
|
||||
rgb_color thisnode;
|
||||
unsigned int pixelcount = 0;
|
||||
double tolerance = 0.05;
|
||||
|
||||
if ( (px < 0) || (py < 0) || (px >= img->width) || (py >= img->height) )
|
||||
return;
|
||||
|
||||
TAILQ_INIT(&head);
|
||||
|
||||
_ffill_rgbcolor(img, &thisnode, px, py);
|
||||
if ( color_distance(&thisnode, bankscolor) <= tolerance ) return;
|
||||
|
||||
_ffill_enqueue(&head, px, py);
|
||||
while( head.tqh_first != NULL ) {
|
||||
_ffill_node_t *n = head.tqh_first;
|
||||
_ffill_rgbcolor(img, &thisnode, n->px, n->py);
|
||||
if ( color_distance(&thisnode, bankscolor) > tolerance ) {
|
||||
put_pixel_unsafe(img, n->px, n->py, rcolor->red, rcolor->green, rcolor->blue);
|
||||
pixelcount++;
|
||||
}
|
||||
int tx = n->px, ty = n->py;
|
||||
_ffill_removehead(&head);
|
||||
NSOE(tx - 1, ty);
|
||||
NSOE(tx + 1, ty);
|
||||
NSOE(tx, ty - 1);
|
||||
NSOE(tx, ty + 1);
|
||||
}
|
||||
return pixelcount;
|
||||
}
|
||||
27
Task/Bitmap-Flood-fill/C/bitmap-flood-fill-4.c
Normal file
27
Task/Bitmap-Flood-fill/C/bitmap-flood-fill-4.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "imglib.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
image animage;
|
||||
rgb_color ic;
|
||||
rgb_color rc;
|
||||
|
||||
if ( argc > 1 ) {
|
||||
animage = read_image(argv[1]);
|
||||
if ( animage != NULL ) {
|
||||
ic.red = 255; /* = 0; */
|
||||
ic.green = 255; /* = 0; */
|
||||
ic.blue = 255; /* = 0; */
|
||||
rc.red = 0;
|
||||
rc.green = 255;
|
||||
rc.blue = 0;
|
||||
floodfill(animage, 100, 100, &ic, &rc);
|
||||
/* 150, 150 */
|
||||
print_jpg(animage, 90);
|
||||
free(animage);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
28
Task/Bitmap-Flood-fill/Forth/bitmap-flood-fill.fth
Normal file
28
Task/Bitmap-Flood-fill/Forth/bitmap-flood-fill.fth
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
: third 2 pick ;
|
||||
: 3dup third third third ;
|
||||
: 4dup 2over 2over ;
|
||||
|
||||
: flood ( color x y bmp -- )
|
||||
3dup b@ >r ( R: color to fill )
|
||||
4dup b!
|
||||
third 0 > if
|
||||
rot 1- -rot
|
||||
3dup b@ r@ = if recurse then
|
||||
rot 1+ -rot
|
||||
then
|
||||
third 1+ over bwidth < if
|
||||
rot 1+ -rot
|
||||
3dup b@ r@ = if recurse then
|
||||
rot 1- -rot
|
||||
then
|
||||
over 0 > if
|
||||
swap 1- swap
|
||||
3dup b@ r@ = if recurse then
|
||||
swap 1+ swap
|
||||
then
|
||||
over 1+ over bheight < if
|
||||
swap 1+ swap
|
||||
3dup b@ r@ = if recurse then
|
||||
swap 1- swap
|
||||
then
|
||||
r> drop ;
|
||||
106
Task/Bitmap-Flood-fill/Fortran/bitmap-flood-fill-1.f
Normal file
106
Task/Bitmap-Flood-fill/Fortran/bitmap-flood-fill-1.f
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
module RCImageArea
|
||||
use RCImageBasic
|
||||
use RCImagePrimitive
|
||||
implicit none
|
||||
|
||||
real, parameter, private :: matchdistance = 0.2
|
||||
|
||||
private :: northsouth, eastwest
|
||||
|
||||
contains
|
||||
|
||||
subroutine northsouth(img, p0, tcolor, fcolor)
|
||||
type(rgbimage), intent(inout) :: img
|
||||
type(point), intent(in) :: p0
|
||||
type(rgb), intent(in) :: tcolor, fcolor
|
||||
|
||||
integer :: npy, spy, y
|
||||
type(rgb) :: pc
|
||||
|
||||
npy = p0%y - 1
|
||||
do
|
||||
if ( inside_image(img, p0%x, npy) ) then
|
||||
call get_pixel(img, p0%x, npy, pc)
|
||||
if ( ((pc .dist. tcolor) > matchdistance ) .or. ( pc == fcolor ) ) exit
|
||||
else
|
||||
exit
|
||||
end if
|
||||
npy = npy - 1
|
||||
end do
|
||||
npy = npy + 1
|
||||
spy = p0%y + 1
|
||||
do
|
||||
if ( inside_image(img, p0%x, spy) ) then
|
||||
call get_pixel(img, p0%x, spy, pc)
|
||||
if ( ((pc .dist. tcolor) > matchdistance ) .or. ( pc == fcolor ) ) exit
|
||||
else
|
||||
exit
|
||||
end if
|
||||
spy = spy + 1
|
||||
end do
|
||||
spy = spy - 1
|
||||
call draw_line(img, point(p0%x, spy), point(p0%x, npy), fcolor)
|
||||
|
||||
do y = min(spy, npy), max(spy, npy)
|
||||
if ( y == p0%y ) cycle
|
||||
call eastwest(img, point(p0%x, y), tcolor, fcolor)
|
||||
end do
|
||||
|
||||
end subroutine northsouth
|
||||
|
||||
|
||||
subroutine eastwest(img, p0, tcolor, fcolor)
|
||||
type(rgbimage), intent(inout) :: img
|
||||
type(point), intent(in) :: p0
|
||||
type(rgb), intent(in) :: tcolor, fcolor
|
||||
|
||||
integer :: npx, spx, x
|
||||
type(rgb) :: pc
|
||||
|
||||
npx = p0%x - 1
|
||||
do
|
||||
if ( inside_image(img, npx, p0%y) ) then
|
||||
call get_pixel(img, npx, p0%y, pc)
|
||||
if ( ((pc .dist. tcolor) > matchdistance ) .or. ( pc == fcolor ) ) exit
|
||||
else
|
||||
exit
|
||||
end if
|
||||
npx = npx - 1
|
||||
end do
|
||||
npx = npx + 1
|
||||
spx = p0%x + 1
|
||||
do
|
||||
if ( inside_image(img, spx, p0%y) ) then
|
||||
call get_pixel(img, spx, p0%y, pc)
|
||||
if ( ((pc .dist. tcolor) > matchdistance ) .or. ( pc == fcolor ) ) exit
|
||||
else
|
||||
exit
|
||||
end if
|
||||
spx = spx + 1
|
||||
end do
|
||||
spx = spx - 1
|
||||
call draw_line(img, point(spx, p0%y), point(npx, p0%y), fcolor)
|
||||
|
||||
do x = min(spx, npx), max(spx, npx)
|
||||
if ( x == p0%x ) cycle
|
||||
call northsouth(img, point(x, p0%y), tcolor, fcolor)
|
||||
end do
|
||||
|
||||
end subroutine eastwest
|
||||
|
||||
subroutine floodfill(img, p0, tcolor, fcolor)
|
||||
type(rgbimage), intent(inout) :: img
|
||||
type(point), intent(in) :: p0
|
||||
type(rgb), intent(in) :: tcolor, fcolor
|
||||
|
||||
type(rgb) :: pcolor
|
||||
|
||||
if ( .not. inside_image(img, p0%x, p0%y) ) return
|
||||
call get_pixel(img, p0%x, p0%y, pcolor)
|
||||
if ( (pcolor .dist. tcolor) > matchdistance ) return
|
||||
|
||||
call northsouth(img, p0, tcolor, fcolor)
|
||||
call eastwest(img, p0, tcolor, fcolor)
|
||||
end subroutine floodfill
|
||||
|
||||
end module RCImageArea
|
||||
1
Task/Bitmap-Flood-fill/Fortran/bitmap-flood-fill-2.f
Normal file
1
Task/Bitmap-Flood-fill/Fortran/bitmap-flood-fill-2.f
Normal file
|
|
@ -0,0 +1 @@
|
|||
call floodfill(animage, point(100,100), rgb(0,0,0), rgb(0,255,0))
|
||||
17
Task/Bitmap-Flood-fill/Go/bitmap-flood-fill-1.go
Normal file
17
Task/Bitmap-Flood-fill/Go/bitmap-flood-fill-1.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package raster
|
||||
|
||||
func (b *Bitmap) Flood(x, y int, repl Pixel) {
|
||||
targ, _ := b.GetPx(x, y)
|
||||
var ff func(x, y int)
|
||||
ff = func(x, y int) {
|
||||
p, ok := b.GetPx(x, y)
|
||||
if ok && p.R == targ.R && p.G == targ.G && p.B == targ.B {
|
||||
b.SetPx(x, y, repl)
|
||||
ff(x-1, y)
|
||||
ff(x+1, y)
|
||||
ff(x, y-1)
|
||||
ff(x, y+1)
|
||||
}
|
||||
}
|
||||
ff(x, y)
|
||||
}
|
||||
20
Task/Bitmap-Flood-fill/Go/bitmap-flood-fill-2.go
Normal file
20
Task/Bitmap-Flood-fill/Go/bitmap-flood-fill-2.go
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"raster"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b, err := raster.ReadPpmFile("Unfilledcirc.ppm")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
b.Flood(200, 200, raster.Pixel{127, 0, 0})
|
||||
err = b.WritePpmFile("flood.ppm")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
110
Task/Bitmap-Flood-fill/Haskell/bitmap-flood-fill.hs
Normal file
110
Task/Bitmap-Flood-fill/Haskell/bitmap-flood-fill.hs
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import Data.Array.ST
|
||||
import Data.STRef
|
||||
import Control.Monad
|
||||
import Control.Monad.ST
|
||||
import Bitmap
|
||||
|
||||
-- Implementation of a stack in the ST monad
|
||||
pushST :: STStack s a -> a -> ST s ()
|
||||
pushST s e = do
|
||||
s2 <- readSTRef s
|
||||
writeSTRef s (e : s2)
|
||||
|
||||
popST :: STStack s a -> ST s (Stack a)
|
||||
popST s = do
|
||||
s2 <- readSTRef s
|
||||
writeSTRef s $ tail s2
|
||||
return $ take 1 s2
|
||||
|
||||
isNotEmptySTStack :: STStack s a -> ST s Bool
|
||||
isNotEmptySTStack s = do
|
||||
s2 <- readSTRef s
|
||||
return $ not $ null s2
|
||||
|
||||
emptySTStack :: ST s (STStack s a)
|
||||
emptySTStack = newSTRef []
|
||||
|
||||
consumeSTStack :: STStack s a -> (a -> ST s ()) -> ST s ()
|
||||
consumeSTStack s f = do
|
||||
check <- isNotEmptySTStack s
|
||||
when check $ do
|
||||
e <- popST s
|
||||
f $ head e
|
||||
consumeSTStack s f
|
||||
|
||||
type Spanning s = STRef s (Bool, Bool)
|
||||
|
||||
setSpanLeft :: Spanning s -> Bool -> ST s ()
|
||||
setSpanLeft s v = do
|
||||
(_, r) <- readSTRef s
|
||||
writeSTRef s (v, r)
|
||||
|
||||
setSpanRight :: Spanning s -> Bool -> ST s ()
|
||||
setSpanRight s v = do
|
||||
(l, _) <- readSTRef s
|
||||
writeSTRef s (l, v)
|
||||
|
||||
setSpanNone :: Spanning s -> ST s ()
|
||||
setSpanNone s = writeSTRef s (False, False)
|
||||
|
||||
floodFillScanlineStack :: Color c => Image s c -> Pixel -> c -> ST s (Image s c)
|
||||
floodFillScanlineStack b coords newC = do
|
||||
stack <- emptySTStack -- new empty stack holding pixels to fill
|
||||
spans <- newSTRef (False, False) -- keep track of spans in scanWhileX
|
||||
fFSS b stack coords newC spans -- function loop
|
||||
return b
|
||||
where
|
||||
fFSS b st c newC p = do
|
||||
oldC <- getPix b c
|
||||
unless (oldC == newC) $ do
|
||||
pushST st c -- store the coordinates in the stack
|
||||
(w, h) <- dimensions b
|
||||
consumeSTStack st (scanWhileY b p oldC >=>
|
||||
scanWhileX b st p oldC newC (w, h))
|
||||
|
||||
-- take a buffer, the span record, the color of the Color the fill is
|
||||
-- started from, a coordinate from the stack, and returns the coord
|
||||
-- of the next point to be filled in the same column
|
||||
scanWhileY b p oldC coords@(Pixel (x, y)) =
|
||||
if y >= 0
|
||||
then do
|
||||
z <- getPix b coords
|
||||
if z == oldC
|
||||
then scanWhileY b p oldC (Pixel (x, y - 1))
|
||||
else do
|
||||
setSpanNone p
|
||||
return (Pixel (x, y + 1))
|
||||
else do
|
||||
setSpanNone p
|
||||
return (Pixel (x, y + 1))
|
||||
|
||||
-- take a buffer, a stack, a span record, the old and new color, the
|
||||
-- height and width of the buffer, and a coordinate.
|
||||
-- paint the point with the new color, check if the fill must expand
|
||||
-- to the left or right or both, and store those coordinates in the
|
||||
-- stack for subsequent filling
|
||||
scanWhileX b st p oldC newC (w, h) coords@(Pixel (x, y)) =
|
||||
when (y < h) $ do
|
||||
z <- getPix b coords
|
||||
when (z == oldC) $ do
|
||||
setPix b coords newC
|
||||
(spanLeft, spanRight) <- readSTRef p
|
||||
when (not spanLeft && x > 0) $ do
|
||||
z2 <- getPix b (Pixel (x - 1, y))
|
||||
when (z2 == oldC) $ do
|
||||
pushST st (Pixel (x - 1, y))
|
||||
setSpanLeft p True
|
||||
when (spanLeft && x > 0) $ do
|
||||
z3 <- getPix b (Pixel (x - 1, y))
|
||||
when (z3 /= oldC) $
|
||||
setSpanLeft p False
|
||||
when (not spanRight && x < (w - 1)) $ do
|
||||
z4 <- getPix b (Pixel (x + 1, y))
|
||||
when (z4 == oldC) $ do
|
||||
pushST st (Pixel (x + 1, y))
|
||||
setSpanRight p True
|
||||
when (spanRight && x < (w - 1)) $ do
|
||||
z5 <- getPix b (Pixel (x + 1, y))
|
||||
when (z5 /= oldC) $
|
||||
setSpanRight p False
|
||||
scanWhileX b st p oldC newC (w, h) (Pixel (x, y + 1))
|
||||
42
Task/Bitmap-Flood-fill/Java/bitmap-flood-fill-1.java
Normal file
42
Task/Bitmap-Flood-fill/Java/bitmap-flood-fill-1.java
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import java.awt.Color;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class FloodFill {
|
||||
public void floodFill(BufferedImage image, Point node, Color targetColor, Color replacementColor) {
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
int target = targetColor.getRGB();
|
||||
int replacement = replacementColor.getRGB();
|
||||
if (target != replacement) {
|
||||
Deque<Point> queue = new LinkedList<Point>();
|
||||
do {
|
||||
int x = node.x;
|
||||
int y = node.y;
|
||||
while (x > 0 && image.getRGB(x - 1, y) == target) {
|
||||
x--;
|
||||
}
|
||||
boolean spanUp = false;
|
||||
boolean spanDown = false;
|
||||
while (x < width && image.getRGB(x, y) == target) {
|
||||
image.setRGB(x, y, replacement);
|
||||
if (!spanUp && y > 0 && image.getRGB(x, y - 1) == target) {
|
||||
queue.add(new Point(x, y - 1));
|
||||
spanUp = true;
|
||||
} else if (spanUp && y > 0 && image.getRGB(x, y - 1) != target) {
|
||||
spanUp = false;
|
||||
}
|
||||
if (!spanDown && y < height - 1 && image.getRGB(x, y + 1) == target) {
|
||||
queue.add(new Point(x, y + 1));
|
||||
spanDown = true;
|
||||
} else if (spanDown && y < height - 1 && image.getRGB(x, y + 1) != target) {
|
||||
spanDown = false;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
} while ((node = queue.pollFirst()) != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Task/Bitmap-Flood-fill/Java/bitmap-flood-fill-2.java
Normal file
18
Task/Bitmap-Flood-fill/Java/bitmap-flood-fill-2.java
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import java.io.IOException;
|
||||
import java.awt.Color;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class Test {
|
||||
public Test() throws IOException {
|
||||
BufferedImage image = ImageIO.read(new File("Unfilledcirc.png"));
|
||||
new FloodFill().floodFill(image, new Point(50, 50), Color.WHITE, Color.RED);
|
||||
ImageIO.write(image, "png", new File("output.png"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
new Test();
|
||||
}
|
||||
}
|
||||
10
Task/Bitmap-Flood-fill/Perl/bitmap-flood-fill-1.pl
Normal file
10
Task/Bitmap-Flood-fill/Perl/bitmap-flood-fill-1.pl
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#! /usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use Image::Imlib2;
|
||||
|
||||
my $img = Image::Imlib2->load("Unfilledcirc.jpg");
|
||||
$img->set_color(0, 255, 0, 255);
|
||||
$img->fill(100,100);
|
||||
$img->save("filledcirc.jpg");
|
||||
exit 0;
|
||||
48
Task/Bitmap-Flood-fill/Perl/bitmap-flood-fill-2.pl
Normal file
48
Task/Bitmap-Flood-fill/Perl/bitmap-flood-fill-2.pl
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
use strict;
|
||||
use Image::Imlib2;
|
||||
|
||||
sub colordistance
|
||||
{
|
||||
my ( $c1, $c2 ) = @_;
|
||||
|
||||
my ( $r1, $g1, $b1 ) = @$c1;
|
||||
my ( $r2, $g2, $b2 ) = @$c2;
|
||||
return sqrt(( ($r1-$r2)**2 + ($g1-$g2)**2 + ($b1-$b2)**2 ))/(255.0*sqrt(3.0));
|
||||
}
|
||||
|
||||
sub floodfill
|
||||
{
|
||||
my ( $img, $x, $y, $r, $g, $b ) = @_;
|
||||
my $distparameter = 0.2;
|
||||
|
||||
my %visited = ();
|
||||
my @queue = ();
|
||||
|
||||
my @tcol = ( $r, $g, $b );
|
||||
my @col = $img->query_pixel($x, $y);
|
||||
if ( colordistance(\@tcol, \@col) > $distparameter ) { return; }
|
||||
push @queue, [$x, $y];
|
||||
while ( @queue ) {
|
||||
my $pointref = shift(@queue);
|
||||
( $x, $y ) = @$pointref;
|
||||
if ( ($x < 0) || ($y < 0) || ( $x >= $img->width ) || ( $y >= $img->height ) ) { next; }
|
||||
if ( ! exists($visited{"$x,$y"}) ) {
|
||||
@col = $img->query_pixel($x, $y);
|
||||
if ( colordistance(\@tcol, \@col) <= $distparameter ) {
|
||||
$img->draw_point($x, $y);
|
||||
$visited{"$x,$y"} = 1;
|
||||
push @queue, [$x+1, $y];
|
||||
push @queue, [$x-1, $y];
|
||||
push @queue, [$x, $y+1];
|
||||
push @queue, [$x, $y-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# usage example
|
||||
my $img = Image::Imlib2->load("Unfilledcirc.jpg");
|
||||
$img->set_color(0,255,0,255);
|
||||
floodfill($img, 100,100, 0, 0, 0);
|
||||
$img->save("filledcirc1.jpg");
|
||||
exit 0;
|
||||
10
Task/Bitmap-Flood-fill/PicoLisp/bitmap-flood-fill.l
Normal file
10
Task/Bitmap-Flood-fill/PicoLisp/bitmap-flood-fill.l
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
(de ppmFloodFill (Ppm X Y Color)
|
||||
(let Target (get Ppm Y X)
|
||||
(recur (X Y)
|
||||
(when (= Target (get Ppm Y X))
|
||||
(set (nth Ppm Y X) Color)
|
||||
(recurse (dec X) Y)
|
||||
(recurse (inc X) Y)
|
||||
(recurse X (dec Y))
|
||||
(recurse X (inc Y)) ) ) )
|
||||
Ppm )
|
||||
44
Task/Bitmap-Flood-fill/Python/bitmap-flood-fill-1.py
Normal file
44
Task/Bitmap-Flood-fill/Python/bitmap-flood-fill-1.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import Image
|
||||
def FloodFill( fileName, initNode, targetColor, replaceColor ):
|
||||
img = Image.open( fileName )
|
||||
pix = img.load()
|
||||
xsize, ysize = img.size
|
||||
Q = []
|
||||
if pix[ initNode[0], initNode[1] ] != targetColor:
|
||||
return img
|
||||
Q.append( initNode )
|
||||
while Q != []:
|
||||
node = Q.pop(0)
|
||||
if pix[ node[0], node[1] ] == targetColor:
|
||||
W = list( node )
|
||||
if node[0] + 1 < xsize:
|
||||
E = list( [ node[0] + 1, node[1] ] )
|
||||
else:
|
||||
E = list( node )
|
||||
# Move west until color of node does not match targetColor
|
||||
while pix[ W[0], W[1] ] == targetColor:
|
||||
pix[ W[0], W[1] ] = replaceColor
|
||||
if W[1] + 1 < ysize:
|
||||
if pix[ W[0], W[1] + 1 ] == targetColor:
|
||||
Q.append( [ W[0], W[1] + 1 ] )
|
||||
if W[1] - 1 >= 0:
|
||||
if pix[ W[0], W[1] - 1 ] == targetColor:
|
||||
Q.append( [ W[0], W[1] - 1 ] )
|
||||
if W[0] - 1 >= 0:
|
||||
W[0] = W[0] - 1
|
||||
else:
|
||||
break
|
||||
# Move east until color of node does not match targetColor
|
||||
while pix[ E[0], E[1] ] == targetColor:
|
||||
pix[ E[0], E[1] ] = replaceColor
|
||||
if E[1] + 1 < ysize:
|
||||
if pix[ E[0], E[1] + 1 ] == targetColor:
|
||||
Q.append( [ E[0], E[1] + 1 ] )
|
||||
if E[1] - 1 >= 0:
|
||||
if pix[ E[0], E[1] - 1 ] == targetColor:
|
||||
Q.append( [ E[0], E[1] -1 ] )
|
||||
if E[0] + 1 < xsize:
|
||||
E[0] = E[0] + 1
|
||||
else:
|
||||
break
|
||||
return img
|
||||
7
Task/Bitmap-Flood-fill/Python/bitmap-flood-fill-2.py
Normal file
7
Task/Bitmap-Flood-fill/Python/bitmap-flood-fill-2.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# "FloodFillClean.png" is name of input file
|
||||
# [55,55] the x,y coordinate where fill starts
|
||||
# (0,0,0,255) the target colour being filled( black in this example )
|
||||
# (255,255,255,255) the final colour ( white in this case )
|
||||
img = FloodFill( "FloodFillClean.png", [55,55], (0,0,0,255), (255,255,255,255) )
|
||||
#The resulting image is saved as Filled.png
|
||||
img.save( "Filled.png" )
|
||||
82
Task/Bitmap-Flood-fill/Racket/bitmap-flood-fill.rkt
Normal file
82
Task/Bitmap-Flood-fill/Racket/bitmap-flood-fill.rkt
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#lang racket
|
||||
|
||||
(require racket/draw)
|
||||
|
||||
;; flood-fill: bitmap<%> number number color color -> void
|
||||
;; An example of flood filling a bitmap.
|
||||
;;
|
||||
;; We'll use a raw, byte-oriented interface here for demonstration
|
||||
;; purposes. Racket does provide get-pixel and set-pixel functions
|
||||
;; which work on color% structures rather than bytes, but it's useful
|
||||
;; to see that the byte approach works as well.
|
||||
(define (flood-fill bm start-x start-y target-color replacement-color)
|
||||
;; The main loop.
|
||||
;; http://en.wikipedia.org/wiki/Flood_fill
|
||||
(define (iter x y)
|
||||
(when (and (in-bounds? x y) (target-color-at? x y))
|
||||
(replace-color-at! x y)
|
||||
(iter (add1 x) y)
|
||||
(iter (sub1 x) y)
|
||||
(iter x (add1 y))
|
||||
(iter x (sub1 y))))
|
||||
|
||||
;; With auxillary definitions below:
|
||||
(define width (send bm get-width))
|
||||
(define height (send bm get-height))
|
||||
|
||||
(define buffer (make-bytes (* width height 4)))
|
||||
(send bm get-argb-pixels 0 0 width height buffer)
|
||||
|
||||
(define-values (target-red target-green target-blue)
|
||||
(values (send target-color red)
|
||||
(send target-color green)
|
||||
(send target-color blue)))
|
||||
|
||||
(define-values (replacement-red replacement-green replacement-blue)
|
||||
(values (send replacement-color red)
|
||||
(send replacement-color green)
|
||||
(send replacement-color blue)))
|
||||
|
||||
(define (offset-at x y) (* 4 (+ (* y width) x)))
|
||||
|
||||
(define (target-color-at? x y)
|
||||
(define offset (offset-at x y))
|
||||
(and (= (bytes-ref buffer (+ offset 1)) target-red)
|
||||
(= (bytes-ref buffer (+ offset 2)) target-green)
|
||||
(= (bytes-ref buffer (+ offset 3)) target-blue)))
|
||||
|
||||
(define (replace-color-at! x y)
|
||||
(define offset (offset-at x y))
|
||||
(bytes-set! buffer (+ offset 1) replacement-red)
|
||||
(bytes-set! buffer (+ offset 2) replacement-green)
|
||||
(bytes-set! buffer (+ offset 3) replacement-blue))
|
||||
|
||||
(define (in-bounds? x y)
|
||||
(and (<= 0 x) (< x width) (<= 0 y) (< y height)))
|
||||
|
||||
;; Finally, let's do the fill, and then store the
|
||||
;; result back into the bitmap:
|
||||
(iter start-x start-y)
|
||||
(send bm set-argb-pixels 0 0 width height buffer))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Example: flood fill a hole shape.
|
||||
(define bm (make-bitmap 100 100))
|
||||
(define dc (send bm make-dc))
|
||||
|
||||
;; We intentionally set the smoothing of the dc to
|
||||
;; aligned so that there are no gaps in the shape for the
|
||||
;; flood to leak through.
|
||||
(send dc set-smoothing 'aligned)
|
||||
(send dc draw-rectangle 10 10 80 80)
|
||||
(send dc draw-rounded-rectangle 20 20 50 50)
|
||||
;; In DrRacket, we can print the bm to look at it graphically,
|
||||
;; before the flood fill:
|
||||
bm
|
||||
|
||||
(flood-fill bm 50 50
|
||||
(send the-color-database find-color "white")
|
||||
(send the-color-database find-color "DarkSeaGreen"))
|
||||
;; ... and after:
|
||||
bm
|
||||
57
Task/Bitmap-Flood-fill/Ruby/bitmap-flood-fill.rb
Normal file
57
Task/Bitmap-Flood-fill/Ruby/bitmap-flood-fill.rb
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
class RGBColour
|
||||
def ==(a_colour)
|
||||
values == a_colour.values
|
||||
end
|
||||
end
|
||||
|
||||
class Queue < Array
|
||||
alias_method :enqueue, :push
|
||||
alias_method :dequeue, :shift
|
||||
end
|
||||
|
||||
class Pixmap
|
||||
def flood_fill(pixel, new_colour)
|
||||
current_colour = self[pixel.x, pixel.y]
|
||||
queue = Queue.new
|
||||
queue.enqueue(pixel)
|
||||
until queue.empty?
|
||||
p = queue.dequeue
|
||||
if self[p.x, p.y] == current_colour
|
||||
west = find_border(p, current_colour, :west)
|
||||
east = find_border(p, current_colour, :east)
|
||||
draw_line(west, east, new_colour)
|
||||
q = west
|
||||
while q.x <= east.x
|
||||
[:north, :south].each do |direction|
|
||||
n = neighbour(q, direction)
|
||||
queue.enqueue(n) if self[n.x, n.y] == current_colour
|
||||
end
|
||||
q = neighbour(q, :east)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def neighbour(pixel, direction)
|
||||
case direction
|
||||
when :north then Pixel[pixel.x, pixel.y - 1]
|
||||
when :south then Pixel[pixel.x, pixel.y + 1]
|
||||
when :east then Pixel[pixel.x + 1, pixel.y]
|
||||
when :west then Pixel[pixel.x - 1, pixel.y]
|
||||
end
|
||||
end
|
||||
|
||||
def find_border(pixel, colour, direction)
|
||||
nextp = neighbour(pixel, direction)
|
||||
while self[nextp.x, nextp.y] == colour
|
||||
pixel = nextp
|
||||
nextp = neighbour(pixel, direction)
|
||||
end
|
||||
pixel
|
||||
end
|
||||
end
|
||||
|
||||
bitmap = Pixmap.new(300, 300)
|
||||
bitmap.draw_circle(Pixel[149,149], 120, RGBColour::BLACK)
|
||||
bitmap.draw_circle(Pixel[200,100], 40, RGBColour::BLACK)
|
||||
bitmap.flood_fill(Pixel[140,160], RGBColour::BLUE)
|
||||
74
Task/Bitmap-Flood-fill/Tcl/bitmap-flood-fill.tcl
Normal file
74
Task/Bitmap-Flood-fill/Tcl/bitmap-flood-fill.tcl
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
package require Tcl 8.5
|
||||
package require Tk
|
||||
package require struct::queue
|
||||
|
||||
proc floodFill {img colour point} {
|
||||
set new [colour2rgb $colour]
|
||||
set old [getPixel $img $point]
|
||||
struct::queue Q
|
||||
Q put $point
|
||||
while {[Q size] > 0} {
|
||||
set p [Q get]
|
||||
if {[getPixel $img $p] eq $old} {
|
||||
set w [findBorder $img $p $old west]
|
||||
set e [findBorder $img $p $old east]
|
||||
drawLine $img $new $w $e
|
||||
set q $w
|
||||
while {[x $q] <= [x $e]} {
|
||||
set n [neighbour $q north]
|
||||
if {[getPixel $img $n] eq $old} {Q put $n}
|
||||
set s [neighbour $q south]
|
||||
if {[getPixel $img $s] eq $old} {Q put $s}
|
||||
set q [neighbour $q east]
|
||||
}
|
||||
}
|
||||
}
|
||||
Q destroy
|
||||
}
|
||||
|
||||
proc findBorder {img p colour dir} {
|
||||
set lookahead [neighbour $p $dir]
|
||||
while {[getPixel $img $lookahead] eq $colour} {
|
||||
set p $lookahead
|
||||
set lookahead [neighbour $p $dir]
|
||||
}
|
||||
return $p
|
||||
}
|
||||
|
||||
proc x p {lindex $p 0}
|
||||
proc y p {lindex $p 1}
|
||||
|
||||
proc neighbour {p dir} {
|
||||
lassign $p x y
|
||||
switch -exact -- $dir {
|
||||
west {return [list [incr x -1] $y]}
|
||||
east {return [list [incr x] $y]}
|
||||
north {return [list $x [incr y -1]]}
|
||||
south {return [list $x [incr y]]}
|
||||
}
|
||||
}
|
||||
|
||||
proc colour2rgb {color_name} {
|
||||
foreach part [winfo rgb . $color_name] {
|
||||
append colour [format %02x [expr {$part >> 8}]]
|
||||
}
|
||||
return #$colour
|
||||
}
|
||||
|
||||
set img [newImage 70 50]
|
||||
fill $img white
|
||||
|
||||
drawLine $img blue {0 0} {0 25}
|
||||
drawLine $img blue {0 25} {35 25}
|
||||
drawLine $img blue {35 25} {35 0}
|
||||
drawLine $img blue {35 0} {0 0}
|
||||
floodFill $img yellow {3 3}
|
||||
|
||||
drawCircle $img black {35 25} 24
|
||||
drawCircle $img black {35 25} 10
|
||||
floodFill $img orange {34 5}
|
||||
floodFill $img red {36 5}
|
||||
|
||||
toplevel .flood
|
||||
label .flood.l -image $img
|
||||
pack .flood.l
|
||||
Loading…
Add table
Add a link
Reference in a new issue