Selaa lähdekoodia

script colors

johann 5 vuotta sitten
vanhempi
commit
8920808cf4

+ 50 - 6
lazpaint/dialog/color/uadjustcurves.pas

@@ -642,15 +642,47 @@ end;
 
 procedure TFAdjustCurves.EnsureCurveExist(AParameters: TVariableSet;
   AName: string);
+var
+  listX, listY: TScriptVariableReference;
+  post: Boolean;
+  cnt: NativeInt;
+  i: Integer;
 begin
   if not AParameters.IsDefined(AName) then
-  with AParameters.AddSubset(AName) do
+    AParameters.AddSubset(AName);
+
+  with AParameters.Subsets[AName] do
   begin
-    if AParameters.Booleans['Posterize'] then
-      AddList('X','[0.0, 0.5]') else
-      AddList('X','[0.0, 1.0]');
+    post := Booleans['Posterize'];
+    listX := GetVariable('X');
+    listY := GetVariable('Y');
+    if not IsList(listX) or (GetListCount(listX)<=integer(not post)) then Remove(listX);
+    if not IsList(listY) or (GetListCount(listY)<=integer(not post)) then Remove(listY);
+
+    if IsReferenceDefined(listX) then cnt := GetListCount(listX)
+    else if IsReferenceDefined(listY) then cnt := GetListCount(listY)
+    else cnt := 2;
+
+    if not IsReferenceDefined(listX) then
+    begin
+      listX := AddFloatList('X');
+      if Booleans['Posterize'] then
+        for i := 0 to cnt-1 do
+          AppendFloat(listX, i/cnt)
+      else
+        for i := 0 to cnt-1 do
+          AppendFloat(listX, i/(cnt-1));
+    end;
 
-    AddList('Y','[0.0, 1.0]');
+    if not IsReferenceDefined(listY) then
+    begin
+      listY := AddFloatList('Y');
+      if cnt > 0 then
+        for i := 0 to cnt-1 do
+          AppendFloat(listY, i/(cnt-1))
+      else
+        AppendFloat(listY, 0);
+    end;
   end;
 end;
 
