HOW TO: Make Text Watermarks

Some time ago, I posted a request for help regarding watermarks on
photos. The only reply was for text with transparent background. After
a lot of frustration, I have come up with an answer, be it slow. If
anyone can suggest a quicker way, or code the Colour adjustment in
assembler it would be appreciated.

How it works: On a hidden image, sized to suit the final text, print
text in black. Then by using the Pixels[] property, interrogate the
hidden image. Where a pixel is black, adjust the red/green/blue
settings of a corresponding pixel in the photograph.

The following procedure MakeWatermark will do just that, placing the
text where you want it.

type
  wmType=(
    wmTopLeft,wmTopCentre,wmTopRight,
    wmCentreLeft,wmCentre,wmCentreRight,
    wmBottomLeft,wmBottomCentre,wmBottomRight,
    wmRndXRndY,wmSetXRndY,wmRndXSetY,wmSetXSetY);

function Limit256(I:integer):integer;
begin
  if I<0 then I:=0;
  if I>255 then I:=255;
  Limit256:=I;
end;

function ColourAdjust(Z,R,G,B:integer):integer;
var B1,G1,R1:integer;
begin  {shl 1 = Multiply by 2} {TColor}
  R1:=Limit256((Z and $000000FF) +R);
  G1:=Limit256(((Z and $0000FF00) shr 8) +G);
  B1:=Limit256(((Z and $00FF0000) shr 16) +B);
  ColourAdjust:=(B1 shl 16) + (G1 shl 8) +R1;
end;

procedure TForm1.MakeWatermark( const wmMode:wmType;
  var vImage:TImage;
  const Txt,FntName:string; FntStyle:TFontStyles;
    FntSize,X,Y,AdjRed,AdjGrn,AdjBlu:integer);
var
 I,J,IH,IW,TH,TW,Z:integer;
    TmpImg:TImage;
begin
    TmpImg:=TImage.Create(Form1);
    TmpImg.Picture:=nil;
    with TmpImg do
    begin
      Canvas.Pen.Color:=clWhite;
      Canvas.Pen.Style:=psSolid;
      Canvas.Font.Name:=FntName;
      Canvas.Font.Color:=clBlack;
      Canvas.Font.Style:=FntStyle;
      if FntSize>0 then
        begin
          Canvas.Font.Size:=FntSize;
          TW:=Canvas.TextWidth(Txt);
          TH:=Canvas.TextHeight(Txt);
        end
      else
        begin
          TW:=vImage.Width;
          TH:=vImage.Height;
          I:=7;
          repeat
            inc(I);
            Canvas.Font.Size:=I;
          until (Canvas.TextWidth(Txt)>TW) or
(Canvas.TextHeight(Txt)>TH);
          dec(I);
          Canvas.Font.Size:=I;
          TW:=Canvas.TextWidth(Txt);
          TH:=Canvas.TextHeight(Txt);
        end;
    end;
    TmpImg.Width:=TW;
    TmpImg.Picture.Bitmap.Width:=TW;
    TmpImg.Height:=TH;
    TmpImg.Picture.Bitmap.Height:=TH;
    TmpImg.Repaint;
    TmpImg.Canvas.TextOut(0,0,Txt);
    TmpImg.Refresh;
    if TmpImg.Canvas.Pixels[0,0]<0 then
      ShowMessage('TmpImg pixel error.');
  if vImage.Picture.Bitmap.Canvas.Pixels[0,0]<0 then
    ShowMessage('vImage pixel error.');
  IW:=vImage.Picture.Width;
  IH:=vImage.Picture.Height;
  case wmMode of
    wmTopLeft:
      begin
        X:=0;
        Y:=0;
      end;
    wmTopCentre:
      begin
        X:=IW div 2 - TW div 2;
        Y:=0;
      end;
    wmTopRight:
      begin
        X:=IW -TW;
        Y:=0;
      end;
    wmCentreLeft:
      begin
        X:=0;
        Y:=IH div 2 - TH div 2;
      end;
    wmCentre:
      begin
        X:=IW div 2 - TW div 2;
        Y:=IH div 2 - TH div 2;
      end;
    wmCentreRight:
      begin
        X:=IW -TW;
        Y:=IH div 2 - TH div 2;
      end;
    wmBottomLeft:
      begin
        X:=0;
        Y:=IH -TH;
      end;
    wmBottomCentre:
      begin
        X:=IW div 2 - TW div 2;
        Y:=IH -TH;
      end;
    wmBottomRight:
      begin
        X:=IW -TW;
        Y:=IH -TH;
      end;
    wmRndXRndY:
      begin
        X:=Random(IW-TW);
        Y:=Random(IH-TH);
      end;
    wmSetXRndY:
      begin
        {X passed}
        Y:=Random(IH-TH);
      end;
    wmRndXSetY:
      begin
        X:=Random(IW-TW);
        {Y passed}
      end;
    wmSetXSetY:
      begin
        {X passed}
        {Y passed}
        DoNothing;
      end;
  end;
  for I:=0 to TW do
    for J:= 0 to TH do
        if TmpImg.Canvas.Pixels[I,J]=clBlack then
        begin
          Z:=vImage.Picture.Bitmap.Canvas.Pixels[I+X,J+Y];
          Z:=ColourAdjust(Z,AdjRed,AdjGrn,AdjBlu);
          vImage.Picture.Bitmap.Canvas.Pixels[I+X,J+Y]:=Z;
        end;
    TmpImg.Free;
end;

Call MakeWatermark with the following parameters:
* watermark type eg wmTopLeft places the watermark in the top left of
the image;
* Image to be watermarked;
* Text to be shown;
* Name of the font to use;
* style of the font eg [fsBold,fsItalic];
* size of the text, use -1 for maximum size;
* X & Y co-ordinates (used only in  wmSetXRndY, wmRndXSetY and
wmSetXSetY, X being only used where type contains "SetX";
* adjustments for Red, Green, and Blue, negative = darken.

If the image you wish to watermark objects to reading the pixels then
an error message will be given and the procedure exited.

This may not be be the best solution, but it works and is offered as a
community thank you to all those who have in the past and will in the
future answer a question or two from me.