Browse Source

blur for text tool

Unknown 6 years ago
parent
commit
c483cfe62d

+ 3 - 4
lazpaint/lazpaintmainform.lfm

@@ -1127,7 +1127,7 @@ object FMain: TFMain
       Left = 85
       Height = 24
       Top = 1
-      Width = 118
+      Width = 143
       Align = alNone
       EdgeBorders = []
       Images = ImageList16
@@ -1139,12 +1139,11 @@ object FMain: TFMain
         ImageIndex = 61
       end
       object Tool_TextShadow: TToolButton
-        Left = 1
+        Left = 116
         Hint = 'Text shadow'
-        Top = 22
+        Top = 0
         ImageIndex = 62
         Style = tbsCheck
-        Visible = False
       end
       object Tool_TextPhong: TToolButton
         Left = 93

+ 6 - 5
lazpaint/maintoolbar.inc

@@ -125,8 +125,9 @@ begin
   SpinEdit_TextSize.OnChange := @SpinEdit_TextSizeChange;
   SpinEdit_TextSize.BarExponent:= 3;
 
-  SpinEdit_TextBlur := TBarUpDown.Create(vsTextBlur,1,100,3);
-  SpinEdit_TextBlur.Increment := 1;
+  SpinEdit_TextBlur := TBarUpDown.Create(vsTextBlur,1,999,40);
+  SpinEdit_TextBlur.Increment := 5;
+  SpinEdit_TextBlur.BarExponent:= 3;
   SpinEdit_TextBlur.OnChange := @SpinEdit_TextBlurChange;
 
   SpinEdit_GridNbX := TBarUpDown.Create(vsGridNbX,1,100,10);
@@ -314,7 +315,7 @@ begin
   Tool_TextShadow.Down := ToolManager.ToolTextShadow;
   Tool_TextPhong.Down := ToolManager.ToolTextPhong;
   FontDialog1.Font := ToolManager.ToolTextFont;
-  SpinEdit_TextBlur.Value := ToolManager.ToolTextBlur;
+  SpinEdit_TextBlur.Value := round(ToolManager.ToolTextBlur*PenWidthFactor);
   SpinEdit_TextSize.Value := ToolManager.ToolTextFont.Size;
   UpdateTextSizeIncrement;
   SpinEdit_TextShadowX.Value := ToolManager.ToolTextShadowOffset.X;
@@ -569,8 +570,8 @@ procedure TFMain.SpinEdit_TextBlurChange(Sender: TObject);
 begin
   if initialized then
   begin
-    if ToolManager.ToolTextBlur = SpinEdit_TextBlur.Value then exit;
-    ToolManager.ToolTextBlur := SpinEdit_TextBlur.Value;
+    if ToolManager.ToolTextBlur = SpinEdit_TextBlur.Value/PenWidthFactor then exit;
+    ToolManager.ToolTextBlur := SpinEdit_TextBlur.Value/PenWidthFactor;
     UpdateEditPicture(True);
     FActiveSpinEdit := SpinEdit_TextBlur;
   end;

+ 7 - 7
lazpaint/uconfig.pas

@@ -195,8 +195,8 @@ type
     procedure SetDefaultToolTextShadow(value: boolean);
     function DefaultToolTextFont: TFont;
     procedure SetDefaultToolTextFont(value: TFont);
-    function DefaultToolTextBlur: integer;
-    procedure SetDefaultToolTextBlur(value: integer);
+    function DefaultToolTextBlur: single;
+    procedure SetDefaultToolTextBlur(value: single);
     function DefaultToolTextShadowOffsetX: integer;
     procedure SetDefaultToolTextShadowOffsetX(value: integer);
     function DefaultToolTextShadowOffsetY: integer;
@@ -793,7 +793,7 @@ end;
 
 function TLazPaintConfig.DefaultToolTextShadow: boolean;
 begin
-  result := false; //iniOptions.ReadBool('Tool','TextShadow',false);
+  result := iniOptions.ReadBool('Tool','TextShadow',false);
 end;
 
 procedure TLazPaintConfig.SetDefaultToolTextShadow(value: boolean);
@@ -829,14 +829,14 @@ begin
   iniOptions.WriteBool('Tool','TextFontUnderline',fsUnderline in tempFont.Style);
 end;
 
-function TLazPaintConfig.DefaultToolTextBlur: integer;
+function TLazPaintConfig.DefaultToolTextBlur: single;
 begin
-  result := iniOptions.ReadInteger('Tool','TextBlur',4);
+  result := iniOptions.ReadFloat('Tool','TextBlur',4);
 end;
 