@@ -790,6 +822,7 @@ function TFAdjustCurves.ShowModal(AInstance: TLazPaintCustomInstance;
 var
   topmostInfo: TTopMostInfo;
   tempParameters: TVariableSet;
+  task: TAdjustCurvesTask;
 
   procedure CopyCurveIfNonTrivial(ASource: TVariableSet; AName: string);
   var subset: TVariableSet;
@@ -841,7 +874,18 @@ begin
     topmostInfo := AInstance.HideTopmost;
     ToolBar8.Images := AInstance.Icons[DoScaleY(16,OriginalDPI)];
     try
-      Result := self.ShowModal;
+      if tempParameters.Booleans['Validate'] then
+      begin
+        task := TAdjustCurvesTask.Create(FFilterConnector);
+        try
+          task.Execute;
+        finally
+          task.Free;
+        end;
+        FFilterConnector.ValidateAction;
+        result := mrOk;
+      end else
+        Result := self.ShowModal;
     except
       on ex: Exception do
       begin

+ 8 - 3
lazpaint/dialog/color/ucolorintensity.pas

@@ -217,6 +217,7 @@ end;
 function TFColorIntensity.ShowModal(AInstance: TLazPaintCustomInstance;
   AMode: TColorIntensityMode; AParameters: TVariableSet): integer;
 var topmostInfo: TTopMostInfo;
+  f, s: Double;
 begin
   FMode := AMode;
   try
@@ -232,11 +233,15 @@ begin
   end;
   try
     FInstance := AInstance;
-    if AParameters.IsDefined('Factor') and AParameters.IsDefined('Shift') then
+    if AParameters.Booleans['Validate'] then
     begin
+      if AParameters.IsDefined('Factor') then f := AParameters.Floats['Factor']
+      else f := ChosenFactor;
+      if AParameters.IsDefined('Shift') then s := AParameters.Floats['Shift']
+      else s := ChosenShift;
       case FMode of
-        ciIntensity: FilterIntensity(FFilterConnector, AParameters.Floats['Factor'],AParameters.Floats['Shift']);
-        ciLightness: FilterLightness(FFilterConnector, AParameters.Floats['Factor'],AParameters.Floats['Shift']);
+        ciIntensity: FilterIntensity(FFilterConnector, f,s);
+        ciLightness: FilterLightness(FFilterConnector, f,s);
       end;
       FFilterConnector.ValidateAction;
       result := mrOk;

+ 9 - 2
lazpaint/dialog/color/ucolorize.pas

@@ -296,6 +296,7 @@ end;
 function TFColorize.ShowModal(AInstance: TLazPaintCustomInstance; AParameters: TVariableSet): integer;
 var gsbaOptionFromConfig: boolean;
     topmostInfo: TTopMostInfo;
+    h, s: Double; corr: boolean;
 begin
   try
     FFilterConnector := TFilterConnector.Create(AInstance,AParameters,false);
@@ -310,9 +311,15 @@ begin
   end;
   try
     FInstance := AInstance;
-    if AParameters.IsDefined('Correction') and AParameters.IsDefined('Hue') and AParameters.IsDefined('Saturation') then
+    if AParameters.Booleans['Validate'] then
     begin
-      Colorize(FFilterConnector, AParameters.Floats['Hue'], AParameters.Floats['Saturation'], AParameters.Booleans['Correction']);
+      if AParameters.IsDefined('Hue') then h := AParameters.Floats['Hue']
+      else h := FloatSpinEdit_Hue.Value;
+      if AParameters.IsDefined('Saturation') then s := AParameters.Floats['Saturation']
+      else s := FloatSpinEdit_Saturation.Value;
+      if AParameters.IsDefined('Correction') then corr := AParameters.Booleans['Correction']
+      else corr := AInstance.Config.DefaultUseGSBA;
+      Colorize(FFilterConnector, h, s, corr);
       FFilterConnector.ValidateAction;
       result := mrOk;
     end else

+ 9 - 2
lazpaint/dialog/color/ushiftcolors.pas

@@ -194,6 +194,7 @@ end;
 function TFShiftColors.ShowModal(AInstance: TLazPaintCustomInstance; AParameters: TVariableSet): integer;
 var gsbaOptionFromConfig: boolean;
     topmostInfo: TTopMostInfo;
+    h, s: Double; corr: boolean;
 begin
   try
     FFilterConnector := TFilterConnector.Create(AInstance,AParameters,false);
@@ -208,9 +209,15 @@ begin
   end;
   try
     FInstance := AInstance;
-    if AParameters.IsDefined('Correction') and AParameters.IsDefined('Hue') and AParameters.IsDefined('Saturation') then
+    if AParameters.Booleans['Validate'] then
     begin
-      ShiftColors(FFilterConnector, AParameters.Floats['Hue'], AParameters.Floats['Saturation'], AParameters.Booleans['Correction']);
+      if AParameters.IsDefined('Hue') then h := AParameters.Floats['Hue']
+      else h := FloatSpinEdit_Hue.Value;
+      if AParameters.IsDefined('Saturation') then s := AParameters.Floats['Saturation']
+      else s := FloatSpinEdit_Saturation.Value;
+      if AParameters.IsDefined('Correction') then corr := AParameters.Booleans['Correction']
+      else corr := AInstance.Config.DefaultUseGSBA;
+      ShiftColors(FFilterConnector, h, s, corr);
       FFilterConnector.ValidateAction;
       result := mrOk;
     end else

+ 32 - 16
lazpaint/dialog/filter/uposterize.pas

@@ -29,6 +29,7 @@ type
     FInitializing: boolean;
     FFilterConnector: TFilterConnector;
     procedure OnTryStopAction({%H-}sender: TFilterConnector);
+    procedure InitParams;
     procedure PreviewNeeded;
     { private declarations }
   public
@@ -59,10 +60,20 @@ begin
   end;
   topmostInfo := AInstance.HideTopmost;
   try
-    if FPosterize.ShowModal = mrOK then
-      result := srOk
-    else
-      result := srCancelledByUser;
+    if Assigned(FPosterize.FFilterConnector.Parameters) and
+       FPosterize.FFilterConnector.Parameters.Booleans['Validate'] then
+    begin
+      FPosterize.InitParams;
+      FPosterize.PreviewNeeded;
+      FPosterize.FFilterConnector.ValidateAction;
+      result := srOk;
+    end else
+    begin
+      if FPosterize.ShowModal = mrOK then
+        result := srOk
+      else
+        result := srCancelledByUser;
+    end;
   finally
     AInstance.ShowTopmost(topmostInfo);
     FPosterize.FFilterConnector.OnTryStopAction := nil;
@@ -96,18 +107,7 @@ end;
 
 procedure TFPosterize.FormShow(Sender: TObject);
 begin
-  FInitializing := true;
-  if Assigned(FFilterConnector.Parameters) and
-     FFilterConnector.Parameters.IsDefined('Levels') then
-    SpinEdit_Levels.Value := FFilterConnector.Parameters.Integers['Levels']
-  else
-    SpinEdit_Levels.Value := FFilterConnector.LazPaintInstance.Config.DefaultPosterizeLevels;
-  if Assigned(FFilterConnector.Parameters) and
-     FFilterConnector.Parameters.IsDefined('ByLightness') then
-    CheckBox_ByLightness.Checked := FFilterConnector.Parameters.Booleans['ByLightness']
-  else
-    CheckBox_ByLightness.Checked := FFilterConnector.LazPaintInstance.Config.DefaultPosterizeByLightness;
-  FInitializing := false;
+  InitParams;
   PreviewNeeded;
   Top := FFilterConnector.LazPaintInstance.MainFormBounds.Top;
 end;
@@ -122,6 +122,22 @@ begin
   if self.visible then Close;
 end;
 
+procedure TFPosterize.InitParams;
+begin
+  FInitializing := true;
+  if Assigned(FFilterConnector.Parameters) and
+     FFilterConnector.Parameters.IsDefined('Levels') then
+    SpinEdit_Levels.Value := FFilterConnector.Parameters.Integers['Levels']
+  else
+    SpinEdit_Levels.Value := FFilterConnector.LazPaintInstance.Config.DefaultPosterizeLevels;
+  if Assigned(FFilterConnector.Parameters) and
+     FFilterConnector.Parameters.IsDefined('ByLightness') then
+    CheckBox_ByLightness.Checked := FFilterConnector.Parameters.Booleans['ByLightness']
+  else
+    CheckBox_ByLightness.Checked := FFilterConnector.LazPaintInstance.Config.DefaultPosterizeByLightness;
+  FInitializing := false;
+end;
+
 procedure TFPosterize.PreviewNeeded;
 var params:TVariableSet;
   levels: integer;

+ 2 - 0
lazpaint/image/uimage.pas

@@ -1919,6 +1919,8 @@ end;
 
 procedure TLazPaintImage.MoveLayer(AFromIndex, AToIndex: integer);
 begin
+  if (AFromIndex < 0) or (AFromIndex >= NbLayers) then
+    raise exception.Create('Index out of bounds');
   if not CheckNoAction then exit;
   try
     AddUndo(FCurrentState.MoveLayer(AFromIndex,AToIndex));

+ 12 - 0
lazpaint/image/uimageaction.pas

@@ -21,6 +21,7 @@ type
     procedure ChooseTool(ATool: TPaintToolType);
     procedure RegisterScripts(ARegister: Boolean);
     function GenericScriptFunction(AVars: TVariableSet): TScriptResult;
+    function ScriptImageMoveLayerIndex(AVars: TVariableSet): TScriptResult;
     function ScriptLayerFromFile(AVars: TVariableSet): TScriptResult;
     function ScriptLayerSelectId(AVars: TVariableSet): TScriptResult;
     function ScriptLayerAddNew(AVars: TVariableSet): TScriptResult;
@@ -153,6 +154,7 @@ begin
   Scripting.RegisterScriptFunction('LayerRasterize',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerMergeOver',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerRemoveCurrent',@GenericScriptFunction,ARegister);
+  Scripting.RegisterScriptFunction('ImageMoveLayerIndex',@ScriptImageMoveLayerIndex,ARegister);
   Scripting.RegisterScriptFunction('GetLayerIndex',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('SelectLayerIndex',@ScriptSelectLayerIndex,ARegister);
   Scripting.RegisterScriptFunction('GetLayerCount',@GenericScriptFunction,ARegister);
@@ -226,6 +228,16 @@ begin
     result := srFunctionNotDefined;
 end;
 
+function TImageActions.ScriptImageMoveLayerIndex(AVars: TVariableSet): TScriptResult;
+begin
+  try
+    Image.MoveLayer(AVars.Integers['FromIndex']-1, AVars.Integers['ToIndex']-1);
+  except
+    on ex:exception do
+      result := srException;
+  end;
+end;
+
 function TImageActions.ScriptLayerFromFile(AVars: TVariableSet): TScriptResult;
 begin
   if not AVars.IsDefined('FileName') then exit(srInvalidParameters) else

+ 8 - 0
scripts/layer_shadow.py

@@ -0,0 +1,8 @@
+from lazpaint import colors, image, layer, filters
+
+layer.duplicate()
+shadow_index = image.get_layer_index()
+image.move_layer_index(shadow_index, shadow_index-1)
+colors.lightness(shift=-1)
+filters.blur(radius=10)
+

+ 55 - 1
scripts/lazpaint/colors.py

@@ -1,9 +1,17 @@
 import collections
-from lazpaint import dialog
+from lazpaint import dialog, command, filters
+
+GAMMA = 2.2
 
 if __name__ == "__main__":
   dialog.show_message("Library defining colors.")
 
+def to_linear(std_value):
+  return (std_value/255)^(1/gamma)
+
+def to_std(linear_value):
+  return round((linear_value^gamma)*255)
+
 CustomRGBA = collections.namedtuple("RGBA", "red, green, blue, alpha")
 class RGBA(CustomRGBA):
   def __repr__(self):
@@ -13,6 +21,13 @@ class RGBA(CustomRGBA):
       return '#{:02X}{:02X}{:02X}'.format(self.red,self.green,self.blue) 
   def __str__(self):
     return '{:02X}{:02X}{:02X}{:02X}'.format(self.red,self.green,self.blue,self.alpha)
+  def negative(self):
+    return RGBA(to_std(1-to_linear(self.red)), to_std(1-to_linear(self.green)), to_std(1-to_linear(self.blue)), self.alpha)
+  def linear_negative(self):
+    return RGBA(255-self.red, 255-self.green, 255-self.blue, self.alpha)
+  def grayscale(self):
+    gray = to_std(to_linear(self.red)*0.299 + to_linear(self.green)*0.587 + to_linear(self.blue)*0.114)
+    return RGBA(gray, gray, gray, self.alpha)
 
 def RGB(red,green,blue):
   return RGBA(red,green,blue,255)
@@ -48,3 +63,42 @@ PURPLE = RGB(128,0,128)
 OLIVE = RGB(128,128,0)
 SILVER = RGB(192,192,192)
 
+def get_curve(points, posterize=False):
+  return {'X': [float(pt[0]) for pt in points], 'Y': [float(pt[1]) for pt in points], 'Posterize': posterize}
+
+def curves(red=[], red_posterize=False, green=[], green_posterize=False, blue=[], blue_posterize=False, hue=[], hue_posterize=False, saturation=[], saturation_posterize=False, lightness=[], lightness_posterize=False, validate=True):
+  command.send('ColorCurves', Red=get_curve(red, red_posterize), Green=get_curve(green, green_posterize), Blue=get_curve(blue, blue_posterize), Hue=get_curve(hue, hue_posterize), Saturation=get_curve(saturation, saturation_posterize), Lightness=get_curve(lightness, lightness_posterize), Validate=validate)
+
+def posterize(levels=None, by_lightness=True, validate=True):
+  command.send('ColorPosterize', Levels=levels, ByLightness=by_lightness, Validate=validate)
+
+def colorize(hue_angle=None, saturation=None, correction=None, validate=True):
+  command.send('ColorColorize', Hue=hue_angle, Saturation=saturation, Correction=correction, Validate=validate)
+
+def complementary():
+  filters.run(filters.COLOR_COMPLEMENTARY)
+
+def shift(hue_angle=None, saturation=None, correction=None, validate=True):
+  command.send('ColorShiftColors', Hue=hue_angle, Saturation=saturation, Correction=correction, Validate=validate)
+
+def intensity(factor=None, shift=None, validate=True):
+  command.send('ColorIntensity', Factor=factor, Shift=shift, Validate=validate)
+
+def lightness(factor=None, shift=None, validate=True):
+  command.send('ColorLightness', Factor=factor, Shift=shift, Validate=validate)
+
+def negative():
+  filters.run(filters.COLOR_NEGATIVE)
+
+def linear_negative():
+  filters.run(filters.COLOR_LINEAR_NEGATIVE)
+
+def normalize():
+  filters.run(filters.COLOR_NORMALIZE)
+
+def grayscale():
+  filters.run(filters.COLOR_GRAYSCALE)
+
+
+
+

+ 34 - 27
scripts/lazpaint/filters.py

@@ -3,6 +3,7 @@ from lazpaint import command, dialog
 if __name__ == "__main__":
   dialog.show_message("Library to execute filters on the current layer.")
 
+#filters
 BLUR_PRECISE = 'BlurPrecise'
 BLUR_RADIAL = 'BlurRadial'
 BLUR_FAST = 'BlurFast'
@@ -11,42 +12,24 @@ BLUR_CORONA = 'BlurCorona'
 BLUR_DISK = 'BlurDisk'
 BLUR_MOTION = 'BlurMotion'
 BLUR_CUSTOM = 'BlurCustom'
+PIXELATE = 'Pixelate'
+
 SHARPEN = 'Sharpen'
 SMOOTH = 'Smooth'
 MEDIAN = 'Median'
 NOISE = 'Noise'
-PIXELATE = 'Pixelate'
 CLEAR_TYPE = 'ClearType'
 CLEAR_TYPE_INVERSE = 'ClearTypeInverse'
 FILTER_FUNCTION = 'Function'
+CONTOUR = 'Contour'
 EMBOSS = 'Emboss'
 PHONG = 'Phong'
-CONTOUR = 'Contour'
-GRAYSCALE = 'Grayscale'
-NEGATIVE = 'Negative'
-LINEAR_NEGATIVE = 'LinearNegative'
-COMPLEMENTARY_COLOR = 'ComplementaryColor'
-NORMALIZE = 'Normalize'
+
 SPHERE = 'Sphere'
 TWIRL = 'Twirl'
 WAVE_DISPLACEMENT = 'WaveDisplacement'
 CYLINDER = 'Cylinder'
 PLANE = 'Plane'
-PERLIN_NOISE = 'PerlinNoise'
-CYCLIC_PERLIN_NOISE = 'CyclicPerlinNoise'
-CLOUDS = 'Clouds'
-CUSTOM_WATER = 'CustomWater'
-WATER = 'Water'
-RAIN = 'Rain'
-WOOD = 'Wood'
-WOOD_VERTICAL = 'WoodVertical'
-PLASTIK = 'Plastik'
-METAL_FLOOR = 'MetalFloor'
-CAMOUFLAGE = 'Camouflage'
-SNOW_PRINT = 'SnowPrint'
-STONE = 'Stone'
-ROUND_STONE = 'RoundStone'
-MARBLE = 'Marble'
 
 PIXELATE_QUALITY_FAST = 'Fast'
 PIXELATE_QUALITY_LINEAR = 'Linear'
@@ -66,10 +49,37 @@ PHONG_ALTITUDE_RED_CHANNEL = 'Red'
 PHONG_ALTITUDE_GREEN_CHANNEL = 'Green'
 PHONG_ALTITUDE_BLUE_CHANNEL = 'Blue'
 
+#colors
+COLOR_COMPLEMENTARY = 'ComplementaryColor'
+COLOR_NEGATIVE = 'Negative'
+COLOR_LINEAR_NEGATIVE = 'LinearNegative'
+COLOR_NORMALIZE = 'Normalize'
+COLOR_GRAYSCALE = 'Grayscale'
+
+#render
+RENDER_PERLIN_NOISE = 'PerlinNoise'
+RENDER_CYCLIC_PERLIN_NOISE = 'CyclicPerlinNoise'
+RENDER_CLOUDS = 'Clouds'
+RENDER_CUSTOM_WATER = 'CustomWater'
+RENDER_WATER = 'Water'
+RENDER_RAIN = 'Rain'
+RENDER_WOOD = 'Wood'
+RENDER_WOOD_VERTICAL = 'WoodVertical'
+RENDER_PLASTIK = 'Plastik'
+RENDER_METAL_FLOOR = 'MetalFloor'
+RENDER_CAMOUFLAGE = 'Camouflage'
+RENDER_SNOW_PRINT = 'SnowPrint'
+RENDER_STONE = 'Stone'
+RENDER_ROUND_STONE = 'RoundStone'
+RENDER_MARBLE = 'Marble'
+
 def run(name, validate=True):
-  command.send("Filter", Name=name, Validate=validate)
+  if name[0:5] == "Color":
+    command.send(name, Validate=validate)
+  else:
+    command.send("Filter", Name=name, Validate=validate)
 
-def blur(name, radius=None, radius_x=None, radius_y=None, validate=True):
+def blur(name=BLUR_FAST, radius=None, radius_x=None, radius_y=None, validate=True):
   command.send("Filter", Name=name, Radius=radius, RadiusX=radius_x, RadiusY=radius_y, Validate=validate)
 
 def blur_motion(distance=None, angle=None, oriented=None, validate=True):
@@ -93,9 +103,6 @@ def emboss(angle=None, transparent=None, preserve_colors=None, validate=True):
 def rain(amount=None, wind=None, validate=True):
   command.send("Filter", Name=RAIN, Amount=amount, Wind=wind, Validate=validate)
 
-def posterize(levels=None, by_lightness=None, validate=True):
-  command.send("Filter", Name=POSTERIZE, Levels=levels, ByLightness=by_lightness, Validate=validate)
-
 def phong(color_source=None, altitude_percent=None, altitude_source=None, light_x_percent=None, light_y_percent=None, validate=True):
   command.send("Filter", Name=PHONG, ColorSource=color_source, AltitudePercent=altitude_percent, AltitudeSource=altitude_source, LightXPercent=light_x_percent, LightYPercent=light_y_percent, Validate=validate)
 

+ 3 - 0
scripts/lazpaint/image.py

@@ -18,6 +18,9 @@ def get_layer_index():
 def select_layer_index(index):
   return command.send("SelectLayerIndex", Index=index)
 
+def move_layer_index(from_index, to_index):
+  return command.send("ImageMoveLayerIndex", FromIndex=from_index, ToIndex=to_index)
+
 def get_layer_count():
   return command.send("GetLayerCount?")
 

+ 10 - 0
scripts/test_color.py

@@ -0,0 +1,10 @@
+from lazpaint import colors, image
+
+#image.flatten()
+colors.curves(red=[(0, 0), (0.25, 1), (1, 1)])
+colors.curves(lightness=[(0, 0), (0.25, 1), (1, 1)])
+colors.posterize(levels=8, by_lightness=True)
+colors.colorize(hue_angle=0, saturation=0.8, correction=False)
+colors.complementary()
+colors.shift(hue_angle=90, saturation=0, correction=True)
+