Solved

Using A Bitmap As Font

Posted on 2001-06-22
15
339 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 22

Expert Comment

by:Mohammed Nasman
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
 

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

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Ever visit a website where you spotted a really cool looking Font, yet couldn't figure out which font family it belonged to, or how to get a copy of it for your own use? This article explains the process of doing exactly that, as well as showing how…
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…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…

690 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