-procedure TLazPaintConfig.SetDefaultToolTextBlur(value: integer);
+procedure TLazPaintConfig.SetDefaultToolTextBlur(value: single);
 begin
-  iniOptions.WriteInteger('Tool','TextBlur',value);
+  iniOptions.WriteFloat('Tool','TextBlur',value);
 end;
 
 function TLazPaintConfig.DefaultToolTextShadowOffsetX: integer;

+ 1 - 1
lazpaint/utool.pas

@@ -191,7 +191,7 @@ type
     ToolDeformationGridMoveWithoutDeformation: boolean;
     ToolTextOutline,ToolTextShadow,ToolTextPhong: boolean;
     ToolTextFont: TFont;
-    ToolTextBlur: integer;
+    ToolTextBlur: single;
     ToolTextShadowOffset: TPoint;
     ToolLightPosition: TPoint;
     ToolLightAltitude: integer;

+ 19 - 3
lazpaint/utoolbasic.pas

@@ -85,6 +85,8 @@ type
     FRightDown, FLeftDown: boolean;
     FLastPos: TPointF;
     function CreateShape: TVectorShape; virtual; abstract;
+    function GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; ADraft: boolean): TRect; virtual;
+    procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); virtual;
     procedure AssignShapeStyle; virtual;
     function RoundCoordinate(ptF: TPointF): TPointF; virtual;
     function GetIsSelectingTool: boolean; override;
@@ -267,6 +269,17 @@ begin
   result := OnlyRenderChange;
 end;
 
+function TVectorialTool.GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; ADraft: boolean): TRect;
+begin
+  with FShape.GetRenderBounds(ADestBounds,AMatrix,[]) do
+    result := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
+end;
+
+procedure TVectorialTool.DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean);
+begin
+  FShape.Render(ADest,AMatrix,ADraft);
+end;
+
 procedure TVectorialTool.AssignShapeStyle;
 var
   f: TVectorShapeFields;
@@ -326,14 +339,17 @@ function TVectorialTool.UpdateShape(toolDest: TBGRABitmap): TRect;
 var
   newBounds: TRect;
   oldClip: TRect;
+  draft: Boolean;
+  matrix: TAffineMatrix;
 begin
   result := FPreviousUpdateBounds;
   RestoreBackupDrawingLayer;
-  with FShape.GetRenderBounds(toolDest.ClipRect,AffineMatrixIdentity,[]) do
-    newBounds := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
+  matrix := AffineMatrixIdentity;
+  draft := (FRightDown or FLeftDown) and SlowShape;
+  newBounds := GetCustomShapeBounds(toolDest.ClipRect,matrix,draft);
   result := RectUnion(result, newBounds);
   oldClip := toolDest.IntersectClip(newBounds);
-  FShape.Render(toolDest,AffineMatrixIdentity,(FRightDown or FLeftDown) and SlowShape);
+  DrawCustomShape(toolDest,matrix,draft);
   toolDest.ClipRect := oldClip;
   FPreviousUpdateBounds := newBounds;
 end;

+ 93 - 2
lazpaint/utooltext.pas

@@ -14,7 +14,13 @@ type
 
   TToolText = class(TVectorialTool)
   protected
+    FPrevShadow: boolean;
+    FPrevShadowOffset: TPoint;
+    FPrevShadowRadius: single;
     function CreateShape: TVectorShape; override;
+    procedure IncludeShadowBounds(var ARect: TRect);
+    function GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; ADraft: boolean): TRect; override;
+    procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); override;
     procedure ShapeChange(ASender: TObject; ABounds: TRectF); override;
     procedure ShapeEditingChange(ASender: TObject); override;
     procedure AssignShapeStyle; override;
@@ -32,7 +38,8 @@ type
 
 implementation
 
-uses LCVectorTextShapes, BGRALayerOriginal, BGRATransform;
+uses LCVectorTextShapes, BGRALayerOriginal, BGRATransform, BGRAGrayscaleMask,
+  ugraph, math;
 
 { TToolText }
 
@@ -41,11 +48,84 @@ begin
   result := TTextShape.Create(nil);
 end;
 
