如何在图像(Jpg,Bmp)或透明文本(与背景图像相同的颜色)上写半透明文本但带有阴影,我想做的事情是给图像加水印。
我想使用 Delphi win32 来完成。
如何在图像(Jpg,Bmp)或透明文本(与背景图像相同的颜色)上写半透明文本但带有阴影,我想做的事情是给图像加水印。
我想使用 Delphi win32 来完成。
一种选择是在 Windows.pas 单元中使用 AlphaBlend 函数。像这样的东西会产生覆盖在图像上的半透明文本(带有阴影 - 基于 Jim McKeeth 的响应):
uses Windows, Graphics;
.
.
.
var
BackgroundImage: Graphics.TBitmap; { need to call out specifically for Graphics.TBitmap
because the Windows unit also has a TBitmap
declaration }
TextImage: Graphics.TBitmap;
BlendFunc: BLENDFUNCTION;
begin
BlendFunc.BlendOp := AC_SRC_OVER;
BlendFunc.BlendFlags := 0;
BlendFunc.SourceConstantAlpha := $C0; { a hex value from $00-$FF (0-255).
Represents the percent of opaqueness:
$00 is completely transparent,
$FF is completely opaque.
$C0 is 75% opaque }
BlendFunc.AlphaFormat := AC_SRC_ALPHA;
{ BackgroundImage is for holding the image you want to overlay text onto }
BackgroundImage := Graphics.TBitmap.Create;
try
BackgroundImage.LoadFromFile('yourimagehere.bmp');
{ Create another TBitmap to hold the text you want to overlay }
TextImage := Graphics.TBitmap.Create;
try
{ Set this bitmap to have the same dimensions as the
background image you want the text to appear on. }
TextImage.Height := BackgroundImage.Height;
TextImage.Width := BackgroundImage.Width;
{ In my limited experience with AlphaBlend, Black is always 100%
transparent. So, paint TextImage completely Black. Play around
with this to see the effect it has on the final outcome. }
TextImage.Canvas.Brush.Color := clBlack;
TextImage.Canvas.FloodFill(0, 0, clNone, fsBorder);
TextImage.Canvas.Font.Style := [fsBold];
{ Write the shadow first }
TextImage.Canvas.Brush.Style := bsClear;
TextImage.Canvas.Font.Color := clDkGray;
TextImage.Canvas.TextOut(11, 11, 'Test');
{ Then put the text on top (slightly offset) }
TextImage.Canvas.Brush.Style := bsClear;
TextImage.Canvas.Font.Color := clMaroon;
TextImage.Canvas.TextOut(10, 10, 'Test');
{ Use the AlphaBlend function to overlay the bitmap holding the text
on top of the bitmap holding the original image. }
Windows.AlphaBlend(BackgroundImage.Canvas.Handle, 0, 0,
TextImage.Width, TextImage.Height,
TextImage.Canvas.Handle, 0, 0, TextImage.Width,
TextImage.Height, BlendFunc);
{ Assign the now updated BackgroundImage to a TImage control for display }
Image1.Picture.Bitmap.Assign(BackgroundImage);
finally
TextImage.Free;
end;
finally
BackgroundImage.Free;
end;
end;
阴影很简单:
// Bold shows up better when over an image
image1.Canvas.Font.Style := [fsBold];
// Write the shadow first
image1.Canvas.Brush.Style:=bsClear;
image1.Canvas.Font.Color := clGrayText;
image1.Canvas.TextOut(1, 1, 'hi there');
// Then put the text on top (slightly offset)
image1.Canvas.Brush.Style:=bsClear;
image1.Canvas.Font.Color :=clBlack;
image1.Canvas.TextOut(0, 0, 'hi there');
这是具有透明背景的文本。还是您希望文本本身是半透明的?这有点棘手。您需要手动绘制它。一种简单的方法是对您在图像上书写的区域的颜色进行平均采样。然后将你的字体颜色设置为更亮一点,你的阴影设置为更暗一点。然后它有点融入。
我认为您要完成的工作比简单地编写具有透明背景的文本要复杂一些;即,您正在尝试在图像上写入某种形式的 alpha 混合文本。
最简单的方法是使用 GDI+ 例程。它们为 delphi 封装,可从http://www.progdigy.com/下载。那里有许多示例,应该可以用作示例。
我还没有测试它,但它会给你一些想法去哪里。关键是画笔风格。
像这样的东西:
img.Canvas.Brush.Style:=bsClear;
img.Canvas.Font.Color:=clBlack;
img.Canvas.TextOut(0, 0, 'hi there');
这个函数是基于 Dave Elsberry 的想法。
有什么不同:
{-------------------------------------------------------------------------------------------------------------
DrawTextShadowBox
Draws text in a semi-transparent rectangle with shadow text.
The shadow text is blended to the background and then blurred.
Variant:
1: Draws text in a box that is as wide as the BMP and can be aligned to top or bottom
2: Draws text in a box that is as wide as text and is placed into the image at coordinates x,y
Parameters:
Opacity a value from 0-255. 0 => Shadow is completelly transparent
To set the Font color/size, the caller should do: aCanvas.Font.Size:= x
Issues:
The blurring function cuts too suddenly. The rectangle that was blurred is too visible. Do a blur that slowly fades at the edges.
Might be slow becuase of the alpha blending and because of the blur.
Important!
The input img must be pf24bit.
When the AlphaFormat member is AC_SRC_ALPHA, the source bitmap must be 32 bpp. If it is not, the AlphaBlend function will fail.
-------------------------------------------------------------------------------------------------------------}
procedure DrawTextShadowBox(BMP: TBitmap; CONST Text: string; AlignTop: Boolean; ShadowColor: TColor= clTextShadow; ShadowOpacity: Byte= 20; Blur: Byte= 2);
VAR
Shadow: Vcl.Graphics.TBitmap;
BlendFunc: BLENDFUNCTION;
x, y: Integer;
BmpRect: TRect; { Rectangle in the original bitmap where we want to draw the shadowed text }
ShadowRect: TRect;
TextWidth, TextHeight: Integer;
OriginalColor: TColor;
begin
Assert(BMP.PixelFormat= pf24bit, 'Wrong pixel format!!');
OriginalColor:= bmp.Canvas.Font.Color;
TextWidth := BMP.Canvas.TextWidth (Text);
TextHeight:= BMP.Canvas.TextHeight(Text);
{ Write the shadow on a separate bitmap (overlay) }
Shadow := TBitmap.Create;
TRY
{ Bitmap setup }
Shadow.Canvas.Font.Assign(BMP.Canvas.Font);
Shadow.PixelFormat:= pf24bit;
Shadow.SetSize(BMP.Width, TextHeight);
{ Bitmap rectangle as big as ShadowBMP }
ShadowRect.Left:= 0;
ShadowRect.Top := 0;
ShadowRect.Right := Shadow.Width;
ShadowRect.Bottom:= Shadow.Height;
{ Fill shadow rectangle }
Shadow.Canvas.Brush.Color := clBlack; { In AlphaBlend, Black is always 100% transparent. So, paint Shadow completely Black. }
Shadow.Canvas.FillRect(ShadowRect);
BmpRect.Left := 0;
BmpRect.Right := Shadow.Width;
if AlignTop
then BmpRect.Top := 0
else BmpRect.Top := BMP.Height- TextHeight;
BmpRect.Bottom:= BmpRect.Top+ TextHeight;
{ Blend rectangle with orig image } { Use the AlphaBlend function to overlay the bitmap holding the text on top of the bitmap holding the original image. }
BlendFunc.BlendOp := AC_SRC_OVER;
BlendFunc.BlendFlags := 0;
BlendFunc.SourceConstantAlpha := ShadowOpacity;
BlendFunc.AlphaFormat := 0; //AC_SRC_ALPHA; // if I put this back, the shadow will be completly invisible when merged with a white source image
WinApi.Windows.AlphaBlend(BMP.Canvas.Handle, BmpRect.Left, BmpRect.Top, BmpRect.Right, TextHeight, Shadow.Canvas.Handle, 0, 0, Shadow.Width, Shadow.Height, BlendFunc);
{ Copy the blended area back to the Shadow bmp }
Shadow.Canvas.CopyRect(ShadowRect, BMP.Canvas, BmpRect);
{ Diagonal shadow }
x:= (BMP.Width - TextWidth) DIV 2; // Find center
Shadow.Canvas.Brush.Style:= bsClear;
Shadow.Canvas.Font.Color := ShadowColor;
Shadow.Canvas.TextOut(x, 0, Text);
{ Blur the shadow }
janFX.GaussianBlur(Shadow, Blur, 1);
{ Paste it back }
BMP.Canvas.CopyRect(BmpRect, Shadow.Canvas, ShadowRect);
FINALLY
FreeAndNil(Shadow);
END;
{ Draw actual text at 100% opacity }
if AlignTop
then y := 0
else y := BMP.Height- TextHeight;
BMP.Canvas.Brush.Style:= bsClear;
BMP.Canvas.Font.Color := OriginalColor;
BMP.Canvas.TextOut(x, y, Text);
end;
procedure DrawTextShadowBox(aCanvas: TCanvas; CONST Text: string; X, Y: Integer; ShadowColor: TColor= clTextShadow; ShadowOpacity: Byte= 20; Blur: Byte= 2);
VAR
Shadow: Vcl.Graphics.TBitmap;
BlendFunc: BLENDFUNCTION;
H, W: Integer;
OriginalColor: TColor;
R, R2: TRect;
CONST Edge= 5;
begin
OriginalColor:= aCanvas.Font.Color;
{ Write the shadow on a separate bitmap (overlay) }
Shadow := TBitmap.Create;
TRY
{ Assign font }
Shadow.Canvas.Font.Assign(aCanvas.Font);
Shadow.PixelFormat:= pf24bit;
{ Compute overlay size }
W:= Shadow.Canvas.TextWidth (Text);
H:= Shadow.Canvas.TextHeight(Text);
Shadow.SetSize(W, H);
{ Fill shadow rectangle }
R:= Rect(0, 0, Shadow.Width, Shadow.Height);
Shadow.Canvas.Brush.Color := clBlack; { In AlphaBlend, Black is always 100% transparent. So, paint Shadow completely Black. }
Shadow.Canvas.FillRect(R);
{ Blend rectangle with orig image } { Use the AlphaBlend function to overlay the bitmap holding the text on top of the bitmap holding the original image. }
BlendFunc.BlendOp := AC_SRC_OVER;
BlendFunc.BlendFlags := 0;
BlendFunc.SourceConstantAlpha := ShadowOpacity;
BlendFunc.AlphaFormat := 0; //AC_SRC_ALPHA; // if I put this back, the shadow will be completly invisible when merged with a white source image
WinApi.Windows.AlphaBlend(aCanvas.Handle, x, y, Shadow.Width, Shadow.Height, Shadow.Canvas.Handle, 0, 0, Shadow.Width, Shadow.Height, BlendFunc);
{ Copy the blended area back to the Shadow bmp }
R2:= rect(x, y, x+Shadow.Width, y+Shadow.Height);
Shadow.Canvas.CopyRect(R, aCanvas, R2);
{ Diagonal shadow }
Shadow.Canvas.Brush.Style:= bsClear;
Shadow.Canvas.Font.Color := ShadowColor;
Shadow.Canvas.TextOut(0, 0, Text);
{ Blur the shadow }
janFX.GaussianBlur(Shadow, blur, 1);
{ Paste it back }
aCanvas.CopyRect(R2, Shadow.Canvas, R);
FINALLY
FreeAndNil(Shadow);
END;
{ Draw actual text at 100% opacity }
aCanvas.Brush.Style:= bsClear;
aCanvas.Font.Color := OriginalColor;
aCanvas.TextOut(x, y, Text);
end;
procedure TfrmTest.UseIt;
VAR BackgroundImage: tbitmap;
begin
BackgroundImage := Graphics.TBitmap.Create;
try
BackgroundImage.LoadFromFile('c:\test.bmp');
DrawShadowText (BackgroundImage.Canvas, 'This is some demo text', 20, 40, 140, clRed, clSilver);
Image1.Picture.Bitmap.Assign(BackgroundImage);
FINALLY
BackgroundImage.Free;
end;
end;
您可以使用bitblt例程将图像合并到公共画布,然后再次保存图像。