BitmapImage.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. unit BitmapImage;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2025 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. A TImage-like component for bitmaps and png files without the TPicture bloat
  8. Also supports other TGraphic types which can be assigned to a TBitmap
  9. Also see TBitmapButton which is the TWinControl version
  10. }
  11. interface
  12. uses
  13. Windows, Controls, Graphics, Classes, Imaging.pngimage;
  14. type
  15. TPaintEvent = procedure(Sender: TObject; Canvas: TCanvas; var ARect: TRect) of object;
  16. TBitmapImageImplementation = record
  17. private
  18. FControl: TControl;
  19. public
  20. AutoSize: Boolean;
  21. AutoSizeExtraWidth, AutoSizeExtraHeight: Integer;
  22. BackColor: TColor;
  23. Bitmap: TBitmap;
  24. Center: Boolean;
  25. PngImage: TPngImage;
  26. ReplaceColor: TColor;
  27. ReplaceWithColor: TColor;
  28. Stretch: Boolean;
  29. StretchedBitmap: TBitmap;
  30. StretchedBitmapValid: Boolean;
  31. OnPaint: TPaintEvent;
  32. procedure Init(const AControl: TControl; const AAutoSizeExtraWidth: Integer = 0;
  33. const AAutoSizeExtraHeight: Integer = 0);
  34. procedure DeInit;
  35. function InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
  36. procedure BitmapChanged(Sender: TObject);
  37. procedure PngImageChanged(Sender: TObject);
  38. procedure SetAutoSize(Sender: TObject; Value: Boolean);
  39. procedure SetBackColor(Sender: TObject; Value: TColor);
  40. procedure SetBitmap(Value: TBitmap);
  41. procedure SetCenter(Sender: TObject; Value: Boolean);
  42. procedure SetGraphic(Value: TGraphic);
  43. procedure SetPngImage(Value: TPngImage);
  44. procedure SetReplaceColor(Sender: TObject; Value: TColor);
  45. procedure SetReplaceWithColor(Sender: TObject; Value: TColor);
  46. procedure SetStretch(Sender: TObject; Value: Boolean);
  47. function GetPalette: HPALETTE;
  48. procedure Paint(const Sender: TObject; const Canvas: TCanvas; var R: TRect);
  49. end;
  50. TBitmapImage = class(TGraphicControl)
  51. private
  52. FImpl: TBitmapImageImplementation;
  53. procedure SetBackColor(Value: TColor);
  54. procedure SetBitmap(Value: TBitmap);
  55. procedure SetCenter(Value: Boolean);
  56. procedure SetGraphic(Value: TGraphic);
  57. procedure SetPngImage(Value: TPngImage);
  58. procedure SetReplaceColor(Value: TColor);
  59. procedure SetReplaceWithColor(Value: TColor);
  60. procedure SetStretch(Value: Boolean);
  61. protected
  62. function GetPalette: HPALETTE; override;
  63. procedure Paint; override;
  64. procedure SetAutoSize(Value: Boolean); override;
  65. public
  66. constructor Create(AOwner: TComponent); override;
  67. destructor Destroy; override;
  68. function InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
  69. property Graphic: TGraphic write SetGraphic;
  70. published
  71. property Align;
  72. property Anchors;
  73. property AutoSize: Boolean read FImpl.AutoSize write SetAutoSize default False;
  74. property BackColor: TColor read FImpl.BackColor write SetBackColor default clBtnFace;
  75. property Bitmap: TBitmap read FImpl.Bitmap write SetBitmap;
  76. property Center: Boolean read FImpl.Center write SetCenter default False;
  77. property DragCursor;
  78. property DragMode;
  79. property Enabled;
  80. property ParentShowHint;
  81. property PngImage: TPngImage read FImpl.PngImage write SetPngImage;
  82. property PopupMenu;
  83. property ShowHint;
  84. property Stretch: Boolean read FImpl.Stretch write SetStretch default False;
  85. property ReplaceColor: TColor read FImpl.ReplaceColor write SetReplaceColor default clNone;
  86. property ReplaceWithColor: TColor read FImpl.ReplaceWithColor write SetReplaceWithColor default clNone;
  87. property Visible;
  88. property OnClick;
  89. property OnDblClick;
  90. property OnDragDrop;
  91. property OnDragOver;
  92. property OnEndDrag;
  93. property OnMouseDown;
  94. property OnMouseMove;
  95. property OnMouseUp;
  96. property OnPaint: TPaintEvent read FImpl.OnPaint write FImpl.OnPaint;
  97. property OnStartDrag;
  98. end;
  99. procedure Register;
  100. implementation
  101. uses
  102. SysUtils, Math, Resample;
  103. procedure Register;
  104. begin
  105. RegisterComponents('JR', [TBitmapImage]);
  106. end;
  107. { TBitmapImageImplementation }
  108. procedure TBitmapImageImplementation.Init(const AControl: TControl;
  109. const AAutoSizeExtraWidth, AAutoSizeExtraHeight: Integer);
  110. begin
  111. FControl := AControl;
  112. AutoSizeExtraWidth := AAutoSizeExtraWidth;
  113. AutoSizeExtraHeight := AAutoSizeExtraHeight;
  114. BackColor := clNone;
  115. Bitmap := TBitmap.Create;
  116. Bitmap.OnChange := BitmapChanged;
  117. PngImage := TPngImage.Create;
  118. PngImage.OnChange := PngImageChanged;
  119. ReplaceColor := clNone;
  120. ReplaceWithColor := clNone;
  121. StretchedBitmap := TBitmap.Create;
  122. end;
  123. procedure TBitmapImageImplementation.DeInit;
  124. begin
  125. FreeAndNil(StretchedBitmap);
  126. FreeAndNil(PngImage);
  127. FreeAndNil(Bitmap);
  128. end;
  129. function TBitmapImageImplementation.InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
  130. begin
  131. { Find the largest regular icon size smaller than the scaled image }
  132. var Size := 0;
  133. for var I := Length(AscendingTrySizes)-1 downto 0 do begin
  134. if (FControl.Width >= AscendingTrySizes[I]) and (FControl.Height >= AscendingTrySizes[I]) then begin
  135. Size := AscendingTrySizes[I];
  136. Break;
  137. end;
  138. end;
  139. if Size = 0 then
  140. Size := Min(FControl.Width, FControl.Height);
  141. { Load the desired icon }
  142. var Flags := LR_DEFAULTCOLOR;
  143. if Instance = 0 then
  144. Flags := Flags or LR_LOADFROMFILE;
  145. var Handle := LoadImage(Instance, Name, IMAGE_ICON, Size, Size, Flags);
  146. if Handle = 0 then
  147. Handle := LoadImage(Instance, Name, IMAGE_ICON, 0, 0, Flags);
  148. if Handle <> 0 then begin
  149. const Icon = TIcon.Create;
  150. try
  151. Icon.Handle := Handle;
  152. { Set sizes (overrides any scaling) }
  153. FControl.Width := Icon.Width;
  154. FControl.Height := Icon.Height;
  155. { Set bitmap }
  156. AutoSize := False;
  157. BackColor := BkColor;
  158. Bitmap.Assign(Icon);
  159. Result := True;
  160. finally
  161. Icon.Free;
  162. end;
  163. end else
  164. Result := False;
  165. end;
  166. procedure TBitmapImageImplementation.BitmapChanged(Sender: TObject);
  167. begin
  168. StretchedBitmapValid := False;
  169. if AutoSize and (Bitmap.Width > 0) and (Bitmap.Height > 0) then
  170. FControl.SetBounds(FControl.Left, FControl.Top, Bitmap.Width + AutoSizeExtraWidth,
  171. Bitmap.Height + AutoSizeExtraHeight);
  172. FControl.Invalidate;
  173. end;
  174. procedure TBitmapImageImplementation.PngImageChanged(Sender: TObject);
  175. begin
  176. Bitmap.Assign(PngImage);
  177. end;
  178. procedure TBitmapImageImplementation.SetAutoSize(Sender: TObject; Value: Boolean);
  179. begin
  180. AutoSize := Value;
  181. BitmapChanged(Sender);
  182. end;
  183. procedure TBitmapImageImplementation.SetBackColor(Sender: TObject; Value: TColor);
  184. begin
  185. if BackColor <> Value then begin
  186. BackColor := Value;
  187. BitmapChanged(Sender);
  188. end;
  189. end;
  190. procedure TBitmapImageImplementation.SetBitmap(Value: TBitmap);
  191. begin
  192. Bitmap.Assign(Value);
  193. end;
  194. procedure TBitmapImageImplementation.SetCenter(Sender: TObject; Value: Boolean);
  195. begin
  196. if Center <> Value then begin
  197. Center := Value;
  198. BitmapChanged(Sender);
  199. end;
  200. end;
  201. procedure TBitmapImageImplementation.SetGraphic(Value: TGraphic);
  202. begin
  203. if Value is TPngImage then
  204. SetPngImage(Value as TPngImage)
  205. else
  206. Bitmap.Assign(Value);
  207. end;
  208. procedure TBitmapImageImplementation.SetPngImage(Value: TPngImage);
  209. begin
  210. PngImage.Assign(Value);
  211. end;
  212. procedure TBitmapImageImplementation.SetReplaceColor(Sender: TObject; Value: TColor);
  213. begin
  214. if ReplaceColor <> Value then begin
  215. ReplaceColor := Value;
  216. BitmapChanged(Sender);
  217. end;
  218. end;
  219. procedure TBitmapImageImplementation.SetReplaceWithColor(Sender: TObject; Value: TColor);
  220. begin
  221. if ReplaceWithColor <> Value then begin
  222. ReplaceWithColor := Value;
  223. BitmapChanged(Sender);
  224. end;
  225. end;
  226. procedure TBitmapImageImplementation.SetStretch(Sender: TObject; Value: Boolean);
  227. begin
  228. if Stretch <> Value then begin
  229. Stretch := Value;
  230. StretchedBitmap.Assign(nil);
  231. BitmapChanged(Sender);
  232. end;
  233. end;
  234. function TBitmapImageImplementation.GetPalette: HPALETTE;
  235. begin
  236. Result := Bitmap.Palette;
  237. end;
  238. procedure TBitmapImageImplementation.Paint(const Sender: TObject; const Canvas: TCanvas; var R: TRect);
  239. begin
  240. const Is32bit = Bitmap.SupportsPartialTransparency;
  241. var W, H: Integer;
  242. var Bmp: TBitmap;
  243. if Stretch then begin
  244. W := R.Width;
  245. H := R.Height;
  246. Bmp := StretchedBitmap;
  247. if not StretchedBitmapValid or (StretchedBitmap.Width <> W) or
  248. (StretchedBitmap.Height <> H) then begin
  249. StretchedBitmapValid := True;
  250. if (Bitmap.Width = W) and (Bitmap.Height = H) then
  251. StretchedBitmap.Assign(Bitmap)
  252. else begin
  253. StretchedBitmap.Assign(nil);
  254. if not StretchBmp(Bitmap, StretchedBitmap, W, H, Is32bit) then begin
  255. if Is32bit then begin
  256. StretchedBitmapValid := False;
  257. Bmp := Bitmap;
  258. end else begin
  259. StretchedBitmap.Palette := CopyPalette(Bitmap.Palette);
  260. StretchedBitmap.Width := W;
  261. StretchedBitmap.Height := H;
  262. StretchedBitmap.Canvas.StretchDraw(Rect(0, 0, W, H), Bitmap);
  263. end;
  264. end;
  265. end;
  266. end;
  267. end else begin
  268. Bmp := Bitmap;
  269. W := Bmp.Width;
  270. H := Bmp.Height;
  271. end;
  272. if (BackColor <> clNone) and (Is32Bit or (Bmp.Width < FControl.Width) or (Bmp.Height < FControl.Height)) then begin
  273. Canvas.Brush.Style := bsSolid;
  274. Canvas.Brush.Color := BackColor;
  275. Canvas.FillRect(R);
  276. end;
  277. if csDesigning in FControl.ComponentState then begin
  278. Canvas.Pen.Style := psDash;
  279. Canvas.Brush.Style := bsClear;
  280. Canvas.Rectangle(0, 0, FControl.Width, FControl.Height);
  281. end;
  282. var X := R.Left;
  283. var Y := R.Top;
  284. if Center then begin
  285. Inc(X, (R.Width - W) div 2);
  286. if X < 0 then
  287. X := 0;
  288. Inc(Y, (R.Height - H) div 2);
  289. if Y < 0 then
  290. Y := 0;
  291. end;
  292. if not Is32bit and (ReplaceColor <> clNone) and (ReplaceWithColor <> clNone) then begin
  293. Canvas.Brush.Color := ReplaceWithColor;
  294. Canvas.BrushCopy(Rect(X, Y, X + W, Y + H), Bmp, Rect(0, 0, Bmp.Width, Bmp.Height), ReplaceColor);
  295. end else
  296. Canvas.Draw(X, Y, Bmp);
  297. if Assigned(OnPaint) then
  298. OnPaint(Sender, Canvas, R);
  299. end;
  300. { TBitmapImage }
  301. constructor TBitmapImage.Create(AOwner: TComponent);
  302. begin
  303. inherited;
  304. ControlStyle := ControlStyle + [csParentBackground, csReplicatable];
  305. FImpl.Init(Self);
  306. FImpl.BackColor := clBtnFace;
  307. Width := 105;
  308. Height := 105;
  309. end;
  310. destructor TBitmapImage.Destroy;
  311. begin
  312. FImpl.DeInit;
  313. inherited;
  314. end;
  315. function TBitmapImage.InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
  316. begin
  317. Result := FImpl.InitializeFromIcon(HInstance, Name, BkColor, AscendingTrySizes);
  318. end;
  319. procedure TBitmapImage.SetAutoSize(Value: Boolean);
  320. begin
  321. FImpl.SetAutoSize(Self, Value);
  322. end;
  323. procedure TBitmapImage.SetBackColor(Value: TColor);
  324. begin
  325. FImpl.SetBackColor(Self, Value);
  326. end;
  327. procedure TBitmapImage.SetBitmap(Value: TBitmap);
  328. begin
  329. FImpl.SetBitmap(Value);
  330. end;
  331. procedure TBitmapImage.SetCenter(Value: Boolean);
  332. begin
  333. FImpl.SetCenter(Self, Value);
  334. end;
  335. procedure TBitmapImage.SetGraphic(Value: TGraphic);
  336. begin
  337. FImpl.SetGraphic(Value);
  338. end;
  339. procedure TBitmapImage.SetPngImage(Value: TPngImage);
  340. begin
  341. FImpl.SetPngImage(Value);
  342. end;
  343. procedure TBitmapImage.SetReplaceColor(Value: TColor);
  344. begin
  345. FImpl.SetReplaceColor(Self, Value);
  346. end;
  347. procedure TBitmapImage.SetReplaceWithColor(Value: TColor);
  348. begin
  349. FImpl.SetReplaceWithColor(Self, Value);
  350. end;
  351. procedure TBitmapImage.SetStretch(Value: Boolean);
  352. begin
  353. FImpl.SetStretch(Self, Value);
  354. end;
  355. function TBitmapImage.GetPalette: HPALETTE;
  356. begin
  357. Result := FImpl.GetPalette;
  358. end;
  359. procedure TBitmapImage.Paint;
  360. begin
  361. var R := ClientRect;
  362. FImpl.Paint(Self, Canvas, R);
  363. end;
  364. end.