Browse Source

average color and geometry

johann 5 years ago
parent
commit
c2b14edae1

+ 77 - 2
lazpaintcontrols/lcvectorialfill.pas

@@ -66,6 +66,8 @@ type
     FTextureMatrixBackup: TAffineMatrix;
     FTextureMatrixBackup: TAffineMatrix;
     FTextureOpacity: byte;
     FTextureOpacity: byte;
     FTextureRepetition: TTextureRepetition;
     FTextureRepetition: TTextureRepetition;
+    FTextureAverageColor: TBGRAPixel;
+    FTextureAverageColorComputed: boolean;
     FGradient: TBGRALayerGradientOriginal;
     FGradient: TBGRALayerGradientOriginal;
     FOnChange: TVectorialFillChangeEvent;
     FOnChange: TVectorialFillChangeEvent;
     FOnBeforeChange: TNotifyEvent;
     FOnBeforeChange: TNotifyEvent;
@@ -74,6 +76,7 @@ type
     procedure Init; virtual;
     procedure Init; virtual;
     function GetFillType: TVectorialFillType;
     function GetFillType: TVectorialFillType;
     function GetIsEditable: boolean;
     function GetIsEditable: boolean;
+    function GetAverageColor: TBGRAPixel;
     procedure SetOnChange(AValue: TVectorialFillChangeEvent);
     procedure SetOnChange(AValue: TVectorialFillChangeEvent);
     procedure SetTextureMatrix(AValue: TAffineMatrix);
     procedure SetTextureMatrix(AValue: TAffineMatrix);
     procedure SetTextureOpacity(AValue: byte);
     procedure SetTextureOpacity(AValue: byte);
@@ -112,10 +115,13 @@ type
     function Equals(Obj: TObject): boolean; override;
     function Equals(Obj: TObject): boolean; override;
     class function Equal(AFill1, AFill2: TVectorialFill): boolean;
     class function Equal(AFill1, AFill2: TVectorialFill): boolean;
     procedure Assign(Obj: TObject);
     procedure Assign(Obj: TObject);
+    procedure AssignExceptGeometry(Obj: TObject);
+    procedure FitGeometry(const ABox: TAffineBox);
     property FillType: TVectorialFillType read GetFillType;
     property FillType: TVectorialFillType read GetFillType;
     property IsEditable: boolean read GetIsEditable;
     property IsEditable: boolean read GetIsEditable;
     property Gradient: TBGRALayerGradientOriginal read FGradient;
     property Gradient: TBGRALayerGradientOriginal read FGradient;
     property SolidColor: TBGRAPixel read FColor write SetSolid;
     property SolidColor: TBGRAPixel read FColor write SetSolid;
+    property AverageColor: TBGRAPixel read GetAverageColor;
     property Texture: TBGRABitmap read FTexture;
     property Texture: TBGRABitmap read FTexture;
     property TextureMatrix: TAffineMatrix read FTextureMatrix write SetTextureMatrix;
     property TextureMatrix: TAffineMatrix read FTextureMatrix write SetTextureMatrix;
     property TextureOpacity: byte read FTextureOpacity write SetTextureOpacity;
     property TextureOpacity: byte read FTextureOpacity write SetTextureOpacity;
@@ -274,6 +280,7 @@ begin
   FColor := BGRAPixelTransparent;
   FColor := BGRAPixelTransparent;
   FTextureMatrix := AffineMatrixIdentity;
   FTextureMatrix := AffineMatrixIdentity;
   FTextureRepetition:= trRepeatBoth;
   FTextureRepetition:= trRepeatBoth;
+  FTextureAverageColorComputed:= false;
 end;
 end;
 
 
 procedure TVectorialFill.BeginUpdate;
 procedure TVectorialFill.BeginUpdate;
@@ -390,6 +397,7 @@ begin
   FTexture := nil;
   FTexture := nil;
   FTextureMatrix := AffineMatrixIdentity;
   FTextureMatrix := AffineMatrixIdentity;
   FTextureOpacity:= 255;
   FTextureOpacity:= 255;
+  FTextureAverageColorComputed:= false;
   FGradient := nil;
   FGradient := nil;
   FIsSolid := false;
   FIsSolid := false;
 end;
 end;
@@ -416,6 +424,26 @@ begin
   else result := vftNone;
   else result := vftNone;
 end;
 end;
 
 
