1 // SPDX-License-Identifier: GPL-3.0-only
2 unit UImageState;
3 
4 {$mode objfpc}{$H+}
5 
6 interface
7 
8 uses
9   Classes, SysUtils, UStateType, BGRABitmap, BGRABitmapTypes, Types, BGRALayers,
10   UImageType, BGRAWriteLzp, BGRAReadLzp, FPimage, BGRALayerOriginal;
11 
12 type
13   TBoundsState = (bsUndefined, bsWithinCurrent, bsDefined);
14 
15   { TImageState }
16 
17   TImageState = class(TState)
18   private
19     FLayeredBitmap: TBGRALayeredBitmap;
20     FOnActionDone: TNotifyEvent;
21     FOnActionProgress: TLayeredActionProgressEvent;
22     FOnOriginalChange: TEmbeddedOriginalChangeEvent;
23     FOnOriginalEditingChange: TEmbeddedOriginalEditingChangeEvent;
24     FOnOriginalLoadError: TEmbeddedOriginalLoadErrorEvent;
25     FOnSizeChanged: TNotifyEvent;
26     FSelectionMask: TBGRABitmap;
27     FLastSelectionMaskBoundsIsDefined,
28     FLastSelectionLayerBoundsIsDefined: TBoundsState;
29     FLastSelectionMaskBounds, FLastSelectionLayerBounds: TRect;
30     FSelectionTransform: TAffineMatrix;
GetBlendOpnull31     function GetBlendOp(Index: integer): TBlendOperation;
GetSelectedImageLayernull32     function GetSelectedImageLayer: TBGRABitmap;
GetCurrentLayerIndexnull33     function GetCurrentLayerIndex: integer;
GetSelectionMasknull34     function GetSelectionMask: TBGRABitmap;
GetHasOriginalsnull35     function GetHasOriginals: boolean;
GetHeightnull36     function GetHeight: integer;
GetLayerBitmapnull37     function GetLayerBitmap(Index: integer): TBGRABitmap;
GetLayerBitmapByIdnull38     function GetLayerBitmapById(AId: integer): TBGRABitmap;
GetLayerIdnull39     function GetLayerId(Index: integer): integer;
GetLayerNamenull40     function GetLayerName(Index: integer): string;
GetLayerOffsetnull41     function GetLayerOffset(Index: integer): TPoint;
GetLayerOpacitynull42     function GetLayerOpacity(Index: integer): byte;
GetLayerOriginalnull43     function GetLayerOriginal(Index: integer): TBGRALayerCustomOriginal;
GetLayerOriginalDefinednull44     function GetLayerOriginalDefined(Index: integer): boolean;
GetLayerOriginalKnownnull45     function GetLayerOriginalKnown(Index: integer): boolean;
GetLayerOriginalClassnull46     function GetLayerOriginalClass(Index: integer): TBGRALayerOriginalAny;
GetLayerOriginalMatrixnull47     function GetLayerOriginalMatrix(Index: integer): TAffineMatrix;
GetLayerVisiblenull48     function GetLayerVisible(Index: integer): boolean;
GetLinearBlendnull49     function GetLinearBlend: boolean;
GetNbLayersnull50     function GetNbLayers: integer;
GetWidthnull51     function GetWidth: integer;
52     procedure LayeredActionDone(Sender: TObject);
53     procedure LayeredActionProgress({%H-}ASender: TObject; AProgressPercent: integer);
54     procedure OriginalChange({%H-}ASender: TObject;
55       AOriginal: TBGRALayerCustomOriginal; var ADiff: TBGRAOriginalDiff);
56     procedure OriginalEditingChange({%H-}ASender: TObject;
57       AOriginal: TBGRALayerCustomOriginal);
58     procedure OriginalLoadError(ASender: TObject; AError: string;
59       var ARaise: boolean);
60     procedure SelectImageLayer(AValue: TBGRABitmap);
61     procedure SelectImageLayerByIndex(AValue: integer);
62     procedure SetLayeredBitmap(AValue: TBGRALayeredBitmap);
63     procedure SetLinearBlend(AValue: boolean);
64     procedure SetOnActionDone(AValue: TNotifyEvent);
65     procedure SetOnActionProgress(AValue: TLayeredActionProgressEvent);
66     procedure SetOnSizeChanged(AValue: TNotifyEvent);
67     procedure SetSelectionMask(AValue: TBGRABitmap);
MakeLayerNamenull68     function MakeLayerName: string;
69     procedure CheckSizeChanged(APrevSize: TSize);
GetSizenull70     function GetSize: TSize;
71   public
72     SelectionLayer: TBGRABitmap;
73     selectedLayerId: integer;
74     filenameUTF8: string;
75     DiscardOriginalDiff: boolean;
76 
77     // generic state functions
78     constructor Create;
79     destructor Destroy; override;
Equalsnull80     function Equals(Obj: TObject): boolean; override;
81     procedure ApplyDifference(ADifference: TStateDifference); override;
82     procedure ReverseDifference(ADifference: TStateDifference); override;
Duplicatenull83     function Duplicate: TState; override;
84 
85     // whole image
86     procedure SetSize(AWidth,AHeight: integer);
87     procedure NotifySizeChanged;
88     procedure Assign(AValue: TBGRABitmap; AOwned: boolean);
89     procedure Assign(AValue: TBGRACustomLayeredBitmap; AOwned: boolean);
90     procedure Assign(AValue: TImageState; AOwned: boolean);
91 
RotateCWnull92     function RotateCW: TCustomImageDifference;
RotateCCWnull93     function RotateCCW: TCustomImageDifference;
Rotate180null94     function Rotate180: TCustomImageDifference;
HorizontalFlipnull95     function HorizontalFlip: TCustomImageDifference; overload;
VerticalFlipnull96     function VerticalFlip: TCustomImageDifference; overload;
97     procedure Resample(AWidth,AHeight: integer; AQuality: TResampleMode; AFilter: TResampleFilter);
98 
99     // layer
100     procedure SetLayerBitmap(layer: integer; ABitmap: TBGRABitmap; AOwned: boolean);
HorizontalFlipnull101     function HorizontalFlip(ALayerIndex: integer): TCustomImageDifference; overload;
VerticalFlipnull102     function VerticalFlip(ALayerIndex: integer): TCustomImageDifference; overload;
103 
104     // selection mask
105     procedure QuerySelectionMask;
106     procedure ReplaceSelection(ASelectionMask, ASelectionLayer: TBGRABitmap);
107     procedure RemoveSelection;
108 
109     procedure DiscardSelectionMaskBounds(const AChangeRect: TRect);
110     procedure DiscardSelectionMaskBoundsCompletely;
GetSelectionMaskBoundsnull111     function GetSelectionMaskBounds: TRect;
SelectionMaskEmptynull112     function SelectionMaskEmpty: boolean;
SelectionMaskEmptyComputednull113     function SelectionMaskEmptyComputed: boolean;
GetTransformedSelectionMaskBoundsnull114     function GetTransformedSelectionMaskBounds: TRect;
115     procedure ComputeTransformedSelectionMask(out ANewMask: TBGRABitmap; out ALeft,ATop: integer);
116 
117     // selection layer
GetOrCreateSelectionLayernull118     function GetOrCreateSelectionLayer: TBGRABitmap;
119     procedure ReplaceSelectionLayer(bmp: TBGRABitmap; AOwned: boolean);
120     procedure ComputeTransformedSelectionLayer(out ANewLayer: TBGRABitmap; out ALeft,ATop: integer);
121 
122     procedure DiscardSelectionLayerBounds(const AChangeRect: TRect);
123     procedure DiscardSelectionLayerBoundsCompletely;
GetSelectionLayerBoundsnull124     function GetSelectionLayerBounds: TRect;
SelectionLayerEmptynull125     function SelectionLayerEmpty: boolean;
126 
127     procedure PrepareForRendering;
ComputeFlatImageWithoutSelectionnull128     function ComputeFlatImageWithoutSelection(ASeparateXorMask: boolean): TBGRABitmap;
AssignWithUndonull129     function AssignWithUndo(AValue: TBGRACustomLayeredBitmap; AOwned: boolean; ASelectedLayerIndex: integer): TCustomImageDifference;
AssignWithUndonull130     function AssignWithUndo(AValue: TBGRACustomLayeredBitmap; AOwned: boolean; ASelectedLayerIndex: integer; ACurrentSelection: TBGRABitmap; ASelectionLayer:TBGRABitmap): TCustomImageDifference;
AssignWithUndonull131     function AssignWithUndo(AState: TImageState; AOwned: boolean): TCustomImageDifference;
GetUndoAfterAssignnull132     function GetUndoAfterAssign(ABackup: TImageState): TCustomImageDifference;
133     procedure LoadFromStream(AStream: TStream);
134     procedure SaveToStream(AStream: TStream);
135     procedure SaveToStreamAs(AStream: TStream; AFormat: TBGRAImageFormat);
136     procedure SaveOriginalToStream(AStream: TStream);
137     procedure SaveToFile(AFilenameUTF8: string);
AddNewLayernull138     function AddNewLayer(ALayer: TBGRABitmap; AName: string; AOffset: TPoint; ABlendOp: TBlendOperation; AOpacity: byte = 255): TCustomImageDifference;
AddNewLayernull139     function AddNewLayer(AOriginal: TBGRALayerCustomOriginal; AName: string; ABlendOp: TBlendOperation; AMatrix: TAffineMatrix; AOpacity: byte = 255): TCustomImageDifference;
DuplicateLayernull140     function DuplicateLayer: TCustomImageDifference;
MergerLayerOvernull141     function MergerLayerOver(ALayerOverIndex: integer): TCustomImageDifference;
MoveLayernull142     function MoveLayer(AFromIndex,AToIndex: integer): TCustomImageDifference;
RemoveLayernull143     function RemoveLayer: TCustomImageDifference;
DiscardOriginalnull144     function DiscardOriginal(ACreateUndo: boolean): TCustomImageDifference;
SwapRedBluenull145     function SwapRedBlue: TCustomImageDifference;
LinearNegativenull146     function LinearNegative: TCustomImageDifference;
Negativenull147     function Negative: TCustomImageDifference;
ClearLayernull148     function ClearLayer: TCustomImageDifference;
ComputeLayerOffsetDifferencenull149     function ComputeLayerOffsetDifference(AOffsetX, AOffsetY: integer): TCustomImageDifference;
ComputeSelectionTransformDifferencenull150     function ComputeSelectionTransformDifference: TCustomImageDifference;
ComputeLayerMatrixDifferencenull151     function ComputeLayerMatrixDifference(AIndex: integer; APrevMatrix, ANewMatrix: TAffineMatrix): TCustomImageDifference;
ComputeLayerDifferencenull152     function ComputeLayerDifference(APreviousImage: TBGRABitmap; APreviousImageDefined: boolean;
153         APreviousSelection: TBGRABitmap; APreviousSelectionDefined: boolean;
154         APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerDefined: boolean): TCustomImageDifference; overload;
ComputeLayerDifferencenull155     function ComputeLayerDifference(APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
156         APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
157         APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect): TCustomImageDifference; overload;
GetLayeredBitmapCopynull158     function GetLayeredBitmapCopy: TBGRALayeredBitmap;
ComputeFlatImagenull159     function ComputeFlatImage(AFromLayer, AToLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
ComputeFlatImagenull160     function ComputeFlatImage(ARect: TRect; AFromLayer, AToLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
SetLayerNamenull161     function SetLayerName(Index: integer; AValue: string): TCustomImageDifference;
SetLayerOpacitynull162     function SetLayerOpacity(Index: integer; AValue: byte): TCustomImageDifference;
SetLayerVisiblenull163     function SetLayerVisible(Index: integer; AValue: boolean): TCustomImageDifference;
SetLayerOffsetnull164     function SetLayerOffset(Index: integer; AValue: TPoint): TCustomImageDifference;
SetBlendOpnull165     function SetBlendOp(Index: integer; AValue: TBlendOperation): TCustomImageDifference;
166     procedure DrawLayers(ADest: TBGRABitmap; X,Y: Integer; AIconCursor: boolean; ADestinationEmpty: boolean = false);
167     property SelectedImageLayer: TBGRABitmap read GetSelectedImageLayer write SelectImageLayer;
168     property SelectedImageLayerIndex: integer read GetCurrentLayerIndex write SelectImageLayerByIndex;
169     property LayerOriginal[Index: integer]: TBGRALayerCustomOriginal read GetLayerOriginal;
170     property LayerOriginalDefined[Index: integer]: boolean read GetLayerOriginalDefined;
171     property LayerOriginalKnown[Index: integer]: boolean read GetLayerOriginalKnown;
172     property LayerOriginalClass[Index: integer]: TBGRALayerOriginalAny read GetLayerOriginalClass;
173     property LayerOriginalMatrix[Index: integer]: TAffineMatrix read GetLayerOriginalMatrix;
174     property LayerBitmap[Index: integer]: TBGRABitmap read GetLayerBitmap;
175     property LayerBitmapById[AId: integer]: TBGRABitmap read GetLayerBitmapById;
176     property BlendOperation[Index: integer]: TBlendOperation read GetBlendOp;
177     property LayerOpacity[Index: integer]: byte read GetLayerOpacity;
178     property LayerOffset[Index: integer]: TPoint read GetLayerOffset;
179     property LayerName[Index: integer]: string read GetLayerName;
180     property LayerId[Index: integer]: integer read GetLayerId;
181     property NbLayers: integer read GetNbLayers;
182     property Width: integer read GetWidth;
183     property Height: integer read GetHeight;
184     property LinearBlend: boolean read GetLinearBlend write SetLinearBlend;
185     property LayerVisible[Index: integer]: boolean read GetLayerVisible;
186     property HasOriginals: boolean read GetHasOriginals;
187     property SelectionMask: TBGRABitmap read GetSelectionMask write SetSelectionMask;
188     property LayeredBitmap: TBGRALayeredBitmap read FLayeredBitmap;
189     property SelectionTransform: TAffineMatrix read FSelectionTransform write FSelectionTransform;
190     property OnOriginalChange: TEmbeddedOriginalChangeEvent read FOnOriginalChange write FOnOriginalChange;
191     property OnOriginalEditingChange: TEmbeddedOriginalEditingChangeEvent read FOnOriginalEditingChange write FOnOriginalEditingChange;
192     property OnOriginalLoadError: TEmbeddedOriginalLoadErrorEvent read FOnOriginalLoadError write FOnOriginalLoadError;
193     property OnActionProgress: TLayeredActionProgressEvent read FOnActionProgress write SetOnActionProgress;
194     property OnActionDone: TNotifyEvent read FOnActionDone write SetOnActionDone;
195     property OnSizeChanged: TNotifyEvent read FOnSizeChanged write SetOnSizeChanged;
196   end;
197 
198 implementation
199 
200 uses BGRAStreamLayers, UImageDiff, BGRALzpCommon, UFileSystem, BGRATransform,
201   UResourceStrings, LCVectorOriginal, UGraph;
202 
203 { TImageState }
204 
GetSelectedImageLayernull205 function TImageState.GetSelectedImageLayer: TBGRABitmap;
206 var idx: integer;
207 begin
208   if LayeredBitmap = nil then
209   begin
210     result := nil;
211     exit;
212   end else
213   begin
214     idx := LayeredBitmap.GetLayerIndexFromId(selectedLayerId);
215     if idx = -1 then result := nil else
216       result := LayeredBitmap.LayerBitmap[idx]; //assume direct access to bitmap
217   end;
218 end;
219 
GetBlendOpnull220 function TImageState.GetBlendOp(Index: integer): TBlendOperation;
221 begin
222   if LayeredBitmap = nil then
223     result := boTransparent
224   else
225     result := LayeredBitmap.BlendOperation[Index];
226 end;
227 
GetLayerOriginalClassnull228 function TImageState.GetLayerOriginalClass(Index: integer): TBGRALayerOriginalAny;
229 begin
230   if LayeredBitmap = nil then
231     result := nil
232   else
233     result := LayeredBitmap.LayerOriginalClass[Index];
234 end;
235 
GetCurrentLayerIndexnull236 function TImageState.GetCurrentLayerIndex: integer;
237 begin
238   if LayeredBitmap = nil then
239   begin
240     result := -1;
241   end else
242     result := LayeredBitmap.GetLayerIndexFromId(selectedLayerId);
243 end;
244 
TImageState.GetSelectionMasknull245 function TImageState.GetSelectionMask: TBGRABitmap;
246 begin
247   result := FSelectionMask;
248   if Assigned(result) then result.LinearAntialiasing := true;
249 end;
250 
TImageState.GetHasOriginalsnull251 function TImageState.GetHasOriginals: boolean;
252 var
253   i: Integer;
254 begin
255   if LayeredBitmap= nil then
256     result := false
257   else
258   begin
259     for i := 0 to NbLayers-1 do
260       if LayerOriginalDefined[i] then
261         exit(true);
262     result := false
263   end;
264 end;
265 
TImageState.GetHeightnull266 function TImageState.GetHeight: integer;
267 begin
268   if LayeredBitmap= nil then
269     result := 0
270   else
271     result := LayeredBitmap.Height;
272 end;
273 
GetLayerBitmapnull274 function TImageState.GetLayerBitmap(Index: integer): TBGRABitmap;
275 begin
276   result := LayeredBitmap.LayerBitmap[Index];
277 end;
278 
GetLayerBitmapByIdnull279 function TImageState.GetLayerBitmapById(AId: integer): TBGRABitmap;
280 var idx: integer;
281 begin
282   idx := LayeredBitmap.GetLayerIndexFromId(AId);
283   if idx = -1 then
284     result := nil
285   else
286     result := LayeredBitmap.LayerBitmap[idx];
287 end;
288 
TImageState.GetLayerIdnull289 function TImageState.GetLayerId(Index: integer): integer;
290 begin
291   if LayeredBitmap = nil then
292     result := -1
293   else
294     result := LayeredBitmap.LayerUniqueId[index];
295 end;
296 
GetLayerNamenull297 function TImageState.GetLayerName(Index: integer): string;
298 begin
299   if LayeredBitmap = nil then
300     result := ''
301   else
302     result := LayeredBitmap.LayerName[index];
303 end;
304 
GetLayerOffsetnull305 function TImageState.GetLayerOffset(Index: integer): TPoint;
306 begin
307   if LayeredBitmap = nil then
308     result := point(0,0)
309   else
310     result := LayeredBitmap.LayerOffset[index];
311 end;
312 
TImageState.GetLayerOpacitynull313 function TImageState.GetLayerOpacity(Index: integer): byte;
314 begin
315   if LayeredBitmap = nil then
316     result := 255
317   else
318     result := LayeredBitmap.LayerOpacity[index];
319 end;
320 
TImageState.GetLayerOriginalnull321 function TImageState.GetLayerOriginal(Index: integer): TBGRALayerCustomOriginal;
322 begin
323   if LayeredBitmap = nil then
324     result := nil
325   else
326     result := LayeredBitmap.LayerOriginal[Index];
327 end;
328 
GetLayerOriginalDefinednull329 function TImageState.GetLayerOriginalDefined(Index: integer): boolean;
330 begin
331   if LayeredBitmap = nil then
332     result := false
333   else
334     result := LayeredBitmap.LayerOriginalGuid[Index] <> GUID_NULL;
335 end;
336 
TImageState.GetLayerOriginalKnownnull337 function TImageState.GetLayerOriginalKnown(Index: integer): boolean;
338 begin
339   if LayeredBitmap = nil then
340     result := false
341   else
342     result := LayeredBitmap.LayerOriginalKnown[Index];
343 end;
344 
TImageState.GetLayerOriginalMatrixnull345 function TImageState.GetLayerOriginalMatrix(Index: integer): TAffineMatrix;
346 begin
347   if LayeredBitmap = nil then
348     result := AffineMatrixIdentity
349   else
350     result := LayeredBitmap.LayerOriginalMatrix[Index];
351 end;
352 
GetLayerVisiblenull353 function TImageState.GetLayerVisible(Index: integer): boolean;
354 begin
355   if LayeredBitmap = nil then
356     result := false
357   else
358     result := LayeredBitmap.LayerVisible[Index];
359 end;
360 
GetLinearBlendnull361 function TImageState.GetLinearBlend: boolean;
362 begin
363   if LayeredBitmap = nil then
364     result := true
365   else
366     result := LayeredBitmap.LinearBlend;
367 end;
368 
TImageState.GetNbLayersnull369 function TImageState.GetNbLayers: integer;
370 begin
371   if LayeredBitmap = nil then
372     result := 0
373   else
374     result := LayeredBitmap.NbLayers;
375 end;
376 
GetWidthnull377 function TImageState.GetWidth: integer;
378 begin
379   if LayeredBitmap= nil then
380     result := 0
381   else
382     result := LayeredBitmap.Width;
383 end;
384 
385 procedure TImageState.LayeredActionDone(Sender: TObject);
386 begin
387   if Assigned(FOnActionDone) then
388     FOnActionDone(self);
389 end;
390 
391 procedure TImageState.LayeredActionProgress(ASender: TObject;
392   AProgressPercent: integer);
393 begin
394   if Assigned(FOnActionProgress) then
395     FOnActionProgress(self, AProgressPercent);
396 end;
397 
398 procedure TImageState.OriginalChange(ASender: TObject;
399   AOriginal: TBGRALayerCustomOriginal; var ADiff: TBGRAOriginalDiff);
400 begin
401   If Assigned(FOnOriginalChange) then
402   begin
403     if DiscardOriginalDiff then FreeAndNil(ADiff);
404     FOnOriginalChange(self, AOriginal, ADiff);
405   end;
406 end;
407 
408 procedure TImageState.OriginalEditingChange(ASender: TObject;
409   AOriginal: TBGRALayerCustomOriginal);
410 begin
411   If Assigned(FOnOriginalEditingChange) then
412     FOnOriginalEditingChange(self, AOriginal);
413 end;
414 
415 procedure TImageState.OriginalLoadError(ASender: TObject; AError: string;
416   var ARaise: boolean);
417 begin
418   If Assigned(FOnOriginalLoadError) then
419     FOnOriginalLoadError(self, AError, ARaise);
420 end;
421 
422 procedure TImageState.SelectImageLayer(AValue: TBGRABitmap);
423 var
424   i: Integer;
425 begin
426   if LayeredBitmap = nil then exit;
427 
428   for i := 0 to NbLayers-1 do
429     if LayeredBitmap.LayerBitmap[i] = AValue then
430     begin
431       selectedLayerId := LayeredBitmap.LayerUniqueId[i];
432       exit;
433     end;
434   selectedLayerId := -1;
435 end;
436 
437 procedure TImageState.SelectImageLayerByIndex(AValue: integer);
438 begin
439   if (LayeredBitmap = nil) or (AValue < 0) or (AValue >= LayeredBitmap.NbLayers) then
440   begin
441     selectedLayerId := -1;
442   end else
443   begin
444     selectedLayerId := LayeredBitmap.LayerUniqueId[AValue];
445     LayeredBitmap.Unfreeze(AValue);
446   end;
447 end;
448 
449 procedure TImageState.SetLayeredBitmap(AValue: TBGRALayeredBitmap);
450 begin
451   if FLayeredBitmap=AValue then Exit;
452 
453   if Assigned(FLayeredBitmap) then
454   begin
455     FLayeredBitmap.OnOriginalChange:= nil;
456     FLayeredBitmap.OnOriginalEditingChange:= nil;
457     FLayeredBitmap.OnActionProgress:= nil;
458     FLayeredBitmap.OnActionDone:= nil;
459     FLayeredBitmap.OnOriginalLoadError:= nil;
460   end;
461   FLayeredBitmap:=AValue;
462   if Assigned(FLayeredBitmap) then
463   begin
464     FLayeredBitmap.OnOriginalChange:= @OriginalChange;
465     FLayeredBitmap.OnOriginalEditingChange:= @OriginalEditingChange;
466     FLayeredBitmap.OnActionProgress:= @LayeredActionProgress;
467     FLayeredBitmap.OnActionDone:=@LayeredActionDone;
468     FLayeredBitmap.OnOriginalLoadError:=@OriginalLoadError;
469   end;
470 end;
471 
TImageState.SetLayerNamenull472 function TImageState.SetLayerName(Index: integer; AValue: string): TCustomImageDifference;
473 begin
474   if LayeredBitmap <> nil then
475   begin
476     if LayerName[Index] <> AValue then
477       result := TSetLayerNameStateDifference.Create(self,LayeredBitmap.LayerUniqueId[index],AValue)
478     else
479       result := nil;
480   end
481   else
482     result := nil;
483 end;
484 
SetLayerOffsetnull485 function TImageState.SetLayerOffset(Index: integer; AValue: TPoint
486   ): TCustomImageDifference;
487 begin
488   if LayeredBitmap <> nil then
489   begin
490     if (LayerOffset[index].x <> AValue.x) or (LayerOffset[index].y <> AValue.y) then
491       result := TSetLayerOffsetStateDifference.Create(self,LayeredBitmap.LayerUniqueId[index],AValue)
492     else
493       result := nil;
494   end
495   else
496     result := nil;
497 end;
498 
SetLayerOpacitynull499 function TImageState.SetLayerOpacity(Index: integer; AValue: byte
500   ): TCustomImageDifference;
501 begin
502   if LayeredBitmap <> nil then
503   begin
504     if LayerOpacity[index] <> AValue then
505       result := TSetLayerOpacityStateDifference.Create(self,LayeredBitmap.LayerUniqueId[index],AValue)
506     else
507       result := nil;
508   end
509   else
510     result := nil;
511 end;
512 
SetLayerVisiblenull513 function TImageState.SetLayerVisible(Index: integer; AValue: boolean
514   ): TCustomImageDifference;
515 begin
516   if LayeredBitmap <> nil then
517   begin
518     if LayerVisible[Index] <> AValue then
519       result := TSetLayerVisibleStateDifference.Create(self,LayeredBitmap.LayerUniqueId[index],AValue)
520     else
521       result := nil;
522   end
523   else
524     result := nil;
525 end;
526 
SetBlendOpnull527 function TImageState.SetBlendOp(Index: integer; AValue: TBlendOperation
528   ): TCustomImageDifference;
529 begin
530   if LayeredBitmap <> nil then
531   begin
532     if BlendOperation[index] <> Avalue then
533       result := TSetLayerBlendOpStateDifference.Create(self,LayeredBitmap.LayerUniqueId[index],AValue)
534     else
535       result := nil;
536   end
537   else
538     result := nil;
539 end;
540 
541 procedure TImageState.SetLinearBlend(AValue: boolean);
542 begin
543   if LayeredBitmap <> nil then
544     LayeredBitmap.LinearBlend := AValue;
545 end;
546 
547 procedure TImageState.SetOnActionDone(AValue: TNotifyEvent);
548 begin
549   if FOnActionDone=AValue then Exit;
550   FOnActionDone:=AValue;
551 end;
552 
553 procedure TImageState.SetOnActionProgress(AValue: TLayeredActionProgressEvent);
554 begin
555   if FOnActionProgress=AValue then Exit;
556   FOnActionProgress:=AValue;
557 end;
558 
559 procedure TImageState.SetOnSizeChanged(AValue: TNotifyEvent);
560 begin
561   if FOnSizeChanged=AValue then Exit;
562   FOnSizeChanged:=AValue;
563 end;
564 
565 procedure TImageState.SetSelectionMask(AValue: TBGRABitmap);
566 begin
567   If AValue = FSelectionMask then exit;
568   FSelectionMask := AValue;
569   DiscardSelectionMaskBoundsCompletely;
570 end;
571 
MakeLayerNamenull572 function TImageState.MakeLayerName: string;
573 
LayerNameUsednull574   function LayerNameUsed(AName: string): Boolean;
575   var
576     j: Integer;
577   begin
578     if LayeredBitmap = nil then
579       result := false else
580     begin
581       for j := 0 to NbLayers-1 do
582         if trim(LayerName[j]) = trim(AName) then exit(true);
583       result := false;
584     end;
585   end;
586 
587 var i: integer;
588 begin
589   for i := 1 to 1000 do
590   begin
591     result := rsLayer + inttostr(i);
592     if not LayerNameUsed(result) and not LayerNameUsed('Layer' + inttostr(i)) then exit;
593   end;
594 end;
595 
596 procedure TImageState.CheckSizeChanged(APrevSize: TSize);
597 begin
598   if GetSize <> APrevSize then NotifySizeChanged;
599 end;
600 
GetSizenull601 function TImageState.GetSize: TSize;
602 begin
603   if Assigned(FLayeredBitmap) then
604     result := Size(FLayeredBitmap.Width, FLayeredBitmap.Height)
605     else result := Size(0,0);
606 end;
607 
608 procedure TImageState.SetLayerBitmap(layer: integer; ABitmap: TBGRABitmap;
609   AOwned: boolean);
610 begin
611   if LayeredBitmap <> nil then
612     LayeredBitmap.SetLayerBitmap(layer,ABitmap,AOwned);
613 end;
614 
GetOrCreateSelectionLayernull615 function TImageState.GetOrCreateSelectionLayer: TBGRABitmap;
616 begin
617     if SelectionMask = nil then
618       raise Exception.Create(rsNoActiveSelection) else
619     begin
620       if SelectionLayer = nil then
621       begin
622         SelectionLayer := TBGRABitmap.Create(Width,Height);
623         FLastSelectionLayerBounds := EmptyRect;
624         FLastSelectionLayerBoundsIsDefined := bsDefined;
625       end;
626       result := SelectionLayer;
627     end;
628 end;
629 
630 procedure TImageState.ReplaceSelectionLayer(bmp: TBGRABitmap; AOwned: boolean);
631 begin
632   if (SelectionMask <> nil) then
633   begin
634     if AOwned or (bmp= nil) then
635     begin
636       if (SelectionLayer <> nil) and (SelectionLayer <> bmp) then FreeAndNil(SelectionLayer);
637       SelectionLayer := bmp;
638     end
639     else
640     begin
641       if SelectionLayer <> nil then FreeAndNil(SelectionLayer);
642       SelectionLayer := bmp.Duplicate(True) as TBGRABitmap;
643     end;
644   end else
645   begin
646     if (bmp = nil) then FreeAndNil(SelectionLayer);
647     if AOwned and (bmp <>nil) then bmp.Free; //ignore if there is no active selection
648   end;
649 end;
650 
651 procedure TImageState.ComputeTransformedSelectionLayer(out
652   ANewLayer: TBGRABitmap; out ALeft, ATop: integer);
653 var
654   r: TRect;
655 begin
656   if SelectionLayer = nil then
657   begin
658     ANewLayer := nil;
659     ALeft := 0;
660     ATop := 0;
661   end else
662   begin
663     r := SelectionLayer.GetImageAffineBounds(FSelectionTransform, GetSelectionLayerBounds);
664     ANewLayer := TBGRABitmap.Create(r.Width,r.Height);
665     ANewLayer.PutImageAffine(AffineMatrixTranslation(-r.Left,-r.Top)*FSelectionTransform, SelectionLayer, rfHalfCosine);
666     ALeft := r.Left;
667     ATop := r.Top;
668   end;
669 end;
670 
671 procedure TImageState.DiscardSelectionLayerBounds(const AChangeRect: TRect);
672 begin
673   if FLastSelectionLayerBoundsIsDefined in[bsDefined,bsWithinCurrent] then
674   begin
675     FLastSelectionLayerBounds := RectUnion(FLastSelectionLayerBounds, AChangeRect);
676     FLastSelectionLayerBoundsIsDefined := bsWithinCurrent;
677   end;
678 end;
679 
680 procedure TImageState.DiscardSelectionLayerBoundsCompletely;
681 begin
682   FLastSelectionLayerBoundsIsDefined := bsUndefined;
683 end;
684 
GetSelectionLayerBoundsnull685 function TImageState.GetSelectionLayerBounds: TRect;
686 begin
687   if FLastSelectionLayerBoundsIsDefined = bsDefined then
688     result := FLastSelectionLayerBounds
689   else
690   if SelectionLayer = nil then
691   begin
692     result := EmptyRect;
693     FLastSelectionLayerBounds := result;
694     FLastSelectionLayerBoundsIsDefined := bsDefined;
695   end else
696   begin
697     if FLastSelectionLayerBoundsIsDefined = bsWithinCurrent then
698       result := SelectionLayer.GetImageBoundsWithin(FLastSelectionLayerBounds)
699       else result := SelectionLayer.GetImageBounds;
700     FLastSelectionLayerBounds := result;
701     FLastSelectionLayerBoundsIsDefined := bsDefined;
702   end;
703 end;
704 
SelectionLayerEmptynull705 function TImageState.SelectionLayerEmpty: boolean;
706 begin
707   result := IsRectEmpty(GetSelectionLayerBounds);
708 end;
709 
710 procedure TImageState.SetSize(AWidth, AHeight: integer);
711 var
712   prevSize: TSize;
713 begin
714   if LayeredBitmap <> nil then
715   begin
716     prevSize := GetSize;
717     LayeredBitmap.SetSize(AWidth,AHeight);
718     CheckSizeChanged(prevSize);
719   end;
720 end;
721 
722 procedure TImageState.NotifySizeChanged;
723 begin
724   if Assigned(OnSizeChanged) then OnSizeChanged(self);
725 end;
726 
727 procedure TImageState.PrepareForRendering;
728 begin
729   if LayeredBitmap <> nil then
730     LayeredBitmap.FreezeExceptOneLayer(SelectedImageLayerIndex);
731 end;
732 
ComputeFlatImageWithoutSelectionnull733 function TImageState.ComputeFlatImageWithoutSelection(ASeparateXorMask: boolean): TBGRABitmap;
734 begin
735   if LayeredBitmap <> nil then
736     result := LayeredBitmap.ComputeFlatImage(ASeparateXorMask)
737   else
738     result := TBGRABitmap.Create(Width,Height);
739 end;
740 
741 procedure TImageState.Assign(AValue: TBGRABitmap; AOwned: boolean);
742 var
743   xorMask: TBGRABitmap;
744   idx: Integer;
745   prevSize: TSize;
746 begin
747   prevSize := GetSize;
748 
749   if LayeredBitmap = nil then
750     SetLayeredBitmap(TBGRALayeredBitmap.Create);
751 
752   LayeredBitmap.Clear;
753   LayeredBitmap.SetSize(AValue.Width,AValue.Height);
754   if AOwned then
755   begin
756     idx := LayeredBitmap.AddOwnedLayer(AValue);
757     LayeredBitmap.LayerName[idx] := MakeLayerName;
758     if Assigned(AValue.XorMask) then
759     begin
760       xorMask := TBGRABitmap.Create(AValue.XorMask);
761       xorMask.AlphaFill(255);
762       xorMask.ReplaceColor(BGRABlack,BGRAPixelTransparent);
763       LayeredBitmap.LayerName[LayeredBitmap.AddOwnedLayer(xorMask,boXor)] := 'Xor';
764       AValue.DiscardXorMask;
765     end;
766   end
767   else
768   begin
769     idx := LayeredBitmap.AddLayer(AValue);
770     LayeredBitmap.LayerName[idx] := MakeLayerName;
771     if Assigned(AValue.XorMask) then
772     begin
773       xorMask := AValue.XorMask.Duplicate as TBGRABitmap;
774       xorMask.AlphaFill(255);
775       xorMask.ReplaceColor(BGRABlack,BGRAPixelTransparent);
776       LayeredBitmap.LayerName[LayeredBitmap.AddOwnedLayer(xorMask,boXor)] := 'Xor';
777     end;
778   end;
779   SelectedImageLayerIndex := 0;
780 
781   CheckSizeChanged(prevSize);
782 end;
783 
784 procedure TImageState.Assign(AValue: TBGRACustomLayeredBitmap; AOwned: boolean);
785 var
786   prevSize: TSize;
787 begin
788   if AOwned and (AValue is TBGRALayeredBitmap) then
789   begin
790     prevSize := GetSize;
791     FreeAndNil(FLayeredBitmap);
792     SetLayeredBitmap(TBGRALayeredBitmap(AValue));
793     CheckSizeChanged(prevSize);
794   end else
795   begin
796     LayeredBitmap.Assign(AValue, true, true);
797     if AOwned then AValue.Free;
798   end;
799   if NbLayers > 0 then
800   begin
801     SelectedImageLayerIndex := 0
802   end
803   else
804     SelectedImageLayerIndex := -1;
805 end;
806 
807 procedure TImageState.Assign(AValue: TImageState; AOwned: boolean);
808 var
809   layered: TBGRALayeredBitmap;
810 begin
811   layered := AValue.LayeredBitmap;
812   Assign(layered, AOwned);
813   if AOwned then AValue.SetLayeredBitmap(nil);
814   BGRAReplace(FSelectionMask, AValue.SelectionMask);
815   if AOwned then AValue.SelectionMask := nil;
816   BGRAReplace(SelectionLayer, AValue.SelectionLayer);
817   if AOwned then AValue.SelectionLayer := nil;
818   if AOwned then AValue.Free;
819 end;
820 
821 procedure TImageState.RemoveSelection;
822 begin
823   FreeAndNil(SelectionLayer);
824   FreeAndNil(FSelectionMask);
825   FSelectionTransform := AffineMatrixIdentity;
826 end;
827 
828 procedure TImageState.ReplaceSelection(ASelectionMask,
829   ASelectionLayer: TBGRABitmap);
830 begin
831   if ASelectionMask<>FSelectionMask then
832   begin
833     FSelectionMask.Free;
834     FSelectionMask := ASelectionMask;
835   end;
836   if ASelectionLayer<>SelectionLayer then
837   begin
838     SelectionLayer.Free;
839     SelectionLayer := ASelectionLayer;
840   end;
841 end;
842 
TImageState.AssignWithUndonull843 function TImageState.AssignWithUndo(AValue: TBGRACustomLayeredBitmap;
844   AOwned: boolean; ASelectedLayerIndex: integer): TCustomImageDifference;
845 begin
846   if LayeredBitmap = nil then
847     result := nil
848   else
849     result := TAssignStateDifference.Create(self, AValue, AOwned, ASelectedLayerIndex);
850 end;
851 
TImageState.AssignWithUndonull852 function TImageState.AssignWithUndo(AValue: TBGRACustomLayeredBitmap;
853   AOwned: boolean; ASelectedLayerIndex: integer; ACurrentSelection: TBGRABitmap;
854   ASelectionLayer: TBGRABitmap): TCustomImageDifference;
855 begin
856   if LayeredBitmap = nil then
857     result := nil
858   else
859     result := TAssignStateDifference.Create(self, AValue, AOwned, ASelectedLayerIndex, ACurrentSelection, ASelectionLayer);
860 end;
861 
TImageState.AssignWithUndonull862 function TImageState.AssignWithUndo(AState: TImageState; AOwned: boolean): TCustomImageDifference;
863 begin
864   result := AssignWithUndo(AState.LayeredBitmap, AOwned, SelectedImageLayerIndex, AState.SelectionMask, AState.SelectionLayer);
865   if AOwned then AState.Free;
866 end;
867 
GetUndoAfterAssignnull868 function TImageState.GetUndoAfterAssign(ABackup: TImageState): TCustomImageDifference;
869 begin
870   if LayeredBitmap = nil then
871     result := nil
872   else
873     result := TAssignStateDifferenceAfter.Create(self, ABackup);
874 end;
875 
876 procedure TImageState.LoadFromStream(AStream: TStream);
877 var loadedLayerIndex: integer;
878   loadedLayeredBitmap: TBGRALayeredBitmap;
879 begin
880   loadedLayeredBitmap := LoadLayersFromStream(AStream, loadedLayerIndex, False);
881   Assign(loadedLayeredBitmap,True);
882   SelectedImageLayerIndex:= loadedLayerIndex;
883 end;
884 
885 procedure TImageState.SaveToStream(AStream: TStream);
886 begin
887   SaveLayersToStream(AStream, LayeredBitmap, SelectedImageLayerIndex, lzpRLE);
888 end;
889 
890 procedure TImageState.SaveToStreamAs(AStream: TStream; AFormat: TBGRAImageFormat);
891 var
892   i: Integer;
893   curGuid: TGuid;
894 begin
895   if LayeredBitmap <> nil then
896   begin
897     if AFormat = ifLazPaint then
898     begin
899       curGuid := LayeredBitmap.LayerOriginalGuid[GetCurrentLayerIndex];
900       for i := 0 to LayeredBitmap.OriginalCount-1 do
901         if LayeredBitmap.OriginalGuid[i] <> curGuid then
902           LayeredBitmap.UnloadOriginal(i);
903     end;
904     LayeredBitmap.SaveToStreamAs(AStream, SuggestImageExtension(AFormat));
905   end;
906 end;
907 
908 procedure TImageState.SaveOriginalToStream(AStream: TStream);
909 begin
910   LayeredBitmap.SaveOriginalToStream(
911     LayeredBitmap.LayerOriginalGuid[SelectedImageLayerIndex],
912     AStream);
913 end;
914 
915 procedure TImageState.SaveToFile(AFilenameUTF8: string);
916 var
917   s: TStream;
918 begin
919   if LayeredBitmap <> nil then
920   begin
921     s := FileManager.CreateFileStream(AFilenameUTF8, fmCreate);
922     try
923       LayeredBitmap.SaveToStream(s);
924     finally
925       s.Free;
926     end;
927   end;
928 end;
929 
TImageState.AddNewLayernull930 function TImageState.AddNewLayer(ALayer: TBGRABitmap; AName: string; AOffset: TPoint; ABlendOp: TBlendOperation; AOpacity: byte): TCustomImageDifference;
931 var
932   idxLayer: Integer;
933 begin
934   if AName = '' then AName := MakeLayerName;
935   //no undo if no previous image
936   if LayeredBitmap = nil then
937   begin
938     SetLayeredBitmap(TBGRALayeredBitmap.Create);
939     idxLayer := LayeredBitmap.AddOwnedLayer(ALayer, ABlendOp, AOpacity);
940     LayeredBitmap.LayerOffset[idxLayer] := AOffset;
941     LayeredBitmap.LayerName[idxLayer] := AName;
942     result := nil;
943   end else
944   begin
945     result := TAddLayerStateDifference.Create(self, ALayer, AName, AOffset, ABlendOp, AOpacity);
946     ALayer.Free;
947   end;
948 end;
949 
TImageState.AddNewLayernull950 function TImageState.AddNewLayer(AOriginal: TBGRALayerCustomOriginal;
951   AName: string; ABlendOp: TBlendOperation; AMatrix: TAffineMatrix; AOpacity: byte): TCustomImageDifference;
952 var
953   idx: Integer;
954 begin
955   if AName = '' then AName := MakeLayerName;
956   //no undo if no previous image
957   if LayeredBitmap = nil then
958   begin
959     SetLayeredBitmap(TBGRALayeredBitmap.Create);
960     idx := LayeredBitmap.AddLayerFromOwnedOriginal(AOriginal, ABlendOp, AOpacity);
961     LayeredBitmap.LayerOriginalMatrix[idx] := AMatrix;
962     LayeredBitmap.LayerName[idx] := AName;
963     LayeredBitmap.RenderLayerFromOriginal(idx);
964     result := nil;
965   end else
966     result := TAddLayerFromOwnedOriginalStateDifference.Create(self, AOriginal, AName, ABlendOp, AMatrix, AOpacity);
967 end;
968 
DuplicateLayernull969 function TImageState.DuplicateLayer: TCustomImageDifference;
970 begin
971   if LayeredBitmap = nil then
972     result := nil
973   else
974     result := TDuplicateLayerStateDifference.Create(self, true);
975 end;
976 
MergerLayerOvernull977 function TImageState.MergerLayerOver(ALayerOverIndex: integer): TCustomImageDifference;
978 begin
979   if (LayeredBitmap = nil) or (ALayerOverIndex <= 0) or (ALayerOverIndex >= LayeredBitmap.NbLayers) then
980     result := nil
981   else
982     result := TMergeLayerOverStateDifference.Create(self, ALayerOverIndex);
983 end;
984 
TImageState.MoveLayernull985 function TImageState.MoveLayer(AFromIndex, AToIndex: integer): TCustomImageDifference;
986 begin
987   if LayeredBitmap = nil then
988     result := nil
989   else
990     result := TMoveLayerStateDifference.Create(self, AFromIndex, AToIndex);
991 end;
992 
TImageState.RemoveLayernull993 function TImageState.RemoveLayer: TCustomImageDifference;
994 begin
995   if LayeredBitmap = nil then
996     result := nil
997   else
998   begin
999     result := TRemoveLayerStateDifference.Create(self, True);
1000   end;
1001 end;
1002 
DiscardOriginalnull1003 function TImageState.DiscardOriginal(ACreateUndo: boolean): TCustomImageDifference;
1004 begin
1005   if ACreateUndo then
1006     result := TDiscardOriginalDifference.Create(self, SelectedImageLayerIndex, true)
1007   else
1008   begin
1009     LayeredBitmap.LayerOriginalGuid[SelectedImageLayerIndex] := GUID_NULL;
1010     LayeredBitmap.LayerOriginalMatrix[SelectedImageLayerIndex] := AffineMatrixIdentity;
1011     LayeredBitmap.RemoveUnusedOriginals;
1012   end;
1013 end;
1014 
HorizontalFlipnull1015 function TImageState.HorizontalFlip: TCustomImageDifference;
1016 begin
1017   if LayeredBitmap = nil then
1018     result := nil
1019   else
1020     result := TInversibleStateDifference.Create(self, iaHorizontalFlip);
1021 end;
1022 
HorizontalFlipnull1023 function TImageState.HorizontalFlip(ALayerIndex: integer): TCustomImageDifference;
1024 begin
1025   if LayeredBitmap = nil then
1026     result := nil
1027   else
1028     result := TInversibleStateDifference.Create(self, iaHorizontalFlipLayer, ALayerIndex);
1029 end;
1030 
TImageState.VerticalFlipnull1031 function TImageState.VerticalFlip: TCustomImageDifference;
1032 begin
1033   if LayeredBitmap = nil then
1034     result := nil
1035   else
1036   result := TInversibleStateDifference.Create(self, iaVerticalFlip);
1037 end;
1038 
TImageState.VerticalFlipnull1039 function TImageState.VerticalFlip(ALayerIndex: integer): TCustomImageDifference;
1040 begin
1041   if LayeredBitmap = nil then
1042     result := nil
1043   else
1044     result := TInversibleStateDifference.Create(self, iaVerticalFlipLayer, ALayerIndex);
1045 end;
1046 
1047 procedure TImageState.QuerySelectionMask;
1048 begin
1049   if SelectionMask = nil then
1050   begin
1051     SelectionMask := TBGRABitmap.Create(Width,Height, BGRABlack);
1052     FLastSelectionMaskBoundsIsDefined := bsDefined;
1053     FLastSelectionMaskBounds := EmptyRect;
1054   end;
1055 end;
1056 
1057 procedure TImageState.DiscardSelectionMaskBounds(const AChangeRect: TRect);
1058 begin
1059   if FLastSelectionMaskBoundsIsDefined in[bsDefined,bsWithinCurrent] then
1060   begin
1061     FLastSelectionMaskBounds := RectUnion(FLastSelectionMaskBounds, AChangeRect);
1062     FLastSelectionMaskBoundsIsDefined := bsWithinCurrent;
1063   end;
1064 end;
1065 
1066 procedure TImageState.DiscardSelectionMaskBoundsCompletely;
1067 begin
1068   FLastSelectionMaskBoundsIsDefined := bsUndefined;
1069 end;
1070 
GetSelectionMaskBoundsnull1071 function TImageState.GetSelectionMaskBounds: TRect;
1072 begin
1073   if FLastSelectionMaskBoundsIsDefined = bsDefined then
1074     result := FLastSelectionMaskBounds
1075   else
1076   if SelectionMask = nil then
1077   begin
1078     result := EmptyRect;
1079     FLastSelectionMaskBounds := result;
1080     FLastSelectionMaskBoundsIsDefined := bsDefined;
1081   end else
1082   begin
1083     if FLastSelectionMaskBoundsIsDefined = bsWithinCurrent then
1084       result := SelectionMask.GetImageBoundsWithin(FLastSelectionMaskBounds, cGreen)
1085       else result := SelectionMask.GetImageBounds(cGreen);
1086     FLastSelectionMaskBounds := result;
1087     FLastSelectionMaskBoundsIsDefined := bsDefined;
1088   end;
1089 end;
1090 
SelectionMaskEmptynull1091 function TImageState.SelectionMaskEmpty: boolean;
1092 begin
1093   result := IsRectEmpty(GetSelectionMaskBounds);
1094 end;
1095 
SelectionMaskEmptyComputednull1096 function TImageState.SelectionMaskEmptyComputed: boolean;
1097 begin
1098   result := FLastSelectionMaskBoundsIsDefined = bsDefined;
1099 end;
1100 
TImageState.GetTransformedSelectionMaskBoundsnull1101 function TImageState.GetTransformedSelectionMaskBounds: TRect;
1102 begin
1103   if SelectionMaskEmpty then
1104     result := EmptyRect
1105   else
1106   begin
1107     result := SelectionMask.GetImageAffineBounds(SelectionTransform, GetSelectionMaskBounds);
1108   end;
1109 end;
1110 
1111 procedure TImageState.ComputeTransformedSelectionMask(out ANewMask: TBGRABitmap; out ALeft,ATop: integer);
1112 var
1113   r: TRect;
1114 begin
1115   if SelectionMask = nil then
1116   begin
1117     ANewMask := nil;
1118     ALeft := 0;
1119     ATop := 0;
1120   end else
1121   begin
1122     r := SelectionMask.GetImageAffineBounds(FSelectionTransform, GetSelectionMaskBounds);
1123     ANewMask := TBGRABitmap.Create(r.Width,r.Height,BGRABlack);
1124     ANewMask.PutImageAffine(AffineMatrixTranslation(-r.Left,-r.Top)*FSelectionTransform, SelectionMask, rfHalfCosine, dmLinearBlend);
1125     ALeft := r.Left;
1126     ATop := r.Top;
1127   end;
1128 end;
1129 
TImageState.SwapRedBluenull1130 function TImageState.SwapRedBlue: TCustomImageDifference;
1131 var
1132   newImg: TBGRALayeredBitmap;
1133   newLayer: TBGRABitmap;
1134   idxLayer, i: Integer;
1135 begin
1136   if LayeredBitmap = nil then
1137     result := nil
1138   else
1139   begin
1140     if HasOriginals then
1141     begin
1142       newImg := TBGRALayeredBitmap.Create(Width,Height);
1143       for i := 0 to NbLayers-1 do
1144       begin
1145         newLayer := TBGRABitmap.Create(Width,Height);
1146         newLayer.PutImage(LayerOffset[i].x,LayerOffset[i].y, LayerBitmap[i], dmSet);
1147         newLayer.SwapRedBlue;
1148         idxLayer := newImg.AddOwnedLayer(newLayer, BlendOperation[i], LayerOpacity[i]);
1149         newImg.LayerName[idxLayer] := LayerName[i];
1150       end;
1151       result := AssignWithUndo(newImg, true, SelectedImageLayerIndex);
1152     end else
1153       result := TInversibleStateDifference.Create(self, iaSwapRedBlue);
1154   end;
1155 end;
1156 
TImageState.LinearNegativenull1157 function TImageState.LinearNegative: TCustomImageDifference;
1158 var
1159   newImg: TBGRALayeredBitmap;
1160   newLayer: TBGRABitmap;
1161   idxLayer, i: Integer;
1162 begin
1163   if LayeredBitmap = nil then
1164     result := nil
1165   else
1166   begin
1167     if HasOriginals then
1168     begin
1169       newImg := TBGRALayeredBitmap.Create(Width,Height);
1170       for i := 0 to NbLayers-1 do
1171       begin
1172         newLayer := TBGRABitmap.Create(Width,Height);
1173         newLayer.PutImage(LayerOffset[i].x,LayerOffset[i].y, LayerBitmap[i], dmSet);
1174         newLayer.LinearNegative;
1175         idxLayer := newImg.AddOwnedLayer(newLayer, BlendOperation[i], LayerOpacity[i]);
1176         newImg.LayerName[idxLayer] := LayerName[i];
1177       end;
1178       result := AssignWithUndo(newImg, true, SelectedImageLayerIndex);
1179     end else
1180       result := TInversibleStateDifference.Create(self, iaLinearNegative);
1181   end;
1182 end;
1183 
TImageState.Negativenull1184 function TImageState.Negative: TCustomImageDifference;
1185 var
1186   newImg: TBGRALayeredBitmap;
1187   newLayer: TBGRABitmap;
1188   idxLayer, i: Integer;
1189 begin
1190   newImg := TBGRALayeredBitmap.Create(Width,Height);
1191   for i := 0 to NbLayers-1 do
1192   begin
1193     newLayer := TBGRABitmap.Create(Width,Height);
1194     newLayer.PutImage(LayerOffset[i].x,LayerOffset[i].y, LayerBitmap[i], dmSet);
1195     newLayer.Negative;
1196     idxLayer := newImg.AddOwnedLayer(newLayer, BlendOperation[i], LayerOpacity[i]);
1197     newImg.LayerName[idxLayer] := LayerName[i];
1198   end;
1199   result := AssignWithUndo(newImg, true, SelectedImageLayerIndex);
1200 end;
1201 
TImageState.ClearLayernull1202 function TImageState.ClearLayer: TCustomImageDifference;
1203 begin
1204   if (LayeredBitmap = nil) or SelectedImageLayer.Empty then
1205     result := nil
1206   else
1207   begin
1208     result := TReplaceLayerByCustomOriginalDifference.Create(self,
1209                    SelectedImageLayerIndex, true,
1210                    TVectorOriginal.Create);
1211   end;
1212 end;
1213 
RotateCWnull1214 function TImageState.RotateCW: TCustomImageDifference;
1215 begin
1216   if LayeredBitmap = nil then
1217     result := nil
1218   else
1219   result := TInversibleStateDifference.Create(self, iaRotateCW);
1220 end;
1221 
TImageState.RotateCCWnull1222 function TImageState.RotateCCW: TCustomImageDifference;
1223 begin
1224   if LayeredBitmap = nil then
1225     result := nil
1226   else
1227   result := TInversibleStateDifference.Create(self, iaRotateCCW);
1228 end;
1229 
TImageState.Rotate180null1230 function TImageState.Rotate180: TCustomImageDifference;
1231 begin
1232   if LayeredBitmap = nil then
1233     result := nil
1234   else
1235   result := TInversibleStateDifference.Create(self, iaRotate180);
1236 end;
1237 
TImageState.ComputeLayerOffsetDifferencenull1238 function TImageState.ComputeLayerOffsetDifference(AOffsetX, AOffsetY: integer): TCustomImageDifference;
1239 begin
1240   result := TApplyLayerOffsetStateDifference.Create(self, LayeredBitmap.LayerUniqueId[SelectedImageLayerIndex], AOffsetX,AOffsetY, false);
1241 end;
1242 
TImageState.ComputeSelectionTransformDifferencenull1243 function TImageState.ComputeSelectionTransformDifference: TCustomImageDifference;
1244 begin
1245   result := TSelectionTransformDifference.Create(self, false);
1246 end;
1247 
TImageState.ComputeLayerMatrixDifferencenull1248 function TImageState.ComputeLayerMatrixDifference(AIndex: integer; APrevMatrix,
1249   ANewMatrix: TAffineMatrix): TCustomImageDifference;
1250 begin
1251   result := TSetLayerMatrixDifference.Create(self, LayeredBitmap.LayerUniqueId[AIndex], APrevMatrix,ANewMatrix);
1252 end;
1253 
ComputeLayerDifferencenull1254 function TImageState.ComputeLayerDifference(APreviousImage: TBGRABitmap;
1255   APreviousImageDefined: boolean; APreviousSelection: TBGRABitmap;
1256   APreviousSelectionDefined: boolean; APreviousSelectionLayer: TBGRABitmap;
1257   APreviousSelectionLayerDefined: boolean): TCustomImageDifference;
1258 begin
1259   if LayeredBitmap = nil then
1260     result := nil
1261   else
1262     result := TImageLayerStateDifference.Create(self, APreviousImage, APreviousImageDefined,
1263       APreviousSelection, APreviousSelectionDefined, APreviousSelectionLayer, APreviousSelectionLayerDefined);
1264 end;
1265 
ComputeLayerDifferencenull1266 function TImageState.ComputeLayerDifference(APreviousImage: TBGRABitmap;
1267   APreviousImageChangeRect: TRect; APreviousSelection: TBGRABitmap;
1268   APreviousSelectionChangeRect: TRect; APreviousSelectionLayer: TBGRABitmap;
1269   APreviousSelectionLayerChangeRect: TRect): TCustomImageDifference;
1270 begin
1271   if LayeredBitmap = nil then
1272     result := nil
1273   else
1274     result := TImageLayerStateDifference.Create(self, APreviousImage, APreviousImageChangeRect,
1275       APreviousSelection, APreviousSelectionChangeRect, APreviousSelectionLayer, APreviousSelectionLayerChangeRect);
1276 end;
1277 
TImageState.GetLayeredBitmapCopynull1278 function TImageState.GetLayeredBitmapCopy: TBGRALayeredBitmap;
1279 begin
1280   result := LayeredBitmap.Duplicate;
1281 end;
1282 
ComputeFlatImagenull1283 function TImageState.ComputeFlatImage(AFromLayer, AToLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
1284 begin
1285   result := LayeredBitmap.ComputeFlatImage(AFromLayer,AToLayer,ASeparateXorMask);
1286 end;
1287 
ComputeFlatImagenull1288 function TImageState.ComputeFlatImage(ARect: TRect; AFromLayer,
1289   AToLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
1290 begin
1291   result := LayeredBitmap.ComputeFlatImage(ARect,AFromLayer,AToLayer,ASeparateXorMask);
1292 end;
1293 
1294 procedure TImageState.DrawLayers(ADest: TBGRABitmap; X, Y: Integer; AIconCursor: boolean; ADestinationEmpty: boolean);
1295 begin
1296   if LayeredBitmap <> nil then
1297     LayeredBitmap.Draw(ADest,X,Y, AIconCursor, ADestinationEmpty);
1298 end;
1299 
1300 constructor TImageState.Create;
1301 begin
1302   FLayeredBitmap := nil;
1303   SelectionMask := nil;
1304   SelectionLayer := nil;
1305   selectedLayerId := -1;
1306   FLastSelectionMaskBoundsIsDefined := bsUndefined;
1307   FLastSelectionLayerBoundsIsDefined := bsUndefined;
1308   FSelectionTransform := AffineMatrixIdentity;
1309   DiscardOriginalDiff := true;
1310 end;
1311 
1312 destructor TImageState.Destroy;
1313 begin
1314   LayeredBitmap.Free;
1315   SelectionMask.free;
1316   SelectionLayer.Free;
1317   inherited Destroy;
1318 end;
1319 
Equalsnull1320 function TImageState.Equals(Obj: TObject): boolean;
1321 var other: TImageState;
1322   selectedLayerIndex, otherSelectedLayerIndex: integer;
1323 begin
1324   if obj is TImageState then
1325   begin
1326     other := obj as TImageState;
1327     result := false;
1328     if selectedLayerId <> -1 then //compare active layer (where modifications are expected to be)
1329     begin
1330       selectedLayerIndex := LayeredBitmap.GetLayerIndexFromId(selectedLayerId);
1331       otherSelectedLayerIndex := other.LayeredBitmap.GetLayerIndexFromId(selectedLayerId);
1332       if (selectedLayerIndex <> -1) and (otherSelectedLayerIndex <> -1) then
1333         if not other.LayeredBitmap.LayerBitmap[otherSelectedLayerIndex].Equals(LayeredBitmap.LayerBitmap[selectedLayerIndex]) then exit;
1334     end;
1335     if (other.SelectionMask = nil) and (SelectionMask <> nil) and not SelectionMask.Equals(BGRABlack) then exit;
1336     if (other.SelectionMask <> nil) and (SelectionMask = nil) and not other.SelectionMask.Equals(BGRABlack) then exit;
1337     if (other.SelectionMask <> nil) and (SelectionMask <> nil) and not other.SelectionMask.Equals(SelectionMask) then exit;
1338     if (other.SelectionLayer = nil) and (SelectionLayer <> nil) and not SelectionLayer.Empty then exit;
1339     if (other.SelectionLayer <> nil) and (SelectionLayer = nil) and not other.SelectionLayer.Empty then exit;
1340     if (other.SelectionLayer <> nil) and (SelectionLayer <> nil) and not other.SelectionLayer.Equals(SelectionLayer) then exit;
1341     if (other.filenameUTF8 <> filenameUTF8) then exit;
1342     result := true;
1343   end
1344   else
1345     Result:=inherited Equals(Obj);
1346 end;
1347 
1348 procedure TImageState.ApplyDifference(ADifference: TStateDifference);
1349 begin
1350   ADifference.ApplyTo(self);
1351 end;
1352 
1353 procedure TImageState.ReverseDifference(ADifference: TStateDifference);
1354 begin
1355   ADifference.UnapplyTo(self);
1356 end;
1357 
TImageState.Duplicatenull1358 function TImageState.Duplicate: TState;
1359 var copy: TImageState;
1360 begin
1361   copy := TImageState.Create;
1362   copy.SetLayeredBitmap(DuplicateLayeredBitmap(LayeredBitmap));
1363   copy.SelectionMask := DuplicateBitmap(SelectionMask);
1364   copy.SelectionLayer := DuplicateBitmap(SelectionLayer);
1365   copy.selectedLayerId := selectedLayerId;
1366   result := copy;
1367 end;
1368 
1369 procedure TImageState.Resample(AWidth, AHeight: integer;
1370   AQuality: TResampleMode; AFilter: TResampleFilter);
1371 begin
1372   LayeredBitmap.Resample(AWidth,AHeight,AQuality,AFilter);
1373   if SelectionMask <> nil then
1374   begin
1375     SelectionMask.ResampleFilter := AFilter;
1376     BGRAReplace(FSelectionMask, FSelectionMask.Resample(AWidth, AHeight,AQuality));
1377   end;
1378   if SelectionLayer <> nil then
1379   begin
1380     SelectionLayer.ResampleFilter := AFilter;
1381     BGRAReplace(SelectionLayer, SelectionLayer.Resample(AWidth, AHeight,AQuality));
1382   end;
1383 end;
1384 
1385 end.
1386 
1387