From c3557e388c6ee5bebe67c447c798ccce62b14536 Mon Sep 17 00:00:00 2001 From: Nikolay Kuznetsov Date: Sat, 15 Feb 2025 20:32:46 +0300 Subject: [PATCH] Update GraphABC.pas (#3244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Быстрая реализация функции FloodFill Для этого добавлена процедура BitmapFloodFill, которая вызывается из метода Picture.FloodFill и процедуры FloodFill 2.Добавлена поддержка LockDrawing/UnlockDrawing в процедуру FloodFill --- bin/Lib/GraphABC.pas | 194 +++++++++++++++++++------------------------ 1 file changed, 87 insertions(+), 107 deletions(-) diff --git a/bin/Lib/GraphABC.pas b/bin/Lib/GraphABC.pas index 5dbbe0e22..457afbc78 100644 --- a/bin/Lib/GraphABC.pas +++ b/bin/Lib/GraphABC.pas @@ -1,4 +1,4 @@ -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) ///Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне unit GraphABC; @@ -13,7 +13,7 @@ interface uses System, - System.Drawing, + System.Drawing, System.Windows.Forms, System.Drawing.Drawing2D; @@ -477,6 +477,8 @@ procedure DrawTextCentered(x, y: integer; n: integer); procedure DrawTextCentered(x, y: integer; r: real); /// Заливает область одного цвета цветом c, начиная с точки (x,y). procedure FloodFill(x, y: integer; c: Color); +/// Заливает область Bitmap одного цвета цветом c, начиная с точки (x,y) . +procedure BitmapFloodFill(bmp: Bitmap; x, y: integer; c: Color); {procedure FillCircle(x,y,r: integer; c: Color); procedure DrawCircle(x,y,r: integer; c: Color); @@ -2345,7 +2347,7 @@ begin GraphABCHelper.TextOut(x, y, s, gb); end; -function ExtFloodFill(hdc: IntPtr; x, y: integer; color: integer; filltype: integer): boolean; external 'Gdi32.dll' name 'ExtFloodFill'; + function SelectObject(hdc, hgdiobj: IntPtr): IntPtr; external 'Gdi32.dll' name 'SelectObject'; @@ -2356,46 +2358,11 @@ function DeleteObject(obj: IntPtr): integer; external 'Gdi32.dll' name 'DeleteOb function CreateCompatibleDC(obj: IntPtr): IntPtr; external 'Gdi32.dll' name 'CreateCompatibleDC'; procedure Picture.FloodFill(x, y: integer; c: Color); -//var hdc, hBrush, hOldBrush: IntPtr; begin - {var borderColor: Color := GetPixel(x, y); - - var bc := ColorTranslator.ToWin32(borderColor); - var cc := ColorTranslator.ToWin32(c); - - Monitor.Enter(f); - - hdc := gbmp.GetHDC(); - hBrush := CreateSolidBrush(cc); - - hOldBrush := SelectObject(hdc, hBrush); - ExtFloodFill(hdc, x, y, bc, 1); - SelectObject(hdc, holdBrush); - - DeleteObject(hBrush); - - gbmp.ReleaseHdc(); - - DeleteObject(hdc); - - Monitor.Exit(f);} - var st := new Stack(); - var targetColor := bmp.GetPixel(x,y); - st.Push(Pnt(x,y)); - while st.Count > 0 do - begin - var p := st.Pop; - if (p.x < 0) or (p.x >= WindowWidth) or (p.y < 0) or (p.y >= WindowHeight) then - continue; - if bmp.GetPixel(p.x,p.y) = targetColor then - begin - bmp.SetPixel(p.x,p.y,c); - st.Push(Pnt(p.x,p.y-1)); - st.Push(Pnt(p.x,p.y+1)); - st.Push(Pnt(p.x-1,p.y)); - st.Push(Pnt(p.x+1,p.y)); - end; - end; + Monitor.Enter(f); + BitmapFloodFill(bmp, x, y, c); + gbmp.DrawImage(bmp, 0, 0); + Monitor.Exit(f); end; procedure Picture.Clear; @@ -3039,75 +3006,88 @@ begin ClosedCurve(pnts.ToArray); end; -// Fills -{procedure FloodFill(x, y: integer; c: Color); -var - hdc, hBrush, hOldBrush: IntPtr; -begin - var borderColor: Color := GetPixel(x, y); - // var bc: integer := integer(borderColor.R) + (integer(borderColor.G) shl 8) + (integer(borderColor.B) shl 16); - // var cc: integer := integer(c.R) + (integer(c.G) shl 8) + (integer(c.B) shl 16); - - var bc := ColorTranslator.ToWin32(borderColor); - var cc := ColorTranslator.ToWin32(c); - - Monitor.Enter(f); - - hdc := gr.GetHDC(); - hBrush := CreateSolidBrush(cc); - - hOldBrush := SelectObject(hdc, hBrush); - ExtFloodFill(hdc, x, y, bc, 1); - SelectObject(hdc, holdBrush); - - var hbmp := bmp.GetHbitmap(); // Создается GDI Bitmap - var memdc: IntPtr := CreateCompatibleDC(hdc); - SelectObject(memdc, hbmp); - - hOldBrush := SelectObject(memdc, hBrush); - ExtFloodFill(memdc, x, y, bc, 1); - SelectObject(hdc, holdBrush); - - var bmp1 := Bitmap.FromHbitmap(hbmp); - gbmp.DrawImage(bmp1, 0, 0); - - bmp1.Dispose(); - // bmp := Bitmap.FromHbitmap(hbmp); - - DeleteObject(memdc); - DeleteObject(hbmp); - DeleteObject(hBrush); - - gr.ReleaseHdc(); - - DeleteObject(hdc); - - Monitor.Exit(f); -end;} +procedure BitmapFloodFill(bmp: Bitmap; x, y: integer; c: Color); +type + RGB = record + r,g,b: byte; + end; + PRGB = ^uint32; +begin + var data := bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), + System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + var pixelFormatSize := Image.GetPixelFormatSize(bmp.PixelFormat) div 8; + //ссылка на начало картинки + var ptr1: IntPtr := data.Scan0; + var w := data.Stride div 4; + var h := bmp.Height; + var check: LinkedList := new LinkedList; + var newColor := c.ToArgb(); + var oldColor := PRGB(pointer(ptr1 + (x + y * w ) * pixelFormatSize))^; + var spanAbove := false; + var spanBelow := false; + var x1 := 0; + ///starts filling + if (newColor <> oldColor) then + begin + check.AddLast(new Point(x, y)); + while (check.Count > 0) do + begin + var cur:Point := check.First.Value; + check.RemoveFirst(); + var _x := cur.X; + var _y := cur.Y; + x1 := _x; + while((x1 >= 0) and ( PRGB(pointer(ptr1 + (x1 + _y * w ) * pixelFormatSize))^ = oldColor)) do dec(x1); + inc(x1); + (spanAbove, spanBelow) := (false, false); + while((x1 < w) and ( PRGB(pointer(ptr1 + (x1 + _y * w ) * pixelFormatSize))^ = oldColor)) do + begin + PRGB(pointer(ptr1 + (x1 + _y * w ) * pixelFormatSize))^ := newColor; + if(not spanAbove and (_y >0 ) and (PRGB(pointer(ptr1 + (x1 + (_y -1) * w ) * pixelFormatSize))^ = oldColor)) then + begin + check.AddLast(new Point(x1, _y - 1)); + spanAbove := true + end + else + if(spanAbove and (_y > 0) and (PRGB(pointer(ptr1 + (x1 + (_y -1) * w ) * pixelFormatSize))^ <> oldColor)) then + begin + spanAbove := false; + end; + if(not spanBelow and (_y < h - 1 ) and (PRGB(pointer(ptr1 + (x1 + (_y + 1) * w ) * pixelFormatSize))^ = oldColor)) then + begin + check.AddLast(new Point(x1, _y + 1)); + spanBelow := true + end + else + if(spanBelow and (_y < h - 1) and (PRGB(pointer(ptr1 + (x1 + (_y + 1) * w ) * pixelFormatSize))^ <> oldColor)) then + begin + spanBelow := false; + end; + inc(x1); + end; + end; + end; + ///end filling + bmp.UnlockBits(data); +end; + + + + +///Fill area by C color procedure FloodFill(x, y: integer; c: Color); begin - LockDrawing; - var st := new Stack(); - var targetColor := GetPixel(x,y); - st.Push(Pnt(x,y)); - while st.Count > 0 do - begin - var p := st.Pop; - if (p.x < 0) or (p.x >= WindowWidth) or (p.y < 0) or (p.y >= WindowHeight) then - continue; - if GetPixel(p.x,p.y) = targetColor then - begin - PutPixel(p.x,p.y,c); - st.Push(Pnt(p.x,p.y-1)); - st.Push(Pnt(p.x,p.y+1)); - st.Push(Pnt(p.x-1,p.y)); - st.Push(Pnt(p.x+1,p.y)); - end; - end; - UnLockDrawing; + Monitor.Enter(f); + BitmapFloodFill(bmp, x, y, c); + if NotLockDrawing then + gr.DrawImage(bmp, 0, 0); + if DrawInBuffer then + gbmp.DrawImage(bmp, 0, 0); + Monitor.Exit(f); end; + procedure FillRect(x1, y1, x2, y2: integer); begin FillRectangle(x1, y1, x2, y2); @@ -4268,4 +4248,4 @@ initialization __InitModule; finalization // Application.Run(MainWindow); -end. \ No newline at end of file +end.