BitmapImage.pas 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. unit BitmapImage;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2019 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. A TImage-like component for bitmaps without the TPicture bloat
  8. }
  9. interface
  10. uses
  11. Windows, Controls, Graphics, Classes;
  12. type
  13. TBitmapImage = class(TGraphicControl)
  14. private
  15. FAutoSize: Boolean;
  16. FBackColor: TColor;
  17. FBitmap: TBitmap;
  18. FCenter: Boolean;
  19. FReplaceColor: TColor;
  20. FReplaceWithColor: TColor;
  21. FStretch: Boolean;
  22. FStretchedBitmap: TBitmap;
  23. FStretchedBitmapValid: Boolean;
  24. procedure BitmapChanged(Sender: TObject);
  25. procedure SetBackColor(Value: TColor);
  26. procedure SetBitmap(Value: TBitmap);
  27. procedure SetCenter(Value: Boolean);
  28. procedure SetReplaceColor(Value: TColor);
  29. procedure SetReplaceWithColor(Value: TColor);
  30. procedure SetStretch(Value: Boolean);
  31. function GetBitmap: TBitmap;
  32. protected
  33. function GetPalette: HPALETTE; override;
  34. procedure Paint; override;
  35. procedure SetAutoSize(Value: Boolean); override;
  36. public
  37. constructor Create(AOwner: TComponent); override;
  38. destructor Destroy; override;
  39. function InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
  40. published
  41. property Align;
  42. property Anchors;
  43. property AutoSize: Boolean read FAutoSize write SetAutoSize default False;
  44. property BackColor: TColor read FBackColor write SetBackColor default clBtnFace;
  45. property Center: Boolean read FCenter write SetCenter default False;
  46. property DragCursor;
  47. property DragMode;
  48. property Enabled;
  49. property ParentShowHint;
  50. property Bitmap: TBitmap read GetBitmap write SetBitmap;
  51. property PopupMenu;
  52. property ShowHint;
  53. property Stretch: Boolean read FStretch write SetStretch default False;
  54. property ReplaceColor: TColor read FReplaceColor write SetReplaceColor default clNone;
  55. property ReplaceWithColor: TColor read FReplaceWithColor write SetReplaceWithColor default clNone;
  56. property Visible;
  57. property OnClick;
  58. property OnDblClick;
  59. property OnDragDrop;
  60. property OnDragOver;
  61. property OnEndDrag;
  62. property OnMouseDown;
  63. property OnMouseMove;
  64. property OnMouseUp;
  65. property OnStartDrag;
  66. end;
  67. procedure Register;
  68. implementation
  69. uses
  70. Math, Resample;
  71. procedure Register;
  72. begin
  73. RegisterComponents('JR', [TBitmapImage]);
  74. end;
  75. function TBitmapImage.InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
  76. var
  77. Flags: Cardinal;
  78. Handle: THandle;
  79. Icon: TIcon;
  80. I, Size: Integer;
  81. begin
  82. { Find the largest regular icon size smaller than the scaled image }
  83. Size := 0;
  84. for I := Length(AscendingTrySizes)-1 downto 0 do begin
  85. if (Width >= AscendingTrySizes[I]) and (Height >= AscendingTrySizes[I]) then begin
  86. Size := AscendingTrySizes[I];
  87. Break;
  88. end;
  89. end;
  90. if Size = 0 then
  91. Size := Min(Width, Height);
  92. { Load the desired icon }
  93. Flags := LR_DEFAULTCOLOR;
  94. if Instance = 0 then
  95. Flags := Flags or LR_LOADFROMFILE;
  96. Handle := LoadImage(Instance, Name, IMAGE_ICON, Size, Size, Flags);
  97. if Handle = 0 then
  98. Handle := LoadImage(Instance, Name, IMAGE_ICON, 0, 0, Flags);
  99. if Handle <> 0 then begin
  100. Icon := TIcon.Create;
  101. try
  102. Icon.Handle := Handle;
  103. { Set sizes (overrides any scaling) }
  104. Width := Icon.Width;
  105. Height := Icon.Height;
  106. { Draw icon into bitmap }
  107. Bitmap.Canvas.Brush.Color := BkColor;
  108. Bitmap.Width := Width;
  109. Bitmap.Height := Height;
  110. Bitmap.Canvas.Draw(0, 0, Icon);
  111. Result := True;
  112. finally
  113. Icon.Free;
  114. end;
  115. end else
  116. Result := False;
  117. end;
  118. constructor TBitmapImage.Create(AOwner: TComponent);
  119. begin
  120. inherited Create(AOwner);
  121. ControlStyle := ControlStyle + [csReplicatable];
  122. FBackColor := clBtnFace;
  123. FBitmap := TBitmap.Create;
  124. FBitmap.OnChange := BitmapChanged;
  125. FReplaceColor := clNone;
  126. FReplaceWithColor := clNone;
  127. FStretchedBitmap := TBitmap.Create;
  128. Height := 105;
  129. Width := 105;
  130. end;
  131. destructor TBitmapImage.Destroy;
  132. begin
  133. FStretchedBitmap.Free;
  134. FBitmap.Free;
  135. inherited Destroy;
  136. end;
  137. procedure TBitmapImage.BitmapChanged(Sender: TObject);
  138. begin
  139. FStretchedBitmapValid := False;
  140. if FAutoSize and (FBitmap.Width > 0) and (FBitmap.Height > 0) then
  141. SetBounds(Left, Top, FBitmap.Width, FBitmap.Height);
  142. if (FBitmap.Width >= Width) and (FBitmap.Height >= Height) then
  143. ControlStyle := ControlStyle + [csOpaque]
  144. else
  145. ControlStyle := ControlStyle - [csOpaque];
  146. Invalidate;
  147. end;
  148. procedure TBitmapImage.SetAutoSize(Value: Boolean);
  149. begin
  150. FAutoSize := Value;
  151. BitmapChanged(Self);
  152. end;
  153. procedure TBitmapImage.SetBackColor(Value: TColor);
  154. begin
  155. if FBackColor <> Value then begin
  156. FBackColor := Value;
  157. BitmapChanged(Self);
  158. end;
  159. end;
  160. procedure TBitmapImage.SetBitmap(Value: TBitmap);
  161. begin
  162. FBitmap.Assign(Value);
  163. end;
  164. procedure TBitmapImage.SetCenter(Value: Boolean);
  165. begin
  166. if FCenter <> Value then begin
  167. FCenter := Value;
  168. BitmapChanged(Self);
  169. end;
  170. end;
  171. procedure TBitmapImage.SetReplaceColor(Value: TColor);
  172. begin
  173. if FReplaceColor <> Value then begin
  174. FReplaceColor := Value;
  175. BitmapChanged(Self);
  176. end;
  177. end;
  178. procedure TBitmapImage.SetReplaceWithColor(Value: TColor);
  179. begin
  180. if FReplaceWithColor <> Value then begin
  181. FReplaceWithColor := Value;
  182. BitmapChanged(Self);
  183. end;
  184. end;
  185. procedure TBitmapImage.SetStretch(Value: Boolean);
  186. begin
  187. if FStretch <> Value then begin
  188. FStretch := Value;
  189. FStretchedBitmap.Assign(nil);
  190. BitmapChanged(Self);
  191. end;
  192. end;
  193. function TBitmapImage.GetBitmap: TBitmap;
  194. begin
  195. Result := FBitmap;
  196. end;
  197. function TBitmapImage.GetPalette: HPALETTE;
  198. begin
  199. Result := FBitmap.Palette;
  200. end;
  201. procedure TBitmapImage.Paint;
  202. var
  203. R: TRect;
  204. Bmp: TBitmap;
  205. X, Y, W, H: Integer;
  206. Is32bit: Boolean;
  207. begin
  208. with Canvas do begin
  209. R := ClientRect;
  210. Is32bit := (FBitmap.PixelFormat = pf32bit) and
  211. (FBitmap.AlphaFormat in [afDefined, afPremultiplied]);
  212. if Stretch then begin
  213. W := R.Right;
  214. H := R.Bottom;
  215. Bmp := FStretchedBitmap;
  216. if not FStretchedBitmapValid or (FStretchedBitmap.Width <> W) or
  217. (FStretchedBitmap.Height <> H) then begin
  218. FStretchedBitmapValid := True;
  219. if (FBitmap.Width = W) and (FBitmap.Height = H) then
  220. FStretchedBitmap.Assign(FBitmap)
  221. else begin
  222. FStretchedBitmap.Assign(nil);
  223. if not StretchBmp(FBitmap, FStretchedBitmap, W, H, Is32bit) then begin
  224. if Is32bit then begin
  225. FStretchedBitmapValid := False;
  226. Bmp := FBitmap;
  227. end else begin
  228. FStretchedBitmap.Palette := CopyPalette(FBitmap.Palette);
  229. FStretchedBitmap.Width := W;
  230. FStretchedBitmap.Height := H;
  231. FStretchedBitmap.Canvas.StretchDraw(R, FBitmap);
  232. end;
  233. end;
  234. end;
  235. end;
  236. end else begin
  237. Bmp := FBitmap;
  238. W := Bmp.Width;
  239. H := Bmp.Height;
  240. end;
  241. if (FBackColor <> clNone) and (Is32Bit or (Bmp.Width < Width) or (Bmp.Height < Height)) then begin
  242. Brush.Style := bsSolid;
  243. Brush.Color := FBackColor;
  244. FillRect(R);
  245. end;
  246. if csDesigning in ComponentState then begin
  247. Pen.Style := psDash;
  248. Brush.Style := bsClear;
  249. Rectangle(0, 0, Width, Height);
  250. end;
  251. if Center then begin
  252. X := R.Left + ((R.Right - R.Left) - W) div 2;
  253. if X < 0 then
  254. X := 0;
  255. Y := R.Top + ((R.Bottom - R.Top) - H) div 2;
  256. if Y < 0 then
  257. Y := 0;
  258. end else begin
  259. X := 0;
  260. Y := 0;
  261. end;
  262. if not Is32bit and (FReplaceColor <> clNone) and (FReplaceWithColor <> clNone) then begin
  263. Brush.Color := FReplaceWithColor;
  264. BrushCopy(Rect(X, Y, X + W, Y + H), Bmp, Rect(0, 0, Bmp.Width, Bmp.Height), FReplaceColor);
  265. end else
  266. Draw(X, Y, Bmp);
  267. end;
  268. end;
  269. end.