Форум: "Основная";
Текущий архив: 2005.10.30;
Скачать: [xml.tar.bz2];
ВнизШирина выводимого текста на Canvas е Найти похожие ветки
← →
Antonn © (2005-10-08 14:38) [0]Здравствуйте! Помогите разобраться с такой проблемой - не могу определить ширину текста, выводимого на канвас TBitmap"а, если у текста стиль fsitalic. Уже весь день потерял на эту фигню:(
На форме лежит Комбобокс(имя CBF), у которого изменяю стиль его шрифта, и с этим стилем(а вообще там и название шрифта) нужно отрисовать на битмапе текст(хранимый в s:string). Но почему то не определяется правильно ширина текста, если текст "Итальянский". Если fsBold есть, то реагирует, но только на него. Уже и textwidth и GetTextExtentPoint пробую - не получается.var s:string; _b:TBitmap; Size: TSize;
begin
_b:=TBitmap.Create;
try
_B.Canvas.Font.Name:="verdana";
_B.Canvas.Font.Size:=10;
_B.Canvas.Font.Style:=[];
if fsBold in CBF.Font.style then
_B.Canvas.Font.Style:=_B.Canvas.Font.Style+ [fsBold];
if fsItalic in CBF.Font.style then
_B.Canvas.Font.Style:=_B.Canvas.Font.Style+ [fsItalic];
s:="8";
GetTextExtentPoint(_B.canvas.Handle,pchar(s),length(s),Size);
label29.Caption:=inttostr(Size.cx);
label7.Caption:=inttostr(_B.Canvas.TextWidth(s));
finally
_b.Free;
end;
end;
пример возвращает 9 при присутствии fsbold и 8 в остальных случаях, хотя при fsItalic ширина почти в 2 раза больше.
← →
MBo © (2005-10-08 15:18) [1]>при fsItalic ширина почти в 2 раза больше.
Не вижу такого эффекта для шрифта Verdana.
← →
Antonn © (2005-10-08 16:29) [2]MBo © (08.10.05 15:18) [1]
ну в 2 разf погорячился, взял шрифт типа "Пушкин", но факт, что размер ненормальный.
можно взять Tahoma.
← →
Antonn © (2005-10-08 16:47) [3]вообще мне нужно в рамку текст взять. вот иллистрацию реализовал:
_B.Canvas.Font.Size:=20;
..
_b.Width:=100;
_B.Height:=100;
_b.Canvas.TextOut(2,2,s);
_b.Canvas.Brush.Style:=bsclear;
_b.Canvas.Rectangle(2,2,Size.cx+2,Size.cy+2);
canvas.CopyRect(rect(0,0,100,100),_b.Canvas,rect(0,0,100,100));
Если шрифт будет Courier New или Comic Sans MS, то текст вылезает за рамку. Особенно если одновременно жирный и курсив. Я понимаю, что у rectangle правая и нижняя граница должна быть +1 пиксел, но все равно не помогает, текст сильно уж выступает.
← →
MBo © (2005-10-08 16:49) [4]На строке "Пушкин" со шрифтом Tahoma размером 20 выдается 95 для обычного и 97 для наклонного, так что разница все же есть.
Она меньше ожидаемой тобой, поскольку GetTextExtentPoint или использующая ее Canvas.TextWidth выдают приблизительный прямоугольник вывода. При выводе строки Windows использует сложные типографские правила, расстояние между буквами меняется для разных их пар (эти расстояния описаны в файле TTF-шрифтов). GetTextExtentPoint учитывает не все. Указанная строка, как легко увидеть, не особо отличается по длине в обычном и наклонном варианте, а при выделении конец последней наклонной буквы выходит за прямоугольник выделения. Это связано с тем, что GetTextExtentPoint, вероятно, не принимает во внимание величины A, B, C для символов. Эти величины можно получить с помощью функции GetCharABCWidths. Грубо говоря, A - промежуток от начала прямоугольника до реального начала символа, а C - расстояние от конца пр-ка до конца (самого правого черного пиксела) символа. Эти величины могут быть отрицательными, т.е. изображение символа выходит за прямоугольник.
← →
MBo © (2005-10-08 16:50) [5]>вообще мне нужно в рамку текст взять
GetCharABCWidths поможет.
← →
Antonn © (2005-10-08 17:12) [6]GetCharABCWidths поможет.
я ее сразу пытался использовать, но не пойму, как.function GetCharABCWidths(DC: HDC; FirstChar, LastChar: UINT; const ABCStructs): BOOL;
а именно, что такое ABCStructs, какой тип?
Подсунул cardinal, получил в ответ 3(против 15 от GetTextExtentPoint), в чем она измеряет?
А FirstChar, LastChar - от 0 до length(s)? Тогда как она определит ширину моего текста, если она его не знает(текст)?
← →
Antonn © (2005-10-08 17:13) [7]Antonn © (08.10.05 17:12) [6]
от 0 до length(s)?
от 1 до length(s)?
← →
Джо © (2005-10-08 17:19) [8][6] Antonn © (08.10.05 17:12)
> а именно, что такое ABCStructs, какой тип?
typedef struct _ABC {
int abcA;
UINT abcB;
int abcC;
} ABC, *PABC;
ты получаешь массив этих структур. Каждая структура для каждого символа в промежутке (range).
← →
MBo © (2005-10-08 17:34) [9]>Antonn © (08.10.05 17:12) [6]
Ну придется читать MSDN, разбираться, как работает функция.
Подробно описано это в книге Фень Юаня.
Есть еще один способ - но тоже придется поработать - использовать функции BeginPath/EndPath, шрифт - TTF должен быть. Нарисовать строку, получится траектория, преобразовать ее в регион PathToRegion, взять у региона окрйжающий прямоугольник GetRgnBox
← →
Antonn © (2005-10-08 18:22) [10]наш человек легких путей не ищет:)))
Вот, попробывал вышеперечисленные функции, и написал свое. Оно работает, но внутренности процедуры во мне сомнения вызывают - стоит ли оно того? А вообще работает. А сделал просто - отрендерил текст и пробежался по битмапу сканлайном:))
Вот, может кому пригодится(правда по правой и нижней координате нужно в результате +1 пиксель прибавлять):procedure GetGrebaniyFontWidth(s:string; _F:Tfont; var _R:Trect);
const MaxPixelCount = MaxInt div SizeOf(TRGBTriple);
type TBack_Settings=(bs_Gradient_horizontal,bs_Gradient_vertical,bs_Picture);
PRGBArray = ^TRGBArray;
TRGBArray = array[0..MaxPixelCount-1] of TRGBTriple;
var _x,_y:integer; used:boolean;
Row: PRGBArray;
_B:TBitmap;
begin
_B:=TBitmap.Create;
try
_B.PixelFormat:=pf24bit;
_B.Canvas.Font:=_F;
_B.Width:=_B.Canvas.TextWidth(s)+trunc(_B.Canvas.TextWidth(s)*0.5);
_B.Height:=_B.Canvas.TextHeight(s); _B.Canvas.FillRect(_B.Canvas.ClipRect);
_R.Top:=_B.Height; _R.Bottom:=0; _R.Left:=_B.Width; _R.Right:=0;
_B.Canvas.TextOut(0,0,s);
for _y:=0 to _b.Height-1 do begin
Row:=_b.ScanLine[_y];
used:=true;
for _x:=_B.Width-1 downto 0 do
if used then begin
if (Row[_x].rgbtRed=0) then begin
used:=false;
if _r.Right<_x then _R.Right:=_x;
end;
end;
used:=true;
for _x:=0 to _B.Width-1 do
if used then begin
if (Row[_x].rgbtRed=0) then begin
used:=false;
if _r.Left>_x then _R.Left:=_x;
end;
end;
used:=true;
for _x:=0 to _B.Width-1 do
if used then begin
if (Row[_x].rgbtRed=0)and(_R.Top>_y) then begin
used:=false;
_R.top:=_y;
end;
end;
used:=true;
for _x:=0 to _B.Width-1 do
if used then begin
if (Row[_x].rgbtRed=0)and(_R.Bottom<_y) then begin
used:=false;
_R.Bottom:=_y;
end;
end;
end;
finally
_B.Free;
end;
end;
Всем спасибо!
← →
Джо © (2005-10-08 19:44) [11]
> [10] Antonn © (08.10.05 18:22)
Хм. Все же, вариант, предложенный [9] MBo © -- гораздо лучше. Вот, например, на его основе можно написать следующую функцию:
function GetStringRect (const AString: string; const X,Y: Integer; AFont: TFont): TRect;
var
DC: HDC;
RGN: HRGN;
begin
DC := CreateCompatibleDC(0);
Win32Check(DC<>0);
try
SelectObject(DC, AFont.Handle);
Win32Check(BeginPath(DC));
try
TextOut(DC,X,Y,PChar(AString),Length(AString));
finally
EndPath(DC);
end;
RGN := PathToRegion(DC);
Win32Check(RGN<>0);
try
GetRgnBox(RGN,Result);
finally
DeleteObject(RGN);
end;
finally
DeleteDC(DC);
end;
end;
Она, имхо, и более понятна и более универсальна, так как будет учитываться Escapement в шрифте (угол разворота), если он задан.
Вот демонстрация использования:
procedure TForm10.Button1Click(Sender: TObject);
var
Rct: TRect;
Size: TSize;
begin
Image1.Canvas.Font.Name := "Tahoma";
Image1.Canvas.Font.Size := 14;
Image1.Canvas.Font.Style := [fsItalic];
Rct := GetStringRect(Caption,10,20,Image1.Canvas.Font);
Image1.Canvas.Brush.Style := bsSolid;
Image1.Canvas.Brush.Color := clRed;
Image1.Canvas.FillRect(Rct);
Image1.Canvas.Brush.Style := bsClear;
Image1.Canvas.TextOut(10,20,Caption);
end;
← →
Fay © (2005-10-09 04:42) [12]DrawText + DT_CALCRECT
Ку?
← →
Джо © (2005-10-09 04:56) [13]
> [12] Fay © (09.10.05 04:42)
> Ку?
procedure RotateFont (AFont: TFont; Angle: Integer);
var
LogFont : TLogFont;
begin
GetObject(AFont.Handle, SizeOf(TLogFont), @LogFont);
LogFont.lfEscapement := Angle*10;
AFont.Handle := CreateFontIndirect(LogFont);
end;
procedure TForm10.Button1Click(Sender: TObject);
var
Rct: TRect;
Size: TSize;
begin
with Image1.Canvas.Font do
begin
Name := "Tahoma";
Size := 14;
Style := [fsItalic];
end;
RotateFont(Image1.Canvas.Font,25);
Rct.Left := 50;
Rct.Top := 50;
if DrawText(Image1.Canvas.Handle,PChar(Caption),Length(Caption),Rct,
DT_SINGLELINE or DT_CALCRECT) = 0 then
RaiseLastOSError;
Image1.Canvas.Brush.Style := bsSolid;
Image1.Canvas.Brush.Color := clRed;
Image1.Canvas.FillRect(Rct);
Image1.Canvas.Brush.Style := bsClear;
Image1.Canvas.TextOut(50,50,Caption);
end;
Кю! ;-)
← →
wicked © (2005-10-09 23:46) [14]GetFontLanguageInfo + GetCharacterPlacement.... без извращений с рендерингом в битмап.... учитывает kerning pairs, лигатуры и прочие трутайповые фишечки....
выдаст всё, даже рОдную маму... :)
ЗЫ легких путей нету... есть еще более сложные.... подробности в msdn...
← →
wicked © (2005-10-09 23:49) [15]ЗЗЫ афаир, [14] не поддерживает вращение шрифтов....
← →
Джо © (2005-10-10 00:32) [16]
> [15] wicked © (09.10.05 23:49)
> ЗЗЫ афаир, [14] не поддерживает вращение шрифтов....
ЗЫ. Зато [11] - поддерживает ;-)
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.10.30;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.046 c