+function TVectorialFill.GetAverageColor: TBGRAPixel;
+begin
+  case FillType of
+  vftNone: result := BGRAPixelTransparent;
+  vftGradient: result := Gradient.AverageColor;
+  vftTexture: begin
+      if not FTextureAverageColorComputed then
+      begin
+        if Assigned(FTexture) then
+          FTextureAverageColor := FTexture.AverageColor
+        else
+          FTextureAverageColor := BGRAPixelTransparent;
+        FTextureAverageColorComputed := true;
+      end;
+      result := FTextureAverageColor;
+    end
+  else {vftSolid} result := SolidColor;
+  end;
+end;
+
 procedure TVectorialFill.GradientChange(ASender: TObject; ABounds: PRectF; var ADiff: TBGRAOriginalDiff);
 procedure TVectorialFill.GradientChange(ASender: TObject; ABounds: PRectF; var ADiff: TBGRAOriginalDiff);
 var
 var
   fillDiff: TVectorialFillGradientDiff;
   fillDiff: TVectorialFillGradientDiff;
@@ -489,6 +517,7 @@ begin
   FTextureMatrix := AMatrix;
   FTextureMatrix := AMatrix;
   FTextureOpacity:= AOpacity;
   FTextureOpacity:= AOpacity;
   FTextureRepetition:= ATextureRepetition;
   FTextureRepetition:= ATextureRepetition;
+  FTextureAverageColorComputed:= false;
   EndUpdate;
   EndUpdate;
 end;
 end;
 
 
@@ -637,13 +666,59 @@ begin
     other := TVectorialFill(Obj);
     other := TVectorialFill(Obj);
     case other.FillType of
     case other.FillType of
     vftSolid: SetSolid(other.SolidColor);
     vftSolid: SetSolid(other.SolidColor);
-    vftGradient: SetGradient(other.Gradient,false);
-    vftTexture: SetTexture(other.Texture,other.TextureMatrix,other.TextureOpacity,other.TextureRepetition);
+    vftGradient: SetGradient(other.Gradient, false);
+    vftTexture: SetTexture(other.Texture, other.TextureMatrix, other.TextureOpacity, other.TextureRepetition);
+    else Clear;
+    end;
+  end else
+    raise exception.Create('Incompatible type');
+end;
+
+procedure TVectorialFill.AssignExceptGeometry(Obj: TObject);
+var
+  other: TVectorialFill;
+  tempGrad: TBGRALayerGradientOriginal;
+begin
+  if Obj = nil then Clear else
+  if Obj is TVectorialFill then
+  begin
+    other := TVectorialFill(Obj);
+    case other.FillType of
+    vftSolid: SetSolid(other.SolidColor);
+    vftGradient: begin
+        tempGrad := self.Gradient.Duplicate as TBGRALayerGradientOriginal;
+        tempGrad.AssignExceptGeometry(other.Gradient);
+        SetGradient(tempGrad, true);
+      end;
+    vftTexture: SetTexture(other.Texture, self.TextureMatrix, other.TextureOpacity, other.TextureRepetition);
     else Clear;
     else Clear;
     end;
     end;
   end else
   end else
     raise exception.Create('Incompatible type');
     raise exception.Create('Incompatible type');
 end;
 end;
 
 
+procedure TVectorialFill.FitGeometry(const ABox: TAffineBox);
+var
+  sx,sy: single;
+  u, v: TPointF;
+begin
+  case FillType of
+  vftTexture:
+    if Assigned(Texture) then
+    begin
+      if not (TextureRepetition in [trRepeatX,trRepeatBoth]) and (Texture.Width > 0) then
+        sx:= 1/Texture.Width else if ABox.Width > 0 then sx:= 1/ABox.Width else sx := 1;
+      if not (TextureRepetition in [trRepeatY,trRepeatBoth]) and (Texture.Height > 0) then
+        sy:= 1/Texture.Height else if ABox.Height > 0 then sy:= 1/ABox.Height else sy := 1;
+
+      u := (ABox.TopRight-ABox.TopLeft)*sx;
+      v := (ABox.BottomLeft-ABox.TopLeft)*sy;
+      TextureMatrix := AffineMatrix(u, v, ABox.TopLeft);
+    end;
+  vftGradient:
+    Gradient.FitGeometry(ABox);
+  end;
+end;
+
 end.
 end.
 
 

+ 7 - 0
lazpaintcontrols/lcvectorialfillcontrol.pas

@@ -23,6 +23,7 @@ type
   TLCVectorialFillControl = class(TWinControl)
   TLCVectorialFillControl = class(TWinControl)
   private
   private
     function GetAllowedFillTypes: TVectorialFillTypes;
     function GetAllowedFillTypes: TVectorialFillTypes;
+    function GetAverageColor: TBGRAPixel;
     function GetCanAdjustToShape: boolean;
     function GetCanAdjustToShape: boolean;
     function GetFillType: TVectorialFillType;
     function GetFillType: TVectorialFillType;
     function GetGradEndColor: TBGRAPixel;
     function GetGradEndColor: TBGRAPixel;
