| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034 |
- unit GR32.Design.BitmapEditor;
- (* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1 or LGPL 2.1 with linking exception
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * Alternatively, the contents of this file may be used under the terms of the
- * Free Pascal modified version of the GNU Lesser General Public License
- * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
- * of this license are applicable instead of those above.
- * Please see the file LICENSE.txt for additional information concerning this
- * license.
- *
- * The Original Code is Graphics32
- *
- * The Initial Developer of the Original Code is
- * Alex A. Denisov
- *
- * Portions created by the Initial Developer are Copyright (C) 2000-2009
- * the Initial Developer. All Rights Reserved.
- *
- * ***** END LICENSE BLOCK ***** *)
- interface
- {$include GR32.inc}
- uses
- {$IFDEF FPC}
- LCLIntf, LCLType, RtlConsts, Buttons, LazIDEIntf, PropEdits,
- ComponentEditors,
- {$ELSE}
- Windows, ExtDlgs, ToolWin, Registry, ImgList, Consts, DesignIntf,
- DesignEditors, VCLEditors, Actions, System.ImageList,
- {$ENDIF}
- Forms, Controls, ComCtrls, ExtCtrls, StdCtrls, Graphics, Dialogs, Menus,
- SysUtils, Classes, Clipbrd, ActnList,
- GR32,
- GR32_Image,
- GR32_Layers;
- type
- TPictureEditorForm = class(TForm)
- TabSheetAlpha: TTabSheet;
- Bevel1: TBevel;
- Cancel: TButton;
- ButtonClear: TToolButton;
- ButtonCopy: TToolButton;
- ImageList: TImageList;
- TabSheetRGB: TTabSheet;
- ButtonLoad: TToolButton;
- MenuItemClear: TMenuItem;
- MenuItemCopy: TMenuItem;
- MenuItemInvert: TMenuItem;
- MenuItemLoad: TMenuItem;
- MenuItemPaste: TMenuItem;
- MenuItemSave: TMenuItem;
- mnSeparator: TMenuItem;
- mnSeparator2: TMenuItem;
- OKButton: TButton;
- PageControl: TPageControl;
- Panel1: TPanel;
- ButtonPaste: TToolButton;
- PopupMenu: TPopupMenu;
- ButtonSave: TToolButton;
- ToolBar: TToolBar;
- ToolButton2: TToolButton;
- ActionList: TActionList;
- ActionLoad: TAction;
- ActionSave: TAction;
- ActionClear: TAction;
- ActionCopy: TAction;
- ActionPaste: TAction;
- ActionInvert: TAction;
- TabSheetRGBA: TTabSheet;
- StatusBar: TStatusBar;
- LabelZoom: TLabel;
- ToolButton1: TToolButton;
- ButtonHelp: TToolButton;
- ActionHelp: TAction;
- ButtonGrid: TToolButton;
- ActionGrid: TAction;
- procedure ActionLoadExecute(Sender: TObject);
- procedure ActionSaveExecute(Sender: TObject);
- procedure ActionHasBitmapUpdate(Sender: TObject);
- procedure ActionClearExecute(Sender: TObject);
- procedure ActionPasteUpdate(Sender: TObject);
- procedure ActionCopyExecute(Sender: TObject);
- procedure ActionPasteExecute(Sender: TObject);
- procedure ActionInvertExecute(Sender: TObject);
- procedure ActionHelpExecute(Sender: TObject);
- procedure ActionGridExecute(Sender: TObject);
- procedure ActionGridUpdate(Sender: TObject);
- protected
- {$IFDEF PLATFORM_INDEPENDENT}
- FOpenDialog: TOpenDialog;
- FSaveDialog: TSaveDialog;
- {$ELSE}
- FOpenDialog: TOpenPictureDialog;
- FSaveDialog: TSavePictureDialog;
- {$ENDIF}
- FImageAllChannels: TImage32;
- FImageRGBChannels: TImage32;
- FImageAlphaChannel: TImage32;
- FLayerPixelGrid: TCustomLayer;
- procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
- procedure ImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
- procedure ImageChanged(Sender: TObject);
- function CurrentImage: TImage32;
- procedure ResetZoomAndCenter(Image: TImage32);
- procedure SyncZoomAndPan;
- public
- constructor Create(AOwner: TComponent); override;
- procedure LoadFromImage(Source: TPersistent);
- end;
- TBitmap32Editor = class(TComponent)
- private
- FBitmap32: TBitmap32;
- procedure SetBitmap32(Value: TBitmap32);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function Execute: Boolean;
- property Bitmap32: TBitmap32 read FBitmap32 write SetBitmap32;
- end;
- TBitmap32Property = class(TClassProperty
- {$IFDEF EXT_PROP_EDIT}
- , ICustomPropertyDrawing, ICustomPropertyDrawing80
- {$ENDIF}
- )
- public
- procedure Edit; override;
- function GetAttributes: TPropertyAttributes; override;
- function GetValue: string; override;
- procedure SetValue(const Value: string); override;
- {$IFDEF EXT_PROP_EDIT}
- { ICustomPropertyDrawing }
- procedure PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
- procedure PropDrawValue(Canvas: TCanvas; const ARect: TRect; ASelected: Boolean);
- { ICustomPropertyDrawing80 }
- function PropDrawNameRect(const ARect: TRect): TRect;
- function PropDrawValueRect(const ARect: TRect): TRect;
- {$ENDIF}
- end;
- TImage32Editor = class(TComponentEditor)
- public
- procedure ExecuteVerb(Index: Integer); override;
- function GetVerb(Index: Integer): string; override;
- function GetVerbCount: Integer; override;
- end;
- implementation
- uses
- Math,
- Types,
- GR32.ImageFormats,
- GR32_Filters,
- GR32_Resamplers,
- GR32_Backends_Generic;
- {$R *.dfm}
- {$R 'GR32.Design.BitmapEditor.res'}
- resourcestring
- sInfo = 'Width: %.0n, Height: %.0n';
- sInfoEmpty = '(empty)';
- sZoom = 'Zoom: %.0n%%';
- sHelp = 'Pan by clicking and dragging.'#13+
- 'Zoom with the mouse wheel.'#13+
- 'Reset zoom and center with the middle mouse button.';
- //------------------------------------------------------------------------------
- //
- // TPixelGridLayer
- //
- //------------------------------------------------------------------------------
- // Displays a pixel grid on top of the image
- //------------------------------------------------------------------------------
- type
- TPixelGridLayer = class(TCustomLayer)
- private
- FImage: TCustomImage32;
- FNeedStipple: array[0..1] of boolean;
- FStipple: array[0..1] of TArrayOfColor32;
- FPattern: array[0..1] of DWORD;
- FColorOn: array[0..1] of TColor32;
- FColorOff: array[0..1] of TColor32;
- procedure SetColorOff(const Index: Integer; const Value: TColor32);
- procedure SetColorOn(const Index: Integer; const Value: TColor32);
- procedure SetPattern(const Index: Integer; const Value: DWORD);
- procedure SetStipple(const Index: Integer; const Value: TArrayOfColor32);
- function GetStipple(const Index: Integer): TArrayOfColor32;
- protected
- procedure Paint(Buffer: TBitmap32); override;
- public
- constructor Create(ALayerCollection: TLayerCollection; AImage: TCustomImage32); reintroduce;
- class procedure CreateStipple(var Stipple: TArrayOfColor32; Pattern: DWORD; ColorOn, ColorOff: TColor32);
- property MajorStipple: TArrayOfColor32 index 0 read GetStipple write SetStipple;
- property MajorPattern: DWORD index 0 read FPattern[0] write SetPattern;
- property MajorColorOn: TColor32 index 0 read FColorOn[0] write SetColorOn;
- property MajorColorOff: TColor32 index 0 read FColorOff[0] write SetColorOff;
- property MinorStipple: TArrayOfColor32 index 1 read GetStipple write SetStipple;
- property MinorPattern: DWORD index 1 read FPattern[1] write SetPattern;
- property MinorColorOn: TColor32 index 1 read FColorOn[1] write SetColorOn;
- property MinorColorOff: TColor32 index 1 read FColorOff[1] write SetColorOff;
- end;
- //------------------------------------------------------------------------------
- //
- // TPixelGridLayer
- //
- //------------------------------------------------------------------------------
- constructor TPixelGridLayer.Create(ALayerCollection: TLayerCollection;
- AImage: TCustomImage32);
- begin
- inherited Create(ALayerCollection);
- FImage := AImage;
- FNeedStipple[0] := True;
- FNeedStipple[1] := True;
- FPattern[0] := $55555555;
- FColorOn[0] := $ff353535;
- FColorOff[0] := $ffa0a0a0;
- FPattern[1] := $55555555;
- FColorOn[1] := $ffa0a0a0;
- FColorOff[1] := $ffbfbfbf;
- end;
- class procedure TPixelGridLayer.CreateStipple(var Stipple: TArrayOfColor32; Pattern: DWORD; ColorOn, ColorOff: TColor32);
- var
- i: integer;
- Mask: DWORD;
- begin
- SetLength(Stipple, 32);
- Mask := $80000000;
- i := 0;
- while (Mask <> 0) do
- begin
- if (Pattern and Mask = 0) then
- Stipple[i] := ColorOff
- else
- Stipple[i] := ColorOn;
- Mask := Mask shr 1;
- inc(i);
- end;
- end;
- function TPixelGridLayer.GetStipple(const Index: Integer): TArrayOfColor32;
- begin
- if (FNeedStipple[Index]) then
- CreateStipple(FStipple[Index], FPattern[Index], FColorOn[Index], FColorOff[Index]);
- Result := FStipple[Index];
- end;
- procedure TPixelGridLayer.Paint(Buffer: TBitmap32);
- var
- i: integer;
- Step: integer;
- MinStep: integer;
- Lines: integer;
- Rect: TRect;
- Size: TSize;
- p: TPoint;
- begin
- try
- if (Abs(FImage.Scale) >= 4) then
- Step := 1
- else
- Step := 4;
- // Enforce minimal grid of 4 pixels
- MinStep := Ceil(4 / Abs(FImage.Scale));
- Step := Max(Step, MinStep);
- Rect := FImage.GetBitmapRect;
- Size.cx := FImage.Bitmap.Width;
- Size.cy := FImage.Bitmap.Height;
- // Minor grid
- Buffer.StippleStep := 1;
- Buffer.SetStipple(MinorStipple);
- i := Step;
- Lines := 1;
- while (i < Size.cx) or (i < Size.cy) do
- begin
- if (Abs(FImage.Scale) <= 4) or (Lines mod 8 <> 0) then
- begin
- p := FImage.BitmapToControl(GR32.Point(i, i));
- // Vertical line
- if (i < Size.cx) then
- begin
- Buffer.StippleCounter := 0;
- Buffer.VertLineTSP(p.X, Rect.Top+1, Rect.Bottom-1);
- end;
- // Horizontal line
- if (i < Size.cy) then
- begin
- Buffer.StippleCounter := 0;
- Buffer.HorzLineTSP(Rect.Left+1, p.Y, Rect.Right-1);
- end;
- end;
- inc(i, Step);
- inc(Lines);
- end;
- // Major grid
- Buffer.SetStipple(MajorStipple);
- i := Step*8;
- if (Abs(FImage.Scale) > 4) then
- while (i < Size.cx) or (i < Size.cy) do
- begin
- p := FImage.BitmapToControl(GR32.Point(i, i));
- // Vertical line
- if (i < Size.cx) then
- begin
- Buffer.StippleCounter := 0;
- Buffer.VertLineTSP(p.X, Rect.Top+1, Rect.Bottom-1);
- end;
- // Horizontal line
- if (i < Size.cy) then
- begin
- Buffer.StippleCounter := 0;
- Buffer.HorzLineTSP(Rect.Left+1, p.Y, Rect.Right-1);
- end;
- inc(i, Step*8);
- end;
- // Vertical border kines
- Buffer.StippleCounter := 1;
- Buffer.VertLineTSP(Rect.Left, Rect.Top, Rect.Bottom);
- Buffer.StippleCounter := 1;
- Buffer.VertLineTSP(Rect.Right, Rect.Top, Rect.Bottom);
- // Horizontal border lines
- Buffer.StippleCounter := 0;
- Buffer.HorzLineTSP(Rect.Left+1, Rect.Top, Rect.Right-1);
- Buffer.StippleCounter := 0;
- Buffer.HorzLineTSP(Rect.Left+1, Rect.Bottom, Rect.Right-1);
- except
- // Prevent AV flood due to repaint
- Visible := False;
- raise;
- end;
- end;
- procedure TPixelGridLayer.SetColorOff(const Index: Integer; const Value: TColor32);
- begin
- FColorOff[Index] := Value;
- FNeedStipple[Index] := True;
- end;
- procedure TPixelGridLayer.SetColorOn(const Index: Integer; const Value: TColor32);
- begin
- FColorOn[Index] := Value;
- FNeedStipple[Index] := True;
- end;
- procedure TPixelGridLayer.SetPattern(const Index: Integer; const Value: DWORD);
- begin
- FPattern[Index] := Value;
- FNeedStipple[Index] := True;
- end;
- procedure TPixelGridLayer.SetStipple(const Index: Integer;
- const Value: TArrayOfColor32);
- begin
- FStipple[Index] := Value;
- FNeedStipple[Index] := False;
- end;
- { TPictureEditorForm }
- function TPictureEditorForm.CurrentImage: TImage32;
- begin
- if PageControl.ActivePage = TabSheetRGB then
- Result := FImageRGBChannels
- else
- if PageControl.ActivePage = TabSheetAlpha then
- Result := FImageAlphaChannel
- else
- Result := FImageAllChannels
- end;
- procedure TPictureEditorForm.LoadFromImage(Source: TPersistent);
- procedure UpdateImageBackground(Image: TImage32);
- begin
- if (Image.Bitmap.Empty) then
- begin
- Image.Background.OuterBorderColor := clNone;
- Image.Background.InnerBorderColor := clNone;
- Image.Background.InnerBorderWidth := 0;
- Image.Background.FillStyle := bfsCheckers;
- end else
- begin
- Image.Background.OuterBorderColor := clGray;
- Image.Background.InnerBorderColor := clWhite;
- Image.Background.InnerBorderWidth := 8;
- Image.Background.FillStyle := bfsColor;
- end;
- end;
- begin
- FImageAllChannels.BeginUpdate;
- FImageRGBChannels.BeginUpdate;
- FImageAlphaChannel.BeginUpdate;
- try
- if CurrentImage = FImageAllChannels then
- begin
- // Load RGBA bitmap, separate into RGB and A
- // Load RGBA
- FImageAllChannels.Bitmap.Assign(Source);
- FImageAllChannels.Bitmap.DrawMode := dmBlend;
- // Separate RGB
- FImageRGBChannels.Bitmap.Assign(FImageAllChannels.Bitmap);
- FImageRGBChannels.Bitmap.ResetAlpha;
- // Separate A
- AlphaToGrayscale(FImageAlphaChannel.Bitmap, FImageAllChannels.Bitmap);
- FImageAlphaChannel.Bitmap.ResetAlpha;
- end else
- if CurrentImage = FImageRGBChannels then
- begin
- // Load RGB bitmap, keep existing A
- // Load RGB
- if (Source <> nil) then
- begin
- FImageRGBChannels.Bitmap.Assign(Source);
- FImageRGBChannels.Bitmap.ResetAlpha;
- end else
- FImageRGBChannels.Bitmap.Clear($FF000000);
- // Merge A and RGB into RGBA
- FImageAllChannels.Bitmap.Assign(FImageRGBChannels.Bitmap);
- FImageAllChannels.Bitmap.DrawMode := dmBlend;
- if (not FImageAlphaChannel.Bitmap.Empty) then
- IntensityToAlpha(FImageAllChannels.Bitmap, FImageAlphaChannel.Bitmap)
- else
- FImageAllChannels.Bitmap.ResetAlpha;
- end else
- if CurrentImage = FImageAlphaChannel then
- begin
- // Load A bitmap, keep existing RGB
- if (Source <> nil) then
- FImageAlphaChannel.Bitmap.Assign(Source)
- else
- FImageAlphaChannel.Bitmap.Clear($FFFFFFFF);
- ColorToGrayscale(FImageAlphaChannel.Bitmap, FImageAlphaChannel.Bitmap);
- // Merge A and RGB into RGBA
- if (not FImageRGBChannels.Bitmap.Empty) then
- begin
- FImageAllChannels.Bitmap.Assign(FImageRGBChannels.Bitmap);
- FImageAllChannels.Bitmap.DrawMode := dmBlend;
- end else
- begin
- FImageAllChannels.Bitmap.SetSizeFrom(FImageAlphaChannel.Bitmap);
- FImageAllChannels.Bitmap.Clear;
- end;
- IntensityToAlpha(FImageAllChannels.Bitmap, FImageAlphaChannel.Bitmap);
- end;
- ResetZoomAndCenter(FImageAllChannels);
- ResetZoomAndCenter(FImageRGBChannels);
- ResetZoomAndCenter(FImageAlphaChannel);
- UpdateImageBackground(FImageAllChannels);
- UpdateImageBackground(FImageRGBChannels);
- UpdateImageBackground(FImageAlphaChannel);
- finally
- FImageAllChannels.EndUpdate;
- FImageRGBChannels.EndUpdate;
- FImageAlphaChannel.EndUpdate;
- end;
- FImageAllChannels.Changed;
- FImageRGBChannels.Changed;
- FImageAlphaChannel.Changed;
- if (FImageAllChannels.Bitmap.Empty) then
- StatusBar.Panels[3].Text := sInfoEmpty
- else
- StatusBar.Panels[3].Text := Format(sInfo, [1.0*FImageAllChannels.Bitmap.Width, 1.0*FImageAllChannels.Bitmap.Height]);
- end;
- procedure TPictureEditorForm.ResetZoomAndCenter(Image: TImage32);
- var
- Size: TSize;
- begin
- Image.BeginUpdate;
- try
- // Reset Zoom...
- Image.Scale := 1;
- // ...and Center image
- Size := Image.GetBitmapSize;
- Image.OffsetHorz := (Image.Width-Size.cx) div 2;
- Image.OffsetVert := (Image.Height-Size.cy) div 2;
- finally
- Image.EndUpdate;
- end;
- Image.Changed;
- end;
- procedure TPictureEditorForm.SyncZoomAndPan;
- procedure DoSync(Image: TImage32);
- begin
- if (Image = CurrentImage) then
- exit;
- Image.BeginUpdate; // Avoid recursion
- try
- Image.Scale := CurrentImage.Scale;
- Image.OffsetHorz := CurrentImage.OffsetHorz;
- Image.OffsetVert := CurrentImage.OffsetVert;
- finally
- Image.EndUpdate;
- end;
- // Invalidate without firing OnChange
- Image.ForceFullInvalidate;
- end;
- begin
- if (CurrentImage = nil) then
- exit;
- LabelZoom.Caption := Format(sZoom, [CurrentImage.Scale * 100]);
- DoSync(FImageAllChannels);
- DoSync(FImageRGBChannels);
- DoSync(FImageAlphaChannel);
- end;
- constructor TPictureEditorForm.Create(AOwner: TComponent);
- function CreateImage32(AParent: TWinControl): TImage32;
- begin
- Result := TImage32.Create(Self);
- Result.Parent := AParent;
- Result.Align := alClient;
- Result.BitmapAlign := baCustom;
- Result.Cursor := crCross;
- Result.PopupMenu := PopupMenu;
- Result.Background.CheckersStyle := bcsMedium;
- Result.Background.OuterBorderColor := clGray;
- Result.Background.InnerBorderColor := clWhite;
- Result.Background.InnerBorderWidth := 8;
- Result.Background.FillStyle := bfsCheckers;
- Result.MousePan.Enabled := True;
- Result.MousePan.PanCursor := crSizeAll;
- Result.MouseZoom.Enabled := True;
- Result.MouseZoom.Animate := True;
- Result.TabStop := True; // Required for mouse wheel
- Result.Scale := 1;
- Result.ScaleMode := smScale;
- Result.OnMouseMove := ImageMouseMove;
- Result.OnMouseDown := ImageMouseDown;
- Result.OnChange := ImageChanged;
- end;
- procedure LoadGlyphs;
- var
- ResourceName: string;
- Bitmap: TBitmap;
- Stream: TResourceStream;
- const
- sBitmapNames: array[0..7] of string = (
- 'GR32_OPEN',
- 'GR32_SAVE',
- 'GR32_CLEAR',
- 'GR32_COPY',
- 'GR32_PASTE',
- 'GR32_INVERT',
- 'GR32_HELP',
- 'GR32_GRID'
- );
- begin
- // We're not storing bitmaps in the imagelist in order to support FPC.
- // FPC's TImageList doesn't have the ColorDepth property.
- ImageList.Clear;
- {$ifndef FPC}
- ImageList.ColorDepth := cd32bit;
- {$endif FPC}
- Bitmap := TBitmap.Create;
- try
- for ResourceName in sBitmapNames do
- begin
- Stream := TResourceStream.Create(hInstance, ResourceName, 'BITMAP32');
- try
- Bitmap.LoadFromStream(Stream);
- finally
- Stream.Free;
- end;
- ImageList.AddMasked(Bitmap, -1);
- end;
- finally
- Bitmap.Free;
- end;
- end;
- begin
- inherited;
- LoadGlyphs;
- FImageAllChannels := CreateImage32(TabSheetRGBA);
- FImageRGBChannels := CreateImage32(TabSheetRGB);
- FImageAlphaChannel := CreateImage32(TabSheetAlpha);
- FImageAllChannels.Bitmap.DrawMode := dmBlend;
- FLayerPixelGrid := TPixelGridLayer.Create(FImageAllChannels.Layers, FImageAllChannels);
- FLayerPixelGrid.Visible := False;
- {$IFDEF PLATFORM_INDEPENDENT}
- FOpenDialog := TOpenDialog.Create(Self);
- FSaveDialog := TSaveDialog.Create(Self);
- {$ELSE}
- FOpenDialog := TOpenPictureDialog.Create(Self);
- FSaveDialog := TSavePictureDialog.Create(Self);
- {$ENDIF}
- FOpenDialog.Filter := ImageFormatManager.BuildFileFilter(IImageFormatReader, True) +
- '|' + SDefaultFilter;
- FSaveDialog.Filter := ImageFormatManager.BuildFileFilter(IImageFormatWriter) +
- '|' + SDefaultFilter;
- end;
- { TBitmap32Editor }
- constructor TBitmap32Editor.Create(AOwner: TComponent);
- begin
- inherited;
- FBitmap32 := TBitmap32.Create;
- end;
- destructor TBitmap32Editor.Destroy;
- begin
- FBitmap32.Free;
- inherited;
- end;
- function TBitmap32Editor.Execute: Boolean;
- var
- PictureEditorForm: TPictureEditorForm;
- begin
- PictureEditorForm := TPictureEditorForm.Create(Self);
- try
- PictureEditorForm.LoadFromImage(FBitmap32);
- Result := (PictureEditorForm.ShowModal = mrOK);
- if Result then
- FBitmap32.Assign(PictureEditorForm.FImageAllChannels.Bitmap);
- finally
- PictureEditorForm.Free;
- end;
- end;
- procedure TBitmap32Editor.SetBitmap32(Value: TBitmap32);
- begin
- try
- FBitmap32.Assign(Value);
- except
- on E: Exception do
- ShowMessage(E.Message);
- end;
- end;
- { TBitmap32Property }
- procedure TBitmap32Property.Edit;
- var
- BitmapEditor: TBitmap32Editor;
- begin
- try
- BitmapEditor := TBitmap32Editor.Create(nil);
- try
- {$IFDEF FPC}
- BitmapEditor.Bitmap32 := TBitmap32(GetObjectValue);
- {$ELSE}
- BitmapEditor.Bitmap32 := TBitmap32(Pointer(GetOrdValue));
- {$ENDIF}
- if BitmapEditor.Execute then
- begin
- {$IFDEF FPC}
- SetPtrValue(BitmapEditor.Bitmap32);
- {$ELSE}
- SetOrdValue(Longint(BitmapEditor.Bitmap32));
- {$ENDIF}
- end;
- finally
- BitmapEditor.Free;
- end;
- except
- on E: Exception do
- ShowMessage(E.Message);
- end;
- end;
- function TBitmap32Property.GetAttributes: TPropertyAttributes;
- begin
- Result := [paDialog, paSubProperties];
- end;
- function TBitmap32Property.GetValue: string;
- var
- Bitmap: TBitmap32;
- begin
- try
- {$IFDEF FPC}
- Bitmap := TBitmap32(GetObjectValue);
- {$ELSE}
- Bitmap := TBitmap32(GetOrdValue);
- {$ENDIF}
- if (Bitmap = nil) or Bitmap.Empty then
- Result := srNone
- else
- Result := Format('%s [%d,%d]', [Bitmap.ClassName, Bitmap.Width, Bitmap.Height]);
- except
- on E: Exception do
- ShowMessage(E.Message);
- end;
- end;
- {$IFDEF EXT_PROP_EDIT}
- procedure TBitmap32Property.PropDrawValue(Canvas: TCanvas;
- const ARect: TRect; ASelected: Boolean);
- var
- Bitmap32: TBitmap32;
- TmpBitmap: TBitmap32;
- R: TRect;
- begin
- Bitmap32 := TBitmap32(GetOrdValue);
- if Bitmap32.Empty then
- DefaultPropertyDrawValue(Self, Canvas, ARect)
- else
- begin
- R := ARect;
- R.Right := R.Left + R.Bottom - R.Top;
- TmpBitmap := TBitmap32.Create;
- TmpBitmap.Width := R.Right - R.Left;
- TmpBitmap.Height := R.Bottom - R.Top;
- TDraftResampler.Create(TmpBitmap);
- TmpBitmap.Draw(TmpBitmap.BoundsRect, Bitmap32.BoundsRect, Bitmap32);
- TmpBitmap.DrawTo(Canvas.Handle, R, TmpBitmap.BoundsRect);
- TmpBitmap.Free;
- R.Left := R.Right;
- R.Right := ARect.Right;
- DefaultPropertyDrawValue(Self, Canvas, R);
- end;
- end;
- procedure TBitmap32Property.PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
- begin
- DefaultPropertyDrawName(Self, ACanvas, ARect);
- end;
- function TBitmap32Property.PropDrawNameRect(const ARect: TRect): TRect;
- begin
- Result := ARect;
- end;
- function TBitmap32Property.PropDrawValueRect(const ARect: TRect): TRect;
- begin
- if TBitmap32(GetOrdValue).Empty then
- Result := ARect
- else
- Result := Rect(ARect.Left, ARect.Top, (ARect.Bottom - ARect.Top) + ARect.Left, ARect.Bottom);
- end;
- {$ENDIF}
- procedure TBitmap32Property.SetValue(const Value: string);
- begin
- if Value = '' then
- SetOrdValue(0);
- end;
- { TImage32Editor }
- procedure TImage32Editor.ExecuteVerb(Index: Integer);
- var
- Img: TCustomImage32;
- BitmapEditor: TBitmap32Editor;
- begin
- Img := Component as TCustomImage32;
- if Index = 0 then
- begin
- BitmapEditor := TBitmap32Editor.Create(nil);
- try
- BitmapEditor.Bitmap32 := Img.Bitmap;
- if BitmapEditor.Execute then
- begin
- Img.Bitmap := BitmapEditor.Bitmap32;
- Designer.Modified;
- end;
- finally
- BitmapEditor.Free;
- end;
- end;
- end;
- function TImage32Editor.GetVerb(Index: Integer): string;
- begin
- if Index = 0 then
- Result := 'Bitmap32 Editor...';
- end;
- function TImage32Editor.GetVerbCount: Integer;
- begin
- Result := 1;
- end;
- procedure TPictureEditorForm.ActionClearExecute(Sender: TObject);
- begin
- LoadFromImage(nil);
- end;
- procedure TPictureEditorForm.ActionLoadExecute(Sender: TObject);
- var
- Bitmap: TBitmap32;
- begin
- if not FOpenDialog.Execute then
- exit;
- Bitmap := TBitmap32.Create(TMemoryBackend);
- try
- Bitmap.LoadFromFile(FOpenDialog.Filename);
- LoadFromImage(Bitmap);
- finally
- Bitmap.Free;
- end;
- end;
- procedure TPictureEditorForm.ActionPasteExecute(Sender: TObject);
- var
- Bitmap: TBitmap32;
- begin
- Bitmap := TBitmap32.Create;
- try
- Bitmap.Assign(Clipboard);
- LoadFromImage(Bitmap);
- finally
- Bitmap.Free;
- end;
- end;
- procedure TPictureEditorForm.ActionPasteUpdate(Sender: TObject);
- begin
- try
- TAction(Sender).Enabled := ImageFormatManager.ClipboardFormats.CanPasteFromClipboard;
- except
- {$IFDEF FPC}
- TAction(Sender).Enabled := False;
- {$ELSE FPC}
- on E: EClipboardException do
- TAction(Sender).Enabled := False; // Something else has the clipboard open
- {$ENDIF FPC}
- end;
- end;
- procedure TPictureEditorForm.ActionSaveExecute(Sender: TObject);
- var
- Bitmap: TBitmap;
- begin
- if (CurrentImage.Bitmap.Empty) then
- exit;
- FSaveDialog.DefaultExt := GraphicExtension(TBitmap);
- if not FSaveDialog.Execute then
- exit;
- if (CurrentImage = FImageAllChannels) or
- (not SameText(ExtractFileExt(FSaveDialog.Filename), GraphicExtension(TBitmap))) then
- // Save in 32-bit RGBA bitmap (or whatever format we have chosen)
- FImageAllChannels.Bitmap.SaveToFile(FSaveDialog.Filename)
- else
- begin
- // Save 24-bit RGB bitmap
- Bitmap := TBitmap.Create;
- try
- Bitmap.Assign(CurrentImage.Bitmap);
- Bitmap.PixelFormat := pf24Bit;
- Bitmap.SaveToFile(FSaveDialog.Filename)
- finally
- Bitmap.Free;
- end;
- end;
- end;
- procedure TPictureEditorForm.ActionCopyExecute(Sender: TObject);
- begin
- Clipboard.Assign(CurrentImage.Bitmap);
- end;
- procedure TPictureEditorForm.ActionGridExecute(Sender: TObject);
- begin
- FLayerPixelGrid.Visible := TAction(Sender).Checked;
- end;
- procedure TPictureEditorForm.ActionGridUpdate(Sender: TObject);
- begin
- TAction(Sender).Checked := FLayerPixelGrid.Visible;
- end;
- procedure TPictureEditorForm.ActionHasBitmapUpdate(Sender: TObject);
- begin
- TAction(Sender).Enabled := (CurrentImage <> nil) and (not CurrentImage.Bitmap.Empty);
- end;
- procedure TPictureEditorForm.ActionHelpExecute(Sender: TObject);
- begin
- ShowMessage(sHelp);
- end;
- procedure TPictureEditorForm.ActionInvertExecute(Sender: TObject);
- begin
- if (CurrentImage = FImageAllChannels) then
- begin
- Invert(FImageAllChannels.Bitmap, FImageAllChannels.Bitmap);
- InvertRGB(FImageRGBChannels.Bitmap, FImageRGBChannels.Bitmap);
- InvertRGB(FImageAlphaChannel.Bitmap, FImageAlphaChannel.Bitmap);
- end else
- if (CurrentImage = FImageRGBChannels) then
- begin
- InvertRGB(FImageAllChannels.Bitmap, FImageAllChannels.Bitmap);
- InvertRGB(FImageRGBChannels.Bitmap, FImageRGBChannels.Bitmap);
- end else
- begin
- Invert(FImageAllChannels.Bitmap, FImageAllChannels.Bitmap, [ccAlpha]);
- InvertRGB(FImageAlphaChannel.Bitmap, FImageAlphaChannel.Bitmap);
- end;
- end;
- procedure TPictureEditorForm.ImageChanged(Sender: TObject);
- begin
- SyncZoomAndPan;
- end;
- procedure TPictureEditorForm.ImageMouseDown(Sender: TObject;
- Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
- begin
- if (Button = mbMiddle) then
- ResetZoomAndCenter(TImage32(Sender));
- end;
- procedure TPictureEditorForm.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
- var
- Image: TImage32;
- P: TPoint;
- Color: TColor32Entry;
- ColorHex: string;
- ColorChannels: string;
- begin
- Image := TImage32(Sender);
- if (Image.IsMousePanning) then
- exit;
- if (Image.Bitmap = nil) or (Image.Bitmap.Empty) then
- begin
- StatusBar.Panels[0].Text := '';
- StatusBar.Panels[1].Text := '';
- StatusBar.Panels[2].Text := '';
- exit;
- end;
- P := Image.ControlToBitmap(GR32.Point(X, Y));
- if (P.X >= 0) and (P.Y >= 0) and
- (P.X < Image.Bitmap.Width) and (P.Y < Image.Bitmap.Height) then
- begin
- Color := TColor32Entry(Image.Bitmap[P.X, P.Y]);
- if (Image = FImageAllChannels) then
- begin
- ColorHex := Format('ARGB: $%.8X', [Color.ARGB]);
- ColorChannels := Format('A:%-3d R:%-3d G:%-3d B:%-3d', [Color.A, Color.R, Color.G, Color.B]);
- end else
- if (Image = FImageRGBChannels) then
- begin
- ColorHex := Format('RGB: $%.6X', [Color.ARGB and $00FFFFFF]);
- ColorChannels := Format('R:%-3d G:%-3d B:%-3d', [Color.R, Color.G, Color.B]);
- end else
- begin
- ColorHex := Format('Alpha: $%.2X', [Color.R]);
- ColorChannels := Format('A:%-3d', [Color.R]);
- end;
- StatusBar.Panels[0].Text := ColorHex;
- StatusBar.Panels[1].Text := ColorChannels;
- StatusBar.Panels[2].Text := Format('X:%-2d Y:%-2d', [P.X, P.Y])
- end else
- begin
- StatusBar.Panels[0].Text := '';
- StatusBar.Panels[1].Text := '';
- StatusBar.Panels[2].Text := '';
- end;
- end;
- end.
|