+procedure TToolText.IncludeShadowBounds(var ARect: TRect);
+var
+  shadowRect: TRect;
+begin
+  if Manager.ToolTextShadow then
+  begin
+    shadowRect := ARect;
+    shadowRect.Inflate(ceil(Manager.ToolTextBlur),ceil(Manager.ToolTextBlur));
+    shadowRect.Offset(Manager.ToolTextShadowOffset.X,Manager.ToolTextShadowOffset.Y);
+    ARect := RectUnion(ARect, shadowRect);
+  end;
+end;
+
+function TToolText.GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; ADraft: boolean): TRect;
+begin
+  Result:= inherited GetCustomShapeBounds(ADestBounds, AMatrix, ADraft);
+  IncludeShadowBounds(result);
+  result.Intersect(ADestBounds);
+end;
+
+procedure TToolText.DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean);
+var
+  temp: TBGRABitmap;
+  blur, gray, grayShape: TGrayscaleMask;
+  shapeBounds, blurBounds, r, actualShapeBounds: TRect;
+begin
+  if Manager.ToolTextShadow then
+  begin
+    shapeBounds := GetCustomShapeBounds(rect(0,0,ADest.Width,ADest.Height),AMatrix,ADraft);
+    shapeBounds.Intersect(ADest.ClipRect);
+    if (shapeBounds.Width > 0) and (shapeBounds.Height > 0) then
+    begin
+      temp := TBGRABitmap.Create(shapeBounds.Width,shapeBounds.Height);
+      inherited DrawCustomShape(temp, AffineMatrixTranslation(-shapeBounds.Left,-shapeBounds.Top)*AMatrix, ADraft);
+      actualShapeBounds := temp.GetImageBounds;
+      if not actualShapeBounds.IsEmpty then
+      begin
+        actualShapeBounds.Offset(shapeBounds.Left,shapeBounds.Top);
+        grayShape := TGrayscaleMask.Create;
+        grayShape.CopyFrom(temp, cAlpha);
+
+        blurBounds := actualShapeBounds;
+        blurBounds.Inflate(ceil(Manager.ToolTextBlur),ceil(Manager.ToolTextBlur));
+        blurBounds.Offset(Manager.ToolTextShadowOffset.X,Manager.ToolTextShadowOffset.Y);
+        r := ADest.ClipRect;
+        r.Inflate(ceil(Manager.ToolTextBlur),ceil(Manager.ToolTextBlur));
+        blurBounds.Intersect(r);
+        gray := TGrayscaleMask.Create(blurBounds.Width,blurBounds.Height);
+        gray.PutImage(shapeBounds.Left-blurBounds.Left+Manager.ToolTextShadowOffset.X,
+                      shapeBounds.Top-blurBounds.Top+Manager.ToolTextShadowOffset.Y,grayShape,dmSet);
+        grayShape.Free;
+        blur := gray.FilterBlurRadial(Manager.ToolTextBlur,Manager.ToolTextBlur, rbFast) as TGrayscaleMask;
+        gray.Free;
+        ADest.FillMask(blurBounds.Left,blurBounds.Top,blur,BGRABlack,dmDrawWithTransparency);
+        blur.Free;
+      end;
+      ADest.PutImage(shapeBounds.Left,shapeBounds.Top,temp,dmDrawWithTransparency);
+      temp.Free;
+    end;
+    FPrevShadow := true;
+    FPrevShadowRadius := Manager.ToolTextBlur;
+    FPrevShadowOffset := Manager.ToolTextShadowOffset;
+  end else
+  begin
+    inherited DrawCustomShape(ADest, AMatrix, ADraft);
+    FPrevShadow := false;
+  end;
+end;
+
 procedure TToolText.ShapeChange(ASender: TObject; ABounds: TRectF);
+var
+  r: TRect;
 begin
   with (FShape as TTextShape) do
     Manager.ToolLightPosition := Point(round(LightPosition.X),round(LightPosition.Y));
-  inherited ShapeChange(ASender, ABounds);
+  with ABounds do r := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
+  IncludeShadowBounds(r);
+  inherited ShapeChange(ASender, RectF(r.Left,r.Top,r.Right,r.Bottom));
 end;
 
 procedure TToolText.ShapeEditingChange(ASender: TObject);
@@ -56,6 +136,9 @@ begin
 end;
 
 procedure TToolText.AssignShapeStyle;
+var
+  r: TRect;
+  toolDest: TBGRABitmap;
 begin
   with TTextShape(FShape) do
   begin
@@ -90,6 +173,14 @@ begin
     ParagraphAlignment:= Manager.ToolTextAlign;
     PenPhong := Manager.ToolTextPhong;
   end;
+  if (Manager.ToolTextShadow <> FPrevShadow) or
+     (Manager.ToolTextBlur <> FPrevShadowRadius) or
+     (Manager.ToolTextShadowOffset <> FPrevShadowOffset) then
+  begin
+    toolDest := GetToolDrawingLayer;
+    r:= UpdateShape(toolDest);
+    Action.NotifyChange(toolDest, r);
+  end;
 end;
 
 function TToolText.SlowShape: boolean;