Solved

Using A Bitmap As Font

Posted on 2001-06-22
15
328 Views
Last Modified: 2013-12-02
Hello experts, I would like to know how to use a bitmap as a font for my application just like WinAmp does. Can anyone help me?
0
Comment
Question by:New2Delphi
  • 4
  • 4
  • 2
  • +4
15 Comments
 
LVL 1

Expert Comment

by:Dennis9
ID: 6217883
Hi.
What u mean, the text or the skin it uses??

Dennis
0
 
LVL 8

Expert Comment

by:TOndrej
ID: 6217889
Not sure what you mean, but if you want a bitmap tiled within text drawn on a canvas then you can use a path and a clipping region, see TPictureLabel.Paint on http://members.nbci.com/tondrej/Delphi.htm as an example
0
 
LVL 1

Expert Comment

by:edsteele
ID: 6218402
WinAmp uses a bitmap of an alphabet and then chops the bitmap up into little pieces, one per letter and pastes each bitmap when it needs a letter.  Technically, this is not a font, it is simply drawing an image (which happens to be an image of a letter) to a canvas.

Unless you are trying to created a skinned application, I would instead look for a font that will work for you.

Eric
0
 
LVL 22

Expert Comment

by:mnasman
ID: 6222494
Hello

  I didn't understand what u want well, but in winamp the font look like image, if you want to draw font in image here's some code

procedure TForm1.Button1Click(Sender: TObject);
begin
  Image1.Canvas.Brush.Color := clblack;
  Image1.Canvas.Rectangle(0,0,Image1.Width,Image1.Height);
  Image1.Canvas.Font.Color := clGreen;
  Image1.Canvas.Font.Style := [fsBold];
  Image1.Canvas.TextOut(5,5,'Delphi is the Best');
end;

Mohammed
0
 

Author Comment

by:New2Delphi
ID: 6223153
Dennis9, TOndrej, mnasman: edsteele has the idea. Do you know how I can do this? Can you help me out?

edsteele: Yes, that's exactly what I want to do. How can I use a bitmap of an alphabet and then chop the bitmap up into little pieces, one per letter
and paste each bitmap when my app needs a letter. Please help me out. Thanks!
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 6223490
Hi New2Delphi,

I tried this:
1. Create a bitmap file with all the letters I want, each letter *must* have a fixed width
2. Put a TImageList in your Form
3. Set the Height and Width to match the Height and Width for ONE letter
4. Load the bitmap file into the TImageList
5. Drop a PaintBox in your Form
6. Drop a TEdit in your Form
7. Drop a TButton in your Form
8. Handle the OnClick for the TButton and OnPaint for the TPaintBox

In the example below, my PaintBox is called PaintBox1, TButton is called btnDraw, TEdit is called ed.

I grabbed the sample font bitmap from WinAmp's EXE file.



procedure TfrmDownload.btnDrawTextClick(Sender: TObject);
begin
  PaintBox1.Refresh;
end;

procedure TfrmDownload.PaintBox1Paint(Sender: TObject);
var
  i: Integer;
  iLeft: Integer;
  iImage: TBitmap;
  iIndex: Integer;
  sString: string;
const
  LetterWidth = 5;
begin
  sString := UpperCase(Trim(ed.Text));

  if sString = '' then
    Exit;

  PaintBox1.Canvas.FillRect(Rect(0, 0, 297, 33));
  iLeft := 0;

  for i := 1 to Length(sString) do
  begin
    iImage := TBitmap.Create;
    iImage.Transparent := True;
    iImage.TransparentColor := clWhite;
    iImage.TransparentMode := tmFixed;
    iIndex := Byte(sString[i]) - Byte('A');
    ImageList1.GetBitmap(iIndex, iImage);
    PaintBox1.Canvas.Draw(iLeft, 10, iImage);
    Inc(iLeft, LetterWidth);
    iImage.Free;
  end;
end;


Of course, I only limited my character set to 26. You can create your own set, and load the appropriate character (heck, you could even have all the ASCII characters! If you have that, just change iIndex := Byte(sString[i]) - Byte('A'); to iIndex := Byte(sString[i]);).

Also, to make it better, you have to handle word-wrapping, and perhaps a variable-width font... just some suggestions :)



Hope that helped!

DragonSlayer.
0
 
LVL 1

Expert Comment

by:edsteele
ID: 6224867
I haven't run it, but it looks like DragonSlayer's code should do the trick, or at least send you in the right direction.  Using a TImageList is a very nice way to break the master image into smaller images for use.

If you don't want to use a TImageList, you can always use the CopyRect method of the TCanvas object.

var
  LetterBitmap: TBitmap;

procedure DrawLetter(Letter: Char; x, y: Integer; Canvas: TCanvas);
var
  DestRect, SrcRect: TRect;
begin
  LetterBitmap.CopyMode := cmSrcCopy;
  DestRect := TRect(x, y, x + LetterWidth - 1, y + LetterHeight - 1);
  SrcRect := TRect(Ord(Letter) - Ord('A'), 0, Ord(Letter) - Ord('A') + LetterWidth - 1, LetterHeight - 1);
  LetterBitmap.CopyRect(DestRect, Canvas, SrcRect);
end;

I may be off by a pixel here or there.  Of course you will have to load the bitmap of letters into LetterBitmap before calling the DrawLetter procedure.

Good Luck!
Eric
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:New2Delphi
ID: 6233846
Any other suggestions?

I need to use:
A-Z
a-z
0-9
!@#$%^&*()_=+-:;"'[]{}?/>.<,~`

How can I do this?
0
 
LVL 14

Assisted Solution

