bcroundedimage.pas 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // SPDX-License-Identifier: LGPL-3.0-linking-exception
  2. {
  3. BCRoundedImage
  4. by Lainz
  5. Last modified: 2020-09-06 19:16 GMT-3
  6. Changelog:
  7. - 2020-09-06: Initial version supporting circle, rounded rectangle and square.
  8. Changing the quality of the resample, setting the rounding.
  9. OnPaintEvent to customize the final drawing.
  10. }
  11. unit BCRoundedImage;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
  16. BGRABitmap, BGRABitmapTypes;
  17. type
  18. TBCRoundedImage = class;
  19. // Event to draw before the image is sent to canvas
  20. TBCRoundedImagePaintEvent = procedure (const Sender: TBCRoundedImage; const Bitmap: TBGRABitmap) of object;
  21. // Supported styles are circle, rounded rectangle and square
  22. TBCRoundedImageStyle = (isCircle, isRoundedRectangle, isSquare);
  23. // Control that draws an image within a rounded border
  24. { TBCRoundedImage }
  25. TBCRoundedImage = class(TGraphicControl)
  26. private
  27. FBorderStyle: TRoundRectangleOptions;
  28. FOnPaintEvent: TBCRoundedImagePaintEvent;
  29. FPicture: TPicture;
  30. FQuality: TResampleFilter;
  31. FStyle: TBCRoundedImageStyle;
  32. FRounding: single;
  33. procedure SetBorderStyle(AValue: TRoundRectangleOptions);
  34. procedure SetPicture(AValue: TPicture);
  35. procedure SetQuality(AValue: TResampleFilter);
  36. procedure SetStyle(AValue: TBCRoundedImageStyle);
  37. procedure SetRounding(AValue: single);
  38. protected
  39. public
  40. constructor Create(AOwner: TComponent); override;
  41. destructor Destroy; override;
  42. procedure Paint; override;
  43. published
  44. // The image that's used as background
  45. property Picture: TPicture read FPicture write SetPicture;
  46. // The style can be circle, rounded rectangle or square
  47. property Style: TBCRoundedImageStyle read FStyle write SetStyle;
  48. // The style of the rounded rectangle
  49. property BorderStyle: TRoundRectangleOptions read FBorderStyle write SetBorderStyle;
  50. // Rounding is used when you choose the rounded rectangle style
  51. property Rounding: single read FRounding write SetRounding;
  52. // The quality when resizing the image
  53. property Quality: TResampleFilter read FQuality write SetQuality;
  54. // You can paint before the bitmap is drawn on canvas
  55. property OnPaintEvent: TBCRoundedImagePaintEvent read FOnPaintEvent write FOnPaintEvent;
  56. published
  57. property Anchors;
  58. property Align;
  59. property OnMouseEnter;
  60. property OnMouseLeave;
  61. property OnClick;
  62. end;
  63. procedure Register;
  64. implementation
  65. procedure Register;
  66. begin
  67. RegisterComponents('BGRA Controls', [TBCRoundedImage]);
  68. end;
  69. procedure TBCRoundedImage.SetPicture(AValue: TPicture);
  70. begin
  71. if FPicture = AValue then
  72. Exit;
  73. FPicture := AValue;
  74. Invalidate;
  75. end;
  76. procedure TBCRoundedImage.SetBorderStyle(AValue: TRoundRectangleOptions);
  77. begin
  78. if FBorderStyle=AValue then Exit;
  79. FBorderStyle:=AValue;
  80. Invalidate;
  81. end;
  82. procedure TBCRoundedImage.SetQuality(AValue: TResampleFilter);
  83. begin
  84. if FQuality = AValue then
  85. Exit;
  86. FQuality := AValue;
  87. Invalidate;
  88. end;
  89. procedure TBCRoundedImage.SetStyle(AValue: TBCRoundedImageStyle);
  90. begin
  91. if FStyle = AValue then
  92. Exit;
  93. FStyle := AValue;
  94. Invalidate;
  95. end;
  96. procedure TBCRoundedImage.SetRounding(AValue: single);
  97. begin
  98. if FRounding = AValue then
  99. Exit;
  100. FRounding := AValue;
  101. Invalidate;
  102. end;
  103. constructor TBCRoundedImage.Create(AOwner: TComponent);
  104. begin
  105. inherited Create(AOwner);
  106. FPicture := TPicture.Create;
  107. FRounding := 10;
  108. FQuality := rfBestQuality;
  109. end;
  110. destructor TBCRoundedImage.Destroy;
  111. begin
  112. FPicture.Free;
  113. inherited Destroy;
  114. end;
  115. procedure TBCRoundedImage.Paint;
  116. var
  117. bgra: TBGRABitmap;
  118. image: TBGRABitmap;
  119. begin
  120. if (FPicture.Width = 0) or (FPicture.Height = 0) then
  121. Exit;
  122. // Picture
  123. image := TBGRABitmap.Create(FPicture.Bitmap);
  124. bgra := TBGRABitmap.Create(Width, Height, BGRAPixelTransparent);
  125. try
  126. // Quality
  127. image.ResampleFilter := FQuality;
  128. BGRAReplace(image, image.Resample(Width, Height));
  129. // Style
  130. case FStyle of
  131. isCircle: bgra.FillEllipseAntialias(Width div 2, Height div 2,
  132. Width div 2, Height div 2, image);
  133. // Rounding, BorderStyle
  134. isRoundedRectangle: bgra.FillRoundRectAntialias(0, 0, Width,
  135. Height, FRounding, FRounding, image, FBorderStyle);
  136. else
  137. bgra.PutImage(0, 0, image, dmDrawWithTransparency);
  138. end;
  139. // OnPaintEvent
  140. if Assigned(FOnPaintEvent) then
  141. FOnPaintEvent(Self, bgra);
  142. bgra.Draw(Canvas, 0, 0, False);
  143. finally
  144. bgra.Free;
  145. image.Free;
  146. end;
  147. end;
  148. end.