@@ -75,6 +76,7 @@ type
     function CreateShapeFill(AShape: TVectorShape): TVectorialFill;
     function CreateShapeFill(AShape: TVectorShape): TVectorialFill;
     procedure UpdateShapeFill(AShape: TVectorShape; ATarget: TLCFillTarget);
     procedure UpdateShapeFill(AShape: TVectorShape; ATarget: TLCFillTarget);
     property FillType: TVectorialFillType read GetFillType write SetFillType;
     property FillType: TVectorialFillType read GetFillType write SetFillType;
+    property AverageColor: TBGRAPixel read GetAverageColor;
     property SolidColor: TBGRAPixel read GetSolidColor write SetSolidColor;
     property SolidColor: TBGRAPixel read GetSolidColor write SetSolidColor;
     property GradientType: TGradientType read GetGradType write SetGradientType;
     property GradientType: TGradientType read GetGradType write SetGradientType;
     property GradStartColor: TBGRAPixel read GetGradStartColor write SetGradStartColor;
     property GradStartColor: TBGRAPixel read GetGradStartColor write SetGradStartColor;
@@ -132,6 +134,11 @@ begin
   result := FInterface.AllowedFillTypes;
   result := FInterface.AllowedFillTypes;
 end;
 end;
 
 
+function TLCVectorialFillControl.GetAverageColor: TBGRAPixel;
+begin
+  result := FInterface.AverageColor;
+end;
+
 function TLCVectorialFillControl.GetCanAdjustToShape: boolean;
 function TLCVectorialFillControl.GetCanAdjustToShape: boolean;
 begin
 begin
   result := FInterface.CanAdjustToShape;
   result := FInterface.CanAdjustToShape;

+ 31 - 31
lazpaintcontrols/lcvectorialfillinterface.pas

@@ -38,6 +38,8 @@ type
     FTexRepetition: TTextureRepetition;
     FTexRepetition: TTextureRepetition;
     FTexture: TBGRABitmap;
     FTexture: TBGRABitmap;
     FTexOpacity: byte;
     FTexOpacity: byte;
+    FTextureAverageColor: TBGRAPixel;
+    FTextureAverageColorComputed: boolean;
 
 
     //interface
     //interface
     FContainer: TWinControl;
     FContainer: TWinControl;
@@ -89,6 +91,7 @@ type
     procedure OnClickGradInterp(ASender: TObject);
     procedure OnClickGradInterp(ASender: TObject);
     procedure OnClickGradRepeat(ASender: TObject);
     procedure OnClickGradRepeat(ASender: TObject);
     function GetPreferredSize: TSize;
     function GetPreferredSize: TSize;
+    function GetAverageColor: TBGRAPixel;
     procedure SetCanAdjustToShape(AValue: boolean);
     procedure SetCanAdjustToShape(AValue: boolean);
     procedure SetContainer(AValue: TWinControl);
     procedure SetContainer(AValue: TWinControl);
     procedure SetFillType(AValue: TVectorialFillType);
     procedure SetFillType(AValue: TVectorialFillType);
@@ -142,6 +145,7 @@ type
     procedure UpdateShapeFill(AShape: TVectorShape; ATarget: TLCFillTarget);
     procedure UpdateShapeFill(AShape: TVectorShape; ATarget: TLCFillTarget);
     property FillType: TVectorialFillType read FFillType write SetFillType;
     property FillType: TVectorialFillType read FFillType write SetFillType;
     property SolidColor: TBGRAPixel read FSolidColor write SetSolidColor;
     property SolidColor: TBGRAPixel read FSolidColor write SetSolidColor;
+    property AverageColor: TBGRAPixel read GetAverageColor;
     property GradientType: TGradientType read FGradType write SetGradientType;
     property GradientType: TGradientType read FGradType write SetGradientType;
     property GradStartColor: TBGRAPixel read FGradStartColor write SetGradStartColor;
     property GradStartColor: TBGRAPixel read FGradStartColor write SetGradStartColor;
     property GradEndColor: TBGRAPixel read FGradEndColor write SetGradEndColor;
     property GradEndColor: TBGRAPixel read FGradEndColor write SetGradEndColor;
@@ -340,6 +344,7 @@ procedure TVectorialFillInterface.UpdateTextureThumbnail;
 var
 var
   bmpThumb: TBitmap;
   bmpThumb: TBitmap;
 begin
 begin
+  FTextureAverageColorComputed:= false;
   if not Assigned(FTexturePreview) then exit;
   if not Assigned(FTexturePreview) then exit;
   if Assigned(Texture) then
   if Assigned(Texture) then
   begin
   begin
@@ -815,6 +820,26 @@ begin
   UpdateTextureCursor;
   UpdateTextureCursor;
 end;
 end;
 
 