by:DragonSlayer
DragonSlayer earned 25 total points
ID: 6233897
It's the same... just make sure that you retrieve from the correct index.

Load up an ASCII chart, you will see that '!' starts at ASCII 33, and it continues all the way till ASCII 126 ('~').

So what you do is, have a bitmap that has the text you want in the same order as the ASCII chart, and change the part that says
   iIndex := Byte(sString[i]) - Byte('A');
to
   iIndex := Byte(sString[i]) - Byte('!');

The END :)
0
 
LVL 1

Accepted Solution

by:
edsteele earned 25 total points
ID: 6234714
There is another way to make the accessing of the indexes a bit nicer, but you have to carry an extra array around and you have to initialize it.  Something like this:

var
  CharIndex: Array[' '..'~'] of Byte;

procedure TMainForm.FormCreate(Sender: TObject);
var
  c: Char;
  Idx: Integer;
begin
  Idx := 0;
  for c := 'A' to 'Z' do
  begin
    CharIndex[c] := Idx;
    Inc(Idx);
  end;
  for c := 'a' to 'z' do
  begin
    CharIndex[c] := Idx;
    Inc(Idx);
  end;
  for c := '0' to '9' do
  begin
    CharIndex[c] := Idx;
    Inc(Idx);
  end;
  CharIndex[' '] := Idx;  Inc(Idx);
  CharIndex['!'] := Idx;  Inc(Idx);
  CharIndex['@'] := Idx;  Inc(Idx);
  CharIndex['#'] := Idx;  Inc(Idx);
  CharIndex['$'] := Idx;  Inc(Idx);
  CharIndex['%'] := Idx;  Inc(Idx);
  CharIndex['^'] := Idx;  Inc(Idx);
  CharIndex['&'] := Idx;  Inc(Idx);
  CharIndex['*'] := Idx;  Inc(Idx);
  CharIndex['('] := Idx;  Inc(Idx);
  CharIndex[')'] := Idx;  Inc(Idx);
  CharIndex['_'] := Idx;  Inc(Idx);
  CharIndex['='] := Idx;  Inc(Idx);
  CharIndex['+'] := Idx;  Inc(Idx);
  CharIndex['-'] := Idx;  Inc(Idx);
  CharIndex[':'] := Idx;  Inc(Idx);
  CharIndex[';'] := Idx;  Inc(Idx);
  CharIndex['"'] := Idx;  Inc(Idx);
  CharIndex[''''] := Idx;  Inc(Idx);
  CharIndex['['] := Idx;  Inc(Idx);
  CharIndex[']'] := Idx;  Inc(Idx);
  CharIndex['{'] := Idx;  Inc(Idx);
  CharIndex['}'] := Idx;  Inc(Idx);
  CharIndex['?'] := Idx;  Inc(Idx);
  CharIndex['/'] := Idx;  Inc(Idx);
  CharIndex['>'] := Idx;  Inc(Idx);
  CharIndex['.'] := Idx;  Inc(Idx);
  CharIndex['<'] := Idx;  Inc(Idx);
  CharIndex[','] := Idx;  Inc(Idx);
  CharIndex['~'] := Idx;  Inc(Idx);
  CharIndex['`'] := Idx;  Inc(Idx);
end;

Now when you need the index of particular characters, you can just use something like:

for i := 1 to Length(MyString) do
begin
  PlotChar(CharIndex[MyString[i]]);
end;

If you had a procedure called "PlotChar", that loop would call it for each character in the string "MyString", passing the index you defined.

The setup is ugly, but this allows you to put the characters in any order you want if you don't want to follow the ASCII ordering.  You may want to define the "CharIndex" array to hold the whole ASCII range and initialize the whole array to a special character of your choosing.  That way if you request a character that is not part of your defined set of characters, you get the special character back.

Eric
0
 

Author Comment

by:New2Delphi
ID: 6243411
edsteele, could you create the PlotChar procedure? I would really appreciate it. Thanks!
0
 
LVL 1

Expert Comment

by:edsteele
ID: 6245497
Sure.

type
  TForm1 = class(TForm)
  private
    ...
    CurrX, CurrY: Integer;
    ...
  public
    ...
    procedure PlotChar(Idx, X, Y: Integer); overload;
    procedure PlotChar(Idx: Integer); overload;
    ...
  end;

procedure TForm1.PlotChar(Idx, X, Y: Integer);
begin
  CurrX := X;
  CurrY := Y;
  PlotChar(Idx);
end;

procedure TForm1.PlotChar(Idx: Integer);
var
  CharBitmap: TBitmap;
begin
  CharBitmap := TBitmap.Create;
  MyImageList.GetBitmap(Idx, CharBitmap);
  TargetCanvas.Draw(CurrX, CurrY, CharBitmap);
  CurrX := CurrX + CharBitmap.Width;
  CharBitmap.Free;
end;

I used two overloaded procedures to accomplish this so that plotting many characters in a row will be easier.  First, you call PlotChar(Idx, X, Y), where X and Y are the coordinates on the canvas where you would like the character placed.  After that, you can just call PlotChar(Idx) repeatedly for the other characters on the line.  To start plotting in another location, simply call PlotChar(Idx, X, Y) again.

Note: If you will need to plot to more than one canvas, you may want to pass that in to the procedure also instead of coding it directly.

Eric
0
 

Author Comment

by:New2Delphi
ID: 6247853
Okay! Thanks! Let me check it out first.
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 8685193
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

To be split between edsteele and DragonSlayer

Please leave any comments here within the next seven days.
 
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
 
Thank you,
Russell

EE Cleanup Volunteer
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now