GR32_Dsgn_Bitmap.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. unit GR32_Dsgn_Bitmap;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Alex A. Denisov
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. *
  32. * ***** END LICENSE BLOCK ***** *)
  33. interface
  34. {$I GR32.inc}
  35. uses
  36. {$IFDEF FPC}
  37. LCLIntf, LCLType, RtlConsts, Buttons, LazIDEIntf, PropEdits,
  38. ComponentEditors,
  39. {$ELSE}
  40. Windows, ExtDlgs, ToolWin, Registry, ImgList, Consts, DesignIntf,
  41. DesignEditors, VCLEditors, Actions,
  42. {$ENDIF}
  43. Forms, Controls, ComCtrls, ExtCtrls, StdCtrls, Graphics, Dialogs, Menus,
  44. SysUtils, Classes, Clipbrd, ActnList,
  45. GR32, GR32_Image, GR32_Layers, GR32_Filters;
  46. type
  47. TPictureEditorForm = class(TForm)
  48. TabSheetAlpha: TTabSheet;
  49. Bevel1: TBevel;
  50. Cancel: TButton;
  51. ButtonClear: TToolButton;
  52. ButtonCopy: TToolButton;
  53. ImageList: TImageList;
  54. TabSheetRGB: TTabSheet;
  55. Label1: TLabel;
  56. ButtonLoad: TToolButton;
  57. MagnCombo: TComboBox;
  58. MenuItemClear: TMenuItem;
  59. MenuItemCopy: TMenuItem;
  60. MenuItemInvert: TMenuItem;
  61. MenuItemLoad: TMenuItem;
  62. MenuItemPaste: TMenuItem;
  63. MenuItemSave: TMenuItem;
  64. mnSeparator: TMenuItem;
  65. mnSeparator2: TMenuItem;
  66. OKButton: TButton;
  67. PageControl: TPageControl;
  68. Panel1: TPanel;
  69. ButtonPaste: TToolButton;
  70. PopupMenu: TPopupMenu;
  71. ButtonSave: TToolButton;
  72. ToolBar: TToolBar;
  73. ToolButton2: TToolButton;
  74. ActionList: TActionList;
  75. ActionLoad: TAction;
  76. ActionSave: TAction;
  77. ActionClear: TAction;
  78. ActionCopy: TAction;
  79. ActionPaste: TAction;
  80. ActionInvert: TAction;
  81. TabSheetRGBA: TTabSheet;
  82. StatusBar: TStatusBar;
  83. procedure MagnComboChange(Sender: TObject);
  84. procedure ActionLoadExecute(Sender: TObject);
  85. procedure ActionSaveExecute(Sender: TObject);
  86. procedure ActionHasBitmapUpdate(Sender: TObject);
  87. procedure ActionClearExecute(Sender: TObject);
  88. procedure ActionPasteUpdate(Sender: TObject);
  89. procedure ActionCopyExecute(Sender: TObject);
  90. procedure ActionPasteExecute(Sender: TObject);
  91. procedure ActionInvertExecute(Sender: TObject);
  92. protected
  93. {$IFDEF PLATFORM_INDEPENDENT}
  94. OpenDialog: TOpenDialog;
  95. SaveDialog: TSaveDialog;
  96. {$ELSE}
  97. OpenDialog: TOpenPictureDialog;
  98. SaveDialog: TSavePictureDialog;
  99. {$ENDIF}
  100. ImageAllChannels: TImage32;
  101. ImageRGBChannels: TImage32;
  102. ImageAlphaChannel: TImage32;
  103. procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  104. procedure ImagePaintStage(Sender: TObject; Buffer: TBitmap32; StageNum: Cardinal);
  105. function CurrentImage: TImage32;
  106. public
  107. constructor Create(AOwner: TComponent); override;
  108. procedure LoadFromImage(Source: TPersistent);
  109. end;
  110. TBitmap32Editor = class(TComponent)
  111. private
  112. FBitmap32: TBitmap32;
  113. procedure SetBitmap32(Value: TBitmap32);
  114. public
  115. constructor Create(AOwner: TComponent); override;
  116. destructor Destroy; override;
  117. function Execute: Boolean;
  118. property Bitmap32: TBitmap32 read FBitmap32 write SetBitmap32;
  119. end;
  120. TBitmap32Property = class(TClassProperty
  121. {$IFDEF EXT_PROP_EDIT}
  122. , ICustomPropertyDrawing, ICustomPropertyDrawing80
  123. {$ENDIF}
  124. )
  125. public
  126. procedure Edit; override;
  127. function GetAttributes: TPropertyAttributes; override;
  128. function GetValue: string; override;
  129. procedure SetValue(const Value: string); override;
  130. {$IFDEF EXT_PROP_EDIT}
  131. { ICustomPropertyDrawing }
  132. procedure PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
  133. procedure PropDrawValue(Canvas: TCanvas; const ARect: TRect; ASelected: Boolean);
  134. { ICustomPropertyDrawing80 }
  135. function PropDrawNameRect(const ARect: TRect): TRect;
  136. function PropDrawValueRect(const ARect: TRect): TRect;
  137. {$ENDIF}
  138. end;
  139. TImage32Editor = class(TComponentEditor)
  140. public
  141. procedure ExecuteVerb(Index: Integer); override;
  142. function GetVerb(Index: Integer): string; override;
  143. function GetVerbCount: Integer; override;
  144. end;
  145. implementation
  146. uses
  147. GR32_Resamplers,
  148. GR32_Backends_Generic;
  149. {$IFDEF FPC}
  150. {$R *.lfm}
  151. {$ELSE}
  152. {$R *.dfm}
  153. {$ENDIF}
  154. { TPictureEditorForm }
  155. function TPictureEditorForm.CurrentImage: TImage32;
  156. begin
  157. if PageControl.ActivePage = TabSheetRGBA then
  158. Result := ImageAllChannels
  159. else
  160. if PageControl.ActivePage = TabSheetRGB then
  161. Result := ImageRGBChannels
  162. else
  163. Result := ImageAlphaChannel;
  164. end;
  165. procedure TPictureEditorForm.ImagePaintStage(Sender: TObject; Buffer: TBitmap32; StageNum: Cardinal);
  166. const //0..1
  167. Colors: array [Boolean] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
  168. var
  169. R: TRect;
  170. I, J: Integer;
  171. OddY: Integer;
  172. TilesHorz, TilesVert: Integer;
  173. TileX, TileY: Integer;
  174. TileHeight, TileWidth: Integer;
  175. begin
  176. TileHeight := 13;
  177. TileWidth := 13;
  178. TilesHorz := Buffer.Width div TileWidth;
  179. TilesVert := Buffer.Height div TileHeight;
  180. TileY := 0;
  181. for J := 0 to TilesVert do
  182. begin
  183. TileX := 0;
  184. OddY := J and $1;
  185. for I := 0 to TilesHorz do
  186. begin
  187. R.Left := TileX;
  188. R.Top := TileY;
  189. R.Right := TileX + TileWidth;
  190. R.Bottom := TileY + TileHeight;
  191. Buffer.FillRectS(R, Colors[I and $1 = OddY]);
  192. Inc(TileX, TileWidth);
  193. end;
  194. Inc(TileY, TileHeight);
  195. end;
  196. end;
  197. procedure TPictureEditorForm.LoadFromImage(Source: TPersistent);
  198. begin
  199. if CurrentImage = ImageAllChannels then
  200. begin
  201. // Load RGBA bitmap, separate into RGB and A
  202. // Load RGBA
  203. ImageAllChannels.Bitmap.Assign(Source);
  204. ImageAllChannels.Bitmap.DrawMode := dmBlend;
  205. // Separate RGB
  206. ImageRGBChannels.Bitmap.Assign(ImageAllChannels.Bitmap);
  207. ImageRGBChannels.Bitmap.ResetAlpha;
  208. // Separate A
  209. AlphaToGrayscale(ImageAlphaChannel.Bitmap, ImageAllChannels.Bitmap);
  210. ImageAlphaChannel.Bitmap.ResetAlpha;
  211. end else
  212. if CurrentImage = ImageRGBChannels then
  213. begin
  214. // Load RGB bitmap, keep existing A
  215. // Load RGB
  216. if (Source <> nil) then
  217. begin
  218. ImageRGBChannels.Bitmap.Assign(Source);
  219. ImageRGBChannels.Bitmap.ResetAlpha;
  220. end else
  221. ImageRGBChannels.Bitmap.Clear($FF000000);
  222. // Merge A and RGB into RGBA
  223. ImageAllChannels.Bitmap.Assign(ImageRGBChannels.Bitmap);
  224. ImageAllChannels.Bitmap.DrawMode := dmBlend;
  225. if (not ImageAlphaChannel.Bitmap.Empty) then
  226. IntensityToAlpha(ImageAllChannels.Bitmap, ImageAlphaChannel.Bitmap)
  227. else
  228. ImageAllChannels.Bitmap.ResetAlpha;
  229. end else
  230. if CurrentImage = ImageAlphaChannel then
  231. begin
  232. // Load A bitmap, keep existing RGB
  233. if (Source <> nil) then
  234. ImageAlphaChannel.Bitmap.Assign(Source)
  235. else
  236. ImageAlphaChannel.Bitmap.Clear($FFFFFFFF);
  237. ColorToGrayscale(ImageAlphaChannel.Bitmap, ImageAlphaChannel.Bitmap);
  238. // Merge A and RGB into RGBA
  239. if (not ImageRGBChannels.Bitmap.Empty) then
  240. begin
  241. ImageAllChannels.Bitmap.Assign(ImageRGBChannels.Bitmap);
  242. ImageAllChannels.Bitmap.DrawMode := dmBlend;
  243. end else
  244. begin
  245. ImageAllChannels.Bitmap.SetSizeFrom(ImageAlphaChannel.Bitmap);
  246. ImageAllChannels.Bitmap.Clear;
  247. end;
  248. IntensityToAlpha(ImageAllChannels.Bitmap, ImageAlphaChannel.Bitmap);
  249. end;
  250. end;
  251. procedure TPictureEditorForm.MagnComboChange(Sender: TObject);
  252. const
  253. MAGN: array[0..6] of Integer = (25, 50, 100, 200, 400, 800, -1);
  254. var
  255. S: Integer;
  256. begin
  257. S := MAGN[MagnCombo.ItemIndex];
  258. if S = -1 then
  259. begin
  260. ImageAllChannels.ScaleMode := smResize;
  261. ImageRGBChannels.ScaleMode := smResize;
  262. ImageAlphaChannel.ScaleMode := smResize;
  263. end else
  264. begin
  265. ImageAllChannels.ScaleMode := smScale;
  266. ImageAllChannels.Scale := S / 100;
  267. ImageRGBChannels.ScaleMode := smScale;
  268. ImageRGBChannels.Scale := S / 100;
  269. ImageAlphaChannel.ScaleMode := smScale;
  270. ImageAlphaChannel.Scale := S / 100;
  271. end;
  272. end;
  273. constructor TPictureEditorForm.Create(AOwner: TComponent);
  274. function CreateImage32(AParent: TWinControl): TImage32;
  275. begin
  276. Result := TImage32.Create(Self);
  277. Result.Parent := AParent;
  278. Result.Align := alClient;
  279. Result.BitmapAlign := baCenter;
  280. Result.Cursor := crCross;
  281. Result.PopupMenu := PopupMenu;
  282. Result.OnMouseMove := ImageMouseMove;
  283. Result.OnPaintStage := ImagePaintStage;
  284. if (Result.PaintStages[0].Stage = PST_CLEAR_BACKGND) then
  285. Result.PaintStages[0].Stage := PST_CUSTOM;
  286. end;
  287. begin
  288. inherited;
  289. ImageAllChannels := CreateImage32(TabSheetRGBA);
  290. ImageAllChannels.Bitmap.DrawMode := dmBlend;
  291. ImageRGBChannels := CreateImage32(TabSheetRGB);
  292. ImageAlphaChannel := CreateImage32(TabSheetAlpha);
  293. {$IFDEF PLATFORM_INDEPENDENT}
  294. OpenDialog := TOpenDialog.Create(Self);
  295. SaveDialog := TSaveDialog.Create(Self);
  296. {$ELSE}
  297. OpenDialog := TOpenPictureDialog.Create(Self);
  298. SaveDialog := TSavePictureDialog.Create(Self);
  299. {$ENDIF}
  300. MagnCombo.ItemIndex := 2;
  301. OpenDialog.Filter := GraphicFilter(TGraphic);
  302. SaveDialog.Filter := GraphicFilter(TGraphic);
  303. end;
  304. { TBitmap32Editor }
  305. constructor TBitmap32Editor.Create(AOwner: TComponent);
  306. begin
  307. inherited;
  308. FBitmap32 := TBitmap32.Create;
  309. end;
  310. destructor TBitmap32Editor.Destroy;
  311. begin
  312. FBitmap32.Free;
  313. inherited;
  314. end;
  315. function TBitmap32Editor.Execute: Boolean;
  316. var
  317. PictureEditorForm: TPictureEditorForm;
  318. begin
  319. PictureEditorForm := TPictureEditorForm.Create(Self);
  320. try
  321. PictureEditorForm.LoadFromImage(FBitmap32);
  322. Result := (PictureEditorForm.ShowModal = mrOK);
  323. if Result then
  324. FBitmap32.Assign(PictureEditorForm.ImageAllChannels.Bitmap);
  325. finally
  326. PictureEditorForm.Free;
  327. end;
  328. end;
  329. procedure TBitmap32Editor.SetBitmap32(Value: TBitmap32);
  330. begin
  331. try
  332. FBitmap32.Assign(Value);
  333. except
  334. on E: Exception do
  335. ShowMessage(E.Message);
  336. end;
  337. end;
  338. { TBitmap32Property }
  339. procedure TBitmap32Property.Edit;
  340. var
  341. BitmapEditor: TBitmap32Editor;
  342. begin
  343. try
  344. BitmapEditor := TBitmap32Editor.Create(nil);
  345. try
  346. {$IFDEF FPC}
  347. BitmapEditor.Bitmap32 := TBitmap32(GetObjectValue);
  348. {$ELSE}
  349. BitmapEditor.Bitmap32 := TBitmap32(Pointer(GetOrdValue));
  350. {$ENDIF}
  351. if BitmapEditor.Execute then
  352. begin
  353. {$IFDEF FPC}
  354. SetPtrValue(BitmapEditor.Bitmap32);
  355. {$ELSE}
  356. SetOrdValue(Longint(BitmapEditor.Bitmap32));
  357. {$ENDIF}
  358. end;
  359. finally
  360. BitmapEditor.Free;
  361. end;
  362. except
  363. on E: Exception do
  364. ShowMessage(E.Message);
  365. end;
  366. end;
  367. function TBitmap32Property.GetAttributes: TPropertyAttributes;
  368. begin
  369. Result := [paDialog, paSubProperties];
  370. end;
  371. function TBitmap32Property.GetValue: string;
  372. var
  373. Bitmap: TBitmap32;
  374. begin
  375. try
  376. {$IFDEF FPC}
  377. Bitmap := TBitmap32(GetObjectValue);
  378. {$ELSE}
  379. Bitmap := TBitmap32(GetOrdValue);
  380. {$ENDIF}
  381. if (Bitmap = nil) or Bitmap.Empty then
  382. Result := srNone
  383. else
  384. Result := Format('%s [%d,%d]', [Bitmap.ClassName, Bitmap.Width, Bitmap.Height]);
  385. except
  386. on E: Exception do
  387. ShowMessage(E.Message);
  388. end;
  389. end;
  390. {$IFDEF EXT_PROP_EDIT}
  391. procedure TBitmap32Property.PropDrawValue(Canvas: TCanvas;
  392. const ARect: TRect; ASelected: Boolean);
  393. var
  394. Bitmap32: TBitmap32;
  395. TmpBitmap: TBitmap32;
  396. R: TRect;
  397. begin
  398. Bitmap32 := TBitmap32(GetOrdValue);
  399. if Bitmap32.Empty then
  400. DefaultPropertyDrawValue(Self, Canvas, ARect)
  401. else
  402. begin
  403. R := ARect;
  404. R.Right := R.Left + R.Bottom - R.Top;
  405. TmpBitmap := TBitmap32.Create;
  406. TmpBitmap.Width := R.Right - R.Left;
  407. TmpBitmap.Height := R.Bottom - R.Top;
  408. TDraftResampler.Create(TmpBitmap);
  409. TmpBitmap.Draw(TmpBitmap.BoundsRect, Bitmap32.BoundsRect, Bitmap32);
  410. TmpBitmap.DrawTo(Canvas.Handle, R, TmpBitmap.BoundsRect);
  411. TmpBitmap.Free;
  412. R.Left := R.Right;
  413. R.Right := ARect.Right;
  414. DefaultPropertyDrawValue(Self, Canvas, R);
  415. end;
  416. end;
  417. procedure TBitmap32Property.PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
  418. begin
  419. DefaultPropertyDrawName(Self, ACanvas, ARect);
  420. end;
  421. function TBitmap32Property.PropDrawNameRect(const ARect: TRect): TRect;
  422. begin
  423. Result := ARect;
  424. end;
  425. function TBitmap32Property.PropDrawValueRect(const ARect: TRect): TRect;
  426. begin
  427. if TBitmap32(GetOrdValue).Empty then
  428. Result := ARect
  429. else
  430. Result := Rect(ARect.Left, ARect.Top, (ARect.Bottom - ARect.Top) + ARect.Left, ARect.Bottom);
  431. end;
  432. {$ENDIF}
  433. procedure TBitmap32Property.SetValue(const Value: string);
  434. begin
  435. if Value = '' then
  436. SetOrdValue(0);
  437. end;
  438. { TImage32Editor }
  439. procedure TImage32Editor.ExecuteVerb(Index: Integer);
  440. var
  441. Img: TCustomImage32;
  442. BitmapEditor: TBitmap32Editor;
  443. begin
  444. Img := Component as TCustomImage32;
  445. if Index = 0 then
  446. begin
  447. BitmapEditor := TBitmap32Editor.Create(nil);
  448. try
  449. BitmapEditor.Bitmap32 := Img.Bitmap;
  450. if BitmapEditor.Execute then
  451. begin
  452. Img.Bitmap := BitmapEditor.Bitmap32;
  453. Designer.Modified;
  454. end;
  455. finally
  456. BitmapEditor.Free;
  457. end;
  458. end;
  459. end;
  460. function TImage32Editor.GetVerb(Index: Integer): string;
  461. begin
  462. if Index = 0 then
  463. Result := 'Bitmap32 Editor...';
  464. end;
  465. function TImage32Editor.GetVerbCount: Integer;
  466. begin
  467. Result := 1;
  468. end;
  469. procedure TPictureEditorForm.ActionClearExecute(Sender: TObject);
  470. begin
  471. LoadFromImage(nil);
  472. end;
  473. procedure TPictureEditorForm.ActionLoadExecute(Sender: TObject);
  474. var
  475. Picture: TPicture;
  476. Bitmap: TBitmap32;
  477. begin
  478. if not OpenDialog.Execute then
  479. exit;
  480. // Load bitmap directly if file is a BMP
  481. // (this works around alleged bug in TBitmap->TBitmap32 conversion with LCL-Gtk backend)
  482. if (SameText(ExtractFileExt(OpenDialog.Filename), '.bmp')) then
  483. begin
  484. Bitmap := TBitmap32.Create(TMemoryBackend);
  485. try
  486. Bitmap.LoadFromFile(OpenDialog.Filename);
  487. LoadFromImage(Bitmap);
  488. finally
  489. Bitmap.Free;
  490. end;
  491. end else
  492. begin
  493. Picture := TPicture.Create;
  494. try
  495. Picture.LoadFromFile(OpenDialog.Filename);
  496. LoadFromImage(Picture);
  497. finally
  498. Picture.Free;
  499. end;
  500. end;
  501. end;
  502. procedure TPictureEditorForm.ActionPasteExecute(Sender: TObject);
  503. var
  504. Bitmap: TBitmap32;
  505. begin
  506. Bitmap := TBitmap32.Create;
  507. try
  508. Bitmap.Assign(Clipboard);
  509. LoadFromImage(Bitmap);
  510. finally
  511. Bitmap.Free;
  512. end;
  513. end;
  514. procedure TPictureEditorForm.ActionPasteUpdate(Sender: TObject);
  515. begin
  516. try
  517. TAction(Sender).Enabled := Clipboard.HasFormat(CF_PICTURE);
  518. except
  519. {$IFDEF FPC}
  520. TAction(Sender).Enabled := False;
  521. {$ELSE FPC}
  522. on E: EClipboardException do
  523. TAction(Sender).Enabled := False; // Something else has the clipboard open
  524. {$ENDIF FPC}
  525. end;
  526. end;
  527. procedure TPictureEditorForm.ActionSaveExecute(Sender: TObject);
  528. var
  529. Bitmap: TBitmap;
  530. begin
  531. if (CurrentImage.Bitmap.Empty) then
  532. exit;
  533. SaveDialog.DefaultExt := GraphicExtension(TBitmap);
  534. SaveDialog.Filter := GraphicFilter(TBitmap);
  535. if not SaveDialog.Execute then
  536. exit;
  537. if (CurrentImage = ImageAllChannels) then
  538. // Save in 32-bit RGBA bitmap
  539. ImageAllChannels.Bitmap.SaveToFile(SaveDialog.Filename)
  540. else
  541. begin
  542. // Save 24-bit RGB bitmap
  543. Bitmap := TBitmap.Create;
  544. try
  545. Bitmap.Assign(CurrentImage.Bitmap);
  546. Bitmap.PixelFormat := pf24Bit;
  547. Bitmap.SaveToFile(SaveDialog.Filename)
  548. finally
  549. Bitmap.Free;
  550. end;
  551. end;
  552. end;
  553. procedure TPictureEditorForm.ActionCopyExecute(Sender: TObject);
  554. begin
  555. Clipboard.Assign(CurrentImage.Bitmap);
  556. end;
  557. procedure TPictureEditorForm.ActionHasBitmapUpdate(Sender: TObject);
  558. begin
  559. TAction(Sender).Enabled := (CurrentImage <> nil) and (not CurrentImage.Bitmap.Empty);
  560. end;
  561. procedure TPictureEditorForm.ActionInvertExecute(Sender: TObject);
  562. begin
  563. if (CurrentImage = ImageAllChannels) then
  564. begin
  565. Invert(ImageAllChannels.Bitmap, ImageAllChannels.Bitmap);
  566. InvertRGB(ImageRGBChannels.Bitmap, ImageRGBChannels.Bitmap);
  567. InvertRGB(ImageAlphaChannel.Bitmap, ImageAlphaChannel.Bitmap);
  568. end else
  569. if (CurrentImage = ImageRGBChannels) then
  570. begin
  571. InvertRGB(ImageAllChannels.Bitmap, ImageAllChannels.Bitmap);
  572. InvertRGB(ImageRGBChannels.Bitmap, ImageRGBChannels.Bitmap);
  573. end else
  574. begin
  575. Invert(ImageAllChannels.Bitmap, ImageAllChannels.Bitmap, [ccAlpha]);
  576. InvertRGB(ImageAlphaChannel.Bitmap, ImageAlphaChannel.Bitmap);
  577. end;
  578. end;
  579. procedure TPictureEditorForm.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  580. var
  581. Image: TImage32;
  582. P: TPoint;
  583. Color: TColor32Entry;
  584. ColorHex: string;
  585. ColorChannels: string;
  586. begin
  587. Image := TImage32(Sender);
  588. if (Image.Bitmap = nil) or (Image.Bitmap.Empty) then
  589. begin
  590. StatusBar.Panels[0].Text := '';
  591. StatusBar.Panels[1].Text := '';
  592. StatusBar.Panels[2].Text := '';
  593. exit;
  594. end;
  595. P := Image.ControlToBitmap(Point(X, Y));
  596. if (P.X >= 0) and (P.Y >= 0) and
  597. (P.X < Image.Bitmap.Width) and (P.Y < Image.Bitmap.Height) then
  598. begin
  599. Color := TColor32Entry(Image.Bitmap[P.X, P.Y]);
  600. if (Image = ImageAllChannels) then
  601. begin
  602. ColorHex := Format('ARGB: $%.8X', [Color.ARGB]);
  603. ColorChannels := Format('A:%-3d R:%-3d G:%-3d B:%-3d', [Color.A, Color.R, Color.G, Color.B]);
  604. end else
  605. if (Image = ImageRGBChannels) then
  606. begin
  607. ColorHex := Format('RGB: $%.6X', [Color.ARGB and $00FFFFFF]);
  608. ColorChannels := Format('R:%-3d G:%-3d B:%-3d', [Color.R, Color.G, Color.B]);
  609. end else
  610. begin
  611. ColorHex := Format('Alpha: $%.2X', [Color.R]);
  612. ColorChannels := Format('A:%-3d', [Color.R]);
  613. end;
  614. StatusBar.Panels[0].Text := ColorHex;
  615. StatusBar.Panels[1].Text := ColorChannels;
  616. StatusBar.Panels[2].Text := Format('X:%-2d Y:%-2d', [P.X, P.Y])
  617. end else
  618. begin
  619. StatusBar.Panels[0].Text := '';
  620. StatusBar.Panels[1].Text := '';
  621. StatusBar.Panels[2].Text := '';
  622. end;
  623. end;
  624. end.