+function TVectorialFillInterface.GetAverageColor: TBGRAPixel;
+begin
+  case FillType of
+  vftNone: result := BGRAPixelTransparent;
+  vftGradient: result := MergeBGRAWithGammaCorrection(GradStartColor, 1, GradEndColor, 1);
+  vftTexture: begin
+      if not FTextureAverageColorComputed then
+      begin
+        if Assigned(FTexture) then
+          FTextureAverageColor := FTexture.AverageColor
+        else
+          FTextureAverageColor := BGRAPixelTransparent;
+        FTextureAverageColorComputed := true;
+      end;
+      result := FTextureAverageColor;
+    end
+  else {vftSolid} result := SolidColor;
+  end;
+end;
+
 procedure TVectorialFillInterface.AdjustToShapeClick(Sender: TObject);
 procedure TVectorialFillInterface.AdjustToShapeClick(Sender: TObject);
 begin
 begin
   if Assigned(FOnAdjustToShape) then FOnAdjustToShape(self);
   if Assigned(FOnAdjustToShape) then FOnAdjustToShape(self);
@@ -941,51 +966,26 @@ function TVectorialFillInterface.CreateShapeFill(AShape: TVectorShape): TVectori
 var
 var
   grad: TBGRALayerGradientOriginal;
   grad: TBGRALayerGradientOriginal;
   sx,sy: single;
   sx,sy: single;
-  box: TAffineBox;
   u, v: TPointF;
   u, v: TPointF;
 begin
 begin
   if FillType = vftSolid then
   if FillType = vftSolid then
-    result := TVectorialFill.CreateAsSolid(SolidColor)
+    exit(TVectorialFill.CreateAsSolid(SolidColor))
   else if (FillType = vftTexture) and Assigned(Texture) then
   else if (FillType = vftTexture) and Assigned(Texture) then
-  begin
-    box := AShape.SuggestGradientBox(AffineMatrixIdentity);
-    if not (TextureRepetition in [trRepeatX,trRepeatBoth]) and (Texture.Width > 0) then
-      sx:= 1/Texture.Width else if box.Width > 0 then sx:= 1/box.Width else sx := 1;
-    if not (TextureRepetition in [trRepeatY,trRepeatBoth]) and (Texture.Height > 0) then
-      sy:= 1/Texture.Height else if box.Height > 0 then sy:= 1/box.Height else sy := 1;
-
-    u := (box.TopRight-box.TopLeft)*sx;
-    v := (box.BottomLeft-box.TopLeft)*sy;
-    result := TVectorialFill.CreateAsTexture(Texture,AffineMatrix(u,v,box.TopLeft),
-           TextureOpacity, TextureRepetition);
-  end
+    result := TVectorialFill.CreateAsTexture(Texture, AffineMatrixIdentity,
+         TextureOpacity, TextureRepetition)
   else if FillType = vftGradient then
   else if FillType = vftGradient then
   begin
   begin
-    box := AShape.SuggestGradientBox(AffineMatrixIdentity);
     grad := TBGRALayerGradientOriginal.Create;
     grad := TBGRALayerGradientOriginal.Create;
     grad.StartColor := GradStartColor;
     grad.StartColor := GradStartColor;
     grad.EndColor := GradEndColor;
     grad.EndColor := GradEndColor;
     grad.GradientType:= GradientType;
     grad.GradientType:= GradientType;
     grad.Repetition := GradRepetition;
     grad.Repetition := GradRepetition;
     grad.ColorInterpolation:= GradInterpolation;
     grad.ColorInterpolation:= GradInterpolation;
-    if grad.GradientType = gtLinear then
-    begin
-      grad.Origin := box.TopLeft;
-      grad.XAxis := box.BottomRight;
-    end else
-    begin
-      grad.Origin := (box.TopLeft + box.BottomRight)*0.5;
-      if grad.GradientType = gtReflected then
-        grad.XAxis := box.BottomRight
-      else
-      begin
-        grad.XAxis := (box.TopRight + box.BottomRight)*0.5;
-        grad.YAxis := (box.BottomLeft + box.BottomRight)*0.5;
-      end;
-    end;
     result := TVectorialFill.CreateAsGradient(grad, true);
     result := TVectorialFill.CreateAsGradient(grad, true);
   end
   end
-  else result := nil; //none
+  else exit(nil); //none
+
+  result.FitGeometry(AShape.SuggestGradientBox(AffineMatrixIdentity));
 end;
 end;
 
 
 procedure TVectorialFillInterface.UpdateShapeFill(AShape: TVectorShape;
 procedure TVectorialFillInterface.UpdateShapeFill(AShape: TVectorShape;