В предыдущих обсуждениях проблемы с отрисовкой psInsideframe на TFPImageCanvas, мы столкнулись с еще одной задачей: как рисовать полупрозрачный текст, не прибегая к использованию сторонних библиотек, таких как FreeType. Использование FTFont/TFreeTypeFont добавляет значительный объем зависимостей (около 30МБ), что нежелательно для портативных приложений, особенно для встраиваемых устройств с ограниченными ресурсами.
Ранее мы обсуждали проблему с отрисовкой psInsideframe и выяснили, что эта функциональность не реализована в fcl-image. Также мы нашли способ копирования участков изображения между TFPImageCanvas и TPortableNetworkGraphic с использованием CopyRect. Теперь, благодаря помощи @wp, у нас есть решение для отрисовки полупрозрачного текста, которое не требует дополнительных библиотек.
Решение, предложенное @wp, заключается в использовании вспомогательной bitmap для отрисовки текста и последующем смешивании (blending) этой bitmap с основным изображением. Этот подход позволяет добиться полупрозрачности текста, не прибегая к использованию FreeType или других сторонних библиотек.
Альтернативное решение:
Хотя предложенное решение является отличным способом достижения полупрозрачности, оно имеет некоторые недостатки, связанные с созданием и копированием bitmap. Альтернативным (хотя и менее эффективным) решением может быть использование TCanvas.Brush.Style и TCanvas.Brush.Color для создания эффекта полупрозрачности за счет изменения альфа-канала цвета кисти. Однако, этот способ не всегда дает желаемый результат, особенно при работе с текстом, и может привести к непредсказуемым артефактам.
Пример кода (реализация решения @wp):
unit Unit1;
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,
FPImage, FPCanvas, FPImgCanv;
type
{ TForm1 }
TForm1 = class(TForm)
Image1: TImage;
procedure FormCreate(Sender: TObject);
private
public
end;
var
Form1: TForm1;
FImage: TBitmap;
procedure DrawText(AImage: TFPCustomImage; X, Y: Integer; AText: String;
AFont: TFont; ATransparency: Single);
// Calculate the alpha value from the "brightness" of the given pixel
// (average of RGB). Multiply by the transparency factor to get a semitransparent
// mask.
function CalcAlpha(AColor: TFPColor): Word;
begin
Result := trunc((1.0*AColor.Red + AColor.Green + AColor.Blue) / 3 * (1.0 - ATransparency));
end;
var
bmp: TBitmap;
mask: TLazIntfImage;
ext: TSize;
ix, iy: Integer;
fntColor: TFPColor;
maskColor: TFPColor;
imgColor: TFPColor;
begin
// Create aux bitmap for white text on black background as alpha mask
bmp := TBitmap.Create;
try
bmp.Pixelformat := pf32Bit;
// Measure the size of the text and set the size of the aux bitmap accordingly
bmp.Canvas.Font.Assign(AFont);
ext := bmp.Canvas.TextExtent(AText);
bmp.SetSize(ext.CX, ext.CY);
// We need a black background of the aux bitmap
bmp.Canvas.Brush.Color := clBlack;
bmp.Canvas.FillRect(0, 0, bmp.Width, bmp.Height);
// Draw white text on black background of aux bitmap
bmp.Canvas.Font.Color := clWhite;
bmp.Canvas.Brush.Style := bsClear;
bmp.Canvas.TextOut(0, 0, AText);
// Use LazIntfImage to convert the gray scales of the aux bitmap to alpha
// value. The non-zero pixels in the mask are replaced by the original font
// color. Finally the mask pixels are alpha-blended with the image pixels.
fntColor := TColorToFPColor(AFont.Color);
mask := bmp.CreateIntfImage;
try
for iy := 0 to mask.Height-1 do
begin
for ix := 0 to mask.Width-1 do
begin
maskColor := mask.Colors[ix, iy];
if (maskColor = colBlack) then // The mask is fully transparent here
maskColor.Alpha := alphaTransparent
else begin
// Non fully-transparent pixels get the calculated alpha value...
maskColor.Alpha := CalcAlpha(maskColor);
// ... and the color of the font.
maskColor.Red := fntColor.Red;
maskColor.Green := fntColor.Green;
maskColor.Blue := fntColor.Blue;
end;
// Alpha-blend the mask pixel with the image pixel
imgColor := AImage.Colors[X + ix, Y + iy];
AImage.Colors[X + ix, Y + iy] := AlphaBlend(imgColor, maskColor);
end;
end;
finally
mask.Free;
end;
finally
bmp.Free;
end;
end;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
FImage := TBitmap.Create;
FImage.SetSize(800, 400);
FImage.Canvas.GradientFill(Rect(0,0,Width,Height),clAqua,clFuchsia,gdHorizontal);
TImage1.Picture.Bitmap.Assign(FImage);
// Пример использования DrawText
DrawText(FImage, 20, 40, 'HELLO!', FImage.Canvas.Font, 0.5); // Полупрозрачный текст
end;
end.
Пояснения к коду:
DrawText - процедура для отрисовки полупрозрачного текста.
CalcAlpha - функция для расчета альфа-канала на основе яркости пикселя.
Создается вспомогательная bitmap (bmp) черного цвета.
На этой bitmap рисуется текст белым цветом.
TLazIntfImage используется для преобразования оттенков серого bitmap в альфа-канал.
Пиксели маски смешиваются с пикселями основного изображения, создавая эффект полупрозрачности.
Вывод:
Решение, предложенное @wp, позволяет рисовать полупрозрачный текст на TFPImageCanvas без использования сторонних библиотек. Хотя оно и требует создания и копирования bitmap, это компромисс, позволяющий избежать дополнительных зависимостей и сохранить портативность приложения. В будущем, возможно, будут разработаны более эффективные способы решения этой задачи, но на данный момент это является оптимальным вариантом. Благодаря этому решению, мы можем создавать более сложные и визуально привлекательные приложения, сохраняя при этом их легковесность и переносимость.
Решение для отрисовки полупрозрачного текста на TFPImageCanvas без использования сторонних библиотек через создание вспомогательной bitmap и её последующего смешивания с основным изображением.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.