Ignore:
Timestamp:
Apr 17, 2019, 12:58:41 AM (5 years ago)
Author:
chronos
Message:
  • Modified: Propagate project build mode options to used packages.
  • Added: Check memory leaks using heaptrc.
  • Modified: Update BGRABitmap package.
Location:
GraphicTest
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest

    • Property svn:ignore
      •  

        old new  
        88GraphicTest.lps
        99GraphicTest.dbg
         10heaptrclog.trc
  • GraphicTest/Packages/bgrabitmap/bgralayers.pas

    r494 r521  
    22
    33{$mode objfpc}{$H+}
     4{$MODESWITCH ADVANCEDRECORDS}
    45
    56interface
    67
    78uses
    8   BGRAGraphics, Classes, SysUtils, Types, BGRABitmapTypes, BGRABitmap;
     9  BGRAGraphics, Classes, SysUtils, Types, BGRABitmapTypes, BGRABitmap,
     10  BGRAMemDirectory, BGRATransform, fgl, BGRALayerOriginal;
    911
    1012type
     
    1214  TBGRACustomLayeredBitmapClass = class of TBGRACustomLayeredBitmap;
    1315
     16  { TBGRALayerOriginalEntry }
     17
     18  TBGRALayerOriginalEntry = record
     19     Guid: TGuid;
     20     Instance: TBGRALayerCustomOriginal;
     21     class operator = (const AEntry1,AEntry2: TBGRALayerOriginalEntry): boolean;
     22  end;
     23
     24function BGRALayerOriginalEntry(AGuid: TGuid): TBGRALayerOriginalEntry;
     25function BGRALayerOriginalEntry(AInstance: TBGRALayerCustomOriginal): TBGRALayerOriginalEntry;
     26
     27type
     28  TBGRALayerOriginalList = specialize TFPGList<TBGRALayerOriginalEntry>;
     29
    1430  TBGRALayeredBitmap = class;
    1531  TBGRALayeredBitmapClass = class of TBGRALayeredBitmap;
    1632
    1733  TBGRALayeredBitmapSaveToStreamProc = procedure(AStream: TStream; ALayers: TBGRACustomLayeredBitmap);
    18   TBGRALayeredBitmapLoadFromStreamProc = function(AStream: TStream): TBGRALayeredBitmap;
     34  TBGRALayeredBitmapLoadFromStreamProc = procedure(AStream: TStream; ALayers: TBGRACustomLayeredBitmap);
     35  TBGRALayeredBitmapCheckStreamProc = function(AStream: TStream): boolean;
     36  TOriginalRenderStatus = (orsNone, orsDraft, orsPartialDraft, orsProof, orsPartialProof);
    1937
    2038  { TBGRACustomLayeredBitmap }
     
    2846    end;
    2947    FLinearBlend: boolean;
     48    FMemDirectory: TMemDirectory;
     49    FMemDirectoryOwned: boolean;
    3050    function GetDefaultBlendingOperation: TBlendOperation;
     51    function GetHasMemFiles: boolean;
    3152    function GetLinearBlend: boolean;
    3253    procedure SetLinearBlend(AValue: boolean);
     
    3455  protected
    3556    function GetNbLayers: integer; virtual; abstract;
     57    function GetMemDirectory: TMemDirectory;
    3658    function GetBlendOperation(Layer: integer): TBlendOperation; virtual; abstract;
    3759    function GetLayerVisible(layer: integer): boolean; virtual; abstract;
     
    4264    function GetLayerFrozen(layer: integer): boolean; virtual;
    4365    function GetLayerUniqueId(layer: integer): integer; virtual;
     66    function GetLayerOriginal({%H-}layer: integer): TBGRALayerCustomOriginal; virtual;
     67    function GetLayerOriginalKnown({%H-}layer: integer): boolean; virtual;
     68    function GetLayerOriginalMatrix({%H-}layer: integer): TAffineMatrix; virtual;
     69    function GetLayerOriginalGuid({%H-}layer: integer): TGuid; virtual;
     70    function GetLayerOriginalRenderStatus({%H-}layer: integer): TOriginalRenderStatus; virtual;
     71    function GetOriginalCount: integer; virtual;
     72    function GetOriginalByIndex({%H-}AIndex: integer): TBGRALayerCustomOriginal; virtual;
     73    function GetOriginalByIndexKnown({%H-}AIndex: integer): boolean; virtual;
     74    function GetTransparent: Boolean; override;
     75    function GetEmpty: boolean; override;
     76
     77    function IndexOfOriginal(AGuid: TGuid): integer; overload; virtual;
     78    function IndexOfOriginal(AOriginal: TBGRALayerCustomOriginal): integer; overload; virtual;
     79
     80    procedure SetWidth(Value: Integer); override;
     81    procedure SetHeight(Value: Integer); override;
     82    procedure SetMemDirectory(AValue: TMemDirectory);
     83    procedure SetTransparent(Value: Boolean); override;
     84
    4485    procedure SetLayerFrozen(layer: integer; AValue: boolean); virtual;
    4586    function RangeIntersect(first1,last1,first2,last2: integer): boolean;
    4687    procedure RemoveFrozenRange(index: integer);
    4788    function ContainsFrozenRange(first,last: integer): boolean;
    48     function GetEmpty: boolean; override;
    49     procedure SetWidth(Value: Integer); override;
    50     procedure SetHeight(Value: Integer); override;
    51     function GetTransparent: Boolean; override;
    52     procedure SetTransparent(Value: Boolean); override;
    5389
    5490  public
    5591    procedure SaveToFile(const filenameUTF8: string); override;
    5692    procedure SaveToStream(Stream: TStream); override;
     93    procedure SaveToStreamAs(Stream: TStream; AExtension: string);
    5794    constructor Create; override;
    5895    destructor Destroy; override;
     
    6097    function GetLayerBitmapDirectly(layer: integer): TBGRABitmap; virtual;
    6198    function GetLayerBitmapCopy(layer: integer): TBGRABitmap; virtual; abstract;
    62     function ComputeFlatImage: TBGRABitmap; overload;
    63     function ComputeFlatImage(firstLayer, lastLayer: integer): TBGRABitmap; overload;
    64     function ComputeFlatImage(ARect: TRect): TBGRABitmap; overload;
    65     function ComputeFlatImage(ARect: TRect; firstLayer, lastLayer: integer): TBGRABitmap; overload;
     99    function ComputeFlatImage(ASeparateXorMask: boolean = false): TBGRABitmap; overload;
     100    function ComputeFlatImage(firstLayer, lastLayer: integer; ASeparateXorMask: boolean = false): TBGRABitmap; overload;
     101    function ComputeFlatImage(ARect: TRect; ASeparateXorMask: boolean = false): TBGRABitmap; overload;
     102    function ComputeFlatImage(ARect: TRect; firstLayer, lastLayer: integer; ASeparateXorMask: boolean = false): TBGRABitmap; overload;
    66103    procedure Draw(ACanvas: TCanvas; const Rect: TRect); override; overload;
    67104    procedure Draw(Canvas: TCanvas; x,y: integer); overload;
    68105    procedure Draw(Canvas: TCanvas; x,y: integer; firstLayer, lastLayer: integer); overload;
    69106    procedure Draw(Dest: TBGRABitmap; x,y: integer); overload;
    70     procedure Draw(Dest: TBGRABitmap; AX,AY: integer; firstLayer, lastLayer: integer); overload;
     107    procedure Draw(Dest: TBGRABitmap; x,y: integer; ASeparateXorMask: boolean); overload;
     108    procedure Draw(Dest: TBGRABitmap; AX,AY: integer; firstLayer, lastLayer: integer; ASeparateXorMask: boolean = false); overload;
    71109
    72110    procedure FreezeExceptOneLayer(layer: integer); overload;
     
    76114    procedure Unfreeze(layer: integer); overload;
    77115    procedure Unfreeze(firstLayer, lastLayer: integer); overload;
     116
     117    procedure NotifyLoaded; virtual;
     118    procedure NotifySaving; virtual;
    78119
    79120    property NbLayers: integer read GetNbLayers;
     
    85126    property LayerFrozen[layer: integer]: boolean read GetLayerFrozen;
    86127    property LayerUniqueId[layer: integer]: integer read GetLayerUniqueId;
     128    property LayerOriginal[layer: integer]: TBGRALayerCustomOriginal read GetLayerOriginal;
     129    property LayerOriginalKnown[layer: integer]: boolean read GetLayerOriginalKnown;
     130    property LayerOriginalGuid[layer: integer]: TGuid read GetLayerOriginalGuid;
     131    property LayerOriginalMatrix[layer: integer]: TAffineMatrix read GetLayerOriginalMatrix;
     132    property LayerOriginalRenderStatus[layer: integer]: TOriginalRenderStatus read GetLayerOriginalRenderStatus;
    87133    property LinearBlend: boolean read GetLinearBlend write SetLinearBlend; //use linear blending unless specified
    88134    property DefaultBlendingOperation: TBlendOperation read GetDefaultBlendingOperation;
    89   end;
     135    property MemDirectory: TMemDirectory read GetMemDirectory write SetMemDirectory;
     136    property MemDirectoryOwned: boolean read FMemDirectoryOwned write FMemDirectoryOwned;
     137    property HasMemFiles: boolean read GetHasMemFiles;
     138  end;
     139
     140  TEmbeddedOriginalChangeEvent = procedure (ASender: TObject; AOriginal: TBGRALayerCustomOriginal) of object;
     141  TEmbeddedOriginalEditingChangeEvent = procedure (ASender: TObject; AOriginal: TBGRALayerCustomOriginal) of object;
    90142
    91143  TBGRALayerInfo = record
     
    99151    Owner: boolean;
    100152    Frozen: boolean;
     153    OriginalMatrix: TAffineMatrix;
     154    OriginalRenderStatus: TOriginalRenderStatus;
     155    OriginalGuid: TGuid;
     156    OriginalInvalidatedBounds: TRectF;
    101157  end;
    102158
     
    107163    FNbLayers: integer;
    108164    FLayers: array of TBGRALayerInfo;
     165    FOriginalChange: TEmbeddedOriginalChangeEvent;
     166    FOriginalEditingChange: TEmbeddedOriginalEditingChangeEvent;
    109167    FWidth,FHeight: integer;
     168    FOriginals: TBGRALayerOriginalList;
     169    FOriginalEditor: TBGRAOriginalEditor;
     170    FOriginalEditorOriginal: TBGRALayerCustomOriginal;
     171    FOriginalEditorViewMatrix: TAffineMatrix;
     172    function GetOriginalGuid(AIndex: integer): TGUID;
    110173
    111174  protected
     
    119182    function GetLayerName(layer: integer): string; override;
    120183    function GetLayerFrozen(layer: integer): boolean; override;
     184    function GetLayerUniqueId(layer: integer): integer; override;
     185    function GetLayerOriginal(layer: integer): TBGRALayerCustomOriginal; override;
     186    function GetLayerOriginalKnown(layer: integer): boolean; override;
     187    function GetLayerOriginalMatrix(layer: integer): TAffineMatrix; override;
     188    function GetLayerOriginalGuid(layer: integer): TGuid; override;
     189    function GetLayerOriginalRenderStatus(layer: integer): TOriginalRenderStatus; override;
     190    function GetOriginalCount: integer; override;
     191    function GetOriginalByIndex(AIndex: integer): TBGRALayerCustomOriginal; override;
     192    function GetOriginalByIndexKnown(AIndex: integer): boolean; override;
    121193    procedure SetBlendOperation(Layer: integer; op: TBlendOperation);
    122194    procedure SetLayerVisible(layer: integer; AValue: boolean);
     
    125197    procedure SetLayerName(layer: integer; AValue: string);
    126198    procedure SetLayerFrozen(layer: integer; AValue: boolean); override;
    127     function GetLayerUniqueId(layer: integer): integer; override;
    128199    procedure SetLayerUniqueId(layer: integer; AValue: integer);
     200    procedure SetLayerOriginalMatrix(layer: integer; AValue: TAffineMatrix);
     201    procedure SetLayerOriginalGuid(layer: integer; const AValue: TGuid);
     202    procedure SetLayerOriginalRenderStatus(layer: integer; AValue: TOriginalRenderStatus);
     203
     204    procedure FindOriginal(AGuid: TGuid;
     205                out ADir: TMemDirectory;
     206                out AClass: TBGRALayerOriginalAny);
     207    procedure StoreOriginal(AOriginal: TBGRALayerCustomOriginal);
     208    procedure OriginalChange(ASender: TObject; ABounds: PRectF = nil);
     209    procedure OriginalEditingChange(ASender: TObject);
    129210
    130211  public
    131212    procedure LoadFromFile(const filenameUTF8: string); override;
    132213    procedure LoadFromStream(stream: TStream); override;
     214    procedure LoadFromResource(AFilename: string);
    133215    procedure SetSize(AWidth, AHeight: integer); virtual;
    134216    procedure Clear; override;
     217    procedure ClearOriginals;
    135218    procedure RemoveLayer(index: integer);
    136219    procedure InsertLayer(index: integer; fromIndex: integer);
     
    138221    function MoveLayerUp(index: integer): integer;
    139222    function MoveLayerDown(index: integer): integer;
     223
    140224    function AddLayer(Source: TBGRABitmap; Opacity: byte = 255): integer; overload;
    141225    function AddLayer(Source: TBGRABitmap; Position: TPoint; BlendOp: TBlendOperation; Opacity: byte = 255; Shared: boolean = false): integer; overload;
     
    158242    function AddOwnedLayer(ABitmap: TBGRABitmap; Position: TPoint; Opacity: byte = 255): integer; overload;
    159243    function AddOwnedLayer(ABitmap: TBGRABitmap; BlendOp: TBlendOperation; Opacity: byte = 255): integer; overload;
     244    function AddLayerFromOriginal(AGuid: TGuid; Opacity: byte = 255): integer; overload;
     245    function AddLayerFromOriginal(AGuid: TGuid; BlendOp: TBlendOperation; Opacity: byte = 255): integer; overload;
     246    function AddLayerFromOriginal(AGuid: TGuid; Matrix: TAffineMatrix; Opacity: byte = 255): integer; overload;
     247    function AddLayerFromOriginal(AGuid: TGuid; Matrix: TAffineMatrix; BlendOp: TBlendOperation; Opacity: byte = 255): integer; overload;
     248    function AddLayerFromOwnedOriginal(AOriginal: TBGRALayerCustomOriginal; Opacity: byte = 255): integer; overload;
     249    function AddLayerFromOwnedOriginal(AOriginal: TBGRALayerCustomOriginal; BlendOp: TBlendOperation; Opacity: byte = 255): integer; overload;
     250    function AddLayerFromOwnedOriginal(AOriginal: TBGRALayerCustomOriginal; Matrix: TAffineMatrix; Opacity: byte = 255): integer; overload;
     251    function AddLayerFromOwnedOriginal(AOriginal: TBGRALayerCustomOriginal; Matrix: TAffineMatrix; BlendOp: TBlendOperation; Opacity: byte = 255): integer; overload;
     252
     253    function AddOriginal(AOriginal: TBGRALayerCustomOriginal; AOwned: boolean = true): integer;
     254    function AddOriginalFromStream(AStream: TStream; ALateLoad: boolean = false): integer;
     255    function AddOriginalFromStorage(AStorage: TBGRAMemOriginalStorage; ALateLoad: boolean = false): integer;
     256    procedure SaveOriginalToStream(AIndex: integer; AStream: TStream); overload;
     257    procedure SaveOriginalToStream(AGuid: TGUID; AStream: TStream); overload;
     258    function RemoveOriginal(AOriginal: TBGRALayerCustomOriginal): boolean;
     259    procedure DeleteOriginal(AIndex: integer);
     260    procedure NotifyLoaded; override;
     261    procedure NotifySaving; override;
     262    procedure RenderLayerFromOriginal(layer: integer; ADraft: boolean = false; AFullSizeLayer: boolean = false); overload;
     263    procedure RenderLayerFromOriginal(layer: integer; ADraft: boolean; ARenderBounds: TRect; AFullSizeLayer: boolean = false); overload;
     264    procedure RenderLayerFromOriginal(layer: integer; ADraft: boolean; ARenderBoundsF: TRectF; AFullSizeLayer: boolean = false); overload;
     265    function RenderOriginalsIfNecessary(ADraft: boolean = false): TRect;
     266    procedure RemoveUnusedOriginals;
     267
    160268    destructor Destroy; override;
    161     constructor Create; override; overload;
    162     constructor Create(AWidth, AHeight: integer); virtual; overload;
     269    constructor Create; overload; override;
     270    constructor Create(AWidth, AHeight: integer); overload; virtual;
    163271    function GetLayerBitmapDirectly(layer: integer): TBGRABitmap; override;
    164272    function GetLayerBitmapCopy(layer: integer): TBGRABitmap; override;
     
    169277    procedure RotateCW;
    170278    procedure RotateCCW;
    171     procedure HorizontalFlip;
    172     procedure VerticalFlip;
     279    procedure HorizontalFlip; overload;
     280    procedure HorizontalFlip(ALayerIndex: integer); overload;
     281    procedure VerticalFlip; overload;
     282    procedure VerticalFlip(ALayerIndex: integer); overload;
    173283    procedure Resample(AWidth, AHeight: integer; AResampleMode: TResampleMode; AFineResampleFilter: TResampleFilter = rfLinear);
    174284    procedure SetLayerBitmap(layer: integer; ABitmap: TBGRABitmap; AOwned: boolean);
     285    procedure ApplyLayerOffset(ALayerIndex: integer; APadWithTranparentPixels: boolean);
     286
     287    function DrawEditor(ADest: TBGRABitmap; ALayerIndex: integer; X, Y: Integer; APointSize: single): TRect; overload;
     288    function DrawEditor(ADest: TBGRABitmap; ALayerIndex: integer; AMatrix: TAffineMatrix; APointSize: single): TRect; overload;
     289    function GetEditorBounds(ALayerIndex: integer; X, Y: Integer; APointSize: single): TRect; overload;
     290    function GetEditorBounds(ADestRect: TRect; ALayerIndex: integer; X, Y: Integer; APointSize: single): TRect; overload;
     291    function GetEditorBounds(ALayerIndex: integer; AMatrix: TAffineMatrix; APointSize: single): TRect; overload;
     292    function GetEditorBounds(ADestRect: TRect; ALayerIndex: integer; AMatrix: TAffineMatrix; APointSize: single): TRect; overload;
     293    procedure MouseMove(Shift: TShiftState; ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor);
     294    procedure MouseDown(RightButton: boolean; Shift: TShiftState; ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor);
     295    procedure MouseUp(RightButton: boolean; Shift: TShiftState; ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor);
     296    procedure MouseMove(Shift: TShiftState; ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor; out AHandled: boolean);
     297    procedure MouseDown(RightButton: boolean; Shift: TShiftState; ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor; out AHandled: boolean);
     298    procedure MouseUp(RightButton: boolean; Shift: TShiftState; ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor; out AHandled: boolean);
     299    procedure KeyDown(Shift: TShiftState; Key: TSpecialKey; out AHandled: boolean);
     300    procedure KeyUp(Shift: TShiftState; Key: TSpecialKey; out AHandled: boolean);
     301    procedure KeyPress(UTF8Key: string; out AHandled: boolean);
    175302
    176303    property Width : integer read GetWidth;
     
    184311    property LayerOffset[layer: integer]: TPoint read GetLayerOffset write SetLayerOffset;
    185312    property LayerUniqueId[layer: integer]: integer read GetLayerUniqueId write SetLayerUniqueId;
    186   end;
     313    property LayerOriginal[layer: integer]: TBGRALayerCustomOriginal read GetLayerOriginal;
     314    property LayerOriginalKnown[layer: integer]: boolean read GetLayerOriginalKnown;
     315    property LayerOriginalGuid[layer: integer]: TGuid read GetLayerOriginalGuid write SetLayerOriginalGuid;
     316    property LayerOriginalMatrix[layer: integer]: TAffineMatrix read GetLayerOriginalMatrix write SetLayerOriginalMatrix;
     317    property LayerOriginalRenderStatus[layer: integer]: TOriginalRenderStatus read GetLayerOriginalRenderStatus write SetLayerOriginalRenderStatus;
     318
     319    function IndexOfOriginal(AGuid: TGuid): integer; overload; override;
     320    function IndexOfOriginal(AOriginal: TBGRALayerCustomOriginal): integer; overload; override;
     321    property OriginalCount: integer read GetOriginalCount;
     322    property Original[AIndex: integer]: TBGRALayerCustomOriginal read GetOriginalByIndex;
     323    property OriginalGuid[AIndex: integer]: TGUID read GetOriginalGuid;
     324    property OriginalKnown[AIndex: integer]: boolean read GetOriginalByIndexKnown;
     325    property OnOriginalChange: TEmbeddedOriginalChangeEvent read FOriginalChange write FOriginalChange;
     326    property OnOriginalEditingChange: TEmbeddedOriginalEditingChangeEvent read FOriginalEditingChange write FOriginalEditingChange;
     327    property OriginalEditor: TBGRAOriginalEditor read FOriginalEditor;
     328  end;
     329
     330  TAffineMatrix = BGRABitmapTypes.TAffineMatrix;
    187331
    188332procedure RegisterLayeredBitmapWriter(AExtensionUTF8: string; AWriter: TBGRALayeredBitmapClass);
    189333procedure RegisterLayeredBitmapReader(AExtensionUTF8: string; AReader: TBGRACustomLayeredBitmapClass);
     334function TryCreateLayeredBitmapWriter(AExtensionUTF8: string): TBGRALayeredBitmap;
     335function TryCreateLayeredBitmapReader(AExtensionUTF8: string): TBGRACustomLayeredBitmap;
    190336
    191337var
    192338  LayeredBitmapSaveToStreamProc : TBGRALayeredBitmapSaveToStreamProc;
    193339  LayeredBitmapLoadFromStreamProc : TBGRALayeredBitmapLoadFromStreamProc;
     340  LayeredBitmapCheckStreamProc: TBGRALayeredBitmapCheckStreamProc;
    194341
    195342type
     
    209356implementation
    210357
    211 uses BGRAUTF8;
     358uses BGRAUTF8, BGRABlend, BGRAMultiFileType, math;
     359
     360const
     361  OriginalsDirectory = 'originals';
    212362
    213363var
     
    227377  end;
    228378
     379{ TBGRALayerOriginalEntry }
     380
     381class operator TBGRALayerOriginalEntry.=(const AEntry1,
     382  AEntry2: TBGRALayerOriginalEntry): boolean;
     383begin
     384  result := AEntry1.Guid = AEntry2.Guid;
     385end;
     386
     387function BGRALayerOriginalEntry(AGuid: TGuid): TBGRALayerOriginalEntry;
     388begin
     389  result.Guid := AGuid;
     390  result.Instance := nil;
     391end;
     392
     393function BGRALayerOriginalEntry(AInstance: TBGRALayerCustomOriginal): TBGRALayerOriginalEntry;
     394begin
     395  result.Guid := AInstance.Guid;
     396  result.Instance := AInstance;
     397end;
     398
    229399{ TBGRALayeredBitmap }
    230400
     
    237407end;
    238408
     409function TBGRALayeredBitmap.GetLayerOriginal(layer: integer): TBGRALayerCustomOriginal;
     410var
     411  idxOrig: Integer;
     412begin
     413  if (layer < 0) or (layer >= NbLayers) then
     414    raise Exception.Create('Index out of bounds')
     415  else
     416  begin
     417    if FLayers[layer].OriginalGuid = GUID_NULL then exit(nil);
     418    idxOrig := IndexOfOriginal(FLayers[layer].OriginalGuid);
     419    if idxOrig = -1 then exit(nil);
     420    result := Original[idxOrig];
     421  end;
     422end;
     423
     424function TBGRALayeredBitmap.GetLayerOriginalMatrix(layer: integer
     425  ): TAffineMatrix;
     426begin
     427  if (layer < 0) or (layer >= NbLayers) then
     428    raise Exception.Create('Index out of bounds')
     429  else
     430    result := FLayers[layer].OriginalMatrix;
     431end;
     432
     433function TBGRALayeredBitmap.GetLayerOriginalGuid(layer: integer): TGuid;
     434begin
     435  if (layer < 0) or (layer >= NbLayers) then
     436    raise Exception.Create('Index out of bounds')
     437  else
     438    result := FLayers[layer].OriginalGuid;
     439end;
     440
     441function TBGRALayeredBitmap.GetLayerOriginalRenderStatus(layer: integer
     442  ): TOriginalRenderStatus;
     443begin
     444  if (layer < 0) or (layer >= NbLayers) then
     445    raise Exception.Create('Index out of bounds')
     446  else
     447    result := FLayers[layer].OriginalRenderStatus;
     448end;
     449
    239450procedure TBGRALayeredBitmap.SetLayerUniqueId(layer: integer; AValue: integer);
    240451var i: integer;
     
    245456  begin
    246457    for i := 0 to NbLayers-1 do
    247       if (i <> layer) and (FLayers[layer].UniqueId = AValue) then
     458      if (i <> layer) and (FLayers[i].UniqueId = AValue) then
    248459        raise Exception.Create('Another layer has the same identifier');
    249460    FLayers[layer].UniqueId := AValue;
    250461  end;
     462end;
     463
     464procedure TBGRALayeredBitmap.SetLayerOriginalMatrix(layer: integer;
     465  AValue: TAffineMatrix);
     466begin
     467  if (layer < 0) or (layer >= NbLayers) then
     468    raise Exception.Create('Index out of bounds')
     469  else
     470  begin
     471    if FLayers[layer].OriginalMatrix = AValue then exit;
     472    FLayers[layer].OriginalMatrix := AValue;
     473    if FLayers[layer].OriginalGuid <> GUID_NULL then
     474    begin
     475      FLayers[layer].OriginalRenderStatus := orsNone;
     476      Unfreeze(layer);
     477    end;
     478  end;
     479end;
     480
     481procedure TBGRALayeredBitmap.SetLayerOriginalGuid(layer: integer;
     482  const AValue: TGuid);
     483begin
     484  if (layer < 0) or (layer >= NbLayers) then
     485    raise Exception.Create('Index out of bounds')
     486  else
     487  begin
     488    if FLayers[layer].OriginalGuid = AValue then exit;
     489    FLayers[layer].OriginalGuid := AValue;
     490
     491    if (AValue <> GUID_NULL) and (IndexOfOriginal(AValue) <> -1) then
     492    begin
     493      FLayers[layer].OriginalRenderStatus := orsNone;
     494      Unfreeze(layer);
     495    end;
     496  end;
     497end;
     498
     499procedure TBGRALayeredBitmap.SetLayerOriginalRenderStatus(layer: integer;
     500  AValue: TOriginalRenderStatus);
     501begin
     502  if (layer < 0) or (layer >= NbLayers) then
     503    raise Exception.Create('Index out of bounds')
     504  else
     505  begin
     506    if FLayers[layer].OriginalRenderStatus = AValue then exit;
     507    FLayers[layer].OriginalRenderStatus := AValue;
     508    Unfreeze(layer);
     509  end;
     510end;
     511
     512procedure TBGRALayeredBitmap.FindOriginal(AGuid: TGuid; out
     513  ADir: TMemDirectory; out AClass: TBGRALayerOriginalAny);
     514var
     515  c: String;
     516begin
     517  ADir := nil;
     518  AClass := nil;
     519
     520  if HasMemFiles then
     521  begin
     522    ADir := MemDirectory.FindPath(OriginalsDirectory+'/'+GUIDToString(AGuid));
     523    if ADir <> nil then
     524    begin
     525      c := ADir.RawStringByFilename['class'];
     526      AClass := FindLayerOriginalClass(c);
     527    end;
     528  end;
     529end;
     530
     531procedure TBGRALayeredBitmap.StoreOriginal(AOriginal: TBGRALayerCustomOriginal);
     532var
     533  dir, subdir: TMemDirectory;
     534  storage: TBGRAMemOriginalStorage;
     535begin
     536  if AOriginal.Guid = GUID_NULL then raise exception.Create('Original GUID undefined');
     537  dir := MemDirectory.Directory[MemDirectory.AddDirectory(OriginalsDirectory)];
     538  subdir := dir.Directory[dir.AddDirectory(GUIDToString(AOriginal.Guid))];
     539  storage := TBGRAMemOriginalStorage.Create(subdir);
     540  try
     541    AOriginal.SaveToStorage(storage);
     542    storage.RawString['class'] := AOriginal.StorageClassName;
     543  finally
     544    storage.Free;
     545  end;
     546end;
     547
     548procedure TBGRALayeredBitmap.OriginalChange(ASender: TObject; ABounds: PRectF);
     549var
     550  i: Integer;
     551  orig: TBGRALayerCustomOriginal;
     552  transfBounds: TRectF;
     553begin
     554  orig := TBGRALayerCustomOriginal(ASender);
     555  if not (Assigned(ABounds) and IsEmptyRectF(ABounds^)) then
     556  begin
     557    for i := 0 to NbLayers-1 do
     558      if LayerOriginalGuid[i] = orig.Guid then
     559      begin
     560        if ABounds = nil then
     561          LayerOriginalRenderStatus[i] := orsNone
     562        else
     563        begin
     564          transfBounds := (LayerOriginalMatrix[i]*TAffineBox.AffineBox(ABounds^)).RectBoundsF;
     565          case LayerOriginalRenderStatus[i] of
     566          orsDraft: begin
     567                      LayerOriginalRenderStatus[i] := orsPartialDraft;
     568                      FLayers[i].OriginalInvalidatedBounds := transfBounds;
     569                    end;
     570          orsProof: begin
     571                      LayerOriginalRenderStatus[i] := orsPartialProof;
     572                      FLayers[i].OriginalInvalidatedBounds := transfBounds;
     573                    end;
     574          orsPartialDraft: FLayers[i].OriginalInvalidatedBounds :=
     575                             FLayers[i].OriginalInvalidatedBounds.Union(transfBounds, true);
     576          orsPartialProof: FLayers[i].OriginalInvalidatedBounds :=
     577                             FLayers[i].OriginalInvalidatedBounds.Union(transfBounds, true);
     578          end;
     579        end;
     580      end;
     581  end;
     582  if Assigned(FOriginalChange) then
     583    FOriginalChange(self, orig);
     584end;
     585
     586procedure TBGRALayeredBitmap.OriginalEditingChange(ASender: TObject);
     587var
     588  orig: TBGRALayerCustomOriginal;
     589begin
     590  orig := TBGRALayerCustomOriginal(ASender);
     591  if Assigned(FOriginalEditingChange) then
     592    FOriginalEditingChange(self, orig);
     593end;
     594
     595function TBGRALayeredBitmap.GetOriginalCount: integer;
     596begin
     597  if Assigned(FOriginals) then
     598    result := FOriginals.Count
     599  else
     600    result := 0;
     601end;
     602
     603function TBGRALayeredBitmap.GetOriginalByIndex(AIndex: integer
     604  ): TBGRALayerCustomOriginal;
     605var
     606  dir: TMemDirectory;
     607  c: TBGRALayerOriginalAny;
     608  guid: TGuid;
     609  storage: TBGRAMemOriginalStorage;
     610begin
     611  if (AIndex < 0) or (AIndex >= OriginalCount) then
     612    raise ERangeError.Create('Index out of bounds');
     613
     614  result := FOriginals[AIndex].Instance;
     615  guid := FOriginals[AIndex].Guid;
     616
     617  // load original on the fly
     618  if (result = nil) and (guid <> GUID_NULL) then
     619  begin
     620    FindOriginal(guid, dir, c);
     621    if not Assigned(dir) then
     622      raise exception.Create('Original directory not found');
     623    if not Assigned(c) then
     624      raise exception.Create('Original class not found (it can be registered with the RegisterLayerOriginal function)');
     625
     626    result := c.Create;
     627    result.Guid := guid;
     628    storage := TBGRAMemOriginalStorage.Create(dir);
     629    try
     630      result.LoadFromStorage(storage);
     631    finally
     632      storage.Free;
     633    end;
     634    FOriginals[AIndex] := BGRALayerOriginalEntry(result);
     635    result.OnChange:= @OriginalChange;
     636    result.OnEditingChange:= @OriginalEditingChange;
     637  end;
     638end;
     639
     640function TBGRALayeredBitmap.GetLayerOriginalKnown(layer: integer): boolean;
     641var
     642  idxOrig: Integer;
     643begin
     644  if (layer < 0) or (layer >= NbLayers) then
     645    raise Exception.Create('Index out of bounds')
     646  else
     647  begin
     648    if FLayers[layer].OriginalGuid = GUID_NULL then exit(true);
     649    idxOrig := IndexOfOriginal(FLayers[layer].OriginalGuid);
     650    if idxOrig = -1 then exit(false);
     651    result := OriginalKnown[idxOrig];
     652  end;
     653end;
     654
     655function TBGRALayeredBitmap.GetOriginalByIndexKnown(AIndex: integer): boolean;
     656var
     657  dir: TMemDirectory;
     658  c: TBGRALayerOriginalAny;
     659  guid: TGuid;
     660begin
     661  if (AIndex < 0) or (AIndex >= OriginalCount) then
     662    raise ERangeError.Create('Index out of bounds');
     663
     664  if Assigned(FOriginals[AIndex].Instance) then exit(true);
     665  guid := FOriginals[AIndex].Guid;
     666  if guid = GUID_NULL then exit(true);
     667
     668  FindOriginal(guid, dir, c);
     669  result:= Assigned(dir) and Assigned(c);
     670end;
     671
     672function TBGRALayeredBitmap.GetOriginalGuid(AIndex: integer): TGUID;
     673begin
     674  if (AIndex < 0) or (AIndex >= OriginalCount) then
     675    raise ERangeError.Create('Index out of bounds');
     676
     677  result := FOriginals[AIndex].Guid;
    251678end;
    252679
     
    374801      (FLayers[layer].y <> AValue.y) then
    375802    begin
     803      if FLayers[layer].OriginalGuid <> GUID_NULL then
     804        raise exception.Create('The offset of the layer is computed from an original. You can change it by changing the layer original matrix.');
     805
    376806      FLayers[layer].x := AValue.x;
    377807      FLayers[layer].y := AValue.y;
     
    402832end;
    403833
    404 function TBGRALayeredBitmap.GetLayerBitmapDirectly(layer: integer
    405   ): TBGRABitmap;
     834function TBGRALayeredBitmap.GetLayerBitmapDirectly(layer: integer): TBGRABitmap;
    406835begin
    407836  if (layer < 0) or (layer >= NbLayers) then
    408837    result := nil
    409838  else
     839  begin
     840    if FLayers[layer].OriginalRenderStatus = orsNone then
     841      RenderLayerFromOriginal(layer, true)
     842    else if FLayers[layer].OriginalRenderStatus in [orsPartialDraft,orsPartialProof] then
     843      RenderLayerFromOriginal(layer, true, FLayers[layer].OriginalInvalidatedBounds);
    410844    Result:= FLayers[layer].Source;
     845  end;
    411846end;
    412847
    413848procedure TBGRALayeredBitmap.LoadFromFile(const filenameUTF8: string);
    414849var bmp: TBGRABitmap;
    415     index: integer;
    416850    ext: string;
    417851    temp: TBGRACustomLayeredBitmap;
    418852    i: integer;
     853    stream: TFileStreamUTF8;
    419854begin
    420855  ext := UTF8LowerCase(ExtractFileExt(filenameUTF8));
     
    432867    end;
    433868
    434   bmp := TBGRABitmap.Create(filenameUTF8, True);
    435   Clear;
    436   SetSize(bmp.Width,bmp.Height);
    437   index := AddSharedLayer(bmp);
    438   FLayers[index].Owner:= true;
     869  //when using "data" extension, simply deserialize
     870  if (ext='.dat') or (ext='.data') then
     871  begin
     872    if Assigned(LayeredBitmapLoadFromStreamProc) then
     873    begin
     874      stream := TFileStreamUTF8.Create(filenameUTF8, fmOpenRead, fmShareDenyWrite);
     875      try
     876        LayeredBitmapLoadFromStreamProc(stream, self);
     877      finally
     878        stream.Free;
     879      end;
     880    end else
     881      raise exception.Create('Enable layer deserialization by calling BGRAStreamLayers.RegisterStreamLayers');
     882  end else
     883  begin
     884    bmp := TBGRABitmap.Create(filenameUTF8, True);
     885    Clear;
     886    SetSize(bmp.Width,bmp.Height);
     887    AddOwnedLayer(bmp);
     888  end;
    439889end;
    440890
    441891procedure TBGRALayeredBitmap.LoadFromStream(stream: TStream);
    442892var bmp: TBGRABitmap;
    443    index: integer;
    444    temp: TBGRALayeredBitmap;
    445893begin
    446894  if Assigned(LayeredBitmapLoadFromStreamProc) then
    447895  begin
    448     temp := LayeredBitmapLoadFromStreamProc(Stream);
    449     if temp <> nil then
    450     begin
    451       Assign(temp);
    452       temp.Free;
     896    if not Assigned(LayeredBitmapCheckStreamProc) or
     897      LayeredBitmapCheckStreamProc(stream) then
     898    begin
     899      LayeredBitmapLoadFromStreamProc(Stream, self);
    453900      exit;
    454901    end;
    455902  end;
     903
    456904  bmp := TBGRABitmap.Create(stream);
    457905  Clear;
    458906  SetSize(bmp.Width,bmp.Height);
    459   index := AddSharedLayer(bmp);
    460   FLayers[index].Owner:= true;
     907  AddOwnedLayer(bmp);
     908end;
     909
     910procedure TBGRALayeredBitmap.LoadFromResource(AFilename: string);
     911var
     912  stream: TStream;
     913begin
     914  stream := BGRAResource.GetResourceStream(AFilename);
     915  try
     916    LoadFromStream(stream);
     917  finally
     918    stream.Free;
     919  end;
    461920end;
    462921
     
    474933  for i := NbLayers-1 downto 0 do
    475934    RemoveLayer(i);
     935  MemDirectory := nil;
     936  ClearOriginals;
     937end;
     938
     939procedure TBGRALayeredBitmap.ClearOriginals;
     940var
     941  i: Integer;
     942begin
     943  if Assigned(FOriginals) then
     944  begin
     945    for i := 0 to OriginalCount-1 do
     946      FOriginals[i].Instance.Free;
     947    FreeAndNil(FOriginals);
     948  end;
    476949end;
    477950
     
    503976
    504977procedure TBGRALayeredBitmap.Assign(ASource: TBGRACustomLayeredBitmap; ASharedLayerIds: boolean);
    505 var i,idx: integer;
    506 begin
     978var i,idx,idxOrig,idxNewOrig: integer;
     979    usedOriginals: array of record
     980       used: boolean;
     981       sourceGuid,newGuid: TGuid;
     982    end;
     983    orig: TBGRALayerCustomOriginal;
     984    stream: TMemoryStream;
     985
     986begin
     987  if ASource = nil then
     988    raise exception.Create('Unexpected nil reference');
    507989  Clear;
    508990  SetSize(ASource.Width,ASource.Height);
    509991  LinearBlend:= ASource.LinearBlend;
     992  setlength(usedOriginals, ASource.GetOriginalCount);
     993  for idxOrig := 0 to high(usedOriginals) do
     994  with usedOriginals[idxOrig] do
     995  begin
     996    used:= false;
     997    newGuid := GUID_NULL;
     998  end;
     999  for i := 0 to ASource.NbLayers-1 do
     1000  if (ASource.LayerOriginalGuid[i]<>GUID_NULL) and
     1001     (ASource.LayerOriginalKnown[i] or (ASource is TBGRALayeredBitmap)) then
     1002  begin
     1003    idxOrig := ASource.IndexOfOriginal(ASource.LayerOriginalGuid[i]);
     1004    if not usedOriginals[idxOrig].used then
     1005    begin
     1006      if ASource.LayerOriginalKnown[i] then
     1007      begin
     1008        orig := ASource.GetOriginalByIndex(idxOrig);
     1009        idxNewOrig := AddOriginal(orig, false);
     1010        usedOriginals[idxOrig].sourceGuid := orig.Guid;
     1011      end else
     1012      begin
     1013        stream := TMemoryStream.Create;
     1014        (ASource as TBGRALayeredBitmap).SaveOriginalToStream(idxOrig, stream);
     1015        stream.Position:= 0;
     1016        idxNewOrig := AddOriginalFromStream(stream,true);
     1017        stream.Free;
     1018        usedOriginals[idxOrig].sourceGuid := (ASource as TBGRALayeredBitmap).OriginalGuid[idxOrig];
     1019      end;
     1020      usedOriginals[idxOrig].newGuid := OriginalGuid[idxNewOrig];
     1021      usedOriginals[idxOrig].used := true;
     1022    end;
     1023  end;
    5101024  for i := 0 to ASource.NbLayers-1 do
    5111025  begin
     
    5141028    LayerVisible[idx] := ASource.LayerVisible[i];
    5151029    if ASharedLayerIds and (ASource is TBGRALayeredBitmap) then
    516       LayerUniqueId[idx] := TBGRALayeredBitmap(ASource).LayerUniqueId[idx];
     1030      LayerUniqueId[idx] := TBGRALayeredBitmap(ASource).LayerUniqueId[i];
     1031    for idxOrig := 0 to high(usedOriginals) do
     1032      if usedOriginals[i].sourceGuid = ASource.LayerOriginalGuid[i] then
     1033      begin
     1034        LayerOriginalGuid[idx] := usedOriginals[i].newGuid;
     1035        LayerOriginalMatrix[idx] := ASource.LayerOriginalMatrix[i];
     1036        LayerOriginalRenderStatus[idx] := ASource.LayerOriginalRenderStatus[i];
     1037      end;
    5171038  end;
    5181039end;
     
    5811102  FLayers[FNbLayers].Frozen := false;
    5821103  FLayers[FNbLayers].UniqueId := ProduceLayerUniqueId;
     1104  FLayers[FNbLayers].OriginalMatrix := AffineMatrixIdentity;
     1105  FLayers[FNbLayers].OriginalRenderStatus := orsNone;
     1106  FLayers[FNbLayers].OriginalGuid := GUID_NULL;
    5831107  if Shared then
    5841108  begin
     
    6881212end;
    6891213
     1214function TBGRALayeredBitmap.AddLayerFromOriginal(AGuid: TGuid;
     1215  Opacity: byte): integer;
     1216begin
     1217  result := AddLayerFromOriginal(AGuid, DefaultBlendingOperation, Opacity);
     1218end;
     1219
     1220function TBGRALayeredBitmap.AddLayerFromOriginal(AGuid: TGuid;
     1221  BlendOp: TBlendOperation; Opacity: byte): integer;
     1222begin
     1223  result := AddLayerFromOriginal(AGuid, AffineMatrixIdentity, BlendOp, Opacity);
     1224end;
     1225
     1226function TBGRALayeredBitmap.AddLayerFromOriginal(AGuid: TGuid;
     1227  Matrix: TAffineMatrix; Opacity: byte): integer;
     1228begin
     1229  result := AddLayerFromOriginal(AGuid, Matrix, DefaultBlendingOperation, Opacity);
     1230end;
     1231
     1232function TBGRALayeredBitmap.AddLayerFromOriginal(AGuid: TGuid;
     1233  Matrix: TAffineMatrix; BlendOp: TBlendOperation; Opacity: byte): integer;
     1234begin
     1235  result := AddOwnedLayer(TBGRABitmap.Create, BlendOp, Opacity);
     1236  LayerOriginalGuid[result] := AGuid;
     1237  LayerOriginalMatrix[result] := Matrix;
     1238  if not Assigned(LayerOriginal[result]) then
     1239    raise exception.Create('Original data or class not found');
     1240end;
     1241
     1242function TBGRALayeredBitmap.AddLayerFromOwnedOriginal(
     1243  AOriginal: TBGRALayerCustomOriginal; Opacity: byte): integer;
     1244begin
     1245  if IndexOfOriginal(AOriginal) = -1 then AddOriginal(AOriginal);
     1246  result := AddLayerFromOriginal(AOriginal.Guid, Opacity);
     1247end;
     1248
     1249function TBGRALayeredBitmap.AddLayerFromOwnedOriginal(
     1250  AOriginal: TBGRALayerCustomOriginal; BlendOp: TBlendOperation; Opacity: byte): integer;
     1251begin
     1252  if IndexOfOriginal(AOriginal) = -1 then AddOriginal(AOriginal);
     1253  result := AddLayerFromOriginal(AOriginal.Guid, BlendOp, Opacity);
     1254end;
     1255
     1256function TBGRALayeredBitmap.AddLayerFromOwnedOriginal(
     1257  AOriginal: TBGRALayerCustomOriginal; Matrix: TAffineMatrix; Opacity: byte): integer;
     1258begin
     1259  if IndexOfOriginal(AOriginal) = -1 then AddOriginal(AOriginal);
     1260  result := AddLayerFromOriginal(AOriginal.Guid, Matrix, Opacity);
     1261end;
     1262
     1263function TBGRALayeredBitmap.AddLayerFromOwnedOriginal(
     1264  AOriginal: TBGRALayerCustomOriginal; Matrix: TAffineMatrix;
     1265  BlendOp: TBlendOperation; Opacity: byte): integer;
     1266begin
     1267  if IndexOfOriginal(AOriginal) = -1 then AddOriginal(AOriginal);
     1268  result := AddLayerFromOriginal(AOriginal.Guid, Matrix, BlendOp, Opacity);
     1269end;
     1270
     1271function TBGRALayeredBitmap.AddOriginal(AOriginal: TBGRALayerCustomOriginal; AOwned: boolean): integer;
     1272var
     1273  newGuid: TGuid;
     1274begin
     1275  if AOriginal = nil then
     1276    raise exception.Create('Unexpected nil reference');;
     1277  if AOriginal.Guid = GUID_NULL then
     1278  begin
     1279    if CreateGUID(newGuid)<> 0 then
     1280    begin
     1281      if AOwned then AOriginal.Free;
     1282      raise exception.Create('Error while creating GUID');
     1283    end;
     1284    AOriginal.Guid := newGuid;
     1285  end else
     1286  begin
     1287    if IndexOfOriginal(AOriginal) <> -1 then
     1288    begin
     1289      if AOwned then AOriginal.Free;
     1290      raise exception.Create('Original already added');
     1291    end;
     1292    if IndexOfOriginal(AOriginal.Guid) <> -1 then
     1293    begin
     1294      if AOwned then AOriginal.Free;
     1295      raise exception.Create('GUID is already in use');
     1296    end;
     1297  end;
     1298  StoreOriginal(AOriginal);
     1299  if FOriginals = nil then FOriginals := TBGRALayerOriginalList.Create;
     1300  if AOwned then
     1301  begin
     1302    result := FOriginals.Add(BGRALayerOriginalEntry(AOriginal));
     1303    AOriginal.OnChange:= @OriginalChange;
     1304    AOriginal.OnEditingChange:= @OriginalEditingChange;
     1305  end
     1306  else
     1307    result := FOriginals.Add(BGRALayerOriginalEntry(AOriginal.Guid));
     1308end;
     1309
     1310function TBGRALayeredBitmap.AddOriginalFromStream(AStream: TStream;
     1311  ALateLoad: boolean): integer;
     1312var
     1313  storage: TBGRAMemOriginalStorage;
     1314begin
     1315  storage:= TBGRAMemOriginalStorage.Create;
     1316  storage.LoadFromStream(AStream);
     1317  try
     1318    result := AddOriginalFromStorage(storage, ALateLoad);
     1319  finally
     1320    storage.Free;
     1321  end;
     1322end;
     1323
     1324function TBGRALayeredBitmap.AddOriginalFromStorage(AStorage: TBGRAMemOriginalStorage; ALateLoad: boolean): integer;
     1325var
     1326  origClassName: String;
     1327  origClass: TBGRALayerOriginalAny;
     1328  orig: TBGRALayerCustomOriginal;
     1329  newGuid: TGuid;
     1330  dir, subdir: TMemDirectory;
     1331begin
     1332  result := -1;
     1333  origClassName := AStorage.RawString['class'];
     1334  if origClassName = '' then raise Exception.Create('Original class name not defined');
     1335  if ALateLoad then
     1336  begin
     1337    if CreateGUID(newGuid)<> 0 then
     1338      raise exception.Create('Error while creating GUID');
     1339    if IndexOfOriginal(newGuid)<>-1 then
     1340      raise exception.Create('Duplicate GUID');
     1341
     1342    dir := MemDirectory.Directory[MemDirectory.AddDirectory(OriginalsDirectory)];
     1343    subdir := dir.Directory[dir.AddDirectory(GUIDToString(newGuid))];
     1344    AStorage.CopyTo(subdir);
     1345
     1346    if FOriginals = nil then FOriginals := TBGRALayerOriginalList.Create;
     1347    result := FOriginals.Add(BGRALayerOriginalEntry(newGuid));
     1348  end else
     1349  begin
     1350    origClass := FindLayerOriginalClass(origClassName);
     1351    if origClass = nil then raise exception.Create('Original class not found (it can be registered with the RegisterLayerOriginal function)');
     1352    orig := origClass.Create;
     1353    try
     1354      orig.LoadFromStorage(AStorage);
     1355      result := AddOriginal(orig, true);
     1356    except on ex:exception do
     1357      begin
     1358        orig.Free;
     1359        raise exception.Create('Error loading original. '+ ex.Message);
     1360      end;
     1361    end;
     1362  end;
     1363end;
     1364
     1365procedure TBGRALayeredBitmap.SaveOriginalToStream(AIndex: integer;
     1366  AStream: TStream);
     1367var
     1368  dir: TMemDirectory;
     1369  c: TBGRALayerOriginalAny;
     1370begin
     1371  if (AIndex < 0) or (AIndex >= OriginalCount) then
     1372    raise ERangeError.Create('Index out of bounds');
     1373
     1374  if Assigned(FOriginals[AIndex].Instance) then
     1375    FOriginals[AIndex].Instance.SaveToStream(AStream)
     1376  else
     1377  begin
     1378    FindOriginal(FOriginals[AIndex].Guid, dir, c);
     1379    if dir = nil then
     1380      raise exception.Create('Originals directory not found');
     1381    dir.SaveToStream(AStream);
     1382  end;
     1383end;
     1384
     1385procedure TBGRALayeredBitmap.SaveOriginalToStream(AGuid: TGUID; AStream: TStream);
     1386var
     1387  idxOrig: Integer;
     1388begin
     1389  idxOrig := IndexOfOriginal(AGuid);
     1390  if idxOrig = -1 then raise exception.Create('Original not found');
     1391  SaveOriginalToStream(idxOrig, AStream);
     1392end;
     1393
     1394function TBGRALayeredBitmap.RemoveOriginal(AOriginal: TBGRALayerCustomOriginal): boolean;
     1395var
     1396  idx: Integer;
     1397begin
     1398  idx := IndexOfOriginal(AOriginal);
     1399  if idx = -1 then exit(false);
     1400  DeleteOriginal(idx);
     1401  result := true;
     1402end;
     1403
     1404procedure TBGRALayeredBitmap.DeleteOriginal(AIndex: integer);
     1405var
     1406  dir: TMemDirectory;
     1407  i: Integer;
     1408  guid: TGuid;
     1409begin
     1410  if (AIndex < 0) or (AIndex >= OriginalCount) then
     1411    raise ERangeError.Create('Index out of bounds');
     1412
     1413  guid := FOriginals[AIndex].Guid;
     1414  for i := 0 to NbLayers-1 do
     1415    if LayerOriginalGuid[i] = guid then
     1416    begin
     1417      LayerOriginalGuid[i] := GUID_NULL;
     1418      LayerOriginalMatrix[i] := AffineMatrixIdentity;
     1419    end;
     1420
     1421  dir := MemDirectory.Directory[MemDirectory.AddDirectory(OriginalsDirectory)];
     1422  dir.Delete(GUIDToString(guid),'');
     1423
     1424  FOriginals[AIndex].Instance.Free;
     1425  FOriginals.Delete(AIndex); //AOriginals freed
     1426end;
     1427
     1428procedure TBGRALayeredBitmap.NotifyLoaded;
     1429var
     1430  foundGuid: array of TGuid;
     1431  nbFoundGuid: integer;
     1432
     1433  procedure AddGuid(const AGuid: TGuid);
     1434  begin
     1435    foundGuid[nbFoundGuid] := AGuid;
     1436    inc(nbFoundGuid);
     1437  end;
     1438
     1439  function IndexOfGuid(AGuid: TGuid): integer;
     1440  var
     1441    i: Integer;
     1442  begin
     1443    for i := 0 to nbFoundGuid-1 do
     1444      if foundGuid[i] = AGuid then exit(i);
     1445    result := -1;
     1446  end;
     1447
     1448var
     1449  i: Integer;
     1450  dir: TMemDirectory;
     1451  newGuid: TGUID;
     1452
     1453begin
     1454  inherited NotifyLoaded;
     1455
     1456  //if there are no files in memory, we are sure that there are no originals
     1457  if not HasMemFiles then
     1458  begin
     1459    ClearOriginals;
     1460    exit;
     1461  end;
     1462
     1463  //determine list of GUID of originals
     1464  dir := MemDirectory.Directory[MemDirectory.AddDirectory(OriginalsDirectory)];
     1465  setlength(foundGuid, dir.Count);
     1466  nbFoundGuid:= 0;
     1467  for i := 0 to dir.Count-1 do
     1468    if dir.IsDirectory[i] and (dir.Entry[i].Extension = '') then
     1469    begin
     1470      if TryStringToGUID(dir.Entry[i].Name, newGuid) then
     1471        AddGuid(newGuid);
     1472    end;
     1473
     1474  //remove originals that do not exist anymore
     1475  for i := OriginalCount-1 downto 0 do
     1476    if IndexOfGuid(FOriginals[i].Guid) = -1 then
     1477      DeleteOriginal(i);
     1478
     1479  //add originals from memory directory
     1480  for i := 0 to nbFoundGuid-1 do
     1481  begin
     1482    if IndexOfOriginal(foundGuid[i]) = -1 then
     1483    begin
     1484      if FOriginals = nil then FOriginals := TBGRALayerOriginalList.Create;
     1485      FOriginals.Add(BGRALayerOriginalEntry(foundGuid[i]));
     1486    end;
     1487  end;
     1488end;
     1489
     1490procedure TBGRALayeredBitmap.NotifySaving;
     1491var
     1492  i: Integer;
     1493begin
     1494  inherited NotifySaving;
     1495
     1496  RenderOriginalsIfNecessary;
     1497
     1498  for i := 0 to OriginalCount-1 do
     1499    if Assigned(FOriginals[i].Instance) then
     1500      StoreOriginal(FOriginals[i].Instance);
     1501end;
     1502
     1503procedure TBGRALayeredBitmap.RenderLayerFromOriginal(layer: integer;
     1504  ADraft: boolean; AFullSizeLayer: boolean = false);
     1505begin
     1506  RenderLayerFromOriginal(layer, ADraft, rectF(0,0,Width,Height), AFullSizeLayer);
     1507end;
     1508
     1509procedure TBGRALayeredBitmap.RenderLayerFromOriginal(layer: integer;
     1510  ADraft: boolean; ARenderBounds: TRect; AFullSizeLayer: boolean = false);
     1511var
     1512  orig: TBGRALayerCustomOriginal;
     1513  rAll, rNewBounds, rInterRender: TRect;
     1514  newSource: TBGRABitmap;
     1515
     1516  procedure FreeSource;
     1517  begin
     1518    if FLayers[layer].Owner then
     1519      FreeAndNil(FLayers[layer].Source)
     1520    else
     1521      FLayers[layer].Source := nil;
     1522  end;
     1523
     1524begin
     1525  if (layer < 0) or (layer >= NbLayers) then
     1526    raise Exception.Create('Index out of bounds');
     1527
     1528  orig := LayerOriginal[layer];
     1529  if Assigned(orig) then
     1530  begin
     1531    rAll := rect(0,0,Width,Height);
     1532    if AFullSizeLayer then
     1533      rNewBounds := rAll
     1534    else
     1535    begin
     1536      rNewBounds := orig.GetRenderBounds(rAll,FLayers[layer].OriginalMatrix);
     1537      IntersectRect({%H-}rNewBounds, rNewBounds, rAll);
     1538    end;
     1539    IntersectRect({%H-}rInterRender, ARenderBounds, rNewBounds);
     1540    if (FLayers[layer].x = rNewBounds.Left) and
     1541      (FLayers[layer].y = rNewBounds.Top) and
     1542      (FLayers[layer].Source.Width = rNewBounds.Width) and
     1543      (FLayers[layer].Source.Height = rNewBounds.Height) then
     1544    begin
     1545      OffsetRect(rInterRender, -rNewBounds.Left, -rNewBounds.Top);
     1546      FLayers[layer].Source.FillRect(rInterRender, BGRAPixelTransparent, dmSet);
     1547      FLayers[layer].Source.ClipRect := rInterRender;
     1548      orig.Render(FLayers[layer].Source, AffineMatrixTranslation(-rNewBounds.Left,-rNewBounds.Top)*FLayers[layer].OriginalMatrix, ADraft);
     1549      FLayers[layer].Source.NoClip;
     1550    end else
     1551    begin
     1552      if rInterRender = rNewBounds then
     1553      begin
     1554        FreeSource;
     1555        newSource := TBGRABitmap.Create(rNewBounds.Width,rNewBounds.Height);
     1556        orig.Render(newSource, AffineMatrixTranslation(-rNewBounds.Left,-rNewBounds.Top)*FLayers[layer].OriginalMatrix, ADraft);
     1557      end else
     1558      begin
     1559        newSource := TBGRABitmap.Create(rNewBounds.Width,rNewBounds.Height);
     1560        newSource.PutImage(FLayers[layer].x - rNewBounds.Left, FLayers[layer].y - rNewBounds.Top, FLayers[layer].Source, dmSet);
     1561        FreeSource;
     1562        OffsetRect(rInterRender, -rNewBounds.Left, -rNewBounds.Top);
     1563        if not IsRectEmpty(rInterRender) then
     1564        begin
     1565          newSource.FillRect(rInterRender, BGRAPixelTransparent, dmSet);
     1566          newSource.ClipRect := rInterRender;
     1567          orig.Render(newSource, AffineMatrixTranslation(-rNewBounds.Left,-rNewBounds.Top)*FLayers[layer].OriginalMatrix, ADraft);
     1568          newSource.NoClip;
     1569        end;
     1570      end;
     1571      FLayers[layer].Source := newSource;
     1572      FLayers[layer].x := rNewBounds.Left;
     1573      FLayers[layer].y := rNewBounds.Top;
     1574    end;
     1575  end;
     1576  if ADraft then
     1577    FLayers[layer].OriginalRenderStatus := orsDraft
     1578  else
     1579    FLayers[layer].OriginalRenderStatus := orsProof;
     1580  FLayers[layer].OriginalInvalidatedBounds := EmptyRectF;
     1581end;
     1582
     1583procedure TBGRALayeredBitmap.RenderLayerFromOriginal(layer: integer;
     1584  ADraft: boolean; ARenderBoundsF: TRectF; AFullSizeLayer: boolean = false);
     1585var
     1586  r: TRect;
     1587begin
     1588  with ARenderBoundsF do
     1589    r := Rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
     1590  RenderLayerFromOriginal(layer, ADraft, r, AFullSizeLayer);
     1591end;
     1592
     1593function TBGRALayeredBitmap.RenderOriginalsIfNecessary(ADraft: boolean): TRect;
     1594  procedure UnionLayerArea(ALayer: integer);
     1595  var
     1596    r: TRect;
     1597  begin
     1598    if (FLayers[ALayer].Source = nil) or
     1599      (FLayers[ALayer].Source.Width = 0) or
     1600      (FLayers[ALayer].Source.Height = 0) then exit;
     1601
     1602    r := RectWithSize(LayerOffset[ALayer].X, LayerOffset[ALayer].Y,
     1603                      FLayers[ALayer].Source.Width, FLayers[ALayer].Source.Height);
     1604    if IsRectEmpty(result) then result := r else
     1605      UnionRect(result,result,r);
     1606  end;
     1607
     1608var
     1609  i: Integer;
     1610  r: TRect;
     1611
     1612begin
     1613  result:= EmptyRect;
     1614  for i := 0 to NbLayers-1 do
     1615    case LayerOriginalRenderStatus[i] of
     1616    orsNone:
     1617         begin
     1618           UnionLayerArea(i);
     1619           RenderLayerFromOriginal(i, ADraft);
     1620           UnionLayerArea(i);
     1621         end;
     1622    orsDraft: if not ADraft then
     1623         begin
     1624           UnionLayerArea(i);
     1625           RenderLayerFromOriginal(i, ADraft);
     1626           UnionLayerArea(i);
     1627         end;
     1628    orsPartialDraft,orsPartialProof:
     1629         if not ADraft and (LayerOriginalRenderStatus[i] = orsPartialDraft) then
     1630         begin
     1631           UnionLayerArea(i);
     1632           RenderLayerFromOriginal(i, ADraft, rect(0,0,Width,Height), true);
     1633           UnionLayerArea(i);
     1634         end
     1635         else
     1636         begin
     1637           with FLayers[i].OriginalInvalidatedBounds do
     1638             r := Rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
     1639           RenderLayerFromOriginal(i, ADraft, r, true);
     1640           if not IsRectEmpty(r) then
     1641           begin
     1642             if IsRectEmpty(result) then
     1643               result := r
     1644             else
     1645               UnionRect(result, result, r);
     1646           end;
     1647         end;
     1648    end;
     1649end;
     1650
     1651procedure TBGRALayeredBitmap.RemoveUnusedOriginals;
     1652var useCount: array of integer;
     1653  i, idxOrig: Integer;
     1654begin
     1655  if OriginalCount = 0 then exit;
     1656  setlength(useCount, OriginalCount);
     1657  for i := 0 to NbLayers-1 do
     1658  begin
     1659    idxOrig := IndexOfOriginal(LayerOriginalGuid[i]);
     1660    if idxOrig <> -1 then useCount[idxOrig] += 1;
     1661  end;
     1662  for i := high(useCount) downto 0 do
     1663    if useCount[i] = 0 then DeleteOriginal(i);
     1664end;
     1665
    6901666destructor TBGRALayeredBitmap.Destroy;
    6911667begin
     1668  FOriginalEditor.Free;
    6921669  inherited Destroy;
    6931670end;
     
    6991676  FHeight := 0;
    7001677  FNbLayers:= 0;
     1678  FOriginals := nil;
    7011679end;
    7021680
     
    7451723procedure TBGRALayeredBitmap.RotateCW;
    7461724var i: integer;
     1725  newBmp: TBGRABitmap;
     1726  newOfs: TPointF;
     1727  m: TAffineMatrix;
    7471728begin
    7481729  SetSize(Height,Width); //unfreeze
     1730  m := AffineMatrixTranslation(Width,0)*AffineMatrixRotationDeg(90);
    7491731  for i := 0 to NbLayers-1 do
    750     SetLayerBitmap(i, LayerBitmap[i].RotateCW as TBGRABitmap, True);
     1732  begin
     1733    newOfs:= m*PointF(FLayers[i].x,FLayers[i].y+FLayers[i].Source.Height);
     1734    newBmp := FLayers[i].Source.RotateCW as TBGRABitmap;
     1735    if FLayers[i].Owner then FreeAndNil(FLayers[i].Source);
     1736    FLayers[i].Source := newBmp;
     1737    FLayers[i].Owner := true;
     1738    FLayers[i].x := round(newOfs.x);
     1739    FLayers[i].y := round(newOfs.y);
     1740    FLayers[i].OriginalMatrix := m*FLayers[i].OriginalMatrix;
     1741  end;
    7511742end;
    7521743
    7531744procedure TBGRALayeredBitmap.RotateCCW;
    7541745var i: integer;
     1746  newBmp: TBGRABitmap;
     1747  newOfs: TPointF;
     1748  m: TAffineMatrix;
    7551749begin
    7561750  SetSize(Height,Width); //unfreeze
     1751  m := AffineMatrixTranslation(0,Height)*AffineMatrixRotationDeg(-90);
    7571752  for i := 0 to NbLayers-1 do
    758     SetLayerBitmap(i, LayerBitmap[i].RotateCCW as TBGRABitmap, True);
     1753  begin
     1754    newOfs:= m*PointF(FLayers[i].x+FLayers[i].Source.Width,FLayers[i].y);
     1755    newBmp := FLayers[i].Source.RotateCCW as TBGRABitmap;
     1756    if FLayers[i].Owner then FreeAndNil(FLayers[i].Source);
     1757    FLayers[i].Source := newBmp;
     1758    FLayers[i].Owner := true;
     1759    FLayers[i].x := round(newOfs.x);
     1760    FLayers[i].y := round(newOfs.y);
     1761    FLayers[i].OriginalMatrix := m*FLayers[i].OriginalMatrix;
     1762  end;
    7591763end;
    7601764
     
    7641768  Unfreeze;
    7651769  for i := 0 to NbLayers-1 do
    766   begin
    767     if FLayers[i].Owner then
    768       FLayers[i].Source.HorizontalFlip
    769     else
    770     begin
    771       FLayers[i].Source := FLayers[i].Source.Duplicate(True) as TBGRABitmap;
    772       FLayers[i].Source.HorizontalFlip;
    773       FLayers[i].Owner := true;
    774     end;
    775   end;
     1770    HorizontalFlip(i);
     1771end;
     1772
     1773procedure TBGRALayeredBitmap.HorizontalFlip(ALayerIndex: integer);
     1774begin
     1775  if (ALayerIndex < 0) or (ALayerIndex >= NbLayers) then
     1776    raise ERangeError.Create('Index out of bounds');
     1777  Unfreeze(ALayerIndex);
     1778  if FLayers[ALayerIndex].Owner then
     1779    FLayers[ALayerIndex].Source.HorizontalFlip
     1780  else
     1781  begin
     1782    FLayers[ALayerIndex].Source := FLayers[ALayerIndex].Source.Duplicate(True) as TBGRABitmap;
     1783    FLayers[ALayerIndex].Source.HorizontalFlip;
     1784    FLayers[ALayerIndex].Owner := true;
     1785  end;
     1786  FLayers[ALayerIndex].x := Width-FLayers[ALayerIndex].x-FLayers[ALayerIndex].Source.Width;
     1787  FLayers[ALayerIndex].OriginalMatrix := AffineMatrixTranslation(+Width/2,0)*AffineMatrixScale(-1,1)*AffineMatrixTranslation(-Width/2,0)*FLayers[ALayerIndex].OriginalMatrix;
    7761788end;
    7771789
     
    7811793  Unfreeze;
    7821794  for i := 0 to NbLayers-1 do
    783   begin
    784     if FLayers[i].Owner then
    785       FLayers[i].Source.VerticalFlip
    786     else
    787     begin
    788       FLayers[i].Source := FLayers[i].Source.Duplicate(True) as TBGRABitmap;
    789       FLayers[i].Source.VerticalFlip;
    790       FLayers[i].Owner := true;
    791     end;
    792   end;
     1795    VerticalFlip(i);
     1796end;
     1797
     1798procedure TBGRALayeredBitmap.VerticalFlip(ALayerIndex: integer);
     1799begin
     1800  if (ALayerIndex < 0) or (ALayerIndex >= NbLayers) then
     1801    raise ERangeError.Create('Index out of bounds');
     1802  Unfreeze(ALayerIndex);
     1803  if FLayers[ALayerIndex].Owner then
     1804    FLayers[ALayerIndex].Source.VerticalFlip
     1805  else
     1806  begin
     1807    FLayers[ALayerIndex].Source := FLayers[ALayerIndex].Source.Duplicate(True) as TBGRABitmap;
     1808    FLayers[ALayerIndex].Source.VerticalFlip;
     1809    FLayers[ALayerIndex].Owner := true;
     1810  end;
     1811  FLayers[ALayerIndex].y := Height-FLayers[ALayerIndex].y-FLayers[ALayerIndex].Source.Height;
     1812  FLayers[ALayerIndex].OriginalMatrix := AffineMatrixTranslation(0,+Height/2)*AffineMatrixScale(1,-1)*AffineMatrixTranslation(0,-Height/2)*FLayers[ALayerIndex].OriginalMatrix;
    7931813end;
    7941814
    7951815procedure TBGRALayeredBitmap.Resample(AWidth, AHeight: integer;
    7961816  AResampleMode: TResampleMode; AFineResampleFilter: TResampleFilter);
    797 var i: integer;
     1817var i, prevWidth, prevHeight: integer;
    7981818    resampled: TBGRABitmap;
    7991819    oldFilter : TResampleFilter;
     
    8011821  if (AWidth < 0) or (AHeight < 0) then
    8021822    raise exception.Create('Invalid size');
     1823  prevWidth := Width;
     1824  if prevWidth < 1 then prevWidth := AWidth;
     1825  prevHeight := Height;
     1826  if prevHeight < 1 then prevHeight := AHeight;
    8031827  SetSize(AWidth, AHeight); //unfreeze
    8041828  for i := 0 to NbLayers-1 do
     1829  if (FLayers[i].OriginalGuid <> GUID_NULL) and LayerOriginalKnown[i] then
     1830    LayerOriginalMatrix[i] := AffineMatrixScale(AWidth/prevWidth,AHeight/prevHeight)*LayerOriginalMatrix[i]
     1831  else
    8051832  begin
    8061833    oldFilter := LayerBitmap[i].ResampleFilter;
     
    8101837    SetLayerBitmap(i, resampled, True);
    8111838  end;
     1839  if AResampleMode = rmFineResample then RenderOriginalsIfNecessary;
    8121840end;
    8131841
     
    8241852    FLayers[layer].Source := ABitmap;
    8251853    FLayers[layer].Owner := AOwned;
    826   end;
     1854    FLayers[layer].OriginalGuid := GUID_NULL;
     1855    FLayers[layer].OriginalMatrix := AffineMatrixIdentity;
     1856  end;
     1857end;
     1858
     1859procedure TBGRALayeredBitmap.ApplyLayerOffset(ALayerIndex: integer;
     1860  APadWithTranparentPixels: boolean);
     1861var
     1862  r: TRect;
     1863  newBmp: TBGRABitmap;
     1864begin
     1865  if APadWithTranparentPixels then
     1866  begin
     1867    if (LayerOffset[ALayerIndex].X=0) and (LayerOffset[ALayerIndex].Y=0) and
     1868       (LayerBitmap[ALayerIndex].Width=Width) and (LayerBitmap[ALayerIndex].Height=Height) then exit;
     1869    newBmp := TBGRABitmap.Create(Width,Height);
     1870    newBmp.PutImage(LayerOffset[ALayerIndex].X, LayerOffset[ALayerIndex].Y, LayerBitmap[ALayerIndex], dmSet);
     1871    if FLayers[ALayerIndex].Owner then FLayers[ALayerIndex].Source.Free;
     1872    FLayers[ALayerIndex].Source := newBmp;
     1873    FLayers[ALayerIndex].Owner := true;
     1874    FLayers[ALayerIndex].x := 0;
     1875    FLayers[ALayerIndex].y := 0;
     1876  end else
     1877  begin
     1878    if (LayerOffset[ALayerIndex].X>=0) and (LayerOffset[ALayerIndex].Y>=0) and
     1879       (LayerOffset[ALayerIndex].X+LayerBitmap[ALayerIndex].Width <= Width) and
     1880       (LayerOffset[ALayerIndex].Y+LayerBitmap[ALayerIndex].Height <= Height) then exit;
     1881    r := RectWithSize(LayerOffset[ALayerIndex].X, LayerOffset[ALayerIndex].Y,
     1882                      LayerBitmap[ALayerIndex].Width, LayerBitmap[ALayerIndex].Height);
     1883    IntersectRect(r, r, rect(0,0,Width,Height));
     1884    newBmp := TBGRABitmap.Create(r.Width,r.Height);
     1885    newBmp.PutImage(LayerOffset[ALayerIndex].X - r.Left, LayerOffset[ALayerIndex].Y - r.Top, LayerBitmap[ALayerIndex], dmSet);
     1886    if FLayers[ALayerIndex].Owner then FLayers[ALayerIndex].Source.Free;
     1887    FLayers[ALayerIndex].Source := newBmp;
     1888    FLayers[ALayerIndex].Owner := true;
     1889    FLayers[ALayerIndex].x := r.Left;
     1890    FLayers[ALayerIndex].y := r.Top;
     1891  end;
     1892end;
     1893
     1894function TBGRALayeredBitmap.DrawEditor(ADest: TBGRABitmap;
     1895  ALayerIndex: integer; X, Y: Integer; APointSize: single): TRect;
     1896begin
     1897  result := DrawEditor(ADest, ALayerIndex, AffineMatrixTranslation(X,Y), APointSize);
     1898end;
     1899
     1900function TBGRALayeredBitmap.DrawEditor(ADest: TBGRABitmap; ALayerIndex: integer;
     1901  AMatrix: TAffineMatrix; APointSize: single): TRect;
     1902var
     1903  orig: TBGRALayerCustomOriginal;
     1904begin
     1905  orig := LayerOriginal[ALayerIndex];
     1906
     1907  if orig <> FOriginalEditorOriginal then
     1908  begin
     1909    FreeAndNil(FOriginalEditor);
     1910    FOriginalEditorOriginal := orig;
     1911  end;
     1912
     1913  if Assigned(orig) then
     1914  begin
     1915    if FOriginalEditor = nil then
     1916    begin
     1917      FOriginalEditor := orig.CreateEditor;
     1918    end;
     1919    FOriginalEditor.Clear;
     1920    orig.ConfigureEditor(FOriginalEditor);
     1921    FOriginalEditorViewMatrix := AffineMatrixTranslation(-0.5,-0.5)*AMatrix*AffineMatrixTranslation(0.5,0.5);
     1922    FOriginalEditor.Matrix := AffineMatrixTranslation(-0.5,-0.5)*AMatrix*LayerOriginalMatrix[ALayerIndex]*AffineMatrixTranslation(0.5,0.5);
     1923    FOriginalEditor.PointSize := APointSize;
     1924    result := FOriginalEditor.Render(ADest, rect(0,0,ADest.Width,ADest.Height));
     1925  end else
     1926    result := EmptyRect;
     1927end;
     1928
     1929function TBGRALayeredBitmap.GetEditorBounds(ALayerIndex: integer; X,
     1930  Y: Integer; APointSize: single): TRect;
     1931begin
     1932  result := GetEditorBounds(ALayerIndex, AffineMatrixTranslation(X,Y), APointSize);
     1933end;
     1934
     1935function TBGRALayeredBitmap.GetEditorBounds(ADestRect: TRect;
     1936  ALayerIndex: integer; X, Y: Integer; APointSize: single): TRect;
     1937begin
     1938  result := GetEditorBounds(ADestRect, ALayerIndex, AffineMatrixTranslation(X,Y), APointSize);
     1939end;
     1940
     1941function TBGRALayeredBitmap.GetEditorBounds(ALayerIndex: integer;
     1942  AMatrix: TAffineMatrix; APointSize: single): TRect;
     1943begin
     1944  result := GetEditorBounds(rect(-maxLongint,-maxLongint,maxLongint,maxLongint), ALayerIndex, AMatrix, APointSize);
     1945end;
     1946
     1947function TBGRALayeredBitmap.GetEditorBounds(ADestRect: TRect; ALayerIndex: integer;
     1948  AMatrix: TAffineMatrix; APointSize: single): TRect;
     1949var
     1950  orig: TBGRALayerCustomOriginal;
     1951begin
     1952  orig := LayerOriginal[ALayerIndex];
     1953
     1954  if orig <> FOriginalEditorOriginal then
     1955  begin
     1956    FreeAndNil(FOriginalEditor);
     1957    FOriginalEditorOriginal := orig;
     1958  end;
     1959
     1960  if Assigned(orig) then
     1961  begin
     1962    if FOriginalEditor = nil then
     1963    begin
     1964      FOriginalEditor := orig.CreateEditor;
     1965      if FOriginalEditor = nil then
     1966        raise exception.Create('Unexpected nil value');
     1967    end;
     1968    FOriginalEditor.Clear;
     1969    orig.ConfigureEditor(FOriginalEditor);
     1970    FOriginalEditorViewMatrix := AffineMatrixTranslation(-0.5,-0.5)*AMatrix*AffineMatrixTranslation(0.5,0.5);
     1971    FOriginalEditor.Matrix := AffineMatrixTranslation(-0.5,-0.5)*AMatrix*LayerOriginalMatrix[ALayerIndex]*AffineMatrixTranslation(0.5,0.5);
     1972    FOriginalEditor.PointSize := APointSize;
     1973    result := FOriginalEditor.GetRenderBounds(ADestRect);
     1974  end else
     1975    result := EmptyRect;
     1976end;
     1977
     1978procedure TBGRALayeredBitmap.MouseMove(Shift: TShiftState; ImageX, ImageY: Single; out
     1979  ACursor: TOriginalEditorCursor);
     1980var
     1981  handled: boolean;
     1982begin
     1983  MouseMove(Shift, ImageX,ImageY, ACursor, handled);
     1984end;
     1985
     1986procedure TBGRALayeredBitmap.MouseDown(RightButton: boolean;
     1987  Shift: TShiftState; ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor);
     1988var
     1989  handled: boolean;
     1990begin
     1991  MouseDown(RightButton, Shift, ImageX,ImageY, ACursor, handled);
     1992end;
     1993
     1994procedure TBGRALayeredBitmap.MouseUp(RightButton: boolean; Shift: TShiftState;
     1995  ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor);
     1996var
     1997  handled: boolean;
     1998begin
     1999  MouseUp(RightButton, Shift, ImageX,ImageY, ACursor, handled);
     2000end;
     2001
     2002procedure TBGRALayeredBitmap.MouseMove(Shift: TShiftState; ImageX, ImageY: Single; out
     2003  ACursor: TOriginalEditorCursor; out AHandled: boolean);
     2004var
     2005  viewPt: TPointF;
     2006begin
     2007  if Assigned(FOriginalEditor) then
     2008  begin
     2009    viewPt := FOriginalEditorViewMatrix*PointF(ImageX,ImageY);
     2010    FOriginalEditor.MouseMove(Shift, viewPt.X, viewPt.Y, ACursor, AHandled);
     2011  end
     2012  else
     2013  begin
     2014    ACursor:= oecDefault;
     2015    AHandled:= false;
     2016  end;
     2017end;
     2018
     2019procedure TBGRALayeredBitmap.MouseDown(RightButton: boolean;
     2020  Shift: TShiftState; ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor; out
     2021  AHandled: boolean);
     2022var
     2023  viewPt: TPointF;
     2024begin
     2025  if Assigned(FOriginalEditor) then
     2026  begin
     2027    viewPt := FOriginalEditorViewMatrix*PointF(ImageX,ImageY);
     2028    FOriginalEditor.MouseDown(RightButton, Shift, viewPt.X, viewPt.Y, ACursor, AHandled);
     2029  end
     2030  else
     2031  begin
     2032    ACursor:= oecDefault;
     2033    AHandled:= false;
     2034  end;
     2035end;
     2036
     2037procedure TBGRALayeredBitmap.MouseUp(RightButton: boolean; Shift: TShiftState;
     2038  ImageX, ImageY: Single; out ACursor: TOriginalEditorCursor; out AHandled: boolean);
     2039var
     2040  viewPt: TPointF;
     2041begin
     2042  if Assigned(FOriginalEditor) then
     2043  begin
     2044    viewPt := FOriginalEditorViewMatrix*PointF(ImageX,ImageY);
     2045    FOriginalEditor.MouseUp(RightButton, Shift, viewPt.X,viewPt.Y, ACursor, AHandled);
     2046  end
     2047  else
     2048  begin
     2049    ACursor:= oecDefault;
     2050    AHandled:= false;
     2051  end;
     2052end;
     2053
     2054procedure TBGRALayeredBitmap.KeyDown(Shift: TShiftState; Key: TSpecialKey; out
     2055  AHandled: boolean);
     2056begin
     2057  if Assigned(FOriginalEditor) then
     2058    FOriginalEditor.KeyDown(Shift, Key, AHandled)
     2059  else
     2060    AHandled := false;
     2061end;
     2062
     2063procedure TBGRALayeredBitmap.KeyUp(Shift: TShiftState; Key: TSpecialKey; out
     2064  AHandled: boolean);
     2065begin
     2066  if Assigned(FOriginalEditor) then
     2067    FOriginalEditor.KeyUp(Shift, Key, AHandled)
     2068  else
     2069    AHandled := false;
     2070end;
     2071
     2072procedure TBGRALayeredBitmap.KeyPress(UTF8Key: string; out AHandled: boolean);
     2073begin
     2074  if Assigned(FOriginalEditor) then
     2075    FOriginalEditor.KeyPress(UTF8Key, AHandled)
     2076  else
     2077    AHandled := false;
     2078end;
     2079
     2080function TBGRALayeredBitmap.IndexOfOriginal(AGuid: TGuid): integer;
     2081var
     2082  i: Integer;
     2083begin
     2084  for i := 0 to OriginalCount-1 do
     2085    if FOriginals[i].Guid = AGuid then
     2086    begin
     2087      result := i;
     2088      exit;
     2089    end;
     2090  result := -1
     2091end;
     2092
     2093function TBGRALayeredBitmap.IndexOfOriginal(AOriginal: TBGRALayerCustomOriginal): integer;
     2094begin
     2095  if Assigned(FOriginals) then
     2096    result := FOriginals.IndexOf(BGRALayerOriginalEntry(AOriginal))
     2097  else
     2098    result := -1;
    8272099end;
    8282100
     
    8342106end;
    8352107
     2108function TBGRACustomLayeredBitmap.GetMemDirectory: TMemDirectory;
     2109begin
     2110  if FMemDirectory = nil then
     2111  begin
     2112    FMemDirectory:= TMemDirectory.Create;
     2113    FMemDirectoryOwned := true;
     2114  end;
     2115  result := FMemDirectory;
     2116end;
     2117
    8362118function TBGRACustomLayeredBitmap.GetDefaultBlendingOperation: TBlendOperation;
    8372119begin
    8382120  result := boTransparent;
     2121end;
     2122
     2123function TBGRACustomLayeredBitmap.GetHasMemFiles: boolean;
     2124begin
     2125  result := assigned(FMemDirectory) and (FMemDirectory.Count > 0);
     2126end;
     2127
     2128function TBGRACustomLayeredBitmap.GetLayerOriginalGuid(layer: integer): TGuid;
     2129begin
     2130  result := GUID_NULL;
     2131end;
     2132
     2133function TBGRACustomLayeredBitmap.GetLayerOriginalRenderStatus(layer: integer): TOriginalRenderStatus;
     2134begin
     2135  result := orsProof;
     2136end;
     2137
     2138function TBGRACustomLayeredBitmap.GetOriginalCount: integer;
     2139begin
     2140  result := 0;
     2141end;
     2142
     2143function TBGRACustomLayeredBitmap.GetOriginalByIndex(AIndex: integer): TBGRALayerCustomOriginal;
     2144begin
     2145  result := nil;
     2146  raise exception.Create('Not implemented');
     2147end;
     2148
     2149function TBGRACustomLayeredBitmap.GetOriginalByIndexKnown(AIndex: integer): boolean;
     2150begin
     2151  result := true;
     2152end;
     2153
     2154function TBGRACustomLayeredBitmap.GetLayerOriginal(layer: integer): TBGRALayerCustomOriginal;
     2155begin
     2156  result := nil;
     2157end;
     2158
     2159function TBGRACustomLayeredBitmap.GetLayerOriginalKnown(layer: integer): boolean;
     2160begin
     2161  result := true;
     2162end;
     2163
     2164function TBGRACustomLayeredBitmap.GetLayerOriginalMatrix(layer: integer): TAffineMatrix;
     2165begin
     2166  result := AffineMatrixIdentity;
    8392167end;
    8402168
     
    8432171  Unfreeze;
    8442172  FLinearBlend := AValue;
     2173end;
     2174
     2175procedure TBGRACustomLayeredBitmap.SetMemDirectory(AValue: TMemDirectory);
     2176begin
     2177  if AValue = FMemDirectory then exit;
     2178  if FMemDirectoryOwned then FMemDirectory.Free;
     2179  FMemDirectory := AValue;
     2180  FMemDirectoryOwned := false;
    8452181end;
    8462182
     
    9352271end;
    9362272
     2273function TBGRACustomLayeredBitmap.IndexOfOriginal(AGuid: TGuid): integer;
     2274begin
     2275  result := -1;
     2276end;
     2277
     2278function TBGRACustomLayeredBitmap.IndexOfOriginal(
     2279  AOriginal: TBGRALayerCustomOriginal): integer;
     2280begin
     2281  result := -1;
     2282end;
     2283
    9372284procedure TBGRACustomLayeredBitmap.SetWidth(Value: Integer);
    9382285begin
     
    9602307    temp: TBGRALayeredBitmap;
    9612308    i: integer;
     2309    stream: TFileStreamUTF8;
    9622310begin
    9632311  ext := UTF8LowerCase(ExtractFileExt(filenameUTF8));
     
    9752323    end;
    9762324
     2325  //when using "data" extension, simply serialize
     2326  if (ext='.dat') or (ext='.data') then
     2327  begin
     2328    if Assigned(LayeredBitmapLoadFromStreamProc) then
     2329    begin
     2330      stream := TFileStreamUTF8.Create(filenameUTF8, fmCreate);
     2331      try
     2332        LayeredBitmapSaveToStreamProc(stream, self);
     2333      finally
     2334        stream.Free;
     2335      end;
     2336    end else
     2337      raise exception.Create('Enable layer serialization by calling BGRAStreamLayers.RegisterStreamLayers');
     2338  end else
     2339  begin
     2340    bmp := ComputeFlatImage;
     2341    try
     2342      bmp.SaveToFileUTF8(filenameUTF8);
     2343    finally
     2344      bmp.Free;
     2345    end;
     2346  end;
     2347end;
     2348
     2349procedure TBGRACustomLayeredBitmap.SaveToStream(Stream: TStream);
     2350begin
     2351  if Assigned(LayeredBitmapSaveToStreamProc) then
     2352    LayeredBitmapSaveToStreamProc(Stream, self)
     2353  else
     2354    raise exception.Create('Call BGRAStreamLayers.RegisterStreamLayers first');
     2355end;
     2356
     2357procedure TBGRACustomLayeredBitmap.SaveToStreamAs(Stream: TStream;
     2358  AExtension: string);
     2359var bmp: TBGRABitmap;
     2360    ext: string;
     2361    format: TBGRAImageFormat;
     2362    temp: TBGRALayeredBitmap;
     2363    i: integer;
     2364begin
     2365  ext := UTF8LowerCase(AExtension);
     2366  if ext[1] <> '.' then ext := '.'+ext;
     2367
     2368  for i := 0 to high(LayeredBitmapWriters) do
     2369    if '.'+LayeredBitmapWriters[i].extension = ext then
     2370    begin
     2371      temp := LayeredBitmapWriters[i].theClass.Create;
     2372      try
     2373        temp.Assign(self);
     2374        temp.SaveToStream(Stream);
     2375      finally
     2376        temp.Free;
     2377      end;
     2378      exit;
     2379    end;
     2380
     2381  format := SuggestImageFormat(ext);
    9772382  bmp := ComputeFlatImage;
    9782383  try
    979     bmp.SaveToFileUTF8(filenameUTF8);
     2384    bmp.SaveToStreamAs(Stream, format);
    9802385  finally
    9812386    bmp.Free;
     
    9832388end;
    9842389
    985 procedure TBGRACustomLayeredBitmap.SaveToStream(Stream: TStream);
    986 begin
    987   if Assigned(LayeredBitmapSaveToStreamProc) then
    988     LayeredBitmapSaveToStreamProc(Stream, self)
    989   else
    990     raise exception.Create('Call BGRAStreamLayers.RegisterStreamLayers first');
    991 end;
    992 
    9932390constructor TBGRACustomLayeredBitmap.Create;
    9942391begin
    9952392  FFrozenRange := nil;
    9962393  FLinearBlend:= True;
     2394  FMemDirectory := nil;
     2395  FMemDirectoryOwned:= false;
    9972396end;
    9982397
     
    10102409end;
    10112410
    1012 function TBGRACustomLayeredBitmap.ComputeFlatImage: TBGRABitmap;
    1013 begin
    1014   result := ComputeFlatImage(rect(0,0,Width,Height), 0, NbLayers - 1);
     2411function TBGRACustomLayeredBitmap.ComputeFlatImage(ASeparateXorMask: boolean): TBGRABitmap;
     2412begin
     2413  result := ComputeFlatImage(rect(0,0,Width,Height), 0, NbLayers - 1, ASeparateXorMask);
    10152414end;
    10162415
    10172416function TBGRACustomLayeredBitmap.ComputeFlatImage(firstLayer,
    1018   lastLayer: integer): TBGRABitmap;
    1019 begin
    1020   result := ComputeFlatImage(rect(0,0,Width,Height), firstLayer,LastLayer);
    1021 end;
    1022 
    1023 function TBGRACustomLayeredBitmap.ComputeFlatImage(ARect: TRect): TBGRABitmap;
    1024 begin
    1025   result := ComputeFlatImage(ARect,0, NbLayers - 1);
     2417  lastLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
     2418begin
     2419  result := ComputeFlatImage(rect(0,0,Width,Height), firstLayer,LastLayer,ASeparateXorMask);
     2420end;
     2421
     2422function TBGRACustomLayeredBitmap.ComputeFlatImage(ARect: TRect;
     2423  ASeparateXorMask: boolean): TBGRABitmap;
     2424begin
     2425  result := ComputeFlatImage(ARect,0, NbLayers - 1, ASeparateXorMask);
    10262426end;
    10272427
     
    10312431end;
    10322432
    1033 function TBGRACustomLayeredBitmap.ComputeFlatImage(ARect: TRect; firstLayer, lastLayer: integer): TBGRABitmap;
     2433function TBGRACustomLayeredBitmap.ComputeFlatImage(ARect: TRect; firstLayer, lastLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
    10342434var
    10352435  tempLayer: TBGRABitmap;
     
    10382438  op: TBlendOperation;
    10392439begin
     2440  if (firstLayer < 0) or (lastLayer > NbLayers-1) then
     2441    raise ERangeError.Create('Layer index out of bounds');
    10402442  If (ARect.Right <= ARect.Left) or (ARect.Bottom <= ARect.Top) then
    10412443  begin
     
    10762478      begin
    10772479        op := BlendOperation[i];
     2480        //XOR mask
     2481        if (op = boXor) and ASeparateXorMask then
     2482        begin
     2483          result.NeedXorMask;
     2484          result.XorMask.BlendImageOver(x-ARect.Left,y-ARect.Top, tempLayer, op, LayerOpacity[i], LinearBlend);
     2485        end else
    10782486        //first layer is simply the background
    10792487        if i = firstLayer then
     
    10932501    inc(i);
    10942502  end;
     2503  if result.XorMask <> nil then
     2504    AlphaFillInline(result.XorMask.Data, 0, result.XorMask.NbPixels);
    10952505end;
    10962506
     
    11272537end;
    11282538
    1129 procedure TBGRACustomLayeredBitmap.Draw(Dest: TBGRABitmap; AX, AY: integer; firstLayer, lastLayer: integer);
     2539procedure TBGRACustomLayeredBitmap.Draw(Dest: TBGRABitmap; x, y: integer;
     2540  ASeparateXorMask: boolean);
     2541begin
     2542  Draw(Dest,x,y,0,NbLayers-1,ASeparateXorMask);
     2543end;
     2544
     2545procedure TBGRACustomLayeredBitmap.Draw(Dest: TBGRABitmap; AX, AY: integer; firstLayer, lastLayer: integer; ASeparateXorMask: boolean);
    11302546var
    11312547  temp: TBGRABitmap;
     
    11432559    if LayerVisible[i] and not (BlendOperation[i] in[boTransparent,boLinearBlend]) then
    11442560    begin
    1145       temp := ComputeFlatImage(rect(NewClipRect.Left-AX,NewClipRect.Top-AY,NewClipRect.Right-AX,NewClipRect.Bottom-AY));
     2561      temp := ComputeFlatImage(rect(NewClipRect.Left-AX,NewClipRect.Top-AY,NewClipRect.Right-AX,NewClipRect.Bottom-AY), ASeparateXorMask);
    11462562      if self.LinearBlend then
    11472563        Dest.PutImage(NewClipRect.Left,NewClipRect.Top,temp,dmLinearBlend)
     
    11702586    end;
    11712587    if LayerVisible[i] then
    1172     with LayerOffset[i] do
    11732588    begin
    11742589      tempLayer := GetLayerBitmapDirectly(i);
     
    11812596      end;
    11822597      if tempLayer <> nil then
     2598      with LayerOffset[i] do
    11832599      begin
    11842600        if (BlendOperation[i] = boTransparent) and not self.LinearBlend then //here it is specified not to use linear blending
    1185           Dest.PutImage(AX+x,AY+y,GetLayerBitmapDirectly(i),dmDrawWithTransparency, LayerOpacity[i])
     2601          Dest.PutImage(AX+x,AY+y,tempLayer,dmDrawWithTransparency, LayerOpacity[i])
    11862602        else
    1187           Dest.PutImage(AX+x,AY+y,GetLayerBitmapDirectly(i),dmLinearBlend, LayerOpacity[i]);
     2603          Dest.PutImage(AX+x,AY+y,tempLayer,dmLinearBlend, LayerOpacity[i]);
    11882604        if mustFreeCopy then tempLayer.Free;
    11892605      end;
     
    12942710end;
    12952711
     2712procedure TBGRACustomLayeredBitmap.NotifyLoaded;
     2713begin
     2714  //nothing
     2715end;
     2716
     2717procedure TBGRACustomLayeredBitmap.NotifySaving;
     2718begin
     2719  //nothing
     2720end;
     2721
    12962722procedure RegisterLayeredBitmapReader(AExtensionUTF8: string; AReader: TBGRACustomLayeredBitmapClass);
    12972723begin
     
    13022728    theClass := AReader;
    13032729  end;
     2730end;
     2731
     2732function TryCreateLayeredBitmapWriter(AExtensionUTF8: string): TBGRALayeredBitmap;
     2733var
     2734  i: Integer;
     2735begin
     2736  AExtensionUTF8:= UTF8LowerCase(AExtensionUTF8);
     2737  if (AExtensionUTF8 = '') or (AExtensionUTF8[1] <> '.') then
     2738    AExtensionUTF8:= '.'+AExtensionUTF8;
     2739  for i := 0 to high(LayeredBitmapWriters) do
     2740    if '.'+LayeredBitmapWriters[i].extension = AExtensionUTF8 then
     2741    begin
     2742      result := LayeredBitmapWriters[i].theClass.Create;
     2743      exit;
     2744    end;
     2745  result := nil;
     2746end;
     2747
     2748function TryCreateLayeredBitmapReader(AExtensionUTF8: string): TBGRACustomLayeredBitmap;
     2749var
     2750  i: Integer;
     2751begin
     2752  AExtensionUTF8:= UTF8LowerCase(AExtensionUTF8);
     2753  if (AExtensionUTF8 = '') or (AExtensionUTF8[1] <> '.') then
     2754    AExtensionUTF8:= '.'+AExtensionUTF8;
     2755  for i := 0 to high(LayeredBitmapReaders) do
     2756    if '.'+LayeredBitmapReaders[i].extension = AExtensionUTF8 then
     2757    begin
     2758      result := LayeredBitmapReaders[i].theClass.Create;
     2759      exit;
     2760    end;
     2761  result := nil;
    13042762end;
    13052763
Note: See TracChangeset for help on using the changeset viewer.